From dcc5a08c92d7752fbcd78cd8a39d5851a77ee718 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 3 Jan 2023 12:30:33 +0000 Subject: [PATCH 001/196] Rudimentary pkg and folder-per-persion docs --- spec/{ => 2022.12}/API_specification/array_object.rst | 0 spec/{ => 2022.12}/API_specification/broadcasting.rst | 0 spec/{ => 2022.12}/API_specification/constants.rst | 0 spec/{ => 2022.12}/API_specification/creation_functions.rst | 0 spec/{ => 2022.12}/API_specification/data_type_functions.rst | 0 spec/{ => 2022.12}/API_specification/data_types.rst | 0 spec/{ => 2022.12}/API_specification/elementwise_functions.rst | 0 .../API_specification/function_and_method_signatures.rst | 0 spec/{ => 2022.12}/API_specification/index.rst | 0 spec/{ => 2022.12}/API_specification/indexing.rst | 0 spec/{ => 2022.12}/API_specification/indexing_functions.rst | 0 spec/{ => 2022.12}/API_specification/linear_algebra_functions.rst | 0 spec/{ => 2022.12}/API_specification/manipulation_functions.rst | 0 spec/{ => 2022.12}/API_specification/searching_functions.rst | 0 spec/{ => 2022.12}/API_specification/set_functions.rst | 0 spec/{ => 2022.12}/API_specification/sorting_functions.rst | 0 spec/{ => 2022.12}/API_specification/statistical_functions.rst | 0 spec/{ => 2022.12}/API_specification/type_promotion.rst | 0 spec/{ => 2022.12}/API_specification/utility_functions.rst | 0 spec/{ => 2022.12}/API_specification/version.rst | 0 spec/{ => 2022.12}/assumptions.md | 0 spec/{ => 2022.12}/benchmark_suite.md | 0 spec/{ => 2022.12}/changelog.rst | 0 spec/{ => 2022.12}/design_topics/C_API.rst | 0 spec/{ => 2022.12}/design_topics/accuracy.rst | 0 spec/{ => 2022.12}/design_topics/complex_numbers.rst | 0 spec/{ => 2022.12}/design_topics/copies_views_and_mutation.rst | 0 spec/{ => 2022.12}/design_topics/data_dependent_output_shapes.rst | 0 spec/{ => 2022.12}/design_topics/data_interchange.rst | 0 spec/{ => 2022.12}/design_topics/device_support.rst | 0 spec/{ => 2022.12}/design_topics/index.rst | 0 spec/{ => 2022.12}/design_topics/parallelism.rst | 0 spec/{ => 2022.12}/design_topics/static_typing.rst | 0 spec/{ => 2022.12}/extensions/fourier_transform_functions.rst | 0 spec/{ => 2022.12}/extensions/index.rst | 0 spec/{ => 2022.12}/extensions/linear_algebra_functions.rst | 0 spec/{ => 2022.12}/future_API_evolution.md | 0 spec/{ => 2022.12}/index.rst | 0 spec/{ => 2022.12}/purpose_and_scope.md | 0 spec/{ => 2022.12}/usage_data.md | 0 spec/{ => 2022.12}/use_cases.md | 0 spec/{ => 2022.12}/verification_test_suite.md | 0 .../array_api => src/array_api_stubs/_2022_12}/__init__.py | 0 .../array_api => src/array_api_stubs/_2022_12}/_types.py | 0 .../array_api => src/array_api_stubs/_2022_12}/array_object.py | 0 .../array_api => src/array_api_stubs/_2022_12}/constants.py | 0 .../array_api_stubs/_2022_12}/creation_functions.py | 0 .../array_api_stubs/_2022_12}/data_type_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/data_types.py | 0 .../array_api_stubs/_2022_12}/elementwise_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/fft.py | 0 .../array_api_stubs/_2022_12}/indexing_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/linalg.py | 0 .../array_api_stubs/_2022_12}/linear_algebra_functions.py | 0 .../array_api_stubs/_2022_12}/manipulation_functions.py | 0 .../array_api_stubs/_2022_12}/searching_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/set_functions.py | 0 .../array_api_stubs/_2022_12}/sorting_functions.py | 0 .../array_api_stubs/_2022_12}/statistical_functions.py | 0 .../array_api_stubs/_2022_12}/utility_functions.py | 0 60 files changed, 0 insertions(+), 0 deletions(-) rename spec/{ => 2022.12}/API_specification/array_object.rst (100%) rename spec/{ => 2022.12}/API_specification/broadcasting.rst (100%) rename spec/{ => 2022.12}/API_specification/constants.rst (100%) rename spec/{ => 2022.12}/API_specification/creation_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/data_type_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/data_types.rst (100%) rename spec/{ => 2022.12}/API_specification/elementwise_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/function_and_method_signatures.rst (100%) rename spec/{ => 2022.12}/API_specification/index.rst (100%) rename spec/{ => 2022.12}/API_specification/indexing.rst (100%) rename spec/{ => 2022.12}/API_specification/indexing_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/linear_algebra_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/manipulation_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/searching_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/set_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/sorting_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/statistical_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/type_promotion.rst (100%) rename spec/{ => 2022.12}/API_specification/utility_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/version.rst (100%) rename spec/{ => 2022.12}/assumptions.md (100%) rename spec/{ => 2022.12}/benchmark_suite.md (100%) rename spec/{ => 2022.12}/changelog.rst (100%) rename spec/{ => 2022.12}/design_topics/C_API.rst (100%) rename spec/{ => 2022.12}/design_topics/accuracy.rst (100%) rename spec/{ => 2022.12}/design_topics/complex_numbers.rst (100%) rename spec/{ => 2022.12}/design_topics/copies_views_and_mutation.rst (100%) rename spec/{ => 2022.12}/design_topics/data_dependent_output_shapes.rst (100%) rename spec/{ => 2022.12}/design_topics/data_interchange.rst (100%) rename spec/{ => 2022.12}/design_topics/device_support.rst (100%) rename spec/{ => 2022.12}/design_topics/index.rst (100%) rename spec/{ => 2022.12}/design_topics/parallelism.rst (100%) rename spec/{ => 2022.12}/design_topics/static_typing.rst (100%) rename spec/{ => 2022.12}/extensions/fourier_transform_functions.rst (100%) rename spec/{ => 2022.12}/extensions/index.rst (100%) rename spec/{ => 2022.12}/extensions/linear_algebra_functions.rst (100%) rename spec/{ => 2022.12}/future_API_evolution.md (100%) rename spec/{ => 2022.12}/index.rst (100%) rename spec/{ => 2022.12}/purpose_and_scope.md (100%) rename spec/{ => 2022.12}/usage_data.md (100%) rename spec/{ => 2022.12}/use_cases.md (100%) rename spec/{ => 2022.12}/verification_test_suite.md (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/__init__.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/_types.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/array_object.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/constants.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/creation_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/data_type_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/data_types.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/elementwise_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/fft.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/indexing_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/linalg.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/linear_algebra_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/manipulation_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/searching_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/set_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/sorting_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/statistical_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/utility_functions.py (100%) diff --git a/spec/API_specification/array_object.rst b/spec/2022.12/API_specification/array_object.rst similarity index 100% rename from spec/API_specification/array_object.rst rename to spec/2022.12/API_specification/array_object.rst diff --git a/spec/API_specification/broadcasting.rst b/spec/2022.12/API_specification/broadcasting.rst similarity index 100% rename from spec/API_specification/broadcasting.rst rename to spec/2022.12/API_specification/broadcasting.rst diff --git a/spec/API_specification/constants.rst b/spec/2022.12/API_specification/constants.rst similarity index 100% rename from spec/API_specification/constants.rst rename to spec/2022.12/API_specification/constants.rst diff --git a/spec/API_specification/creation_functions.rst b/spec/2022.12/API_specification/creation_functions.rst similarity index 100% rename from spec/API_specification/creation_functions.rst rename to spec/2022.12/API_specification/creation_functions.rst diff --git a/spec/API_specification/data_type_functions.rst b/spec/2022.12/API_specification/data_type_functions.rst similarity index 100% rename from spec/API_specification/data_type_functions.rst rename to spec/2022.12/API_specification/data_type_functions.rst diff --git a/spec/API_specification/data_types.rst b/spec/2022.12/API_specification/data_types.rst similarity index 100% rename from spec/API_specification/data_types.rst rename to spec/2022.12/API_specification/data_types.rst diff --git a/spec/API_specification/elementwise_functions.rst b/spec/2022.12/API_specification/elementwise_functions.rst similarity index 100% rename from spec/API_specification/elementwise_functions.rst rename to spec/2022.12/API_specification/elementwise_functions.rst diff --git a/spec/API_specification/function_and_method_signatures.rst b/spec/2022.12/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/API_specification/function_and_method_signatures.rst rename to spec/2022.12/API_specification/function_and_method_signatures.rst diff --git a/spec/API_specification/index.rst b/spec/2022.12/API_specification/index.rst similarity index 100% rename from spec/API_specification/index.rst rename to spec/2022.12/API_specification/index.rst diff --git a/spec/API_specification/indexing.rst b/spec/2022.12/API_specification/indexing.rst similarity index 100% rename from spec/API_specification/indexing.rst rename to spec/2022.12/API_specification/indexing.rst diff --git a/spec/API_specification/indexing_functions.rst b/spec/2022.12/API_specification/indexing_functions.rst similarity index 100% rename from spec/API_specification/indexing_functions.rst rename to spec/2022.12/API_specification/indexing_functions.rst diff --git a/spec/API_specification/linear_algebra_functions.rst b/spec/2022.12/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/API_specification/linear_algebra_functions.rst rename to spec/2022.12/API_specification/linear_algebra_functions.rst diff --git a/spec/API_specification/manipulation_functions.rst b/spec/2022.12/API_specification/manipulation_functions.rst similarity index 100% rename from spec/API_specification/manipulation_functions.rst rename to spec/2022.12/API_specification/manipulation_functions.rst diff --git a/spec/API_specification/searching_functions.rst b/spec/2022.12/API_specification/searching_functions.rst similarity index 100% rename from spec/API_specification/searching_functions.rst rename to spec/2022.12/API_specification/searching_functions.rst diff --git a/spec/API_specification/set_functions.rst b/spec/2022.12/API_specification/set_functions.rst similarity index 100% rename from spec/API_specification/set_functions.rst rename to spec/2022.12/API_specification/set_functions.rst diff --git a/spec/API_specification/sorting_functions.rst b/spec/2022.12/API_specification/sorting_functions.rst similarity index 100% rename from spec/API_specification/sorting_functions.rst rename to spec/2022.12/API_specification/sorting_functions.rst diff --git a/spec/API_specification/statistical_functions.rst b/spec/2022.12/API_specification/statistical_functions.rst similarity index 100% rename from spec/API_specification/statistical_functions.rst rename to spec/2022.12/API_specification/statistical_functions.rst diff --git a/spec/API_specification/type_promotion.rst b/spec/2022.12/API_specification/type_promotion.rst similarity index 100% rename from spec/API_specification/type_promotion.rst rename to spec/2022.12/API_specification/type_promotion.rst diff --git a/spec/API_specification/utility_functions.rst b/spec/2022.12/API_specification/utility_functions.rst similarity index 100% rename from spec/API_specification/utility_functions.rst rename to spec/2022.12/API_specification/utility_functions.rst diff --git a/spec/API_specification/version.rst b/spec/2022.12/API_specification/version.rst similarity index 100% rename from spec/API_specification/version.rst rename to spec/2022.12/API_specification/version.rst diff --git a/spec/assumptions.md b/spec/2022.12/assumptions.md similarity index 100% rename from spec/assumptions.md rename to spec/2022.12/assumptions.md diff --git a/spec/benchmark_suite.md b/spec/2022.12/benchmark_suite.md similarity index 100% rename from spec/benchmark_suite.md rename to spec/2022.12/benchmark_suite.md diff --git a/spec/changelog.rst b/spec/2022.12/changelog.rst similarity index 100% rename from spec/changelog.rst rename to spec/2022.12/changelog.rst diff --git a/spec/design_topics/C_API.rst b/spec/2022.12/design_topics/C_API.rst similarity index 100% rename from spec/design_topics/C_API.rst rename to spec/2022.12/design_topics/C_API.rst diff --git a/spec/design_topics/accuracy.rst b/spec/2022.12/design_topics/accuracy.rst similarity index 100% rename from spec/design_topics/accuracy.rst rename to spec/2022.12/design_topics/accuracy.rst diff --git a/spec/design_topics/complex_numbers.rst b/spec/2022.12/design_topics/complex_numbers.rst similarity index 100% rename from spec/design_topics/complex_numbers.rst rename to spec/2022.12/design_topics/complex_numbers.rst diff --git a/spec/design_topics/copies_views_and_mutation.rst b/spec/2022.12/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/design_topics/copies_views_and_mutation.rst rename to spec/2022.12/design_topics/copies_views_and_mutation.rst diff --git a/spec/design_topics/data_dependent_output_shapes.rst b/spec/2022.12/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/design_topics/data_dependent_output_shapes.rst rename to spec/2022.12/design_topics/data_dependent_output_shapes.rst diff --git a/spec/design_topics/data_interchange.rst b/spec/2022.12/design_topics/data_interchange.rst similarity index 100% rename from spec/design_topics/data_interchange.rst rename to spec/2022.12/design_topics/data_interchange.rst diff --git a/spec/design_topics/device_support.rst b/spec/2022.12/design_topics/device_support.rst similarity index 100% rename from spec/design_topics/device_support.rst rename to spec/2022.12/design_topics/device_support.rst diff --git a/spec/design_topics/index.rst b/spec/2022.12/design_topics/index.rst similarity index 100% rename from spec/design_topics/index.rst rename to spec/2022.12/design_topics/index.rst diff --git a/spec/design_topics/parallelism.rst b/spec/2022.12/design_topics/parallelism.rst similarity index 100% rename from spec/design_topics/parallelism.rst rename to spec/2022.12/design_topics/parallelism.rst diff --git a/spec/design_topics/static_typing.rst b/spec/2022.12/design_topics/static_typing.rst similarity index 100% rename from spec/design_topics/static_typing.rst rename to spec/2022.12/design_topics/static_typing.rst diff --git a/spec/extensions/fourier_transform_functions.rst b/spec/2022.12/extensions/fourier_transform_functions.rst similarity index 100% rename from spec/extensions/fourier_transform_functions.rst rename to spec/2022.12/extensions/fourier_transform_functions.rst diff --git a/spec/extensions/index.rst b/spec/2022.12/extensions/index.rst similarity index 100% rename from spec/extensions/index.rst rename to spec/2022.12/extensions/index.rst diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/2022.12/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/extensions/linear_algebra_functions.rst rename to spec/2022.12/extensions/linear_algebra_functions.rst diff --git a/spec/future_API_evolution.md b/spec/2022.12/future_API_evolution.md similarity index 100% rename from spec/future_API_evolution.md rename to spec/2022.12/future_API_evolution.md diff --git a/spec/index.rst b/spec/2022.12/index.rst similarity index 100% rename from spec/index.rst rename to spec/2022.12/index.rst diff --git a/spec/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md similarity index 100% rename from spec/purpose_and_scope.md rename to spec/2022.12/purpose_and_scope.md diff --git a/spec/usage_data.md b/spec/2022.12/usage_data.md similarity index 100% rename from spec/usage_data.md rename to spec/2022.12/usage_data.md diff --git a/spec/use_cases.md b/spec/2022.12/use_cases.md similarity index 100% rename from spec/use_cases.md rename to spec/2022.12/use_cases.md diff --git a/spec/verification_test_suite.md b/spec/2022.12/verification_test_suite.md similarity index 100% rename from spec/verification_test_suite.md rename to spec/2022.12/verification_test_suite.md diff --git a/spec/API_specification/array_api/__init__.py b/src/array_api_stubs/_2022_12/__init__.py similarity index 100% rename from spec/API_specification/array_api/__init__.py rename to src/array_api_stubs/_2022_12/__init__.py diff --git a/spec/API_specification/array_api/_types.py b/src/array_api_stubs/_2022_12/_types.py similarity index 100% rename from spec/API_specification/array_api/_types.py rename to src/array_api_stubs/_2022_12/_types.py diff --git a/spec/API_specification/array_api/array_object.py b/src/array_api_stubs/_2022_12/array_object.py similarity index 100% rename from spec/API_specification/array_api/array_object.py rename to src/array_api_stubs/_2022_12/array_object.py diff --git a/spec/API_specification/array_api/constants.py b/src/array_api_stubs/_2022_12/constants.py similarity index 100% rename from spec/API_specification/array_api/constants.py rename to src/array_api_stubs/_2022_12/constants.py diff --git a/spec/API_specification/array_api/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py similarity index 100% rename from spec/API_specification/array_api/creation_functions.py rename to src/array_api_stubs/_2022_12/creation_functions.py diff --git a/spec/API_specification/array_api/data_type_functions.py b/src/array_api_stubs/_2022_12/data_type_functions.py similarity index 100% rename from spec/API_specification/array_api/data_type_functions.py rename to src/array_api_stubs/_2022_12/data_type_functions.py diff --git a/spec/API_specification/array_api/data_types.py b/src/array_api_stubs/_2022_12/data_types.py similarity index 100% rename from spec/API_specification/array_api/data_types.py rename to src/array_api_stubs/_2022_12/data_types.py diff --git a/spec/API_specification/array_api/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py similarity index 100% rename from spec/API_specification/array_api/elementwise_functions.py rename to src/array_api_stubs/_2022_12/elementwise_functions.py diff --git a/spec/API_specification/array_api/fft.py b/src/array_api_stubs/_2022_12/fft.py similarity index 100% rename from spec/API_specification/array_api/fft.py rename to src/array_api_stubs/_2022_12/fft.py diff --git a/spec/API_specification/array_api/indexing_functions.py b/src/array_api_stubs/_2022_12/indexing_functions.py similarity index 100% rename from spec/API_specification/array_api/indexing_functions.py rename to src/array_api_stubs/_2022_12/indexing_functions.py diff --git a/spec/API_specification/array_api/linalg.py b/src/array_api_stubs/_2022_12/linalg.py similarity index 100% rename from spec/API_specification/array_api/linalg.py rename to src/array_api_stubs/_2022_12/linalg.py diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py similarity index 100% rename from spec/API_specification/array_api/linear_algebra_functions.py rename to src/array_api_stubs/_2022_12/linear_algebra_functions.py diff --git a/spec/API_specification/array_api/manipulation_functions.py b/src/array_api_stubs/_2022_12/manipulation_functions.py similarity index 100% rename from spec/API_specification/array_api/manipulation_functions.py rename to src/array_api_stubs/_2022_12/manipulation_functions.py diff --git a/spec/API_specification/array_api/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py similarity index 100% rename from spec/API_specification/array_api/searching_functions.py rename to src/array_api_stubs/_2022_12/searching_functions.py diff --git a/spec/API_specification/array_api/set_functions.py b/src/array_api_stubs/_2022_12/set_functions.py similarity index 100% rename from spec/API_specification/array_api/set_functions.py rename to src/array_api_stubs/_2022_12/set_functions.py diff --git a/spec/API_specification/array_api/sorting_functions.py b/src/array_api_stubs/_2022_12/sorting_functions.py similarity index 100% rename from spec/API_specification/array_api/sorting_functions.py rename to src/array_api_stubs/_2022_12/sorting_functions.py diff --git a/spec/API_specification/array_api/statistical_functions.py b/src/array_api_stubs/_2022_12/statistical_functions.py similarity index 100% rename from spec/API_specification/array_api/statistical_functions.py rename to src/array_api_stubs/_2022_12/statistical_functions.py diff --git a/spec/API_specification/array_api/utility_functions.py b/src/array_api_stubs/_2022_12/utility_functions.py similarity index 100% rename from spec/API_specification/array_api/utility_functions.py rename to src/array_api_stubs/_2022_12/utility_functions.py From 314d1a9297ba602e0eefa8a805b69310c7f1409b Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 3 Jan 2023 17:08:29 +0000 Subject: [PATCH 002/196] Move old `2021.12` docs to respective sub-folders --- spec/{ => 2021.12}/API_specification/array_object.rst | 0 spec/{ => 2021.12}/API_specification/broadcasting.rst | 0 spec/{ => 2021.12}/API_specification/constants.rst | 0 spec/{ => 2021.12}/API_specification/creation_functions.rst | 0 spec/{ => 2021.12}/API_specification/data_type_functions.rst | 0 spec/{ => 2021.12}/API_specification/data_types.rst | 0 spec/{ => 2021.12}/API_specification/elementwise_functions.rst | 0 .../API_specification/function_and_method_signatures.rst | 0 spec/{ => 2021.12}/API_specification/index.rst | 0 spec/{ => 2021.12}/API_specification/indexing.rst | 0 spec/{ => 2021.12}/API_specification/linear_algebra_functions.rst | 0 spec/{ => 2021.12}/API_specification/manipulation_functions.rst | 0 spec/{ => 2021.12}/API_specification/searching_functions.rst | 0 spec/{ => 2021.12}/API_specification/set_functions.rst | 0 spec/{ => 2021.12}/API_specification/sorting_functions.rst | 0 spec/{ => 2021.12}/API_specification/statistical_functions.rst | 0 spec/{ => 2021.12}/API_specification/type_promotion.rst | 0 spec/{ => 2021.12}/API_specification/utility_functions.rst | 0 spec/{ => 2021.12}/assumptions.md | 0 spec/{ => 2021.12}/benchmark_suite.md | 0 spec/{ => 2021.12}/conf.py | 0 spec/{ => 2021.12}/design_topics/C_API.rst | 0 spec/{ => 2021.12}/design_topics/accuracy.rst | 0 spec/{ => 2021.12}/design_topics/copies_views_and_mutation.rst | 0 spec/{ => 2021.12}/design_topics/data_dependent_output_shapes.rst | 0 spec/{ => 2021.12}/design_topics/data_interchange.rst | 0 spec/{ => 2021.12}/design_topics/device_support.rst | 0 spec/{ => 2021.12}/design_topics/index.rst | 0 spec/{ => 2021.12}/design_topics/parallelism.rst | 0 spec/{ => 2021.12}/design_topics/static_typing.rst | 0 spec/{ => 2021.12}/extensions/index.rst | 0 spec/{ => 2021.12}/extensions/linear_algebra_functions.rst | 0 spec/{ => 2021.12}/future_API_evolution.md | 0 spec/{ => 2021.12}/index.rst | 0 spec/{ => 2021.12}/purpose_and_scope.md | 0 spec/{ => 2021.12}/usage_data.md | 0 spec/{ => 2021.12}/use_cases.md | 0 spec/{ => 2021.12}/verification_test_suite.md | 0 .../signatures => src/array_api_stubs/_2021_12}/__init__.py | 0 .../signatures => src/array_api_stubs/_2021_12}/_types.py | 0 .../signatures => src/array_api_stubs/_2021_12}/array_object.py | 0 .../signatures => src/array_api_stubs/_2021_12}/constants.py | 0 .../array_api_stubs/_2021_12}/creation_functions.py | 0 .../array_api_stubs/_2021_12}/data_type_functions.py | 0 .../signatures => src/array_api_stubs/_2021_12}/data_types.py | 0 .../array_api_stubs/_2021_12}/elementwise_functions.py | 0 .../signatures => src/array_api_stubs/_2021_12}/linalg.py | 0 .../array_api_stubs/_2021_12}/linear_algebra_functions.py | 0 .../array_api_stubs/_2021_12}/manipulation_functions.py | 0 .../array_api_stubs/_2021_12}/searching_functions.py | 0 .../signatures => src/array_api_stubs/_2021_12}/set_functions.py | 0 .../array_api_stubs/_2021_12}/sorting_functions.py | 0 .../array_api_stubs/_2021_12}/statistical_functions.py | 0 .../array_api_stubs/_2021_12}/utility_functions.py | 0 54 files changed, 0 insertions(+), 0 deletions(-) rename spec/{ => 2021.12}/API_specification/array_object.rst (100%) rename spec/{ => 2021.12}/API_specification/broadcasting.rst (100%) rename spec/{ => 2021.12}/API_specification/constants.rst (100%) rename spec/{ => 2021.12}/API_specification/creation_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/data_type_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/data_types.rst (100%) rename spec/{ => 2021.12}/API_specification/elementwise_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/function_and_method_signatures.rst (100%) rename spec/{ => 2021.12}/API_specification/index.rst (100%) rename spec/{ => 2021.12}/API_specification/indexing.rst (100%) rename spec/{ => 2021.12}/API_specification/linear_algebra_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/manipulation_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/searching_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/set_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/sorting_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/statistical_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/type_promotion.rst (100%) rename spec/{ => 2021.12}/API_specification/utility_functions.rst (100%) rename spec/{ => 2021.12}/assumptions.md (100%) rename spec/{ => 2021.12}/benchmark_suite.md (100%) rename spec/{ => 2021.12}/conf.py (100%) rename spec/{ => 2021.12}/design_topics/C_API.rst (100%) rename spec/{ => 2021.12}/design_topics/accuracy.rst (100%) rename spec/{ => 2021.12}/design_topics/copies_views_and_mutation.rst (100%) rename spec/{ => 2021.12}/design_topics/data_dependent_output_shapes.rst (100%) rename spec/{ => 2021.12}/design_topics/data_interchange.rst (100%) rename spec/{ => 2021.12}/design_topics/device_support.rst (100%) rename spec/{ => 2021.12}/design_topics/index.rst (100%) rename spec/{ => 2021.12}/design_topics/parallelism.rst (100%) rename spec/{ => 2021.12}/design_topics/static_typing.rst (100%) rename spec/{ => 2021.12}/extensions/index.rst (100%) rename spec/{ => 2021.12}/extensions/linear_algebra_functions.rst (100%) rename spec/{ => 2021.12}/future_API_evolution.md (100%) rename spec/{ => 2021.12}/index.rst (100%) rename spec/{ => 2021.12}/purpose_and_scope.md (100%) rename spec/{ => 2021.12}/usage_data.md (100%) rename spec/{ => 2021.12}/use_cases.md (100%) rename spec/{ => 2021.12}/verification_test_suite.md (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/__init__.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/_types.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/array_object.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/constants.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/creation_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/data_type_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/data_types.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/elementwise_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/linalg.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/linear_algebra_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/manipulation_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/searching_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/set_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/sorting_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/statistical_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/utility_functions.py (100%) diff --git a/spec/API_specification/array_object.rst b/spec/2021.12/API_specification/array_object.rst similarity index 100% rename from spec/API_specification/array_object.rst rename to spec/2021.12/API_specification/array_object.rst diff --git a/spec/API_specification/broadcasting.rst b/spec/2021.12/API_specification/broadcasting.rst similarity index 100% rename from spec/API_specification/broadcasting.rst rename to spec/2021.12/API_specification/broadcasting.rst diff --git a/spec/API_specification/constants.rst b/spec/2021.12/API_specification/constants.rst similarity index 100% rename from spec/API_specification/constants.rst rename to spec/2021.12/API_specification/constants.rst diff --git a/spec/API_specification/creation_functions.rst b/spec/2021.12/API_specification/creation_functions.rst similarity index 100% rename from spec/API_specification/creation_functions.rst rename to spec/2021.12/API_specification/creation_functions.rst diff --git a/spec/API_specification/data_type_functions.rst b/spec/2021.12/API_specification/data_type_functions.rst similarity index 100% rename from spec/API_specification/data_type_functions.rst rename to spec/2021.12/API_specification/data_type_functions.rst diff --git a/spec/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst similarity index 100% rename from spec/API_specification/data_types.rst rename to spec/2021.12/API_specification/data_types.rst diff --git a/spec/API_specification/elementwise_functions.rst b/spec/2021.12/API_specification/elementwise_functions.rst similarity index 100% rename from spec/API_specification/elementwise_functions.rst rename to spec/2021.12/API_specification/elementwise_functions.rst diff --git a/spec/API_specification/function_and_method_signatures.rst b/spec/2021.12/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/API_specification/function_and_method_signatures.rst rename to spec/2021.12/API_specification/function_and_method_signatures.rst diff --git a/spec/API_specification/index.rst b/spec/2021.12/API_specification/index.rst similarity index 100% rename from spec/API_specification/index.rst rename to spec/2021.12/API_specification/index.rst diff --git a/spec/API_specification/indexing.rst b/spec/2021.12/API_specification/indexing.rst similarity index 100% rename from spec/API_specification/indexing.rst rename to spec/2021.12/API_specification/indexing.rst diff --git a/spec/API_specification/linear_algebra_functions.rst b/spec/2021.12/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/API_specification/linear_algebra_functions.rst rename to spec/2021.12/API_specification/linear_algebra_functions.rst diff --git a/spec/API_specification/manipulation_functions.rst b/spec/2021.12/API_specification/manipulation_functions.rst similarity index 100% rename from spec/API_specification/manipulation_functions.rst rename to spec/2021.12/API_specification/manipulation_functions.rst diff --git a/spec/API_specification/searching_functions.rst b/spec/2021.12/API_specification/searching_functions.rst similarity index 100% rename from spec/API_specification/searching_functions.rst rename to spec/2021.12/API_specification/searching_functions.rst diff --git a/spec/API_specification/set_functions.rst b/spec/2021.12/API_specification/set_functions.rst similarity index 100% rename from spec/API_specification/set_functions.rst rename to spec/2021.12/API_specification/set_functions.rst diff --git a/spec/API_specification/sorting_functions.rst b/spec/2021.12/API_specification/sorting_functions.rst similarity index 100% rename from spec/API_specification/sorting_functions.rst rename to spec/2021.12/API_specification/sorting_functions.rst diff --git a/spec/API_specification/statistical_functions.rst b/spec/2021.12/API_specification/statistical_functions.rst similarity index 100% rename from spec/API_specification/statistical_functions.rst rename to spec/2021.12/API_specification/statistical_functions.rst diff --git a/spec/API_specification/type_promotion.rst b/spec/2021.12/API_specification/type_promotion.rst similarity index 100% rename from spec/API_specification/type_promotion.rst rename to spec/2021.12/API_specification/type_promotion.rst diff --git a/spec/API_specification/utility_functions.rst b/spec/2021.12/API_specification/utility_functions.rst similarity index 100% rename from spec/API_specification/utility_functions.rst rename to spec/2021.12/API_specification/utility_functions.rst diff --git a/spec/assumptions.md b/spec/2021.12/assumptions.md similarity index 100% rename from spec/assumptions.md rename to spec/2021.12/assumptions.md diff --git a/spec/benchmark_suite.md b/spec/2021.12/benchmark_suite.md similarity index 100% rename from spec/benchmark_suite.md rename to spec/2021.12/benchmark_suite.md diff --git a/spec/conf.py b/spec/2021.12/conf.py similarity index 100% rename from spec/conf.py rename to spec/2021.12/conf.py diff --git a/spec/design_topics/C_API.rst b/spec/2021.12/design_topics/C_API.rst similarity index 100% rename from spec/design_topics/C_API.rst rename to spec/2021.12/design_topics/C_API.rst diff --git a/spec/design_topics/accuracy.rst b/spec/2021.12/design_topics/accuracy.rst similarity index 100% rename from spec/design_topics/accuracy.rst rename to spec/2021.12/design_topics/accuracy.rst diff --git a/spec/design_topics/copies_views_and_mutation.rst b/spec/2021.12/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/design_topics/copies_views_and_mutation.rst rename to spec/2021.12/design_topics/copies_views_and_mutation.rst diff --git a/spec/design_topics/data_dependent_output_shapes.rst b/spec/2021.12/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/design_topics/data_dependent_output_shapes.rst rename to spec/2021.12/design_topics/data_dependent_output_shapes.rst diff --git a/spec/design_topics/data_interchange.rst b/spec/2021.12/design_topics/data_interchange.rst similarity index 100% rename from spec/design_topics/data_interchange.rst rename to spec/2021.12/design_topics/data_interchange.rst diff --git a/spec/design_topics/device_support.rst b/spec/2021.12/design_topics/device_support.rst similarity index 100% rename from spec/design_topics/device_support.rst rename to spec/2021.12/design_topics/device_support.rst diff --git a/spec/design_topics/index.rst b/spec/2021.12/design_topics/index.rst similarity index 100% rename from spec/design_topics/index.rst rename to spec/2021.12/design_topics/index.rst diff --git a/spec/design_topics/parallelism.rst b/spec/2021.12/design_topics/parallelism.rst similarity index 100% rename from spec/design_topics/parallelism.rst rename to spec/2021.12/design_topics/parallelism.rst diff --git a/spec/design_topics/static_typing.rst b/spec/2021.12/design_topics/static_typing.rst similarity index 100% rename from spec/design_topics/static_typing.rst rename to spec/2021.12/design_topics/static_typing.rst diff --git a/spec/extensions/index.rst b/spec/2021.12/extensions/index.rst similarity index 100% rename from spec/extensions/index.rst rename to spec/2021.12/extensions/index.rst diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/2021.12/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/extensions/linear_algebra_functions.rst rename to spec/2021.12/extensions/linear_algebra_functions.rst diff --git a/spec/future_API_evolution.md b/spec/2021.12/future_API_evolution.md similarity index 100% rename from spec/future_API_evolution.md rename to spec/2021.12/future_API_evolution.md diff --git a/spec/index.rst b/spec/2021.12/index.rst similarity index 100% rename from spec/index.rst rename to spec/2021.12/index.rst diff --git a/spec/purpose_and_scope.md b/spec/2021.12/purpose_and_scope.md similarity index 100% rename from spec/purpose_and_scope.md rename to spec/2021.12/purpose_and_scope.md diff --git a/spec/usage_data.md b/spec/2021.12/usage_data.md similarity index 100% rename from spec/usage_data.md rename to spec/2021.12/usage_data.md diff --git a/spec/use_cases.md b/spec/2021.12/use_cases.md similarity index 100% rename from spec/use_cases.md rename to spec/2021.12/use_cases.md diff --git a/spec/verification_test_suite.md b/spec/2021.12/verification_test_suite.md similarity index 100% rename from spec/verification_test_suite.md rename to spec/2021.12/verification_test_suite.md diff --git a/spec/API_specification/signatures/__init__.py b/src/array_api_stubs/_2021_12/__init__.py similarity index 100% rename from spec/API_specification/signatures/__init__.py rename to src/array_api_stubs/_2021_12/__init__.py diff --git a/spec/API_specification/signatures/_types.py b/src/array_api_stubs/_2021_12/_types.py similarity index 100% rename from spec/API_specification/signatures/_types.py rename to src/array_api_stubs/_2021_12/_types.py diff --git a/spec/API_specification/signatures/array_object.py b/src/array_api_stubs/_2021_12/array_object.py similarity index 100% rename from spec/API_specification/signatures/array_object.py rename to src/array_api_stubs/_2021_12/array_object.py diff --git a/spec/API_specification/signatures/constants.py b/src/array_api_stubs/_2021_12/constants.py similarity index 100% rename from spec/API_specification/signatures/constants.py rename to src/array_api_stubs/_2021_12/constants.py diff --git a/spec/API_specification/signatures/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py similarity index 100% rename from spec/API_specification/signatures/creation_functions.py rename to src/array_api_stubs/_2021_12/creation_functions.py diff --git a/spec/API_specification/signatures/data_type_functions.py b/src/array_api_stubs/_2021_12/data_type_functions.py similarity index 100% rename from spec/API_specification/signatures/data_type_functions.py rename to src/array_api_stubs/_2021_12/data_type_functions.py diff --git a/spec/API_specification/signatures/data_types.py b/src/array_api_stubs/_2021_12/data_types.py similarity index 100% rename from spec/API_specification/signatures/data_types.py rename to src/array_api_stubs/_2021_12/data_types.py diff --git a/spec/API_specification/signatures/elementwise_functions.py b/src/array_api_stubs/_2021_12/elementwise_functions.py similarity index 100% rename from spec/API_specification/signatures/elementwise_functions.py rename to src/array_api_stubs/_2021_12/elementwise_functions.py diff --git a/spec/API_specification/signatures/linalg.py b/src/array_api_stubs/_2021_12/linalg.py similarity index 100% rename from spec/API_specification/signatures/linalg.py rename to src/array_api_stubs/_2021_12/linalg.py diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/src/array_api_stubs/_2021_12/linear_algebra_functions.py similarity index 100% rename from spec/API_specification/signatures/linear_algebra_functions.py rename to src/array_api_stubs/_2021_12/linear_algebra_functions.py diff --git a/spec/API_specification/signatures/manipulation_functions.py b/src/array_api_stubs/_2021_12/manipulation_functions.py similarity index 100% rename from spec/API_specification/signatures/manipulation_functions.py rename to src/array_api_stubs/_2021_12/manipulation_functions.py diff --git a/spec/API_specification/signatures/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py similarity index 100% rename from spec/API_specification/signatures/searching_functions.py rename to src/array_api_stubs/_2021_12/searching_functions.py diff --git a/spec/API_specification/signatures/set_functions.py b/src/array_api_stubs/_2021_12/set_functions.py similarity index 100% rename from spec/API_specification/signatures/set_functions.py rename to src/array_api_stubs/_2021_12/set_functions.py diff --git a/spec/API_specification/signatures/sorting_functions.py b/src/array_api_stubs/_2021_12/sorting_functions.py similarity index 100% rename from spec/API_specification/signatures/sorting_functions.py rename to src/array_api_stubs/_2021_12/sorting_functions.py diff --git a/spec/API_specification/signatures/statistical_functions.py b/src/array_api_stubs/_2021_12/statistical_functions.py similarity index 100% rename from spec/API_specification/signatures/statistical_functions.py rename to src/array_api_stubs/_2021_12/statistical_functions.py diff --git a/spec/API_specification/signatures/utility_functions.py b/src/array_api_stubs/_2021_12/utility_functions.py similarity index 100% rename from spec/API_specification/signatures/utility_functions.py rename to src/array_api_stubs/_2021_12/utility_functions.py From f56de3c1777256e5727a6f73d2776af17686d754 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:20:15 +0000 Subject: [PATCH 003/196] Squashed previous all-versions work * Rudimentary `array_api_stubs` pkg and folder-per-version docs * Regex nitpick ignore for array types * Move `2021.12` docs to respective sub-folders * Fix autosummary by patching stub sub-modules in `conf.py` * Rudimentary build-all Makefile rule * Specify versions in `conf.py` * Use `versions.json` method for sphinx-material Otherwise don't think we can get links working on nested pages Notably this usually won't work locally - see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSRequestNotHttp * Update image paths to shared `_static/` * Use vars in `make build` definition * Expand regex used to identify unwanted type hint prefixes * Update `pages.yml` workflow * Store gh-pages `.gitignore` in `main` to be copied over * `_spec_conf.py` -> `_array_api_conf.py` * Basic package necessities * Replace `requirements.txt` with extra dependency `doc` * Basic local build guide * Update preview workflow * Remove out-of-date make things, new top-level Makefile * Minor `CONTRIBUTING.md` improvements * Basic `_array_api_conf.py` module docstring * Move quickstart to `README.md` * Use `array_api` as opposed to `signatures` for `2021.12` autodoc * More consistent Makefile * Introduce `_ghpages` to hold the non-Sphinx static files * Rudimentary spec release guide * Guide to preserve history for future spec releases --- .circleci/config.yml | 6 +- .github/workflows/pages.yml | 20 +-- .github/workflows/preview.yml | 2 +- .gitignore | 7 +- MANIFEST.in | 3 + Makefile | 22 ++++ PACKAGE.md | 9 ++ README.md | 116 ++++++++++++++++++ pyproject.toml | 30 +++++ requirements.txt | 7 -- spec/Makefile | 25 ---- spec/_ghpages/_gitignore.txt | 36 ++++++ spec/_ghpages/index.html | 10 ++ spec/_ghpages/versions.json | 5 + spec/draft/conf.py | 7 ++ spec/make.bat | 35 ------ src/_array_api_conf.py | 211 ++++++++++++++++++++++++++++++++ src/array_api_stubs/__init__.py | 2 + 18 files changed, 466 insertions(+), 87 deletions(-) create mode 100644 MANIFEST.in create mode 100644 Makefile create mode 100644 PACKAGE.md create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 spec/Makefile create mode 100644 spec/_ghpages/_gitignore.txt create mode 100644 spec/_ghpages/index.html create mode 100644 spec/_ghpages/versions.json create mode 100644 spec/draft/conf.py delete mode 100644 spec/make.bat create mode 100644 src/_array_api_conf.py create mode 100644 src/array_api_stubs/__init__.py diff --git a/.circleci/config.yml b/.circleci/config.yml index aab5a1744..cecae43c8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,10 +19,10 @@ jobs: name: build docs no_output_timeout: 25m command: | - pip install -r requirements.txt - sphinx-build -b html -WT --keep-going spec build/draft -d doctrees + pip install .[doc] + make - store_artifacts: - path: build/draft + path: _site/ workflows: version: 2 diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index fc8a97015..e615135d3 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -76,22 +76,14 @@ jobs: # Install dependencies: - name: 'Install dependencies' run: | - pip install -r ./requirements.txt + pip install .[doc] # Generate the documentation: - name: 'Build documentation' run: | # Turn warnings into errors and ensure .doctrees is not deployed: - sphinx-build -b html -WT --keep-going spec build/draft -d doctrees - - # Upload the build artifact: - - name: 'Upload build artifact' - uses: actions/upload-artifact@v2 - if: ${{ github.event_name == 'pull_request'}} - with: - name: html - path: build/ - if-no-files-found: error + export SPHINXOPTS="-b html -WT --keep-going -d doctrees" + make # Configure Git: - name: 'Configure Git' @@ -107,10 +99,10 @@ jobs: git checkout gh-pages timeout-minutes: 5 - # Copy build artifact: - - name: 'Copy build artifact' + - name: 'Copy build to root' run: | - rm -rf ./draft && cp -R ./build/draft ./draft + cp -R ./_site/* . + cp ./_site/.gitignore . timeout-minutes: 10 # Commit changes to: diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index cdfa3c57b..347dbfb8d 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -11,6 +11,6 @@ jobs: uses: larsoner/circleci-artifacts-redirector-action@master with: repo-token: ${{ secrets.GITHUB_TOKEN }} - artifact-path: 0/build/draft/index.html + artifact-path: 0/_site/draft/index.html circleci-jobs: build_page job-title: Check the rendered docs here! diff --git a/.gitignore b/.gitignore index 86bab2717..d4f538406 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ # SOFTWARE. #/ -spec/_build/ +_site/ doctrees/ build/ .vscode/ @@ -30,4 +30,7 @@ node_modules/ __pycache__/ *.pyc spec/**/generated -tmp/ \ No newline at end of file +tmp/ +*.egg-info/ +*.egg +dist/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..7616b26fd --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +exclude README.md +exclude src/_array_api_conf.py +include PACKAGE.md diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..451b9224c --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +# You can set these variables from the command line. +SPHINXOPTS ?= -W --keep-going +SOURCEDIR = spec +BUILDDIR = _site + +.PHONY: default clean build + +default: clean build + +clean: + -rm -rf $(BUILDDIR) + -find . -type d -name generated -exec rm -rf {} + + +build: + -mkdir -p $(BUILDDIR) + -cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" + -cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" + -cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" + -touch "$(BUILDDIR)/.nojekyll" + -sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) + -cp -r "$(BUILDDIR)/2021.12" "$(BUILDDIR)/latest" + -sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/PACKAGE.md b/PACKAGE.md new file mode 100644 index 000000000..199c4e2a2 --- /dev/null +++ b/PACKAGE.md @@ -0,0 +1,9 @@ +# Stubs for the array API standard + +Documentation specific to singular Python objects in the spec (i.e. functions, +methods and attributes) are infact represented by stub objects in the package +`array-api-stubs`. These stubs ultimately get rendered via the autodoc +capabilities in Sphinx. + +TODO: describe how `array-api-stubs` can be used for tooling, once it actually +has the capacity to do so. diff --git a/README.md b/README.md index d0d88ae4c..96edb338e 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,122 @@ These are relevant documents related to the content in this repository: See [CONTRIBUTING.md](CONTRIBUTING.md) for how to go about contributing to this array API standard. + +## Building docs locally + +The spec website comprises of multiple Sphinx docs (one for each spec version), +all of which exist in `spec/` and rely on the modules found in `src/` (most +notably `array_api_stubs`). To install these modules and the additional +dependencies of the Sphinx docs, you can use + +```sh +$ pip install -e .[doc] # ensure you install the dependencies extra "doc" +``` + +To build specific versions of the spec, run `sphinx-build` on the respective +folder in `spec/`, e.g. + +```sh +$ sphinx-build spec/draft/ _site/draft/ +``` + +To build the whole website, which includes every version of +the spec, you can utilize the `make` commands defined in `spec/Makefile`, e.g. + +```sh +$ make +$ ls _site/ +2021.12/ draft/ index.html latest/ versions.json +``` + + +## Making a spec release + +The Sphinx doc at `spec/draft/` should be where the in-development spec resides, +with `src/array_api_stubs/_draft/` containing its respective stubs. A spec +release should involve: + +* Renaming `src/array_api_stubs/_draft/` to `src/array_api_stubs/_YYYY_MM` +* Renaming `spec/draft/` to `spec/YYYY.MM` +* Updating `spec/YYYY.MM/conf.py` + + ```diff + ... + - from array_api_stubs import _draft as stubs_mod + + from array_api_stubs import _YYYY_MM as stubs_mod + ... + - release = "DRAFT" + + release = "YYYY.MM" + ... + ``` + +* Updating `spec/_ghpages/versions.json` + + ```diff + { + + "YYYY.MM": "YYYY.MM", + ... + ``` + +* Updating `Makefile` + + ```diff + ... + -sphinx-build "$(SOURCEDIR)/PREVIOUS.VER" "$(BUILDDIR)/PREVIOUS.VER" $(SPHINXOPTS) + + -sphinx-build "$(SOURCEDIR)/YYYY.MM" "$(BUILDDIR)/YYYY.MM" $(SPHINXOPTS) + - -cp -r "$(BUILDDIR)/PREVIOUS.VER" "$(BUILDDIR)/latest" + + -cp -r "$(BUILDDIR)/YYYY.MM" "$(BUILDDIR)/latest" + ... + ``` + +These changes should be committed and tagged. The next draft should then be +created. To preserve git history for both the new release and the next draft: + +1. Create and checkout to a new temporary branch. + + ```sh + $ git checkout -b tmp + ``` + +2. Make an empty commit. This is required so merging the temporary branch + (4.) is not automatic. + + ```sh + $ git commit --allow-empty -m "Empty commit for draft at YYYY.MM " + ``` + +3. Checkout back to the branch you are making a spec release in. + + ```sh + $ git checkout YYYY.MM-release + ``` + +4. Merge the temporary branch, specifying no commit and no fast-forwarding. + + ```sh + $ git merge --no-commit --no-ff tmp + Automatic merge went well; stopped before committing as requested + ``` + +5. Checkout the `spec/draft/` files from the temporary branch. + + ```sh + $ git checkout tmp -- spec/draft/ + ``` + +6. Commit your changes. + + ```sh + $ git commit -m "Copy YYYY.MM as draft with preserved git history" + ``` + +You can run `git blame` on both `spec/YYYY.MM` and `spec/draft` files to verify +we've preserved history. See this [StackOverflow question](https://stackoverflow.com/q/74365771/5193926) +for more background on the approach we use. + + + + ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..b8240a665 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,30 @@ +[project] +name = "array-api-stubs" +version = "0.0.2" +description = "Stubs for the array API standard" +authors = [] +license = {file = "LICENSE"} +readme = "PACKAGE.md" +requires-python = ">=3.8" +keywords = [] +classifiers = [] + +[project.urls] +Source = "https://github.com/data-apis/array-api/" +Documentation = "https://data-apis.org/array-api/" +Homepage = "https://data-apis.org/" + +[project.optional-dependencies] +doc = [ + "sphinx==4.3.0", + "sphinx-material==0.0.30", + "myst-parser", + "sphinx_markdown_tables", + "sphinx_copybutton", + "docutils<0.18", + "sphinx-math-dollar", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 230413784..000000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -sphinx==4.3.0 -sphinx-material==0.0.30 -myst-parser -sphinx_markdown_tables -sphinx_copybutton -docutils<0.18 -sphinx-math-dollar diff --git a/spec/Makefile b/spec/Makefile deleted file mode 100644 index e71fa39e1..000000000 --- a/spec/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -W --keep-going -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile clean - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -clean: - -rm -rf $(BUILDDIR) - -rm -rf "$(SOURCEDIR)/API_specification/generated" - -rm -rf "$(SOURCEDIR)/extensions/generated" diff --git a/spec/_ghpages/_gitignore.txt b/spec/_ghpages/_gitignore.txt new file mode 100644 index 000000000..4e7ddcaad --- /dev/null +++ b/spec/_ghpages/_gitignore.txt @@ -0,0 +1,36 @@ +#/ +# @license MIT +# +# Copyright (c) 2022 Python Data APIs Consortium. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#/ +# +# Note this file is not intended to be a .gitignore for the main branch, but to +# be copied into gh-pages branch. + +_site +build/ +doctrees/ +.vscode/ +node_modules/ +__pycache__/ +*.pyc +spec/**/generated/ +src/*.egg-info/ diff --git a/spec/_ghpages/index.html b/spec/_ghpages/index.html new file mode 100644 index 000000000..e209341a3 --- /dev/null +++ b/spec/_ghpages/index.html @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json new file mode 100644 index 000000000..5a6aa4692 --- /dev/null +++ b/spec/_ghpages/versions.json @@ -0,0 +1,5 @@ +{ + "2021.12": "2021.12", + "latest": "latest", + "draft": "draft" +} diff --git a/spec/draft/conf.py b/spec/draft/conf.py new file mode 100644 index 000000000..f3804e7ad --- /dev/null +++ b/spec/draft/conf.py @@ -0,0 +1,7 @@ +import sys + +from array_api_stubs import _draft as stubs_mod +from _array_api_conf import * + +release = "DRAFT" +sys.modules["array_api"] = stubs_mod diff --git a/spec/make.bat b/spec/make.bat deleted file mode 100644 index 2119f5109..000000000 --- a/spec/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py new file mode 100644 index 000000000..82126be83 --- /dev/null +++ b/src/_array_api_conf.py @@ -0,0 +1,211 @@ +""" +Base config for all individual Sphinx docs in the array API repo. + +The array-api repo contains an individual Sphinx doc for each spec version, all +of which exist in ../spec/. This file is star-imported in the conf.py files of +these docs, allowing us to standardize configuration accross API versions. + +Every conf.py file which star-imports this should define + +* `release`, the str YYYY.MM release. Use "DRAFT" for the draft. +* `sys.modules['array_api']`, the stubs module to use for autodoc. +""" +import re + +import sphinx_material + +# -- Project information ----------------------------------------------------- + +project = 'Python array API standard' +copyright = '2020, Consortium for Python Data API Standards' +author = 'Consortium for Python Data API Standards' + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'myst_parser', + 'sphinx.ext.extlinks', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx_markdown_tables', + 'sphinx_copybutton', + 'sphinx.ext.autosummary', + 'sphinx.ext.napoleon', + 'sphinx.ext.autodoc', +] + +autosummary_generate = True +autodoc_typehints = 'signature' +add_module_names = False +napoleon_custom_sections = [('Returns', 'params_style')] +default_role = 'code' + +# nitpicky = True makes Sphinx warn whenever a cross-reference target can't be +# found. +nitpicky = True +# autodoc wants to make cross-references for every type hint. But a lot of +# them don't actually refer to anything that we have a document for. +nitpick_ignore = [ + ('py:class', 'collections.abc.Sequence'), + ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), + ('py:class', "Union[int, float, Literal[inf, - inf]]"), + ('py:obj', "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]"), + ('py:obj', "typing.Union[int, float, typing.Literal[inf, - inf]]"), + ('py:class', 'enum.Enum'), + ('py:class', 'ellipsis'), +] +nitpick_ignore_regex = [ + ('py:class', '.*array'), + ('py:class', '.*device'), + ('py:class', '.*dtype'), + ('py:class', '.*NestedSequence'), + ('py:class', '.*SupportsBufferProtocol'), + ('py:class', '.*PyCapsule'), + ('py:class', '.*finfo_object'), + ('py:class', '.*iinfo_object'), +] +# In array_object.py we have to use aliased names for some types because they +# would otherwise refer back to method objects of array +autodoc_type_aliases = { + 'array': 'array', + 'Device': 'device', + 'Dtype': 'dtype', +} + +# Make autosummary show the signatures of functions in the tables using actual +# Python syntax. There's currently no supported way to do this, so we have to +# just patch out the function that processes the signatures. See +# https://github.com/sphinx-doc/sphinx/issues/10053. +import sphinx.ext.autosummary as autosummary_mod +if hasattr(autosummary_mod, '_module'): + # It's a sphinx deprecated module wrapper object + autosummary_mod = autosummary_mod._module +autosummary_mod.mangle_signature = lambda sig, max_chars=30: sig + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['../_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# MyST options +myst_heading_anchors = 3 +myst_enable_extensions = ["colon_fence"] + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +extensions.append("sphinx_material") +html_theme_path = sphinx_material.html_theme_path() +html_context = sphinx_material.get_html_context() +html_theme = 'sphinx_material' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['../_static'] + + +# -- Material theme options (see theme.conf for more information) ------------ +html_show_sourcelink = False +html_sidebars = { + "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] +} + +html_theme_options = { + + # Set the name of the project to appear in the navigation. + 'nav_title': f'Python array API standard', + + # Set you GA account ID to enable tracking + #'google_analytics_account': 'UA-XXXXX', + + # Specify a base_url used to generate sitemap.xml. If not + # specified, then no sitemap will be built. + #'base_url': 'https://project.github.io/project', + + # Set the color and the accent color (see + # https://material.io/design/color/the-color-system.html) + 'color_primary': 'indigo', + 'color_accent': 'green', + + # Set the repo location to get a badge with stats + #'repo_url': 'https://github.com/project/project/', + #'repo_name': 'Project', + + "html_minify": False, + "html_prettify": False, + "css_minify": True, + "logo_icon": "", + "repo_type": "github", + "touch_icon": "images/apple-icon-152x152.png", + "theme_color": "#2196f3", + "master_doc": False, + + # Visible levels of the global TOC; -1 means unlimited + 'globaltoc_depth': 2, + # If False, expand all TOC entries + 'globaltoc_collapse': True, + # If True, show hidden TOC entries + 'globaltoc_includehidden': True, + + "nav_links": [ + {"href": "index", "internal": True, "title": "Array API standard"}, + { + "href": "https://data-apis.org", + "internal": False, + "title": "Consortium for Python Data API Standards", + }, + ], + "heroes": { + "index": "A common API for array and tensor Python libraries", + #"customization": "Configuration options to personalize your site.", + }, + + "version_dropdown": True, + "version_json": "../versions.json", + "table_classes": ["plain"], +} + + +todo_include_todos = True +#html_favicon = "images/favicon.ico" + +html_use_index = True +html_domain_indices = True + +extlinks = { + "duref": ( + "http://docutils.sourceforge.net/docs/ref/rst/" "restructuredtext.html#%s", + "", + ), + "durole": ("http://docutils.sourceforge.net/docs/ref/rst/" "roles.html#%s", ""), + "dudir": ("http://docutils.sourceforge.net/docs/ref/rst/" "directives.html#%s", ""), + "pypa": ("https://packaging.python.org/%s", ""), +} + +# -- Prettify type hints ----------------------------------------------------- +r_type_prefix = re.compile(r"array_api(?:_stubs\._[a-z0-9_]+)?\._types\.") + +def process_signature(app, what, name, obj, options, signature, return_annotation): + if signature: +<<<<<<<< HEAD:spec/2021.12/conf.py + signature = signature.replace("signatures._types.", "") + if return_annotation: + return_annotation = return_annotation.replace("signatures._types.", "") +======== + signature = re.sub(r_type_prefix, "", signature) + if return_annotation: + return_annotation = re.sub(r_type_prefix, "", return_annotation) +>>>>>>>> bbd0384 (Squashed old all-versions work):src/_array_api_conf.py + return signature, return_annotation + +def setup(app): + app.connect("autodoc-process-signature", process_signature) diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py new file mode 100644 index 000000000..54614644a --- /dev/null +++ b/src/array_api_stubs/__init__.py @@ -0,0 +1,2 @@ +from . import _2021_12, _draft + From c280699be3460c10413c85fdb93d8997821a3ed6 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:45:24 +0000 Subject: [PATCH 004/196] Move 2022.12 docs into respective draft folders --- spec/{ => draft}/2022.12/API_specification/array_object.rst | 0 spec/{ => draft}/2022.12/API_specification/broadcasting.rst | 0 spec/{ => draft}/2022.12/API_specification/constants.rst | 0 spec/{ => draft}/2022.12/API_specification/creation_functions.rst | 0 .../{ => draft}/2022.12/API_specification/data_type_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/data_types.rst | 0 .../2022.12/API_specification/elementwise_functions.rst | 0 .../2022.12/API_specification/function_and_method_signatures.rst | 0 spec/{ => draft}/2022.12/API_specification/index.rst | 0 spec/{ => draft}/2022.12/API_specification/indexing.rst | 0 spec/{ => draft}/2022.12/API_specification/indexing_functions.rst | 0 .../2022.12/API_specification/linear_algebra_functions.rst | 0 .../2022.12/API_specification/manipulation_functions.rst | 0 .../{ => draft}/2022.12/API_specification/searching_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/set_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/sorting_functions.rst | 0 .../2022.12/API_specification/statistical_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/type_promotion.rst | 0 spec/{ => draft}/2022.12/API_specification/utility_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/version.rst | 0 spec/{ => draft}/2022.12/assumptions.md | 0 spec/{ => draft}/2022.12/benchmark_suite.md | 0 spec/{ => draft}/2022.12/changelog.rst | 0 spec/{ => draft}/2022.12/design_topics/C_API.rst | 0 spec/{ => draft}/2022.12/design_topics/accuracy.rst | 0 spec/{ => draft}/2022.12/design_topics/complex_numbers.rst | 0 .../2022.12/design_topics/copies_views_and_mutation.rst | 0 .../2022.12/design_topics/data_dependent_output_shapes.rst | 0 spec/{ => draft}/2022.12/design_topics/data_interchange.rst | 0 spec/{ => draft}/2022.12/design_topics/device_support.rst | 0 spec/{ => draft}/2022.12/design_topics/index.rst | 0 spec/{ => draft}/2022.12/design_topics/parallelism.rst | 0 spec/{ => draft}/2022.12/design_topics/static_typing.rst | 0 .../2022.12/extensions/fourier_transform_functions.rst | 0 spec/{ => draft}/2022.12/extensions/index.rst | 0 spec/{ => draft}/2022.12/extensions/linear_algebra_functions.rst | 0 spec/{ => draft}/2022.12/future_API_evolution.md | 0 spec/{ => draft}/2022.12/index.rst | 0 spec/{ => draft}/2022.12/purpose_and_scope.md | 0 spec/{ => draft}/2022.12/usage_data.md | 0 spec/{ => draft}/2022.12/use_cases.md | 0 spec/{ => draft}/2022.12/verification_test_suite.md | 0 src/array_api_stubs/{_2022_12 => _draft}/__init__.py | 0 src/array_api_stubs/{_2022_12 => _draft}/_types.py | 0 src/array_api_stubs/{_2022_12 => _draft}/array_object.py | 0 src/array_api_stubs/{_2022_12 => _draft}/constants.py | 0 src/array_api_stubs/{_2022_12 => _draft}/creation_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/data_type_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/data_types.py | 0 src/array_api_stubs/{_2022_12 => _draft}/elementwise_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/fft.py | 0 src/array_api_stubs/{_2022_12 => _draft}/indexing_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/linalg.py | 0 .../{_2022_12 => _draft}/linear_algebra_functions.py | 0 .../{_2022_12 => _draft}/manipulation_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/searching_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/set_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/sorting_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/statistical_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/utility_functions.py | 0 60 files changed, 0 insertions(+), 0 deletions(-) rename spec/{ => draft}/2022.12/API_specification/array_object.rst (100%) rename spec/{ => draft}/2022.12/API_specification/broadcasting.rst (100%) rename spec/{ => draft}/2022.12/API_specification/constants.rst (100%) rename spec/{ => draft}/2022.12/API_specification/creation_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/data_type_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/data_types.rst (100%) rename spec/{ => draft}/2022.12/API_specification/elementwise_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/function_and_method_signatures.rst (100%) rename spec/{ => draft}/2022.12/API_specification/index.rst (100%) rename spec/{ => draft}/2022.12/API_specification/indexing.rst (100%) rename spec/{ => draft}/2022.12/API_specification/indexing_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/linear_algebra_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/manipulation_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/searching_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/set_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/sorting_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/statistical_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/type_promotion.rst (100%) rename spec/{ => draft}/2022.12/API_specification/utility_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/version.rst (100%) rename spec/{ => draft}/2022.12/assumptions.md (100%) rename spec/{ => draft}/2022.12/benchmark_suite.md (100%) rename spec/{ => draft}/2022.12/changelog.rst (100%) rename spec/{ => draft}/2022.12/design_topics/C_API.rst (100%) rename spec/{ => draft}/2022.12/design_topics/accuracy.rst (100%) rename spec/{ => draft}/2022.12/design_topics/complex_numbers.rst (100%) rename spec/{ => draft}/2022.12/design_topics/copies_views_and_mutation.rst (100%) rename spec/{ => draft}/2022.12/design_topics/data_dependent_output_shapes.rst (100%) rename spec/{ => draft}/2022.12/design_topics/data_interchange.rst (100%) rename spec/{ => draft}/2022.12/design_topics/device_support.rst (100%) rename spec/{ => draft}/2022.12/design_topics/index.rst (100%) rename spec/{ => draft}/2022.12/design_topics/parallelism.rst (100%) rename spec/{ => draft}/2022.12/design_topics/static_typing.rst (100%) rename spec/{ => draft}/2022.12/extensions/fourier_transform_functions.rst (100%) rename spec/{ => draft}/2022.12/extensions/index.rst (100%) rename spec/{ => draft}/2022.12/extensions/linear_algebra_functions.rst (100%) rename spec/{ => draft}/2022.12/future_API_evolution.md (100%) rename spec/{ => draft}/2022.12/index.rst (100%) rename spec/{ => draft}/2022.12/purpose_and_scope.md (100%) rename spec/{ => draft}/2022.12/usage_data.md (100%) rename spec/{ => draft}/2022.12/use_cases.md (100%) rename spec/{ => draft}/2022.12/verification_test_suite.md (100%) rename src/array_api_stubs/{_2022_12 => _draft}/__init__.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/_types.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/array_object.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/constants.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/creation_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/data_type_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/data_types.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/elementwise_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/fft.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/indexing_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/linalg.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/linear_algebra_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/manipulation_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/searching_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/set_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/sorting_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/statistical_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/utility_functions.py (100%) diff --git a/spec/2022.12/API_specification/array_object.rst b/spec/draft/2022.12/API_specification/array_object.rst similarity index 100% rename from spec/2022.12/API_specification/array_object.rst rename to spec/draft/2022.12/API_specification/array_object.rst diff --git a/spec/2022.12/API_specification/broadcasting.rst b/spec/draft/2022.12/API_specification/broadcasting.rst similarity index 100% rename from spec/2022.12/API_specification/broadcasting.rst rename to spec/draft/2022.12/API_specification/broadcasting.rst diff --git a/spec/2022.12/API_specification/constants.rst b/spec/draft/2022.12/API_specification/constants.rst similarity index 100% rename from spec/2022.12/API_specification/constants.rst rename to spec/draft/2022.12/API_specification/constants.rst diff --git a/spec/2022.12/API_specification/creation_functions.rst b/spec/draft/2022.12/API_specification/creation_functions.rst similarity index 100% rename from spec/2022.12/API_specification/creation_functions.rst rename to spec/draft/2022.12/API_specification/creation_functions.rst diff --git a/spec/2022.12/API_specification/data_type_functions.rst b/spec/draft/2022.12/API_specification/data_type_functions.rst similarity index 100% rename from spec/2022.12/API_specification/data_type_functions.rst rename to spec/draft/2022.12/API_specification/data_type_functions.rst diff --git a/spec/2022.12/API_specification/data_types.rst b/spec/draft/2022.12/API_specification/data_types.rst similarity index 100% rename from spec/2022.12/API_specification/data_types.rst rename to spec/draft/2022.12/API_specification/data_types.rst diff --git a/spec/2022.12/API_specification/elementwise_functions.rst b/spec/draft/2022.12/API_specification/elementwise_functions.rst similarity index 100% rename from spec/2022.12/API_specification/elementwise_functions.rst rename to spec/draft/2022.12/API_specification/elementwise_functions.rst diff --git a/spec/2022.12/API_specification/function_and_method_signatures.rst b/spec/draft/2022.12/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/2022.12/API_specification/function_and_method_signatures.rst rename to spec/draft/2022.12/API_specification/function_and_method_signatures.rst diff --git a/spec/2022.12/API_specification/index.rst b/spec/draft/2022.12/API_specification/index.rst similarity index 100% rename from spec/2022.12/API_specification/index.rst rename to spec/draft/2022.12/API_specification/index.rst diff --git a/spec/2022.12/API_specification/indexing.rst b/spec/draft/2022.12/API_specification/indexing.rst similarity index 100% rename from spec/2022.12/API_specification/indexing.rst rename to spec/draft/2022.12/API_specification/indexing.rst diff --git a/spec/2022.12/API_specification/indexing_functions.rst b/spec/draft/2022.12/API_specification/indexing_functions.rst similarity index 100% rename from spec/2022.12/API_specification/indexing_functions.rst rename to spec/draft/2022.12/API_specification/indexing_functions.rst diff --git a/spec/2022.12/API_specification/linear_algebra_functions.rst b/spec/draft/2022.12/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/2022.12/API_specification/linear_algebra_functions.rst rename to spec/draft/2022.12/API_specification/linear_algebra_functions.rst diff --git a/spec/2022.12/API_specification/manipulation_functions.rst b/spec/draft/2022.12/API_specification/manipulation_functions.rst similarity index 100% rename from spec/2022.12/API_specification/manipulation_functions.rst rename to spec/draft/2022.12/API_specification/manipulation_functions.rst diff --git a/spec/2022.12/API_specification/searching_functions.rst b/spec/draft/2022.12/API_specification/searching_functions.rst similarity index 100% rename from spec/2022.12/API_specification/searching_functions.rst rename to spec/draft/2022.12/API_specification/searching_functions.rst diff --git a/spec/2022.12/API_specification/set_functions.rst b/spec/draft/2022.12/API_specification/set_functions.rst similarity index 100% rename from spec/2022.12/API_specification/set_functions.rst rename to spec/draft/2022.12/API_specification/set_functions.rst diff --git a/spec/2022.12/API_specification/sorting_functions.rst b/spec/draft/2022.12/API_specification/sorting_functions.rst similarity index 100% rename from spec/2022.12/API_specification/sorting_functions.rst rename to spec/draft/2022.12/API_specification/sorting_functions.rst diff --git a/spec/2022.12/API_specification/statistical_functions.rst b/spec/draft/2022.12/API_specification/statistical_functions.rst similarity index 100% rename from spec/2022.12/API_specification/statistical_functions.rst rename to spec/draft/2022.12/API_specification/statistical_functions.rst diff --git a/spec/2022.12/API_specification/type_promotion.rst b/spec/draft/2022.12/API_specification/type_promotion.rst similarity index 100% rename from spec/2022.12/API_specification/type_promotion.rst rename to spec/draft/2022.12/API_specification/type_promotion.rst diff --git a/spec/2022.12/API_specification/utility_functions.rst b/spec/draft/2022.12/API_specification/utility_functions.rst similarity index 100% rename from spec/2022.12/API_specification/utility_functions.rst rename to spec/draft/2022.12/API_specification/utility_functions.rst diff --git a/spec/2022.12/API_specification/version.rst b/spec/draft/2022.12/API_specification/version.rst similarity index 100% rename from spec/2022.12/API_specification/version.rst rename to spec/draft/2022.12/API_specification/version.rst diff --git a/spec/2022.12/assumptions.md b/spec/draft/2022.12/assumptions.md similarity index 100% rename from spec/2022.12/assumptions.md rename to spec/draft/2022.12/assumptions.md diff --git a/spec/2022.12/benchmark_suite.md b/spec/draft/2022.12/benchmark_suite.md similarity index 100% rename from spec/2022.12/benchmark_suite.md rename to spec/draft/2022.12/benchmark_suite.md diff --git a/spec/2022.12/changelog.rst b/spec/draft/2022.12/changelog.rst similarity index 100% rename from spec/2022.12/changelog.rst rename to spec/draft/2022.12/changelog.rst diff --git a/spec/2022.12/design_topics/C_API.rst b/spec/draft/2022.12/design_topics/C_API.rst similarity index 100% rename from spec/2022.12/design_topics/C_API.rst rename to spec/draft/2022.12/design_topics/C_API.rst diff --git a/spec/2022.12/design_topics/accuracy.rst b/spec/draft/2022.12/design_topics/accuracy.rst similarity index 100% rename from spec/2022.12/design_topics/accuracy.rst rename to spec/draft/2022.12/design_topics/accuracy.rst diff --git a/spec/2022.12/design_topics/complex_numbers.rst b/spec/draft/2022.12/design_topics/complex_numbers.rst similarity index 100% rename from spec/2022.12/design_topics/complex_numbers.rst rename to spec/draft/2022.12/design_topics/complex_numbers.rst diff --git a/spec/2022.12/design_topics/copies_views_and_mutation.rst b/spec/draft/2022.12/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/2022.12/design_topics/copies_views_and_mutation.rst rename to spec/draft/2022.12/design_topics/copies_views_and_mutation.rst diff --git a/spec/2022.12/design_topics/data_dependent_output_shapes.rst b/spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/2022.12/design_topics/data_dependent_output_shapes.rst rename to spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst diff --git a/spec/2022.12/design_topics/data_interchange.rst b/spec/draft/2022.12/design_topics/data_interchange.rst similarity index 100% rename from spec/2022.12/design_topics/data_interchange.rst rename to spec/draft/2022.12/design_topics/data_interchange.rst diff --git a/spec/2022.12/design_topics/device_support.rst b/spec/draft/2022.12/design_topics/device_support.rst similarity index 100% rename from spec/2022.12/design_topics/device_support.rst rename to spec/draft/2022.12/design_topics/device_support.rst diff --git a/spec/2022.12/design_topics/index.rst b/spec/draft/2022.12/design_topics/index.rst similarity index 100% rename from spec/2022.12/design_topics/index.rst rename to spec/draft/2022.12/design_topics/index.rst diff --git a/spec/2022.12/design_topics/parallelism.rst b/spec/draft/2022.12/design_topics/parallelism.rst similarity index 100% rename from spec/2022.12/design_topics/parallelism.rst rename to spec/draft/2022.12/design_topics/parallelism.rst diff --git a/spec/2022.12/design_topics/static_typing.rst b/spec/draft/2022.12/design_topics/static_typing.rst similarity index 100% rename from spec/2022.12/design_topics/static_typing.rst rename to spec/draft/2022.12/design_topics/static_typing.rst diff --git a/spec/2022.12/extensions/fourier_transform_functions.rst b/spec/draft/2022.12/extensions/fourier_transform_functions.rst similarity index 100% rename from spec/2022.12/extensions/fourier_transform_functions.rst rename to spec/draft/2022.12/extensions/fourier_transform_functions.rst diff --git a/spec/2022.12/extensions/index.rst b/spec/draft/2022.12/extensions/index.rst similarity index 100% rename from spec/2022.12/extensions/index.rst rename to spec/draft/2022.12/extensions/index.rst diff --git a/spec/2022.12/extensions/linear_algebra_functions.rst b/spec/draft/2022.12/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/2022.12/extensions/linear_algebra_functions.rst rename to spec/draft/2022.12/extensions/linear_algebra_functions.rst diff --git a/spec/2022.12/future_API_evolution.md b/spec/draft/2022.12/future_API_evolution.md similarity index 100% rename from spec/2022.12/future_API_evolution.md rename to spec/draft/2022.12/future_API_evolution.md diff --git a/spec/2022.12/index.rst b/spec/draft/2022.12/index.rst similarity index 100% rename from spec/2022.12/index.rst rename to spec/draft/2022.12/index.rst diff --git a/spec/2022.12/purpose_and_scope.md b/spec/draft/2022.12/purpose_and_scope.md similarity index 100% rename from spec/2022.12/purpose_and_scope.md rename to spec/draft/2022.12/purpose_and_scope.md diff --git a/spec/2022.12/usage_data.md b/spec/draft/2022.12/usage_data.md similarity index 100% rename from spec/2022.12/usage_data.md rename to spec/draft/2022.12/usage_data.md diff --git a/spec/2022.12/use_cases.md b/spec/draft/2022.12/use_cases.md similarity index 100% rename from spec/2022.12/use_cases.md rename to spec/draft/2022.12/use_cases.md diff --git a/spec/2022.12/verification_test_suite.md b/spec/draft/2022.12/verification_test_suite.md similarity index 100% rename from spec/2022.12/verification_test_suite.md rename to spec/draft/2022.12/verification_test_suite.md diff --git a/src/array_api_stubs/_2022_12/__init__.py b/src/array_api_stubs/_draft/__init__.py similarity index 100% rename from src/array_api_stubs/_2022_12/__init__.py rename to src/array_api_stubs/_draft/__init__.py diff --git a/src/array_api_stubs/_2022_12/_types.py b/src/array_api_stubs/_draft/_types.py similarity index 100% rename from src/array_api_stubs/_2022_12/_types.py rename to src/array_api_stubs/_draft/_types.py diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_draft/array_object.py similarity index 100% rename from src/array_api_stubs/_2022_12/array_object.py rename to src/array_api_stubs/_draft/array_object.py diff --git a/src/array_api_stubs/_2022_12/constants.py b/src/array_api_stubs/_draft/constants.py similarity index 100% rename from src/array_api_stubs/_2022_12/constants.py rename to src/array_api_stubs/_draft/constants.py diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/creation_functions.py rename to src/array_api_stubs/_draft/creation_functions.py diff --git a/src/array_api_stubs/_2022_12/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/data_type_functions.py rename to src/array_api_stubs/_draft/data_type_functions.py diff --git a/src/array_api_stubs/_2022_12/data_types.py b/src/array_api_stubs/_draft/data_types.py similarity index 100% rename from src/array_api_stubs/_2022_12/data_types.py rename to src/array_api_stubs/_draft/data_types.py diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/elementwise_functions.py rename to src/array_api_stubs/_draft/elementwise_functions.py diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_draft/fft.py similarity index 100% rename from src/array_api_stubs/_2022_12/fft.py rename to src/array_api_stubs/_draft/fft.py diff --git a/src/array_api_stubs/_2022_12/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/indexing_functions.py rename to src/array_api_stubs/_draft/indexing_functions.py diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_draft/linalg.py similarity index 100% rename from src/array_api_stubs/_2022_12/linalg.py rename to src/array_api_stubs/_draft/linalg.py diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/linear_algebra_functions.py rename to src/array_api_stubs/_draft/linear_algebra_functions.py diff --git a/src/array_api_stubs/_2022_12/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/manipulation_functions.py rename to src/array_api_stubs/_draft/manipulation_functions.py diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/searching_functions.py rename to src/array_api_stubs/_draft/searching_functions.py diff --git a/src/array_api_stubs/_2022_12/set_functions.py b/src/array_api_stubs/_draft/set_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/set_functions.py rename to src/array_api_stubs/_draft/set_functions.py diff --git a/src/array_api_stubs/_2022_12/sorting_functions.py b/src/array_api_stubs/_draft/sorting_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/sorting_functions.py rename to src/array_api_stubs/_draft/sorting_functions.py diff --git a/src/array_api_stubs/_2022_12/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/statistical_functions.py rename to src/array_api_stubs/_draft/statistical_functions.py diff --git a/src/array_api_stubs/_2022_12/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/utility_functions.py rename to src/array_api_stubs/_draft/utility_functions.py From 988f2f86bea64d565857dc05e3feb625fd7729fb Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:46:10 +0000 Subject: [PATCH 005/196] Empty commit for 2022.12 docs From c5afa3897acb03a714b170ee148271de95ea49d8 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:52:08 +0000 Subject: [PATCH 006/196] Fix erroneous draft spec folder structure --- spec/draft/{2022.12 => }/API_specification/array_object.rst | 0 spec/draft/{2022.12 => }/API_specification/broadcasting.rst | 0 spec/draft/{2022.12 => }/API_specification/constants.rst | 0 spec/draft/{2022.12 => }/API_specification/creation_functions.rst | 0 .../draft/{2022.12 => }/API_specification/data_type_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/data_types.rst | 0 .../{2022.12 => }/API_specification/elementwise_functions.rst | 0 .../API_specification/function_and_method_signatures.rst | 0 spec/draft/{2022.12 => }/API_specification/index.rst | 0 spec/draft/{2022.12 => }/API_specification/indexing.rst | 0 spec/draft/{2022.12 => }/API_specification/indexing_functions.rst | 0 .../{2022.12 => }/API_specification/linear_algebra_functions.rst | 0 .../{2022.12 => }/API_specification/manipulation_functions.rst | 0 .../draft/{2022.12 => }/API_specification/searching_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/set_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/sorting_functions.rst | 0 .../{2022.12 => }/API_specification/statistical_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/type_promotion.rst | 0 spec/draft/{2022.12 => }/API_specification/utility_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/version.rst | 0 spec/draft/{2022.12 => }/assumptions.md | 0 spec/draft/{2022.12 => }/benchmark_suite.md | 0 spec/draft/{2022.12 => }/changelog.rst | 0 spec/draft/{2022.12 => }/design_topics/C_API.rst | 0 spec/draft/{2022.12 => }/design_topics/accuracy.rst | 0 spec/draft/{2022.12 => }/design_topics/complex_numbers.rst | 0 .../{2022.12 => }/design_topics/copies_views_and_mutation.rst | 0 .../{2022.12 => }/design_topics/data_dependent_output_shapes.rst | 0 spec/draft/{2022.12 => }/design_topics/data_interchange.rst | 0 spec/draft/{2022.12 => }/design_topics/device_support.rst | 0 spec/draft/{2022.12 => }/design_topics/index.rst | 0 spec/draft/{2022.12 => }/design_topics/parallelism.rst | 0 spec/draft/{2022.12 => }/design_topics/static_typing.rst | 0 .../{2022.12 => }/extensions/fourier_transform_functions.rst | 0 spec/draft/{2022.12 => }/extensions/index.rst | 0 spec/draft/{2022.12 => }/extensions/linear_algebra_functions.rst | 0 spec/draft/{2022.12 => }/future_API_evolution.md | 0 spec/draft/{2022.12 => }/index.rst | 0 spec/draft/{2022.12 => }/purpose_and_scope.md | 0 spec/draft/{2022.12 => }/usage_data.md | 0 spec/draft/{2022.12 => }/use_cases.md | 0 spec/draft/{2022.12 => }/verification_test_suite.md | 0 42 files changed, 0 insertions(+), 0 deletions(-) rename spec/draft/{2022.12 => }/API_specification/array_object.rst (100%) rename spec/draft/{2022.12 => }/API_specification/broadcasting.rst (100%) rename spec/draft/{2022.12 => }/API_specification/constants.rst (100%) rename spec/draft/{2022.12 => }/API_specification/creation_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/data_type_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/data_types.rst (100%) rename spec/draft/{2022.12 => }/API_specification/elementwise_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/function_and_method_signatures.rst (100%) rename spec/draft/{2022.12 => }/API_specification/index.rst (100%) rename spec/draft/{2022.12 => }/API_specification/indexing.rst (100%) rename spec/draft/{2022.12 => }/API_specification/indexing_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/linear_algebra_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/manipulation_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/searching_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/set_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/sorting_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/statistical_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/type_promotion.rst (100%) rename spec/draft/{2022.12 => }/API_specification/utility_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/version.rst (100%) rename spec/draft/{2022.12 => }/assumptions.md (100%) rename spec/draft/{2022.12 => }/benchmark_suite.md (100%) rename spec/draft/{2022.12 => }/changelog.rst (100%) rename spec/draft/{2022.12 => }/design_topics/C_API.rst (100%) rename spec/draft/{2022.12 => }/design_topics/accuracy.rst (100%) rename spec/draft/{2022.12 => }/design_topics/complex_numbers.rst (100%) rename spec/draft/{2022.12 => }/design_topics/copies_views_and_mutation.rst (100%) rename spec/draft/{2022.12 => }/design_topics/data_dependent_output_shapes.rst (100%) rename spec/draft/{2022.12 => }/design_topics/data_interchange.rst (100%) rename spec/draft/{2022.12 => }/design_topics/device_support.rst (100%) rename spec/draft/{2022.12 => }/design_topics/index.rst (100%) rename spec/draft/{2022.12 => }/design_topics/parallelism.rst (100%) rename spec/draft/{2022.12 => }/design_topics/static_typing.rst (100%) rename spec/draft/{2022.12 => }/extensions/fourier_transform_functions.rst (100%) rename spec/draft/{2022.12 => }/extensions/index.rst (100%) rename spec/draft/{2022.12 => }/extensions/linear_algebra_functions.rst (100%) rename spec/draft/{2022.12 => }/future_API_evolution.md (100%) rename spec/draft/{2022.12 => }/index.rst (100%) rename spec/draft/{2022.12 => }/purpose_and_scope.md (100%) rename spec/draft/{2022.12 => }/usage_data.md (100%) rename spec/draft/{2022.12 => }/use_cases.md (100%) rename spec/draft/{2022.12 => }/verification_test_suite.md (100%) diff --git a/spec/draft/2022.12/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst similarity index 100% rename from spec/draft/2022.12/API_specification/array_object.rst rename to spec/draft/API_specification/array_object.rst diff --git a/spec/draft/2022.12/API_specification/broadcasting.rst b/spec/draft/API_specification/broadcasting.rst similarity index 100% rename from spec/draft/2022.12/API_specification/broadcasting.rst rename to spec/draft/API_specification/broadcasting.rst diff --git a/spec/draft/2022.12/API_specification/constants.rst b/spec/draft/API_specification/constants.rst similarity index 100% rename from spec/draft/2022.12/API_specification/constants.rst rename to spec/draft/API_specification/constants.rst diff --git a/spec/draft/2022.12/API_specification/creation_functions.rst b/spec/draft/API_specification/creation_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/creation_functions.rst rename to spec/draft/API_specification/creation_functions.rst diff --git a/spec/draft/2022.12/API_specification/data_type_functions.rst b/spec/draft/API_specification/data_type_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/data_type_functions.rst rename to spec/draft/API_specification/data_type_functions.rst diff --git a/spec/draft/2022.12/API_specification/data_types.rst b/spec/draft/API_specification/data_types.rst similarity index 100% rename from spec/draft/2022.12/API_specification/data_types.rst rename to spec/draft/API_specification/data_types.rst diff --git a/spec/draft/2022.12/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/elementwise_functions.rst rename to spec/draft/API_specification/elementwise_functions.rst diff --git a/spec/draft/2022.12/API_specification/function_and_method_signatures.rst b/spec/draft/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/draft/2022.12/API_specification/function_and_method_signatures.rst rename to spec/draft/API_specification/function_and_method_signatures.rst diff --git a/spec/draft/2022.12/API_specification/index.rst b/spec/draft/API_specification/index.rst similarity index 100% rename from spec/draft/2022.12/API_specification/index.rst rename to spec/draft/API_specification/index.rst diff --git a/spec/draft/2022.12/API_specification/indexing.rst b/spec/draft/API_specification/indexing.rst similarity index 100% rename from spec/draft/2022.12/API_specification/indexing.rst rename to spec/draft/API_specification/indexing.rst diff --git a/spec/draft/2022.12/API_specification/indexing_functions.rst b/spec/draft/API_specification/indexing_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/indexing_functions.rst rename to spec/draft/API_specification/indexing_functions.rst diff --git a/spec/draft/2022.12/API_specification/linear_algebra_functions.rst b/spec/draft/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/linear_algebra_functions.rst rename to spec/draft/API_specification/linear_algebra_functions.rst diff --git a/spec/draft/2022.12/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/manipulation_functions.rst rename to spec/draft/API_specification/manipulation_functions.rst diff --git a/spec/draft/2022.12/API_specification/searching_functions.rst b/spec/draft/API_specification/searching_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/searching_functions.rst rename to spec/draft/API_specification/searching_functions.rst diff --git a/spec/draft/2022.12/API_specification/set_functions.rst b/spec/draft/API_specification/set_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/set_functions.rst rename to spec/draft/API_specification/set_functions.rst diff --git a/spec/draft/2022.12/API_specification/sorting_functions.rst b/spec/draft/API_specification/sorting_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/sorting_functions.rst rename to spec/draft/API_specification/sorting_functions.rst diff --git a/spec/draft/2022.12/API_specification/statistical_functions.rst b/spec/draft/API_specification/statistical_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/statistical_functions.rst rename to spec/draft/API_specification/statistical_functions.rst diff --git a/spec/draft/2022.12/API_specification/type_promotion.rst b/spec/draft/API_specification/type_promotion.rst similarity index 100% rename from spec/draft/2022.12/API_specification/type_promotion.rst rename to spec/draft/API_specification/type_promotion.rst diff --git a/spec/draft/2022.12/API_specification/utility_functions.rst b/spec/draft/API_specification/utility_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/utility_functions.rst rename to spec/draft/API_specification/utility_functions.rst diff --git a/spec/draft/2022.12/API_specification/version.rst b/spec/draft/API_specification/version.rst similarity index 100% rename from spec/draft/2022.12/API_specification/version.rst rename to spec/draft/API_specification/version.rst diff --git a/spec/draft/2022.12/assumptions.md b/spec/draft/assumptions.md similarity index 100% rename from spec/draft/2022.12/assumptions.md rename to spec/draft/assumptions.md diff --git a/spec/draft/2022.12/benchmark_suite.md b/spec/draft/benchmark_suite.md similarity index 100% rename from spec/draft/2022.12/benchmark_suite.md rename to spec/draft/benchmark_suite.md diff --git a/spec/draft/2022.12/changelog.rst b/spec/draft/changelog.rst similarity index 100% rename from spec/draft/2022.12/changelog.rst rename to spec/draft/changelog.rst diff --git a/spec/draft/2022.12/design_topics/C_API.rst b/spec/draft/design_topics/C_API.rst similarity index 100% rename from spec/draft/2022.12/design_topics/C_API.rst rename to spec/draft/design_topics/C_API.rst diff --git a/spec/draft/2022.12/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst similarity index 100% rename from spec/draft/2022.12/design_topics/accuracy.rst rename to spec/draft/design_topics/accuracy.rst diff --git a/spec/draft/2022.12/design_topics/complex_numbers.rst b/spec/draft/design_topics/complex_numbers.rst similarity index 100% rename from spec/draft/2022.12/design_topics/complex_numbers.rst rename to spec/draft/design_topics/complex_numbers.rst diff --git a/spec/draft/2022.12/design_topics/copies_views_and_mutation.rst b/spec/draft/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/draft/2022.12/design_topics/copies_views_and_mutation.rst rename to spec/draft/design_topics/copies_views_and_mutation.rst diff --git a/spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst b/spec/draft/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst rename to spec/draft/design_topics/data_dependent_output_shapes.rst diff --git a/spec/draft/2022.12/design_topics/data_interchange.rst b/spec/draft/design_topics/data_interchange.rst similarity index 100% rename from spec/draft/2022.12/design_topics/data_interchange.rst rename to spec/draft/design_topics/data_interchange.rst diff --git a/spec/draft/2022.12/design_topics/device_support.rst b/spec/draft/design_topics/device_support.rst similarity index 100% rename from spec/draft/2022.12/design_topics/device_support.rst rename to spec/draft/design_topics/device_support.rst diff --git a/spec/draft/2022.12/design_topics/index.rst b/spec/draft/design_topics/index.rst similarity index 100% rename from spec/draft/2022.12/design_topics/index.rst rename to spec/draft/design_topics/index.rst diff --git a/spec/draft/2022.12/design_topics/parallelism.rst b/spec/draft/design_topics/parallelism.rst similarity index 100% rename from spec/draft/2022.12/design_topics/parallelism.rst rename to spec/draft/design_topics/parallelism.rst diff --git a/spec/draft/2022.12/design_topics/static_typing.rst b/spec/draft/design_topics/static_typing.rst similarity index 100% rename from spec/draft/2022.12/design_topics/static_typing.rst rename to spec/draft/design_topics/static_typing.rst diff --git a/spec/draft/2022.12/extensions/fourier_transform_functions.rst b/spec/draft/extensions/fourier_transform_functions.rst similarity index 100% rename from spec/draft/2022.12/extensions/fourier_transform_functions.rst rename to spec/draft/extensions/fourier_transform_functions.rst diff --git a/spec/draft/2022.12/extensions/index.rst b/spec/draft/extensions/index.rst similarity index 100% rename from spec/draft/2022.12/extensions/index.rst rename to spec/draft/extensions/index.rst diff --git a/spec/draft/2022.12/extensions/linear_algebra_functions.rst b/spec/draft/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/draft/2022.12/extensions/linear_algebra_functions.rst rename to spec/draft/extensions/linear_algebra_functions.rst diff --git a/spec/draft/2022.12/future_API_evolution.md b/spec/draft/future_API_evolution.md similarity index 100% rename from spec/draft/2022.12/future_API_evolution.md rename to spec/draft/future_API_evolution.md diff --git a/spec/draft/2022.12/index.rst b/spec/draft/index.rst similarity index 100% rename from spec/draft/2022.12/index.rst rename to spec/draft/index.rst diff --git a/spec/draft/2022.12/purpose_and_scope.md b/spec/draft/purpose_and_scope.md similarity index 100% rename from spec/draft/2022.12/purpose_and_scope.md rename to spec/draft/purpose_and_scope.md diff --git a/spec/draft/2022.12/usage_data.md b/spec/draft/usage_data.md similarity index 100% rename from spec/draft/2022.12/usage_data.md rename to spec/draft/usage_data.md diff --git a/spec/draft/2022.12/use_cases.md b/spec/draft/use_cases.md similarity index 100% rename from spec/draft/2022.12/use_cases.md rename to spec/draft/use_cases.md diff --git a/spec/draft/2022.12/verification_test_suite.md b/spec/draft/verification_test_suite.md similarity index 100% rename from spec/draft/2022.12/verification_test_suite.md rename to spec/draft/verification_test_suite.md From c74b390417c056e67cba31debb08920edd3f73d1 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 13:10:26 +0000 Subject: [PATCH 007/196] Resolve accidental merge artifact --- src/_array_api_conf.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 82126be83..161590fea 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -196,15 +196,9 @@ def process_signature(app, what, name, obj, options, signature, return_annotation): if signature: -<<<<<<<< HEAD:spec/2021.12/conf.py - signature = signature.replace("signatures._types.", "") - if return_annotation: - return_annotation = return_annotation.replace("signatures._types.", "") -======== signature = re.sub(r_type_prefix, "", signature) if return_annotation: return_annotation = re.sub(r_type_prefix, "", return_annotation) ->>>>>>>> bbd0384 (Squashed old all-versions work):src/_array_api_conf.py return signature, return_annotation def setup(app): From ada910275c2105ad3cf1aa4a3d7deb13cd6524a0 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 14:06:02 +0000 Subject: [PATCH 008/196] Fix `2021.12` building --- .../API_specification/array_object.rst | 2 +- spec/2021.12/API_specification/constants.rst | 2 +- .../API_specification/creation_functions.rst | 2 +- .../API_specification/data_type_functions.rst | 2 +- spec/2021.12/API_specification/data_types.rst | 2 +- .../elementwise_functions.rst | 2 +- spec/2021.12/API_specification/indexing.rst | 4 +- .../linear_algebra_functions.rst | 2 +- .../manipulation_functions.rst | 2 +- .../API_specification/searching_functions.rst | 2 +- .../API_specification/set_functions.rst | 2 +- .../API_specification/sorting_functions.rst | 2 +- .../statistical_functions.rst | 2 +- .../API_specification/utility_functions.rst | 2 +- spec/2021.12/conf.py | 207 +----------------- .../extensions/linear_algebra_functions.rst | 2 +- spec/2022.12/API_specification/data_types.rst | 4 +- src/array_api_stubs/_2021_12/__init__.py | 22 ++ src/array_api_stubs/_2021_12/array_object.py | 50 ++--- .../_2021_12/creation_functions.py | 2 +- src/array_api_stubs/_2021_12/linalg.py | 8 +- src/array_api_stubs/_2022_12/__init__.py | 2 +- src/array_api_stubs/_draft/__init__.py | 2 +- 23 files changed, 76 insertions(+), 253 deletions(-) diff --git a/spec/2021.12/API_specification/array_object.rst b/spec/2021.12/API_specification/array_object.rst index 55a8ff0ab..32b775b6a 100644 --- a/spec/2021.12/API_specification/array_object.rst +++ b/spec/2021.12/API_specification/array_object.rst @@ -246,7 +246,7 @@ Bitwise Operators ------------------------------------------------- -.. currentmodule:: signatures.array_object +.. currentmodule:: array_api Attributes ---------- diff --git a/spec/2021.12/API_specification/constants.rst b/spec/2021.12/API_specification/constants.rst index 4d71ed380..abe256533 100644 --- a/spec/2021.12/API_specification/constants.rst +++ b/spec/2021.12/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.constants +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/creation_functions.rst b/spec/2021.12/API_specification/creation_functions.rst index c34f67378..9984ff04c 100644 --- a/spec/2021.12/API_specification/creation_functions.rst +++ b/spec/2021.12/API_specification/creation_functions.rst @@ -11,7 +11,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.creation_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/data_type_functions.rst b/spec/2021.12/API_specification/data_type_functions.rst index 4b35a297a..bb32d2b7f 100644 --- a/spec/2021.12/API_specification/data_type_functions.rst +++ b/spec/2021.12/API_specification/data_type_functions.rst @@ -9,7 +9,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.data_type_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst index f40006c4e..b2393c1a2 100644 --- a/spec/2021.12/API_specification/data_types.rst +++ b/spec/2021.12/API_specification/data_types.rst @@ -100,7 +100,7 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: signatures.data_types +.. currentmodule:: array_api .. autosummary:: :toctree: generated diff --git a/spec/2021.12/API_specification/elementwise_functions.rst b/spec/2021.12/API_specification/elementwise_functions.rst index 316ac8ce9..02e3d50b6 100644 --- a/spec/2021.12/API_specification/elementwise_functions.rst +++ b/spec/2021.12/API_specification/elementwise_functions.rst @@ -19,7 +19,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.elementwise_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/indexing.rst b/spec/2021.12/API_specification/indexing.rst index 13fe70a3f..6d5e77a5b 100644 --- a/spec/2021.12/API_specification/indexing.rst +++ b/spec/2021.12/API_specification/indexing.rst @@ -154,7 +154,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. .. note:: - Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. - Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. @@ -181,7 +181,7 @@ Boolean Array Indexing An array must support indexing where the **sole index** is an ``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)``. .. note:: - The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~array_api.expand_dims`. - 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)]``. diff --git a/spec/2021.12/API_specification/linear_algebra_functions.rst b/spec/2021.12/API_specification/linear_algebra_functions.rst index c12144aa4..9bae18e77 100644 --- a/spec/2021.12/API_specification/linear_algebra_functions.rst +++ b/spec/2021.12/API_specification/linear_algebra_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t * Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. * Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. -.. currentmodule:: signatures.linear_algebra_functions +.. currentmodule:: array_api Objects in API -------------- diff --git a/spec/2021.12/API_specification/manipulation_functions.rst b/spec/2021.12/API_specification/manipulation_functions.rst index f2fcbccc5..86ad2697f 100644 --- a/spec/2021.12/API_specification/manipulation_functions.rst +++ b/spec/2021.12/API_specification/manipulation_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.manipulation_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/searching_functions.rst b/spec/2021.12/API_specification/searching_functions.rst index b8a2b39a5..bf09e4c8a 100644 --- a/spec/2021.12/API_specification/searching_functions.rst +++ b/spec/2021.12/API_specification/searching_functions.rst @@ -16,7 +16,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.searching_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/set_functions.rst b/spec/2021.12/API_specification/set_functions.rst index 4ba2ad424..b7072d100 100644 --- a/spec/2021.12/API_specification/set_functions.rst +++ b/spec/2021.12/API_specification/set_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.set_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/sorting_functions.rst b/spec/2021.12/API_specification/sorting_functions.rst index da0ff99d1..19d7fb439 100644 --- a/spec/2021.12/API_specification/sorting_functions.rst +++ b/spec/2021.12/API_specification/sorting_functions.rst @@ -19,7 +19,7 @@ A conforming implementation of the array API standard must provide and support t While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. -.. currentmodule:: signatures.sorting_functions +.. currentmodule:: array_api Objects in API -------------- diff --git a/spec/2021.12/API_specification/statistical_functions.rst b/spec/2021.12/API_specification/statistical_functions.rst index d87f5d25a..6734506ed 100644 --- a/spec/2021.12/API_specification/statistical_functions.rst +++ b/spec/2021.12/API_specification/statistical_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.statistical_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/utility_functions.rst b/spec/2021.12/API_specification/utility_functions.rst index 887819194..f869b4321 100644 --- a/spec/2021.12/API_specification/utility_functions.rst +++ b/spec/2021.12/API_specification/utility_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.utility_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index 33fccbca8..d9ec5b030 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -1,206 +1,7 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os import sys -import sphinx_material -sys.path.insert(0, os.path.abspath('./API_specification')) - -# -- Project information ----------------------------------------------------- - -project = 'Python array API standard' -copyright = '2020, Consortium for Python Data API Standards' -author = 'Consortium for Python Data API Standards' - -# The full version, including alpha/beta/rc tags -release = '2021.12' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'myst_parser', - 'sphinx.ext.extlinks', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx_markdown_tables', - 'sphinx_copybutton', - 'sphinx.ext.autosummary', - 'sphinx.ext.napoleon', - 'sphinx.ext.autodoc', -] - -autosummary_generate = True -autodoc_typehints = 'signature' -add_module_names = False -napoleon_custom_sections = [('Returns', 'params_style')] -default_role = 'code' - -# nitpicky = True makes Sphinx warn whenever a cross-reference target can't be -# found. -nitpicky = True -# autodoc wants to make cross-references for every type hint. But a lot of -# them don't actually refer to anything that we have a document for. -nitpick_ignore = [ - ('py:class', 'array'), - ('py:class', 'device'), - ('py:class', 'dtype'), - ('py:class', 'NestedSequence'), - ('py:class', 'SupportsBufferProtocol'), - ('py:class', 'collections.abc.Sequence'), - ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:class', "Union[int, float, Literal[inf, - inf]]"), - ('py:obj', "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:obj', "typing.Union[int, float, typing.Literal[inf, - inf]]"), - ('py:class', 'PyCapsule'), - ('py:class', 'enum.Enum'), - ('py:class', 'ellipsis'), - ('py:class', 'finfo_object'), - ('py:class', 'iinfo_object'), -] -# In array_object.py we have to use aliased names for some types because they -# would otherwise refer back to method objects of array -autodoc_type_aliases = { - 'array': 'array', - 'Device': 'device', - 'Dtype': 'dtype', -} - -# Make autosummary show the signatures of functions in the tables using actual -# Python syntax. There's currently no supported way to do this, so we have to -# just patch out the function that processes the signatures. See -# https://github.com/sphinx-doc/sphinx/issues/10053. -import sphinx.ext.autosummary as autosummary_mod -if hasattr(autosummary_mod, '_module'): - # It's a sphinx deprecated module wrapper object - autosummary_mod = autosummary_mod._module -autosummary_mod.mangle_signature = lambda sig, max_chars=30: sig - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# MyST options -myst_heading_anchors = 3 -myst_enable_extensions = ["colon_fence"] - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -extensions.append("sphinx_material") -html_theme_path = sphinx_material.html_theme_path() -html_context = sphinx_material.get_html_context() -html_theme = 'sphinx_material' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - - -# -- Material theme options (see theme.conf for more information) ------------ -html_show_sourcelink = False -html_sidebars = { - "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] -} - -html_theme_options = { - - # Set the name of the project to appear in the navigation. - 'nav_title': f'Python array API standard {release}', - - # Set you GA account ID to enable tracking - #'google_analytics_account': 'UA-XXXXX', - - # Specify a base_url used to generate sitemap.xml. If not - # specified, then no sitemap will be built. - #'base_url': 'https://project.github.io/project', - - # Set the color and the accent color (see - # https://material.io/design/color/the-color-system.html) - 'color_primary': 'indigo', - 'color_accent': 'green', - - # Set the repo location to get a badge with stats - #'repo_url': 'https://github.com/project/project/', - #'repo_name': 'Project', - - "html_minify": False, - "html_prettify": False, - "css_minify": True, - "logo_icon": "", - "repo_type": "github", - "touch_icon": "images/apple-icon-152x152.png", - "theme_color": "#2196f3", - "master_doc": False, - - # Visible levels of the global TOC; -1 means unlimited - 'globaltoc_depth': 2, - # If False, expand all TOC entries - 'globaltoc_collapse': True, - # If True, show hidden TOC entries - 'globaltoc_includehidden': True, - - "nav_links": [ - {"href": "index", "internal": True, "title": "Array API standard"}, - { - "href": "https://data-apis.org", - "internal": False, - "title": "Consortium for Python Data API Standards", - }, - ], - "heroes": { - "index": "A common API for array and tensor Python libraries", - #"customization": "Configuration options to personalize your site.", - }, - - "version_dropdown": True, - "version_json": "../versions.json", - "table_classes": ["plain"], -} - - -todo_include_todos = True -#html_favicon = "images/favicon.ico" - -html_use_index = True -html_domain_indices = True - -extlinks = { - "duref": ( - "http://docutils.sourceforge.net/docs/ref/rst/" "restructuredtext.html#%s", - "", - ), - "durole": ("http://docutils.sourceforge.net/docs/ref/rst/" "roles.html#%s", ""), - "dudir": ("http://docutils.sourceforge.net/docs/ref/rst/" "directives.html#%s", ""), - "pypa": ("https://packaging.python.org/%s", ""), -} - -def process_signature(app, what, name, obj, options, signature, return_annotation): - if signature: - signature = signature.replace("signatures._types.", "") - if return_annotation: - return_annotation = return_annotation.replace("signatures._types.", "") - return signature, return_annotation +from array_api_stubs import _2021_12 as stubs_mod +from _array_api_conf import * -def setup(app): - app.connect("autodoc-process-signature", process_signature) +release = "2021.12" +sys.modules["array_api"] = stubs_mod diff --git a/spec/2021.12/extensions/linear_algebra_functions.rst b/spec/2021.12/extensions/linear_algebra_functions.rst index b82a913de..dbe643bed 100644 --- a/spec/2021.12/extensions/linear_algebra_functions.rst +++ b/spec/2021.12/extensions/linear_algebra_functions.rst @@ -74,7 +74,7 @@ Accordingly, the standardization process affords the opportunity to reduce inter where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. -.. currentmodule:: signatures.linalg +.. currentmodule:: array_api.linalg Objects in API -------------- diff --git a/spec/2022.12/API_specification/data_types.rst b/spec/2022.12/API_specification/data_types.rst index a9be88181..e9f6ff732 100644 --- a/spec/2022.12/API_specification/data_types.rst +++ b/spec/2022.12/API_specification/data_types.rst @@ -101,13 +101,13 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: array_api.data_types +.. currentmodule:: array_api .. autosummary:: :toctree: generated :template: method.rst - __eq__ + dtype.__eq__ .. _data-type-defaults: diff --git a/src/array_api_stubs/_2021_12/__init__.py b/src/array_api_stubs/_2021_12/__init__.py index e69de29bb..28584daf7 100644 --- a/src/array_api_stubs/_2021_12/__init__.py +++ b/src/array_api_stubs/_2021_12/__init__.py @@ -0,0 +1,22 @@ +"""Function stubs and API documentation for the array API standard.""" + +from .array_object import * +from .constants import * +from .creation_functions import * +from .data_type_functions import * +from . import data_types as dtype +from .elementwise_functions import * +from .linear_algebra_functions import * +from .manipulation_functions import * +from .searching_functions import * +from .set_functions import * +from .sorting_functions import * +from .statistical_functions import * +from .utility_functions import * +from . import linalg + + +__array_api_version__: str = "YYYY.MM" +""" +String representing the version of the array API specification which the conforming implementation adheres to. +""" diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index 970f641a1..ac6890f71 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -135,7 +135,7 @@ def __abs__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.abs`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -181,7 +181,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.add`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -202,7 +202,7 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_and`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: @@ -239,7 +239,7 @@ def __bool__(self: array, /) -> bool: def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: """ - Exports the array for consumption by :func:`~signatures.creation_functions.from_dlpack` as a DLPack capsule. + Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. Parameters ---------- @@ -294,7 +294,7 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: """ - Returns device type and device ID in DLPack format. Meant for use within :func:`~signatures.creation_functions.from_dlpack`. + Returns device type and device ID in DLPack format. Meant for use within :func:`~array_api.from_dlpack`. Parameters ---------- @@ -336,7 +336,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. """ def __float__(self: array, /) -> float: @@ -411,7 +411,7 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.floor_divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. """ def __ge__(self: array, other: Union[int, float, array], /) -> array: @@ -432,7 +432,7 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. """ def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: @@ -470,7 +470,7 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. """ def __index__(self: array, /) -> int: @@ -522,7 +522,7 @@ def __invert__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_invert`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_invert`. """ def __le__(self: array, other: Union[int, float, array], /) -> array: @@ -543,7 +543,7 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -564,7 +564,7 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_left_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: @@ -585,7 +585,7 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. """ def __matmul__(self: array, other: array, /) -> array: @@ -616,7 +616,7 @@ def __matmul__(self: array, other: array, /) -> array: .. note:: - Results must equal the results returned by the equivalent function :func:`~signatures.linear_algebra_functions.matmul`. + Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. **Raises** @@ -676,7 +676,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.remainder`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ def __mul__(self: array, other: Union[int, float, array], /) -> array: @@ -715,7 +715,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.multiply`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -736,7 +736,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.not_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. """ def __neg__(self: array, /) -> array: @@ -758,7 +758,7 @@ def __neg__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.negative`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -779,7 +779,7 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_or`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -798,7 +798,7 @@ def __pos__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.positive`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: @@ -853,7 +853,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.pow`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -874,7 +874,7 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_right_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: @@ -918,7 +918,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.subtract`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -971,7 +971,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: @@ -992,7 +992,7 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_xor`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index 88db02340..3285a386d 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -54,7 +54,7 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr .. admonition:: Note :class: note - If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`signatures.data_type_functions.astype`. + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`array_api.astype`. .. note:: If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 275fa3158..0749daf8e 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -157,7 +157,7 @@ def inv(x: array, /) -> array: def matmul(x1: array, x2: array, /) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.matmul`. + Alias for :func:`~array_api.matmul`. """ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: @@ -249,7 +249,7 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a def matrix_transpose(x: array, /) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.matrix_transpose`. + Alias for :func:`~array_api.matrix_transpose`. """ def outer(x1: array, x2: array, /) -> array: @@ -406,7 +406,7 @@ def svdvals(x: array, /) -> array: def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.tensordot`. + Alias for :func:`~array_api.tensordot`. """ def trace(x: array, /, *, offset: int = 0) -> array: @@ -440,7 +440,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.vecdot`. + Alias for :func:`~array_api.vecdot`. """ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: diff --git a/src/array_api_stubs/_2022_12/__init__.py b/src/array_api_stubs/_2022_12/__init__.py index 32f88750d..12b6d9fbb 100644 --- a/src/array_api_stubs/_2022_12/__init__.py +++ b/src/array_api_stubs/_2022_12/__init__.py @@ -4,7 +4,7 @@ from .constants import * from .creation_functions import * from .data_type_functions import * -import array_api.data_types as dtype +from . import data_types as dtype from .elementwise_functions import * from .indexing_functions import * from .linear_algebra_functions import * diff --git a/src/array_api_stubs/_draft/__init__.py b/src/array_api_stubs/_draft/__init__.py index 32f88750d..12b6d9fbb 100644 --- a/src/array_api_stubs/_draft/__init__.py +++ b/src/array_api_stubs/_draft/__init__.py @@ -4,7 +4,7 @@ from .constants import * from .creation_functions import * from .data_type_functions import * -import array_api.data_types as dtype +from . import data_types as dtype from .elementwise_functions import * from .indexing_functions import * from .linear_algebra_functions import * From 85df0ea8c931ca5a4f5bcda705ce00a01caa967e Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 14:07:29 +0000 Subject: [PATCH 009/196] Fix `2022.12` building --- spec/2022.12/conf.py | 7 +++++++ src/array_api_stubs/__init__.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 spec/2022.12/conf.py diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py new file mode 100644 index 000000000..e9d652d44 --- /dev/null +++ b/spec/2022.12/conf.py @@ -0,0 +1,7 @@ +import sys + +from array_api_stubs import _2022_12 as stubs_mod +from _array_api_conf import * + +release = "2022.12" +sys.modules["array_api"] = stubs_mod diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index 54614644a..b3c7f1976 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1,2 +1,2 @@ -from . import _2021_12, _draft +from . import _2021_12, _2022_12, _draft From a206273f3c9ad1e6bff1ef1db47c6b45b2c1894c Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 14:09:42 +0000 Subject: [PATCH 010/196] Update all docs building --- Makefile | 3 ++- spec/_ghpages/versions.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 451b9224c..77a848598 100644 --- a/Makefile +++ b/Makefile @@ -18,5 +18,6 @@ build: -cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" -touch "$(BUILDDIR)/.nojekyll" -sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) - -cp -r "$(BUILDDIR)/2021.12" "$(BUILDDIR)/latest" + -sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) + -cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" -sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json index 5a6aa4692..ad38507bb 100644 --- a/spec/_ghpages/versions.json +++ b/spec/_ghpages/versions.json @@ -1,5 +1,6 @@ { "2021.12": "2021.12", + "2022.12": "2022.12", "latest": "latest", "draft": "draft" } From 58f2e59c91100ae55cb1d8f41124037e3e0e580e Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Sat, 7 Jan 2023 09:17:31 +0000 Subject: [PATCH 011/196] Fix image refs, restore old images --- spec/2021.12/API_specification/data_types.rst | 2 +- .../API_specification/type_promotion.rst | 2 +- spec/2021.12/assumptions.md | 2 +- spec/2021.12/purpose_and_scope.md | 2 +- .../API_specification/type_promotion.rst | 2 +- spec/2022.12/assumptions.md | 2 +- spec/2022.12/purpose_and_scope.md | 2 +- spec/_static/images/dtype_promotion_complex.png | Bin 0 -> 10433 bytes .../dtype_promotion_lattice_no_complex.png | Bin 0 -> 65646 bytes spec/draft/API_specification/type_promotion.rst | 2 +- spec/draft/assumptions.md | 2 +- spec/draft/purpose_and_scope.md | 2 +- 12 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 spec/_static/images/dtype_promotion_complex.png create mode 100644 spec/_static/images/dtype_promotion_lattice_no_complex.png diff --git a/spec/2021.12/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst index b2393c1a2..49373a6f5 100644 --- a/spec/2021.12/API_specification/data_types.rst +++ b/spec/2021.12/API_specification/data_types.rst @@ -72,7 +72,7 @@ IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-20 ``complex64`` and ``complex128`` data types are expected to be included in the next version of this standard and to have the following casting rules (will be added to :ref:`type-promotion`): - .. image:: /_static/images/dtype_promotion_complex.png + .. image:: ../../_static/images/dtype_promotion_complex.png See `array-api/issues/102 `_ for more details diff --git a/spec/2021.12/API_specification/type_promotion.rst b/spec/2021.12/API_specification/type_promotion.rst index d30f6517c..2b1a422a0 100644 --- a/spec/2021.12/API_specification/type_promotion.rst +++ b/spec/2021.12/API_specification/type_promotion.rst @@ -7,7 +7,7 @@ Type Promotion Rules Type promotion rules can be understood at a high level from the following diagram: -.. image:: /_static/images/dtype_promotion_lattice.png +.. image:: ../../_static/images/dtype_promotion_lattice_no_complex.png :target: Type promotion diagram *Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* diff --git a/spec/2021.12/assumptions.md b/spec/2021.12/assumptions.md index 3a315e6cd..3a90710ea 100644 --- a/spec/2021.12/assumptions.md +++ b/spec/2021.12/assumptions.md @@ -35,7 +35,7 @@ such a coupling. Facilitation support of multiple array types in downstream libraries is an important use case however, the assumed dependency structure for that is: -![dependency assumptions diagram](_static/images/dependency_assumption_diagram.png) +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared diff --git a/spec/2021.12/purpose_and_scope.md b/spec/2021.12/purpose_and_scope.md index fc8433c7f..4678ba064 100644 --- a/spec/2021.12/purpose_and_scope.md +++ b/spec/2021.12/purpose_and_scope.md @@ -111,7 +111,7 @@ Furthermore, meta-topics included in this standard include: The concrete set of functionality that is in scope for this version of the standard is shown in this diagram: -![Scope of array API](_static/images/scope_of_array_API.png) +![Scope of array API](../_static/images/scope_of_array_API.png) **Goals** for the API standard include: diff --git a/spec/2022.12/API_specification/type_promotion.rst b/spec/2022.12/API_specification/type_promotion.rst index fc9f6e1bf..339b90e45 100644 --- a/spec/2022.12/API_specification/type_promotion.rst +++ b/spec/2022.12/API_specification/type_promotion.rst @@ -7,7 +7,7 @@ Type Promotion Rules Type promotion rules can be understood at a high level from the following diagram: -.. image:: /_static/images/dtype_promotion_lattice.png +.. image:: ../../_static/images/dtype_promotion_lattice.png :target: Type promotion diagram *Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* diff --git a/spec/2022.12/assumptions.md b/spec/2022.12/assumptions.md index 3a315e6cd..3a90710ea 100644 --- a/spec/2022.12/assumptions.md +++ b/spec/2022.12/assumptions.md @@ -35,7 +35,7 @@ such a coupling. Facilitation support of multiple array types in downstream libraries is an important use case however, the assumed dependency structure for that is: -![dependency assumptions diagram](_static/images/dependency_assumption_diagram.png) +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared diff --git a/spec/2022.12/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md index 62e9bb8ba..eee3c7f4c 100644 --- a/spec/2022.12/purpose_and_scope.md +++ b/spec/2022.12/purpose_and_scope.md @@ -111,7 +111,7 @@ Furthermore, meta-topics included in this standard include: The concrete set of functionality that is in scope for this version of the standard is shown in this diagram: -![Scope of array API](_static/images/scope_of_array_API.png) +![Scope of array API](../_static/images/scope_of_array_API.png) **Goals** for the API standard include: diff --git a/spec/_static/images/dtype_promotion_complex.png b/spec/_static/images/dtype_promotion_complex.png new file mode 100644 index 0000000000000000000000000000000000000000..3503b07f56a885d59a397d35ae3cfc164a4909ef GIT binary patch literal 10433 zcmb_?cT|(x({2!tSdMTkfJ#%5CI|vb2_+VaQi7q1R7F6fm(ZIB6_6$pssW@1lujUo zs!{?81St|q04bp)6zL@d?h77&=ezg&?mu_kEEels@7{a%?3vj!^E^rT1E~7R;}?#D zK%kTN@2Tj5K!+&6^XAbbz<7EK(K9OoImuW>#xSzbHZnHLsSiheXlEX*r*-zfOv#yvA5qna=(is>te{MfKylO zzMSIzVsmId^7`BL+bYwyQ=#tS&*dNG7WAq;GlShJi zGecWXer9I%^z=;YEFNbI8rKt&=(X7S-YFP(O6Zy^QO?Vhzae*G5XSQ4qAY0jFC`VH z&&HGEBU>w8%Y@CT)I^TuJJG(diIgn?r2>NLlS{uRC2!s#7JX#fT}ns#e-Wp>n!5@M z&C^_*7Z z3{=o=qWy+$p8)k7JPN!)^dxa$nLdQhTykTsd?^$|XhWzH+IilqFBtb?H!LUD<0jRd zKr@$o!^pwfPbJ)2WyVB(dP(k!^T=`~H~!z63f3h->`Mt6cr>{-c;A5)LiE{dqU%%4f@#}2oczF%!Znl z^o@?Irtfvf)5b@}c`i3r982Y_rjLn5`}QBhnG&}DMf}<4Q|}yCB8=-ln7p(9 ztui3-gybEcA-6Wcj+^p8bS()s{+|LHsp!KA;Y$>;6K_J}FqFt=(NMnvqThx9K&9Pva z2v%NR8&h`|14f-??T!trig$21o^rh7wC}1Xkk*qAIavIr*Mr~*HN}sHjk^T9WPaIp zJ%k+G9CU4iZsEVjqCA;Xpn+}!$KVAq9SE+^f#2=|vu;Ji-R8A*?Oi*YRVML{Yu{u2 zY;MdPE&Do5!FfUlgf-&iFIK-0)sZ2-~Dg>M~@^0;L}MEc`t?& z8+-$t38d5%_?GLsmnVICq}FFzK;lQzX~(mUs{gK#4aHeo26neiNz5zF;K5h^W5@O- zd+c8Ge$1QKAJasC2W!QtIK3B<4Q6}@ZH*!ai?^_@ZngvkS^X^JYw*z>U)d%IU4&9nhj@l<++~Nm7rhXT=F0vz6uUGXQ(R(yP`R_P)>--HIAB zXqTzx>7v|K;^P-4)U4EpVuxlYIVg~wj!`eX6Cy5EV8J?M@(A)gJ;NcF@t~irAnYLB zoWUr|#y09XS;V_@vf4aQZ*cch32khPa2x|ot$&EDetjmrNvUb{yxksU&yV)h4_sDw z+L6Oi-3b+Eg7&HOlA9Wsy43hoUq`*wJ0&LH08m(S-HJzJCJe4gGVwal`;=sdj*+>s za9Q_2RD&Ki%5C9m*Bi#yFUN(vPQN;bd&%Dy4?aCKu9*Dp6uo)W)pXVpQxp&DFDr^& z_(o~6J{*7u;dHFTi@dA6?L@)d?fnEb2p=6+&J;HzK|_@n?U8!*&#_Fl&4C4)_lHZu zJZj{;X7XUSqrbg?KOY7U#TdjtLmBE&t10p2d=Ibq;jDiS6f;V;K%SC#>IJrf2NBD}YSs&pWPjVU0^vF5&+DQ!F1K3jA6MvV3^00I;0pVFXA{62( ze_uuPIxf(%%k)>px)L%&P0XQ?l?!8*L-M10aeH^Ml}{h!7G}dzdqvU> zoj`)5yGtX9FS8zj2i9w;^>C7~RBazjRy^oM1H$_8A@&=@fo`db%U# zW$#{TVS!g4Jf+o-H*rIcmJ3Job;+E6nh!}C#~6CZhlsg0P+XV13LD*J(ESji!C**& zURo@zo7hy@UEk#FGvW^|nE-nJVlOw{70oJ5KboiM^wR@-a3od5LDT zmKEGny2d0{L&6djPfKeODGmoi!4>9x?(d8tne)D9qMMwAzk4A>*yjve3u`?u;NdPae-%f75NL#e4#f+_HD-+q4cIxIBZ$`)KB>X13XQ^O8 zA{R;9_G6msM_wz$T6;s!Kzo=SwG}BY>v-?{=dhrO4Z}%DWhj&Y?ya^Po>Qj|I~3;y ztv_pFsJG3&Cd4Et3NFfO%q8wgFq>NAb$Fu0Qd1 zx~{V9mML2I;Q*ThQg1{ju-rHE4~?uUhp)_Yc4thk!@M7`9nFe+J>gjTL3ND5Kl%SnSiS26KW zp9KpwKYO9tou8fC@$^IyR%`tRgT>zD2v59@J;bf-rNcDxtITdkS{Irv*)xfr;42#x zQ7JMcI#gL%JUdB(`k;dpCF~@qd2rrDxcwIM#LmmNcE+7~dIKT4L+93+xhRO~Kr_3` z*1InC!pRY`Z;X-4-F9Lt$?6^BFg3Vf)JF-8eCP*D%pIqRWd<$GJNc15AzhEPpf7Op ztA&}gJ-TIf((gU&r*Hc5hGDcfEoldIFZ2^RsJlW0e-@k2XrWX3e!Juol;DB4E#<42 zFbk54C)!s!S8DRe!+Vhy@Gt1RE!}lQ<^@L3L zV&_;m@I)ffb_%#ZJ}nbdaYW7>Exp!-wq?ytG}On8)OUhojjCHefp6GMOh4D2DQtT! z-;&PQZ5TO%)jpFW(P_qN-l5Cpz;p9G;X(dLE>rNT1d7Bo-nE#c>b1X>axcaLHEe( zZrCFAkHzIPQh0Ngzoky*@=iQh1TH>5av5gFy7uJy`NzU63%y;lcHI}HUS$$a(cBaX z@mFk(wQRYN%Le#D^2j^0YnU>7SMIFKQ;4hAgXpl_OoY1+s%TcjB3}s!_g0|lETHlw-1OMkC0&*#zjUGr zG{mSl{9DRt*97EpnNT6p)t-z9qx@*>W-3IrU1Je$ffL-b;~<54_0aXK-ieGM0y+v| zMto~d7amoNR+vu-1vLtmymGz85IN@CFXHLx#2x z4zuSd|2RB&hz%-FfAQTVAM=_p?{ueBYkA-;SMb{RyYH!pbOSn!_~C0HXi>1fge9FZ z$R_Wgm+-87jDS@Kn$;3Mf`oj-+7*#2tAEkI1X|7y%%}UU^jLTgoRGB+mx-w42m022 zw(3`mi?Tm@=O8<2MgY{4mmnhq2E_)Wflk;GGQ+Xoj{CSU7<`*=Ii2u8n_@D5)WK~? z3(GXea?mJ$o9uQyzte2NXxEf|99~H+3@l;6I_8o=>mdhy{>;;h4Gz_{Wn+Z<2TB3T z+;;lx-#@?6usNpVkB``2^+x8GGQMGeGL~uFRD4SH3EJC#yYcDbDR<|Q+Ld>lE?VI- zk5D49t&Y+Z;EVuXjph3G)Yf*|C#zJ5D}d*}H0lozvnVk`1bJp$|84gl9`&2<9NqfC zw-?S?n)QFcgtq3*%R6(Vz!~d()bZ1P>oOo5z|s3kWi%lmZta8e)-*+))4vaR88BhB zT)zTl?-PWv(y*$_s)<%b-*>Ka$Nz8oEq$-8@mtB*s9(fPNd#Pn*a5SS{VO|vZncv! z`7?_TvLa!NzK#Cl-ywG7pSyB|VPn_Dx(=?%+y50!K-1<@yI=#&c{HJaVV9_Y8ZY0@ z7rxz<^nexT&i07&8y7Ze+p>z<0AQoS7RyC{ac$g+kKWJ61IdPjg|6-6d74Fg6>cnI zD`aA5bjY%69ys)Y_W;Dmq^_>sIb7?r;;ER;Sm88}iZ86(`XkCO!Y|Tq_#I~)8MN<% z{rJ-J*;&GEM6**PFiyi4$W^Wr8ucF({QR69XeUx6Y{(M{bx8pD1E5ep8*p1cK4{=P zeiN^!qXaMAbsMQPEpHbX8kewkW8O!3b1d{1+LzAGlwJ-{Vt>BVu=cl2(SS@OG1^a# zAN%xQF*ITnmn>^cbabGxaIf&_xuw5bj#8r1I&Vz#^NbLTy(NKT({BSHcaEj+VTO4= z!Y+Yk#j2FtdBd<_FgwR5s|YqdGLRaB_~#r<1!p9|^>;H`E~YjfgStv4WCa|sC4&A+ z>O5IRjRGE>%Wuqn?{E42PnJnVQqF@c?!Cb4vs=H(hwpUA&x{JwV`9{^@CdM)nG(}~ zR`8sqZm5a$M&AZc$h9KNlWb;y8|g!lurY<#mz&mj&UYg}xg?pH zZV51&3OiG4AH;6l?0Ek8AGT+iP_^M{^!-wJ+&@7Q4A=h{s;44KaIV+|fMdc~G`TzP6Ge^gPfFhcFusHj$T{ejncO#D8Nkd<+`g~BmLSEC zMR@80ypgi|&f>h=kW0FzQrvDa^L{3qV`)8^6t5Gw92ewKAh&1Jq;DwkTmS^3Gl5QA z$>PD`S8AeiVyAE3V*z~*1c4qkfsp!X8Kzb*LX+yBe+lsbf#z617sHUBpF|Ik@L%L8 zx6=M#>t+IC7v$n8!ZM4_Jl_~UnAQt$hU?5Aj$6a?d8!9%#A0E?(V+c#C5Kz!3WxT^ ze}0Gf=%jwIx#*S4+|@ix`_li%kEKF**U~;_>OFlR*|4e51XG0bF9U9s#PgE}GBl?i z#_~>nwCC{owa=mG_*vQ48f)+fMGz1OpodbiEJ?8Fi9L(1%LhUd?y1}a=GfoO**_0g4wf%PVIZ8|H_>)Q+aVx zgqz<(yra=;dXW;~nP3KBo&xF8(*tqS#8i6U$jHb62P!Wo=S?fc@p468E!A1zJ76&z z-HT5CXNmQdiHA%h_XW0F`D1F~Yt-*w=7%sWUW+3<FM}bJ7Gg+F271L>SIvv86mI8qnRK9em#JU<<6-&FCMRI6Oj zsQaG=IrnIonZQiYnmB2*4|WVQIC ze5&VRAiFa_CA~8(3kwU3uq#a;lI@O=#cEWBGoxXo$ElpB*TRm5{@#%={^ZZF@P)c_ z9rZJl@tFAo~42#Bh#mk`n_QX0)3tNv)W&uQk7P}-Q7cLAFt3aaCL5E zAKv#rU{WQ1?hFre@3B{fdU?kCJg88Vchk`=E?FmTUoa2|fSbjT!^6W_BMET%Xxba@ zk(GOH(1EP1EKVhXUsmC0i!aZ7VBZX`-4K*abSSE|$zb_q)QHI^fW6jA56Md(zo|)f zC;JskvN?Jv@QU`3fSY*pgc1<{Ujji7&jC&?Hm~>JY8UAhb6xB@0lVH zsor$DlAPQ*(}q9>C$OQVBiw zZO0i1o9htw-#QtW;vm1@)HzTai}=z=Wk*R6(5 z0KOD~Mc*?C&)Xbj43DPDjVw9uC~0RaA}OuvL0go>pdfNKiD;!Z&lyYCLdk2Rvt(^@ zWB^B<1tO#!2?^RI=qN5VY2kA{s!<&xF{AutBbU1$KO*`#(3fI@c8Vs(7v*v(-nd;9 z9G|7arE22y1oUHdeL@WA)<0iq`W*Mgy;DgxE;IZdJo|Na98$VC@_m5767wi0OJ9U02tTh6APAA(y2zMkp6;C+id~)JC$E>yyNMS0*LlR}qG8aHST z=Rb!7Bcw{oTba^<)zH+z_j;s>8&Dr?p}iWSXu#Aazfm#O&Ft;IcU%pTZorv^S?}K7 z&szCVpUD?7dVywim6wWvqCL9LIc5>+CMV;m88{XY-8Eg07zj#Y#zGI^|1I?-XrI3ZQ`d+sVU^AQ06@>v-Ce(T4 zAz4n;Csa$+Jp7T>RQNP@C8ZGE25Ay{EvH%xr3kh4j;Hb^ToZboSwT%2Q@sYMe~~j^6t&y|j+Y5%fWD0b?bdLOSKd)ELe? zbT}(J11Bo5Enx+%Png|~1HZb$)BlZ5L02yA^$oJ;FsFOwq`^LYGPR;;+YInkr$IQkg! zoCWjgX^agi5Pn?{?mtWzs8E{Mo=0GmIi3so_l{=e(H;~vc4<^Rg@DjiyZu%%g<`sC zv9W!@>AoOnVXyR|SRfcf#y1SjsN|-e5ofd+Is-W6YcOR|SPwk2Si(1foHtOQ6eic_ zy5ijvk_=}*-W8312Nb%qs2#Kbs{VOl@4(fuZ=~T^f*9gzu%jCuc4i>#kN1WVMc-je~GZ}+lw3Yz1&JZihk%=$!on7X{3jC__=6bx$?1#DCQx6LE(k^ zK(9XNv+ou;MX(}F5LOYsGKsz^P0Lo+GYFGgM?olmv()7`BO=Jx06%t6iPm zksyad5l{<}EW%juYw4jB))KM=a@wWIgjtXf@Tli}WhG7??;bDe`?{PPr&{;OXT-IL zyLJH2&SyX>(4p}@nvSnO6s#wX;s%sjU{)ekAOH@7DOisv!V+BJh1Zc5xQs$FKrY~^ zYVU8xq8ve>k}>EOnS*T{QO*Z~;&RMOwaTQ-W{m~Uf1Z-3jDs2E)%dEG8>Da< zn(-zRP}IB9$^fmZ!@eko&^H!!C~_>Z>#%4i2_sR_L{3&)r44&kq7_|JqHdMG(zGR= zdL_C;Ai~PTyxblUK-=g~7^=}Vkh%=He*q{Ti?>M=zY=v&E-(IQHL_9`{?0zKj0<(` zv4Y#<%=_y=rH>qcT0+eBc`^Gev1<`F%XcaO%A%b3z)9Q4K*EYUcJo2smdTc%QiVZ) zgK4=(k#t9{=@a?N_?C+_$>(cWHRTVt!Jz&akrh1c7IZM&_ZZ#98+G3-awWl2*s)P6 z*VLi#5FRKJ=ARbk8EfA^8QDTtjy6A1Bhu!vL2^A~=Sb5hC|qx3v%b%Yg@z#U^2&$q zY&Gu@xL35|j#0R9syyAtI>{SXsAn2bnc@(!<*di2n=d%BJ5IGReGb%eg6NWLK3e5x z-L;+8U4!Y8NH35uplRN&(<(1;Bwp4qm7PCFXZnHGLLXHD7r|3Bz%64cs5{!BwPXke zuG+6x`dvhTvWCAASG1kolPZlt@EtK@^}g`>KGH2h8T8p>Jqvm9q6WCcEOyFcMEdBN z2GZ;+EMsVNcYSeQvp-hR=!nCUhRr&5A2x+pKIT$q9@96YnN1b$>D9agA&U36`GNk$ zp(IQ8Hs@2L5qL!8OT_HO*_WtpQU1YXh&kJ`82>a}*)Q>OdjNjM?>u|wQGe{UlZ{ok z^Q(E8EPd%+7h?1W0>?oML5_jq_dN@(tlVayw}t$wDy1F-AWM*ZxObpW)PojweC4GO&GJ=r86QZHqT&B#w8qQ%>4>S)Gn+yA`kohT)(@w4 zzsJ5#h)ctvP8Yd<)1)MwS~P?{zB*NeNGz&WANn(k+elFybREl>DPun$Adcz*Jj9K* zV0la})yk1J+cjSgOkhejjIj$CA*0&uopXk?qy&LddYzpSxQEI*GKWSE=v&4Wg(XJ^ z$m4u?R3-RH)`$6d)*|tV{F`@SxYB`+hs1Pq@LnN089XlaJQ#|O75W2|Th5o&&39KQ z5$ZFu>XJavSBa=TV>dY#l3Pn0$>qwgbD)(}~5dU&vZ^}-UFh=`bJ;0$R*`u@A zlbuvM)#E+JO-{Y?$a61w7Eq{<&lwkGK>);i%zk`SkJH?eN-NmlQqJQeDb>muSw8$5=kp+_EsxA zJXqmoLrgfmH??QdfKlrVZ8Ud|X`nIOP3EgeU8{X%tz9x{e}R%l0@2*$Kf|=jlvS`v zrlea8^m(({D}dNH2-1smL$>EMxj&fWi#ZJBnZizx`V}l=%{uG(bvmJagv*+@2g^UH;riu^T z)a;k5*%!*b-=tCYp|X6=_Zyo0wyTd*m@*>7<*OTz5|~daCMxf}r9hT4^sYBrB-gh7D7a@RrpWFTE~j7;5k3Kw(t(~w#TEMq?*=FEomX*s2;;iT4U~GSk z@A@b0Yi80ffa1f^(e`W`z~1Zaa+9vbN?DYDNQN^tH8twCs-?Mict)gup}_(+fPqU7 zn#l;=&A+)fSBa>?RN<Y8ai?w3Li zS2;H}HiC8!2#k$|;V4)hfZg4D>uhV+v$3HjfWAH`(wnE(dky%tlz{j@GPu?N>cU6x^0BTu3@iU!7Aq`q zB;<=+XPDD3%q%C$-SliVuwjq(;2EjNjEfB961z7yev_B{6Kr9B{6hc9k^bC?v_>Y$ z5JI9vx(BoPoi8o&6J*z@s=l8oBvqMTmiXZ)-u&Fw58##8Uk}GgJ`+6qIMOEFCRk^V z3)fWY8a-zo>CR@PUz3gfWd_R|l2N^JxZ^)f@}FjLb92|SyEjDdlRgmr%u%XRl2Bi- z{x5sF4Bl&X#diCBv-Z|~&1~V9N?JvKt M3RNk(WBK?00t!l|VgLXD literal 0 HcmV?d00001 diff --git a/spec/_static/images/dtype_promotion_lattice_no_complex.png b/spec/_static/images/dtype_promotion_lattice_no_complex.png new file mode 100644 index 0000000000000000000000000000000000000000..669d3047683d4e149ee03f560bc33093d76977a1 GIT binary patch literal 65646 zcmeFZc|6qb_cuPIq7ZKq*^=HxOSjH+=>2?tH8eexx{e~y&TC7zj{=YU0>zQ7mjMX z$M!LH`{rII)&s%NMl>kgf`Q$XLV z?Kotl<-hzBdN)a|dUf7T!*8a9Z>%XP%zt?>cvNw0)}g_lR&ZU-GGB;twwZ{hpP! zFpATFP5fQ0@Zp>RkREMGaAPQZIn~H8H+ErXwETPz0^>tZ2_K7WSkqdr6PJ^nnK==f zVZf^v7jW!5CxRbmANd{@;k_q0Voh5?-yN}{?dT8hj>jr3u5VeV+*4lkZzzaeh+Rl% ziD`*zq1`!^ULaQ>$=TFDJKP8#7fGCm#?35R@}jlhsCQ0aedzV*TZ6)_oq~|x@2UO8=JPfxppum%j%6^qru^Sri}!WSMtykKlWGY z%4qBIO1AQL(Jx_P+YPY!>D$x6ztc0;0~gV5u#^Rvf^s`h<+D@xn^y#jVpE>(WM94! znxs+q{Hap$G^-E)I-6o&RMoeTi#Z(44BeXIXSYWr!}P@Z%z3jvzv6H%R6q4PiT;5| z2<($PvFQ;+2S{r?v*OGCoZA0~Euzd7GO{~w694@w+lA(R!pr>Ha$%m^Axc7xcd)S$ z#$u~E$D~#?M<=!?>DHo}!E=nWzu$uo0dhbeSxy#cvAZG-tG7e@cYXN)W6AiW<^5S2 zM*Dk~&Lexs-8(9{_$tt=+W=p|*$cD2ar)=MOuq6+$rJTKG#(T^Z%L16=$9*B1zA^^x zaSe@g&n^q*z-XhJci0rUAw=4;o7|TDqb$XB<@Y>|*|%)m74NbszFT+4;3h_WYJgWd3TgLnI2rLgxNLj)bd3&d;~pfH^k`*i7@d zQ?UKBY&K*ie9>W?8XK|OVe&H=`VnM8wZZQ9f%SK_ml?Sw7R*EPEXlRQT1Z5YZyawe zO4o=wqi1$TKJlV-zk@*A+XRy+20PwRBF6X>y9`I?F{kg1RnjNX69i9~ zevugwB#uTu`~gN^Q@O&DAf0gx6}aw|E!^x#I-8Onp_ghRL1vd`s*V0!;-|cSe{rUR zr)M1vVx&&&wK@Wu)6D>c%;bnL=y5pvp2s$7vJuiCuV>MVk9!bJ;7o9X0MusbEd!Xz z9@EZoI0A6OBATie_oOdA!7)k|?woA9ei>oy2y0fEx+*9MyEDPRn{&)b=EfQE&@iTQ*x$&wVc~EIvR*n^*m2e|NHiBm~R zqkS-|wYB0Y?sPQa2@8v$BSJ4G%Q({j5zVJ0wEyKk&-BKsbI)OHO>%=w-Cy?Gyh*;W zY1#gQNpB?pP?F7GBZA4DvzE=kz{eKCZ4*o}pS*5-jYx)*`hnTh25OM+N&ZMDzmWgA zLW|}CNoF?vw&j$-O!KZ84H+?2ctdZncS;IC?h~M(TE0f?D|ODEFfgWLLa)DCO6mBi z`NTT7AgMt9XCCdyl1R#Dbx)_Sf}v3?UUCa2*Jh1`M|bFKVKgt|P@$D>py>bf@xo4EgsraS0;{WH-5+k4qBmW?`chY8)NI z-`x8^0CBj_%~;Y~wo4Sz^jAJaV=UeP0cKTA_6l!u|dVzKtgjyuW(%<(OocSO_CqUeAb*dcnn*VLmO|SpSCE65ptnMQQpHW49pc zfw|E(jin;uc;2Mv6x<5m5zNH=?C+w}6e3IE5&AXvZt=vWT&a3(o zOP@!c`?zdMFBuF-sdRjh5EDM^v?aPI^5%)Nuksnc{;JD z9V(0`VDce@Lf+arP4EmbAB)mbkUG8fh5f-o_2J_2twj=tp|XS*qz9|>Dl|6GQ+}Gw z`dJN0kV>viv`&`_JBa&yNZ6+kE)eK*ufy3hKg}yrk3zd0^vtomprJ7TlF7#(nC7V# zJm&=>N_DYC^$ToJAA%5>FO@c0)HXy9eJjP0 zHZug$kyFB-w+cW!a{)afuWM#DVVF!&)FsoC09WIH$*ugYAz!;+HPJ7eR_V?mv zfmSv=8^PIHkuU_vnSDv|aKLTHym{TAA$?tI5bl`PF%oRY>Y1jQ+?*y@<$E%m|V^S%shqr!3+exf9X#ZijVsK+}Nx@r~z! z;6ls@u;W+VAS3IHeiGBiWBj~ME$Q{lZUT6BYlE?8NG_rAYp;Z#FERLNP!36TBoFk% zI|9+Nj%qFNvXcIPyMpc8P!uOa;QCURunq!T&@?Fn-Q}&Rx%}1ufjSOY9tcyFGDb?( zh*?asg%6%_IKTt3v$gyqF+1=x_RYGrbpTDiRmdYu)=`!<_|h;S%3zLEBW3naUW7xL zP3#VEr}_njuryc5U{+JTf+K_e`|*Lw9|~St$V@X3-?PW&S_k7vVT=dcN$=1#?|7zE zx&lSKvnPiN#=cjK!Ow@*Prb?FmR}&y%F@E6zssld))*<_TYDWw10YKtYLbb^_}SP% zpr7@`y{84A-Ar5_ONJHT5yjP_{@((AHcikJnhRfCsC?=Nsb;1B8-%n&HF68^Z6w$~fPgR0$*iG4FQyzS%<%vIIn z1-;4r#mcWc;AaZuXMS3Ag?S_c&nphI$l+Jr)QKFa?U&dCT1t=NtPy%=><1*nYFr^Z zy$xzj1{mI;QNdullFmW_p^q^y7G)#uViy zS##FZA%FjnR~!yBCH4UNKa;b5z+ijN{PgImDG8wQs--#c{K*-2;|8H_VR^sds4*iY z1bDa--l>4DSim^Nw(q&(9*r4oYOmAGi2Bgei(73W?_5OVjoQL?(ic>$JoU!5g~cZ! zC2z)z+O&3ePcgdTdfWL>B&x@Is8vQRl9sh0qI{}A0fH0;p-ixWqfxzV0w~4NwLEZ1 z7=m$sqD`GiLug<>wiz+-oT{yNJMO}gNR&43+BW3 zJTQsapPNK9*`Iac79?%C*O4&{#tuW|62&bOtG5cJ(|qt1 z0C{=zIUT-WyeEo6OPPg~I9cTSpf&_aOsX4{{&E=*`7SnAR+9A?g_hY=n$t9if-Nl0 zmJ#=5hwo!~NSFU|UtYVrKx;t#f_6#8kSYIl0jh&$$Q*LXiGf79%a#}SWd<@uHVvPI zJA`i~kQ3`lDEQXkdbh;cVTA;k8wh*{8@NMikK#jVjII@cyAGrluMHK`-f9((qblyJ z0650Jm{T8DI)Rg^Q%IOo1-Cqa+XpAI!bG~*iEal%uS2!({PtOz-Mk8U z-@@1gB`Uub#XA1h$2q`~@2U=)hy9+jCMY-B^;vp46d5luEqj|_JTF?J#G<6xJD?{; z!LHsdiH72;{SAm?6U44w;}+J%3cJx!Sp)IHG{o2tnd-l`w9gy{Owq}{zp!HH&7WKe zox%OzohC4QL2a_{;kRw!b1%g+=Z_@9mAnw&)7sUlvy) zK58<51(+HZiRYx_2YMZR93ehVtiT?~kEAsg7X_g=YHzFBYL^tb=MG!$PS2~@SBMO@ zJaI}uu?%RojQ8Qk?PLGs7D?+=dR2fhv>$W3- z#Y||tB=>r^=i?MrntKlj^AWtnpjsc35CkXzDt4Mc8z+hr&g)IBH!8R9uN-D*wC}~y zHz94PXU3{_VGaY(Q5xdfaVZgn zq4J~aF9}L#_q{fimo+O==H z{OUz4@`*FATStrRy~EktPy0$*VPz(oJz9>~gec+NwD(N^k8a<5_Uqb~m)2*a?|Y_= zGqGbg6mdA@iYOSpJ{)lqYOUrZx&L8RqrD9xaB8dvp_`53C z%Ej!nXv3+%>JLAaNv zVA1$bCB%NRB3;%o1s??H!nC$&vxIBI%d8O@vUl!{~)`>4)l`Tg(As zj8Y_EdbKw#_rH7MldKRjS|dz%%$mytg%~Dj>5G)8Ug+x#?H!>Ddkho0@uC zNedx%hJp!tv{$pks8&2aKQ(}6t`Uvn)9cDdMfsw?42nkl0ygUoJ>v-%rcsg+PoRlg z&uq^shs&SG=#BNeDNk52m7!qjHT9(>uMnFhs(0OXi4 z+_SwNqq_9P8Hx()9$Mr@FACae2_p2X^qNGJj>;4Eh4Pp%bI_-h@UxS#r>vmjn8q<6 zhTzjJ0_@}%6}z?v-ImIUIH-tH?;A-5r+#bMM2u>kF&YHTY&v+m1)NTpFMu(@d&6Ll zB^hCVTJ}~Z=k`_$lBhLXX?tJ5KME5GgK7Pg{uV!<`XTLg>fTmt8IN0?rO2Ey`Y1G{ zt-lEvUCJ+2huiwCtq6@f?mICR%Vl>p_HgkeEmzO>L9vKmJq|spcJqvkz3s`L;hRL# z-fa1vtHLf;Zg;#xd;9!T>YiA5+uo%{^}Qc8JkGdbV{}PgQ!cvR(%Yl{^k&j7u^@5p z(r(Qs&$vAloRL{^$VeAhy*dG>C*pu=rt5k&);FS!-Ln(CO{6^aF&fYQ+0$mo-=GoQ z-#E2eCk^h@V%t4-wDzdsD?s${@h!cLfNAX=`#%@;s^_DNd&DYNEWFVhG)zxx)V813 zmR1sVP)g%zeU)L_6}$S8wZM&r?|0LZYvwQH5|2agDLefg6ipJX44FIGu5BM?^=aFB z+v_}I%!67N{f5fE(?u6D*R;q z_rcBWaLoFamaI0bL!b)yMC@vq$wp4S}ux(3x}Duqv?W^cW1&v;AZq_%o~U4Acumg*jsj=9DzF9!A78F0hcl5r&p zH90*-w5{-U?cEluNW|36$C-)gfV>y2Xe^(NsS;jUd$-u+3@J|Dqy%KbX1cq&uv;_G z+wZ-1&75>IVk&K0ZqI3MT%YIC2g-&hdaGtT zV~^5n_@L-cc9^vXRk=FQFLB=%8Ta=e={K)~7flV4O|FHso;sPfnmzbT%%nU*C>r8- znpNZmPKx1NEkMbgDE?Vb5gvE3`Cypag3K?$1MdZx@3Vk8Kf&IK!cnxI{+39B+0kbq z-xa%VHMU)jxWWM)7p)uc>x(b&Dhbt7m_t%F0k-yFh_!Fx;c zGrL-s+0e(J*9zYu%1M*8rPB4L0&UL!sKph;j$9GmoAuhwN56H6PREp8j&Qjybs~4? zMELq3pG2+d6a3#qTaU_TWft0tzM&e7df!W1c%<9{u-Cgj^8>o_r{70iSda10I6q-++4U`?sHSq=twv`x z7SD^APt&UBSPgv9lzi-M?8GxOQQGt_;(~n+lMBrkw7e9#&gvyse{AOnWg}$2iT9&l z^Cr_lEP5u`Sj39#uT)br8yjw0GW#JVF6FB{B-sFCKX+>jYEJeUlSRtQsMpz7K{qat z0uf|4c6qLP)2NpW9#q_S`$1|{vAntWj_Fh<-Q6qzohonQv(oG%cNox)rIGFoVFwR= z@1=krji!|JlfqQ9FR{gjO7^O4A9$Koa7~o{c9a+^{E7fVy)$?Ec8_lxwa7b*{g^Ln*w1S0(rU*V23=Xm^)GX z#}$H1Y`&3%%Q@Z;*QD{Yyd(dLW`FeIQ9Qfcwc0G1Wm5rnX}`}m^nKQ(j!S(&dcA9b z_xCog+?RZ*kVAkc^Vnb%Lri`=cLrEz_bI<=?6O4+gyGHh>hG2U!%yUBGSDYFjoOkY zjJlEN44j;7A_Tk!05yewd%KQwh2RNq09ypjwr9% zH3Rt+KdN*SR)8>!F#h4dOnj8p!F_e(v!3ERx8BXWb&ZWof0Z#y4avSN^xKU&)wN_sq=GkJ0HsCA{6kHn$ z_U&GRqI)+=k}_3vp+Pbxx^Ux%#7l3#BW@GWiWx$e$Y=Zf{+5c@!S#MJ>?@a0n; zu*NZ`dDqmFmxYp1g`S>{&=V|VAsZq-Tjg#L>r=9pK zlNv%lOAnQ22b<=;T3&Qd-TL{ptGzvI-{q4&HO4i#lN1uJD0;~bEhX+qyqr@F-W4I< zEGl}H)OSW!{bR-~q$^=)J9x=>mhk+D48haRmrHjps9xiq07%v_gg%sfiX&}%(qDZh z&Qxh34*hxB%`TtnSTAxZKWd#qIdf|f(#0*`kY)yRS_%{ut}5!V+%EV13ZDY|JO9%h zvt@6VO!UA2`Lnj()&wDqiJ{oRO(0-3D}$lTqp#EG%c|#ght|;7Ei!P$w{BxsZuQub zXM=nK!v=m(VpU5mmHh#xj~3Z3nkzi%wK5ZppRNWoJhk?^daZny)M~1hS4?+9%*qVo z)8CPiukGe?`CvB=nJ!uq@{Da<~5Y8WTE_eSMdj>lbc zcH&LPUb(q@U5cNciz)Yx?_vTK%L%mhu%)MZYY36xJ1Hkze&)JX`*1-ULb8Y>4U+v7 zwr8Uc?c4a}ly_6|x6IbAsV)31OHNuJplr~8U$6g^icB=j-4v~#TY%D*fwLs~;E>Qf z`Yr8fT7_D3{&mMkvDpQ&t;NM-{+(_7j=~5>{Te0J%kSNuekh8@+le_YsjNE5c~11s zhub)<`C==~%3@CwDZbR7-M&Q^)K{}_^shA@LHCd6^Pz62)9Tv=O{mWSi!PsGA1+Y7 zvba{$*Az_Mr2 zzoy?GDj0rB_mu``r($6zxy1BGOrT;0fd-iCkLaWC$V(qQa8h9-E;^Yv*dhm>u-IFD zuzg2qNi48ltG-}Wv%E#{6TR>BUgB#NpJ|#cxkXvqhaUjb)aqPSLkM zX#6w`+sgs{u-0JSbF-;PTc6KbIk-PDNonph>PF0S0?q&G@L&Gz5nh@RGWU_NRjmlTbEsmA4cfk%19azHt``D+le4n7sio7xW(MM)oFk4JWI zazY!7qxwU%E-*t^(&Z(hVjCq1@+R)n0?K|%B!j<+{8Pr~9EE)wB=2;#iTF}!AM_Iy zxm@0BlbSj%@3YHuP1D#qbma%Ba_mp@tBcB3f#a`^t6M4eGHG=w(fGsL4hbnx?dJ89 zUsWyLwD>7Ux0LmJC^ZPrS4ZW0<^lqG1x%c;E&632-nLxj$!#|`gj6n{&nL#Kb34~l z=u<^xqigmO_GVY^9)^_pO1Va>i z_T2NhTUY3z#sWN2>ag4bZiUdp@0%|RH}Kpe@-8_WD&bYca;HK|rtBG`e_JjGY;<@v zR3Lj6b3GGZMw1U?5mkwTrf61`tc4j**DBk#Ozbn zex!Y-e=1|AoEIf6W`FzSu^ZYA)~C+6qJ1pgr89(kb6`I@6AC_lNzC%YSqQYn*(YBs zP4!ot`3EKK2}wR2HoDMhqlYxNH9JrCc!F;=T^uNtL_kQ$#R1GV4O=z$Wvkcn~-c<^ml(r)J0^wRUxg)M)e+eRMYCmKN zAfJM!t4_~kiGN(arOWbkoQvT>8g)Ln!X}rUcq6{XC{oB*H)Xkarut)U3qpbRED>=e zVbqVjX8lBKb6W`EHIc7I<17Mqkx3Tx9i;LJVl=*!G@ea~HS@i2(NFZ=gj-AEQ(6*g zX7f{FHq^p08CT+Mu`%8dF8S$X_y~i&Ih*=%*}vNfC)EgS9N=u|Q@&)h6Z#m zYcp7!DtY`?8ctU~3KQegkn<+m%)9>` zGl4&7HT_rQ_Q{WvlC+opA{YH|QtHJy?LV(-h@VU=i2knhz(f>vCkp?<+o|rq$htn{ zwC!rKI#26X{AOA;jClOpm)gRmN-J$T5H%lq#DY5QW%NIB)b274(O15gq{TQ+^?opL zA}vqmQvg@Ymi);u&>uhYI^@=w6VZws*`=zxxdAl=gNrU8CA*7 zC^?6G^Qd^c?2{nPS8S8-V`&$2%G5qw;3h#NJFJq37$4A|UA*pH5xmpoWq zd0GwKVDjoBLb}!9PP1h0D)A57rpRKq3Oo0t0+~Syw zEOXJQmpAdQQ}gt4hf#ZfOM2eyC$DCYi7RW0ZT?E~2b}Ck1n=ae>f0iAs3s6q(?5lB z?R=Cu#hV`b1V4Qh@SWR3pW4QY`q**JQ7)Qba5wws>);uW5t?2@GEB{?@DUi*ANT&C z8FiZJths=0Z2$tNeZKyl)N!`_AhEbY6N|gG3QzE(WjDbzHu+2ft-LK&9GGw}`gRw$ zuFC~UR&Jt7Sl;|YzyZ%YX6K{1n>V%Si%_%8JFSp*#1z|aTIk{}9KJa-a^fuQ<&hve zO~sv^b(B}2D_a^1hm4JO2siRD}jiJ0X#$?qAzFbhH)IlOQbbRLB zypq{~ql=kf&N?CA6TzuKd+F1mF*e6jJMRYR;B{cPB~ONRD*o&^$KKtm;EuR*V-Ps6 z>>i~h3TH4puN0f@DJ1$Go;^$Etv@=liW{VQU*6V{so9D&FPh7B}^7e7K}nhDHEwI zqiz6r&e*3&x95Gy7o9qIs6S418vXkVnVTiyv-^8Mo00f31W?)2&z>J4bgq1CnTHE& z$j-c-C@W!yect}t5-ghE)|TWn`wz+$k`~R6y3xC>Ch>WFcyuLU;=P0~_fWUDg=Q2U zkVsLOr(c+ceXqPpS4BDCQeZ(=3Z-|~HWfb0`nHQovP0(r)!7QS2((*Y;VzSJ=e(T| zhmKFJB=MMqEnD^r0s$4l!pzDvqS&S6BlykfZzWk{#jso0snhOi`AwV>fY$m_Od1_{ zl1QNC;V$w9NsDPFCzjstrT}W|`yFIo=Dd@s@BKJx3i(SuS2UhmLkS34a%Mh&tpFpk zx!T1w3lr{e)VIkycK(&`QNbIhFj7(Yo=FX~rHb%~#4`k7Yj{PS?6fj$F+9j`6s-|~L*ZAZzbSr|?@|+1CUHT1xh7UbQQ0%y z$@!#Z!A>*aV1Cc~D;%Vl)x@bp>xLC}F+OFhyvWW0NHw#H@P3T@b4}XwN^%P(LQlc@ zpLB9HMKeK)R@yi-Hb$WF)WJQ}31t@k-Zb0Ow_RQ7@+SSK-8KcE59>QpuaWi5^7n~@ zKv1a^&HYH6fd28a{uslWk1i9*lVpXL&#n#fE=dVnw)^D~$bg^d&4mmzeV;kkddp@#L6mEScL^Z6 z_JGMNnJ8H{A0fAgB6^&Hs)n*Bi0Qx)O9{?Y6u5l=3ydgla{9MW5YFX?w}nR{TRhL* zfk5zMc&I2fISFTEpWmby5L%Vl6f#D1a^ge98NwS3t$>JG8GdhyV$`d5`p^9`S*9|r z-bk0{0~~pt<4%>^rF+ln;4_|Asf}LAWAlGWp_`m>v+wF?OYPcwBOVG7rA0O-20He} zDucfIP+M|XPxGxFi(y+v`|fP}U*E2~>{B*JXBdU=K%bWqQ9v}|mG8P+knm{W#m`~9 z!{!s26b~O<#X|K~BKS{8iFtwd_7vUQ+LjLJ%gR}2*hgTY-DK1*nfY$sjAS5W{WERJ zmru27dOZdCSz}`p&j1v!JtaXFLl?akR~+^8xc;T_OU_*|^R>K#mA}D8+~kIgi=x_6 z)stDUl1lG>z+sK`I9v}J? z55!H-wqPKyDIw7I1P?3WrLP42CIwWrKZDhx1W;-}0vS!`(?Y;}sMB!3!^yUP^aLMm z9I=bl-r%z(Uy8za%6nidMAH*|E;TG#Ug3ryh_`T{Jl5i9r6m5nT0>Yw?d1s#BJKHW!jc4e_u&?DFyK*(t z_Bx=@cM}H-r-RRCz8Y5Mbr`5$A>PAf&4!MTYz2oejIi%Z2p;Gs(}PQ#HyQS2>`-_Qkw?0H&4V6DCWcdPIA}k7d6u z(azBnqnNAlFFi#7^$+T_9Zu@2fyb3=E-~-sai3HOvL|)P3K|m*U*TWjn$^2E)S)MP zC&07QWvTLfwS}$_K+^ICZNX-oeD9O#%Q4x-3o}p}Khmp*<4f+Qsv|vO-92F~9r69fzKN=h0wk{0{i=TQ@l?DB z6gcStW}o7X)DXx-tPwtH`(tg%l}qz-qEO`pd6NMoc(=-sTAVF!YVj-!abDOKOr>#M zqP-N;KF#tWzdf%3hy?M0h}lh?|I%LiU5_=qfhf@LH#TnwPx^U#AoN4i`0J=gJzPQ` zQauOQAfx7=$mRB@bO9oBV4yvRE8mM8b;_kwFPH0utwFPZPo<@&$aUuxUElZ7HKq`O z5|2Bb&_bKxTn-6$xZFCMC?GVpc-KRpmf^@^Q`6o=X$5tSw6AZ0N8231_f{%6wGAL-|%hM z=1t7oq$n$2;tXVC1-EBnVCG>G<8K?ZK9*1ba&w=huU-orm zsq)G1Im~JA@!q;-dW(=dLZQa22l^)QI+mBXP?h(UabUdXY3vE868+ZAnu2WXwSGNs z%cSjZ&qj^Gj{58MX*sa&(c-QG@xdc#37SuOd((hZ#MJyJuY{b3fMiR5=2q~}NoqZ?ql!glLCW+o6~dhwcN`a3PQ`;$DHaNFBt>n@lZw zE9^DDxzhZm{qIBuu4O|ley`E-y<4#?C($ZteVC$jPx%NBib7wa^pEIH6iYAS2PGPVp0`aHJK{FTSC_g`5#ZNF?megpL>emV8MH|v}0 zUY6A2vH9%znbKgBZPn_JE#^>~Vm$%g3o>yzSfcNS+w)z%0!!JsGv;RNQmIBoiKA-# z6X

U2+Ed_YcUl(FMYjg};Ni0wUS%QkYd()%|L}&Y9tJzm+27yL^oh%=B*IDX;G8 z-S7Tj;CRiIr}Y(XCT!uDZ0(hI!AG2&uA9 z2_st#UQR$%?6@OyM-+Hudq%3l$Ssd=A47x&t-f^wfcv7FY`8c9QIuHV zR&oh9)a>xf?CJs;ok5i6-6-3Z$41Dx=`|rV5Z}@-+3|fGe$ZNYRKczd5XBa+zoCwg z$YytZSA~OdQdX4?!jsNNbk+`zRHlIKVxKDVZaCB6(#*T@1~2VDT*f} z1su~clr6H%vkp__`UjcyZnI=nK)2~A;j3A9KPcgun88TEoDobGq1hC0!*+q1R#7h2 zoK9(yyBO-8skT~}D|{cjMQ+)Q9W?e;_ZLNNe#z19zs}5Q7XsEsLUVC|41V zoE&hsNe+#xnOD2^HcPh9^rX-9SPV8x1X&zuw3P=a!vE+kWc<5GI5NO_(3ULwh>Y}m z)!(^@IeLHI@{ZF4)zJe=GxgVS4q|h`&U7 zHTF*qtG>tMP~SBK(2tMH^u=$bvGQHyL?<9=_O^1Yhh`METxrbaIEwvS)bTPY``NWc zx6$j*Ws^ToZ`nm=xAH#Rh#tuH6!a~3o0Mc2e@rLcJk8$%6Sa}PCz8Cv%y!IHCvI4z z6qxDHDq6_Rgjhd$+Wc6kNCH`9IOXUkis(UGX7nxRA5&@=q56v5?kxeZ;k)ESR`Zi6 zwY~=tS;Jpe>!VK&SYQa-44%4er~eGS$wu~C&+asTAixC+taN@)yl@(*edjhY{p zrjT6RDgv-ldcFJ?)1s{712BTkZUxyDbYH8|jcRjo$1l}pGnX!3HIw*iZnTKD5B1no zaAI#)UmW;%uyzpx%Ds!-==a+F?s7=$@$sUpw4`jw;lF2$7l9C3lJxPdt2XH}=U)1| z#I;-!3;b~|!tA74bJClO$2l5SF8FCmS8^@-IzGzEZfUJK&w9gA-|l4i9X6diQ3{Bqp%5jzA+Hf@iowdc$_7?%Co(>Ql0g|D%MoZwP!=P@cWPzZ7WpR(|fgsgnK@ zX`-3ov>odGxnVDv9&LWe#YTG9(tm`1AuW4FWDkf5^!dF{a+ zq8hdAOjKY^*@=HGRzf#$Uqg$UjJ8g^HNR83#0|Y7!uwWm)KaWYtp&C=)gLM9Bb!qU zJU0pAmTH^H(s;_5N$TI_R!cVPZ_(=kOl;B|l5*kN+Y8pp9=&w_MzR`#rO*n2O67(Q zittv)bbzZ$rI(*uqegm_v|V#%Jchbg27VvpDVRa~xRIM$?L;omqdyl#U0%C^w|I^gn6si zd#y`wwa-)^3hK#W+V)2IzX$PU0NJ@5tlT3;oOK5FaBYwePC;+cW$%*cMAu7hXyXMn z0+%~|)=`ZnC^_jY@au!<(Y@Og=hKl3&PQs4fC?X=eYB>Xm`65v>2HhN0+%yg#+8XL z8(yFb`T*U5KtUHk8o-%SSfg8Tj_F$^+5%%2%#6p| zhhuh=wkuQ?ebLs8K5^2XWVk2or|N_u!`Xy1Vvks$+0g6lBT0ya>LjJl?FWJSefZQd zOqo87RPn=MG)BHA*gln)da~^Rk1Op2rS1yuh;N|x6Tj%$q>hE>+6UR)M3~a1X3ugD zXAeRHrZUhyxn$mT#p@9$`Yx7NTE0gVNIBQ@+J>z)0)XU;DF;wWA0V&(1cG@3`^I?K zxINk@p3X_4^86g;>}eeph+Or`n~|E1 zyX+6zyLf>m(>V^B7+J5?OX>)$-)>@*>3(E)WHP)aoV2u$?7H(Har9>gkm;*k7%_LN z7a>@D3G@ygQ>a@QnN(xu($jd()K0oWfHIW}<~BZJ3gHa%eO&JLZbBOq-<5KIKO^pw z?{ry6FI?E6*QwZ3)`58~Q9B5=P*%i-*L_b#;wo(=VQiMz+AAL0zH9n3OnSnI|^Qopzr_Aal8?}90B43@c52`GZ-Le zpVxHNUld)-!wP6uTmXyCg}OrBp151l5^Q~M4t{@DNU-h0S8qjk)EQfpo{ny z%kuM=+rq#fg?mXj<$ew2ZvyEUCW=x+{$3IQ{)Y8FUINfp#G`u2#^%asX%%s=hmH16 z18qu07w`SMl!cD?((3@gsWe#*kyid2Bc*%-)58Qp^;R$uG3QptTA4}nk?5q3p!zC{ z>Wz_o=-P2{zznFPzc?$kAw$)zm6^CTi=kB}kl#}NUIGpp^>}FrNQjOW)mh39U;+|u zn=1zouYx$s!Ao-sTK_uOl!^gBBmgiAC{`O;!MsKQ$lq3Rkf?WBVy$IjB89c}#(0oXt(GYu-HX`BvHoW z4phC{O8|ws{Q9WP`hod>e1u8z8Un1o$wcakWA2OrknHw@j@A4}5ktU^EnKu$6jQK% z?X|l=^PvyL4DS6ONW!?o6I-ZHp0bS|dq9*3cS0|R7mcd$lx=$ezyq{B>+NGUY!pQo zPdlpmdj?b(gb+hjof&s*+}S(Wk2DEP`Q(Mq{)dRg!_S#(H~1Xr#t3#^`8C z1_gKsJX;k}a#FF&*VJznO2i$)=`z0p-U8s^{TJN8A`b|7w2D`+=5w8~ACC!q(OQ`r z=-JV;{pfreR1WiMtmuB4i_@+?Rljx06{R>O3tf_AJOu6<>|-lzb5Ac0oI}@(Fn1Vp z>(>4Ui&}9PTk&Uki4j%w@V`q5B**#oqURxV0GUbIu7rHlf8D(0kY5DQ>0G>O@;=Ef z*4U08G;^geplWwNH=s8Sw*oN>@!Z*jUP&_a{k$S)F(0t>#I4bxALRfp_hTje{~M}1 z>5A%32tX94Tr9sN9I^O=nY=Xla)|V>e)|?y6^RX89Y8GAWr{G-T+{aa9EGs6r?brm_krqS$Z&h{op@K(*;cIv7m>FC}=rL9*SU@z!-<0Oog%4KXFd99klsCP;L@1fVIGW$BqNFd_eC&(`hiwHlF!vX#J&V= z3lLkF=wa9sW|M0u`wE&JdIPB8rfMh{CIF>xj@6#k&F(U%<}NKHlb9vnj5u$*`jl_( z-7i&3LS!s7KH@IwsR3Q0NJngzmGI(Kn|v&6W8E=<>0lEicB7|ai4p7V%7psv*Tul= z8)yswaBkmU^zV65al9kCKeON5kF(Y#Ub2MEIf3ve*B)eeUqn|@$F2K`lV~fu{38O* zD10Yamu)PdKI9hG0*Q_N8Mk4_um5CdpXcN{MzO7Zg(k5jI$?a3&6(?0|NgH96Q=Cr z1d*mdvYNX8_a(q=_>)%0y2gjWuw*Xb7CQU)(_c&GIGDdoMDApp!(?-JHJGH1O~1&D zi_M(*cf?w<9LH((By{-RK_8{B>;O8HO&}Z+Tz9?EBx&nY{fno-6g`=-$7`4Ub zQeyW7l9X6Wm&6tc_7$Gh_o@Y0Y%cG+>z4AiOroxkxdThN0UhJD{RjkYa`(#(o&Zx^ z2>-nWi(^(wr1hJ7js>9m6%v-1#a5{W#5!8zL%!gat(nOVe=UWlD78`lG+>%zKz%7{ z5ogccx^}_lmqmoje?Zs&yWWCNSAeS6=C2VvN8azKUiE9eg2g?E{}@h>>YxhF(WEM> zfm;+T=2XcY#?KQW4Ok^L;$FIdtY9``A!tt`ujcc36@sm zHy?aQt4xdM{bPAoy~DiEMaV)+=25F=C=xj@Ah*N7M7iYnYt~vHHwcAB^QvE{1V|F# z)cw*ZSFP4^BK}}V*DhKiQ9u>TO~$IHBhd6SvEQQQZP`t{EEK(f@@s-P&$*MajG;J;UEk1Y`vQs5Nft_5&d@}ne4r%Z{a?*gMPKNl z{R#{eLt%6+7u;oyU;sGu){Ar+AdtAihVumX7p=0-eqncKROca*>?%1r(ME0g6Q5cz zXMX0g3TdfUz8TBsdK^)5Jaqx_7!3C85;7T*7Xjb{5IL^-LU~^X1qP0=wf9n8)VZ*gbhPIhjyn>TR2h=(JH~{ zUsDr@Pk{kJ$N_hS1C_dViA3Ujz+&FoK?k04B?hnzoyIp(Bk>os#88hT&>Rl4#J`_a zzp=4Q{PRsko*rD1#=+Y5uTL1R|0f&H0|AE39~K0QGY4D29Bk|2rhZz^L7`lg0i!S1 zK-^-qHN0jOLPfRyGS_>A3A@&@kwYu8FwuU!m;*mU@}lbM=pQoLG;h>25w#gs5~89I zZuJW$2-MO+9o7grScbF@=vad_F(KH*n|y+c!TjI)K8?LwVmbg-#OqG@%V(}U#kBUd z^tN8n-YyDMe$HFd0+i=r6SYIdl8n`e2>W`sr?eyIL4dw=|5*bR^|5mOhmIA3p}(-( zTt%#nu|HG;6c_BXLq%d(WEiM$Lnu7+rV{rOD6cqJ4V9jG_bdCx5?w)ebPsjqbg3YApdvHKOMqN2n1Ks!K3BjeaTYtkdqW z%{B&ibt-IfSnGW@MzKPVS31JG9wr`q?n z+xP0=Zw;QswlzQ>fpvlUQ|Esi-U%}=LEzsXlC9K&$D3bm_Zc&v^ZgpF9iV2W!zgzb_MNXw2Cg=${{PV3Z;ewhtP@ihg1p&%b zg(@G2u+i8Eje-uvUpQ)u?gH2-yKcMr#GS9!;y_g_^BbV@)ElAq*5#${LFK98y(4%} zxp=3ijt7GrIMvQZV8c7luA7vyB1p#|Q!*v@SrL!nAdICC)vCwt?}^urj!HtzF#|pi zvn{Ys1&f>=#aPHy0e76;!mV)ZPO3=p8LPp zdhd8B{P=PFjHD!F?@AG}$7M_5oy_b_IGgOfN6M-c&RG$0va+{`OU|CzBb&4L`o50$ z`}6&LAHU!IQxEsL*Ld#rdcOX)V}GcV$;tvo0#m(_kWvp0+K|*#U;bz<(h|F-;Kf8f zm&^YX8gB%^5%Q9Ywc29HHxfIeZU6u5;C*`nkFiRKVmt1LU*6k`1Ou-b1Yx%6qbf*W z+mJ>HW}&TNCNcKW?y);i#!tdtR&wz`vG`vNyWMBX`b+TXrp})A*#T9o+dKw?7YL60 zC1d{9kE{=RXypD5>hhj5uNjI3bB?{}d}HE`bRU8_!1@g1i7gbq2n~GXJjORM9n;-h zJBBL@JURJzUJsW*mzAHmu7xRnh2L@KugS6!RxEzMJ!}?xDux}iW)9ZwUPwMYJyl7F zwXe3mSs3@{N(n_^f|2*qYF=Tzw~kh9?&1eS-MAiWSjFS)%JTtpx!KAKONr8oPMJ;M zf{K-?I)6*zB*rcd_D{Wxks7#{SiIfAm$t>6BmRqG#pY1E_%I;x8tle>$f9})9>`MZ zKrcex@eC>V!B9xLO2H9#|OR(IMOL-h>qvnCv9$xEAW?3>$0b183D=# z%B5z`VvY@!V6MvG!c(Haw%1pjOHN9n?u<{vw>!$+tg}1J%~s?!(?*yXa|MvxP~`ii zF|2dbDKyih6#zE@-D~ezhs?|Ue-+_tD8 z>~@Hbuvf*v?4U=^=L>l|7ti=IiK4Tbs!N#y2OB2#-3q`nw3zYlu#1V7sh&^}j(1@T zrmaToGDCd9g-r^Ce8%6nWz96j$@c3%uw~7{lRivNX|T5)W=3Mi_l@0OW(qLThjksV zC$mEcrDY}NwVJ)r{wQXb4AyPXjfYXJBB+4hsR7xh*y#k?SP(2Z3MHF z?AMGV8%GQtI8m205o`m+S5`I99C6GiR+a19gJvptJ7r?1cChDu~2gqb)yPIp5} zHpdKgpdRsEYmgjNDH2tSt>v&i`$aAU$F>DX&v;F?pP7XIl9F>#vI}6qi!FfM(Gj_z zWsKKSRzjzoWn^|(3C*U2?b$GS+DWW~ObpJl|4)_P=r*=Qf`V+k5v0m+>cKsGJ6-#i?cN2bWMtdP)Ii#zaNms8x5|cobJ)^TB~}@c z7&|+##!~A=-CW}{aM$9_FACrRFCHR)vJHZ3pWoF6*`u7^9sZr1YT1mEV4@}sOI?BU zPKlaE4HFIv2)wqZZO!p9vZ*m8O$m*O9UvvJV{AR(=!>?d&|=i>+Y+(l;bh3Wb7PqO zmA^#EGrYzZD3W;l3?>&OXf1;$-&J?=Hkl-D@g| zA%yPEkDJtt^u*Bb_iii_=3jp6U@mMex2;#m{fi>Axg}Ls(mj$er74&iYSss(BXp2hJzT;l&b!J{{zrb z7)w9vul~MPXN(38mwvba(6e!E4iB_L z&neJy*`QGf?f129r%jCAy z_crkNzPAu{3PK)>>m4QDog*6qZ)a9^AO0z&H7m+xZ3Nx7qQU;CP+T{y1a{C{#Rtm5 zTbEO%{}DKbY%NQ2g^zDWXj=y~B9mr`>3_S? ztSUp}0y{ zY+g$851wDqcC+tG5fK z;t%P&+$bM!zYJ_^WrZlEr8({x#=gl+yy{-f`do_c7Lzmu*I;#Z6CIoZJr^VDINK~dD_n_tXKC|;T2{dFH_ zh*7m=8jPq)yDGe;M&~g^kwf;do5p*`GPHqsQPU z|I^-(B#T;J^B;C*uWlZa;{kk&NJJ8p|A!PrREO!*yE4cd9Zfb)91V1J7;DolFC7*V zI|_L^@83@pTHXgZ8YmkW85AVlVCk=9CEpg8libgo)p1h#7?#@WM*g_rV1n?t#X{4S z^P>MpdH`@79><22jIz{=b#fEo4wX#Qb+~EYK=XG0S))TQd@eb9g%WYkqrB1q^DtokY)h2TRB=r7aU+i8 z!YUW@wxc;`aF9f7Gic?A4nt?NLQdecoEHK?ag?*L*7?rJ`$GLk zHNJ;iyVt0$?8Q5xx0Mz`;;#fZH|_tW2Z-`Rm0YSel#`Dye2YoL5IeIi~y(V>>$aod5G^jGl_W|K0Ttj_x zOeIxpB=ltKvKuG7kr|@zT{x_r!!C-Ghuztwi=(K*U|Ob}V}0*2(J-<;Sdnk$`&cGg zR^@T_qtu>FYaOXRVgZ~+^9g7Hy^S*uXr=+-wLU&R4mbx6ZG-xwklh_x^Y5*Rap0%H z<>(&%x7A(U-(fKSUW|TNI#$%vbL0Bm$_0_D5V=#PtrssWs~Ef1 zm72~jCouV*5vTafYKiwuQf{1e`xB=&#)YJbd3Rj5wUytc+f1I;loe)4Yc9I#w6=(W zKt=<&rQB9+`(MVd^R4Ikq+MK?gfyDBs5#|Hj%%w)*UV0Y_}Jc)qD${0GnLurCN~zV zdkvZGTgB*RJJ8BC^lcxJ!Egh)Boh+c_PE5jFYcH^0(IF}BFL_MM;7u>b%#Do_m3Xd z35Ughjyh!$LoZsj{vARS#0a_h@Spkmu z`BmVb9oo{jcaH(G-kKSA+x9VK&7uC0Z6V*-nbMKux_}QERNwpYeX;*W>y*6SAYrHmg%B|{%m7@6}HDDi%w zziMBk#R4Ow#W&10vFWktx`!9WS4QLJs2B|m`kgf_D{OD!6AxzW?pJ%-|u=ZfY&a9F=BK)*Y0~2UgPq| zH7io$d_8Y=`rN^J?5QT30E%^VbW|*v6>UBbF)7Z7_M8`(d;!S|BJa|mG><03;I{)l z3&y;uRHa);Rm`cQ;XyM&9=3+kw}(4C1R*pqPc$Amx51AOb)ubnNg55mLX#NM?7mf# znjB7MeP%5|g)@t>x#fqVP#wz7Y6E~FsP1`~>G~=QVw3X_yIMlkFG1Jm(5ClMMswM2 z?8(zj{0QH%)iUcK%7v26A*)XB~|`#`B+mQf3mmhLj*{I8djLgarl4jrj?;MR!nFCHX%j9F3 zQrIZ@!6q)?6N7-t1ojm4U<2>q(|wIBBf^x`#O-e7M*|&64+ELgLr!8G%=-GIfPkt` zCpcW7Lvmc1CuoTP2~6I+lJ7ztXzDg2<9yh(_2b8n_qstN+X?@IcAQj`47D&LVXK3k z`T@IrD&=gLlAuljcJtOX%pQv}0FH^vm45*C0z309x=MX7=KaxJEYu9jO zd;sQ)yqz#g`t^G4Se4Xxn>oG6i=cgfxl-&|UM8HO-jA?_{YWjjBdu;jxF=$$GCT)rPoAO?_D#m6}&(vM2n}hZt3umUMC#eG!`Ok zWcSem$-kCJt8-ZVK!Z>y6k;k0_R#&NE6|c-8@mJPy9x>NCU^gc`}7~l4PX+Z#tj`rMFV_) zQ^mA?*ADQofnkRad-f=B6RT7b-pG4TK$LkJ`!6M5!s|is^MASVCzhJIT&Sn8@{Kwl zzmz&~Z>IJ>KH=J5nZROh!0|=ZT>-%@*g1KBO|f-y-G6N(0J@d<`!lIHGG*CEH4MjwU<%75te`vXt8kL{fhd+ zVXbO!V5&+;s`ndzBn*sy=6uXIScF}kmqzpZKcnp_M9PiJ3`|V*6x^ZifVt}o2sZ{q zEKz7kqqF&*S?F8r0dMzxVAG2n6A~z*s}ghZ@bGYi)8X|A|1tj!Z{QUu5`F#p_1BnZR+cg~{q%rquYuG3mfRozr6Dga^q+`*_Qhki z=714<>?E=)~LJrLpULSOGs z?Q*b6xV~l~vxcR5{3>Kdk8|e*Qy29(&!G()g9nZdW@8I2Ms5(&$efC-Jq5BskI1Mx zf{t3N;|AoR(a8M35hZp3f*D$qB+DVN4QAHDIku?^j54!DmIP^eCHPUAh* z3la9lsxC8G#8t)H!@Ozy<)_j8SXEkY9ftYninoBg@s5A~MQa*h%?9yl>03!oG zIQdjTg*!_rf(F_(6iaf6h1>xOa|H4Dex0}9Q4uQOy271yGt0zlv%TP*m zxZ(nrvhs2U1t&6*x*`T@M8^${$m=k0^iHhO_`k{vXuW#HU`2osm)0}v;n;ux4=hKEkJ{z&(dvgDKlExQL^HQ{D!?ZNJ?ZJ7uA2#q_fZrMvq* z00Se>qbkS;Jn~hr?45oOSMeFqd$8>k2`!#0{24ak@SqX11r4BHz1;k(5UDPq6F4S! z(l%F7*t1A;a4%(^l*a(@Gx+C7m)9z{?+cjpf0E?fea1?9ito+pe?d zl)!F@3kCc)#t_9J_zHZ0`2of{hC(t8GvPRaRjH0^|ISSv^9V~?uymh{6ocv>MpO|z zXmFv55m*UEjBIS!>APLlh>!WO^S^WQ^z=*$XTcIQoOUs_@?El>YZ|Z{B)YOZYSM^s zWXcQ(d2!1C9_Nn^F=3}P*kAp#ij~*U&J4;}co62zprmj$)~fkW8@KcrfvP45gum5e zEG=v8i9t@V!*2~WA5*P#J?>KaHF01+JRgc^!a#V3y4*+Fu`rZYHu$K(vmrM}Er2&J zFtN(Sy5^5bqRojf$3&(I--^9P9GIM5PV2k$P=vDgCxa5qG&gF&lx-2J93W` zYwati@2gz24@hmIo&+vcVNwAaT{_DD+^dUBEv?ndU`D}Om3m(`JF~!EV5wfyMz9YbO|n`1Q-d} z^;v(7U!e)Ggr(Q?LT2*J_WHj`m*w2UYRnXuPR&S2U`s&3ze5QQYanF_Aw~=p3Bt9^ zlD?H-5j|G?93hteUty3k7=B=t?|);R$F2~blH)}Et&{-F#MNnkVFoQ^0j@!xo*?T$ zV?7AuFBY9{)VFt@0~UtXWn#$}2-xnHyE)WBQlC8_iBiyb90+e)w6+;1EmV;R@~vMB zR&={cI&_)4+mGy#V$7%ufQ4RxP$ubZK~Z<*vbzMsH2Qcx{OzI*Hau4$ML}=h^-g%! z(!_3Sn+-cBC)C$_*5(IwlS4`=7rK0AU6$Go#*Uodx@^BXapP%?ErI%vajB0PWh;Gh z7wg6&6Me{BarNp|dDs=3Sgg?r{vCP?@V9bDa$z)XY4A|fM+96D@Gz^@k)-2EfBl?^ zr*-mpLb~zI?s?;=`J$ZRy+uW#3Ut4vMWtm5lk6;2z9mTz3uzxf z&u>nb`6ehcP)mON;ax3s#`xl}hNUxee|?fUMLRYohP$&&B~3D40*Z-11kvNhUrfFlJs4>{5CNFITV&7N`zaPI zySM10_F1`FSqyfjeuP9`@r*0#{gz26*0LY9Zb_IEWCgWdK{6$OLu zx{XTLfKGAeztiY)M>?>xh^?^?Wfz>=yWUg+sh?!V7KEc{Rd zPV@v=X{p{mPxfUY&8^VVINLmA^ws|7d7glAza>k+&(icSFdcH`@bGqSJ%#;5bvaF; zeh$i|Q^Q`A*={OKJsvaog`^_nZY9O%to74Zo~I?VgF#uka-qouej6cbuaI}AG(yku z5$W{bDQ{&adk!_VCB5SlKF*%2DN{q1>`ib4c)~o4ITt#gM zd*Z_S^R@^7l%l6zWWMUNL}ez1@uGy76j** zQxN@G=t|p{{P{7)Q)zRAe;~=|Mrcx^5x(DqRT~XXc1~dF>hI?zF*#I}nh5?M*)z@G zY95;wza=hl{EadRbw1X(Q*1BP;_276p6p0qTOJfYD(+%>{fNcoq&kw?1{nVg_fZ|d zjh3@*1(MQg$O;CDZ%ReeVcM*)``{_Q=FI-Hw63nMoM`J=ELC^{o!Y8Dkc#BUPX12MF_6Sdtx)KNkY=Z)(SSnT3E z;lE~{3>0fTXy7M*VG~!8rVmCzh%8lL(fj7T?$cP!;o3#-L1pJ1k^4BudTnHsx1{|} z_WBr&k>7b-S#DE*rCy(WY`A0Hwh?##mlx!v6+#a*6~=amOTy``>TasVtP_e?coCeE z<@=T113}EBDBw*?I_v>YCmv>Nq5@;tGjB~>>hz7rgDlQxoMccAVr3Z{8ynSMayhgT zTFpAhUs%-();G?@{3MgKZ*L*fMixQw(mPYH@2l~=jFMAOlN@J%8bYgYh@pYRR<1exkJ&eb{LbaAS45bt z{+Rc~EFxw+N%>O)raWI&b!6?SG#Y@%7?S@NZK?7QJXSx)ZkDF#L!ks&H7<8UGqc8$^}4V^jQ5)>deyV0*pyo#akAde=U`_^eWCYC zRN_$LWYDdJMh00STA=H9|F_-q?+HXJD{F4+eNIVE)_Ka~`I8}Gq_b)^eG+q1!DAt( zwKS1Ksi&ZDCuq+#9Z9>g{-W&X@%}nVnp6OWp}LW5n|@nd^)Xpuh}Bx0kxoox$Av=% z%q2YPlJv7mFBW_&EyyK~)7LS?3ifkjhDBpyH$RlS;3}QE^k`vzcT~uKrk~DiiOyRO z$XH`Qlv=y1t*vd&qB;@J8TcmK*69$I(zaNC8aNqPzt93}waMUF+qM!y;gk>`{ylRD zWU(afrDj3#aJ)hR-z}3r0i>mvwjs%{jEoOa-&tTOrJ(OWo5tBOvHSH z6E3x+^k-i8N1;%i37j;1>si;|F5pc+OAouY=KoDMT`u(O!|lFYV8veY{3R`QTT(yH zzDmNRbFa|zXP3$C?tbb7Oy?V$$1-x9R$?C8_L?0!LrNu)<%P)m1@*x%dv6WS({}%w zo}PZ@Y9lrUt>xu}{0k0w&=cS^wPu{$ z`*w2AACj`n+kN{1_Z0g--|7A-YM&$#a5h#|6vE=qE!-8z+UqU_3__&5%&AjJLOA6A zdX@i?y0k1SWm4kill2Ou0QW zLydZtG22`LPl%Xwz6`m?{pg0{M6Jk$%rYjCJ4v2d5IU1^5k3>?thRQ~bS2vtZz8=( zviQ|%J??)+C%Zcg_lz85}u#cxVr>K?3hrLrKl`5~Smtr`sv% z7Z>mzXG>m9Ds}tZj)3vlC*`-y|7q8ScJ*$AL{@gI6fdPPwg2bHbJN{lkcQru29Sy? zhiNF`Hl{{Nzy}xl=;7Btk1*mv9=6G9!q?X9Bga!?4*n4Dgc$vKt@k*4;%ZVTWGN$Z zuuvsc+^Jw?IwEb<Hax|8`<5kLj)aX!qEEpUwzBf@-LG1z+ZB$j3g`_ns5$Zm2OBwy)Q067@ z#okRLGw|%UU8wCo-tNK=a5D^qh!?_0ZwE@ynjJ~NpFtB2Zvf|of!c#683?uE0)X;4 zlkgg1tG`Bks3FONAk}VB{3M5Zi3Fx)-m3{5tfGbaU5VM=FEKY8o12>%Util%AHm4i z{F6iNQE%IE5huL}m}4bopPdTKKyx46VF7{U6$=^F5;IHr+dZy_2il9r;n7o0?dI*Uh-wZLIc8u7=sl(wA(> z0Jyhpr7#Ly{0l;ANmZOTSf1wxH1y`Lm!0{Iii!#@*pTbbF8A6;QuH~30{docdU3L{ z%#YJ|X?wU|ZHVG8HnZmysn=dj6Ze`iC=X}xFHrLDQmn+=FxbF3;a_l`V_SnnsR_OnMCtJD4jJS zugn(g3RthlPK7l;N37u0V)b=M<1K^IU)2HU^(`ymQ3tvtr3i$kT~Yw~wkI$yuJ{l7 z8l0cS$_-SsqN1aX^0}eaW6x$EkIRDlp7k2e z|JW}y#QWy_1H@s$fNLI58I82tyVrQM zu_V{-)U$uMxcDpBty%5_eU-88+q7jLqyoKWZ7X+2Iw!%l0~^BtYMN#j(86Gv*pinZ zuJTPXNZ=feX8arf#z;NL*!<`5A0$sNBA(}x=z2B9p;!Y17>QSgh$Kaq=;WNnbiJ_#768{kJORi?}YWWwbNMa zhJKYDI~hDFb7~*hzBg8520VH?+^Bc8x;TsTsp!~%liBI6fV1sLzfXk?XGgsg3I;3> z)@x2yEu~6cf1i?o2OO!KFP(p{sW~%Ul#;i0?JJ&sW@y!5)IR!#bj6>l4HJhr5LV zeoL(1pPhH;pi>o{&cq)*I>^*s=sy23jRPqXSNq`Sd46^p#(feBuV#e3C0h^rQSsx3 z#nH+*P1nH2$Wc5PNV)y&l$ZzJGpZ z>NG9PtstV9-r&6EA4>7r$O-DZ6x@qV$N{dil?%kIw>^Deeakd^0Mm9d8*mb<3B`x# z%r%_=N4`mso(cALzj4aVjn!jGlYUn*_I9Ld7cAD6S%QNZ$}PjslbOC5a+Sn80CNkL zfO0?O zCwWdp$Mf=M6;j-PD=zKP*DgLg-?fo462`mTjw7dyu6K75{#C%+&%HaH$f(kNz=}x4 z;;*;z7yOU<(qh7S`)u~j?{=F5lgdO1yW%OKKyGLMuN+Hnd>wqRD7Bg@m4=7RQ2m=^ zu>Mh`Vt5gsD$mGEfZw&JnoWZ5$kymUxca%i0233FP3+C?VhK1QN0$F)q_M`tQ;_@z z^ENgaBwEilDN-$zl@lQOX^{fOkLn73_qULF@U_z2lS|8cdX2u>JHm#>x+V>)R6rp2 zZXk%CuRWat2EL8CZ^Z^45OgCBwJwNwlGHxr&`d@~MIC1L@;)7>G?@ky+=QuH_M@bq|JtmXk!iyBLN#F5+3F`As;=7M>hUtFd7 zhB^FE;(kZ{UaypA6BXRVxl!230|fyikbS|zzDcn| z?$E99WdI6zD~-+u`24BjUcGQxuaC;nL@~t&XC03I0w?3^{?McIV&3R}zmH@ob3Ulq zpR+9yC~hVxxt;Wwb-wnM$lh$V)6XY#GAE8FhuRHC0~-rc=U#cYa`HesVV}&>M-9_O zv~MDnnmM79RAYSKXGi2?8K7uDmOef;`-tard`q0=xS-uk42TYs$n#Zzna=vTGeGjak`EWw* zVI^j)st+!9<2O+c$DFKBpX6^P<{F(+l@it1NM!MCN92<1uqJ4>{nN)BD01iF8yTl4 zC?7MK4%rwVYcyd^bSyo!uGO&^Y-d75L_{|a8SHfCxV8R!dY+JH;0*EE@RC#K? znNvPb#-#qF>)!W9j;#RYnqRm@(N4Cl+kY$n@CiTw16sRu+$DafL=UrZA!a!n7aV$d zH>ZDI^cj9t(!@_A|1r(AOS-GAq__2Sb?pbwT3|XuyzrAUGM*s9wgriHb*xY={nmn2 zgf+{&>b3H%L@pj1#02|tE}JRzxMFf{ZrLRMQBtTD8y}cx*j|w8x%# zJT1(|r+Ht{H1hyD_j}mB5T$s;)N-a|u(I^~ECy@Ow^WH4SrG#tw0;Y8dV622<0~KB zV6&-DE&TS}sBDAhcL~*fWtZjPC&i7aJ7rEzLR9^-@Zo2L7QM2=1%RX__&xo;{>V1A z^P=5;wR@_9?;iEr=`^yC0jhW^HV>UUKV*qRCC49<@O|!RPgJ0agIn^se>zr+a-ADvlj?Fhj1#<^(x*8OWtCV(vv|&tx z+%u4OfjoQqSOcUGLGIAz>3|gAhodq!f!s{lzLi_xAr>#g=A7#CTSIQnKH_l&`%fve zvL`bmkHxV5H`Rh~(a(u4@Mwi5(df&+dOb?jkCOD$q1N;XM1o3s_zM`ToFh`zUDI@q z#DTELf-K4I1$y5xh86~csr0Uy6_Q0QEBZS!ov2Pqb+3X37hMQjIT*u5$;mF15RoEKORBRMJWDfp#B%Ph1?acGT>r>+Kz%FXf}bP}KTS=(rIo-8g}%{D8} zeFs|9ND123yX|Jo$u}ogYfSJv=?Tx5HUFFcllcXPx7cMcVSF-97xZQFAkO6erJ-qW z-76Gj&~24u%SV=ObCjfAcS#&)T7xegdNXR5n#!%aA7~pctrRvmoJh<}3hRCW5VaDZ zUP>X3tFPw-eUBW4zP2QP9$<(p)#93mf&Q_?1SmPfIMRO6*YJ-*ul*ww__2N;Fk3*1 z8A!gq3xd7s!ykEFKq%L@e|~-o>F(aL64B%8__bpNGjhpmhxBEMVv>>=bVlv7E8)oW z7uCGV&y$pq-!z1JW&NvpJ2kbCoQRPxJ2nZ;ikqplb`E(WT=O^b=XJiQiEINKv{306 zY=l>RJX=RIF?Y!@Vub>$c@RP0=ew=JhI}sIp=!^7rMmRjU_0Oqj@)m8D?(9T^%&0y zzdskMi&u(zz#>&DU;^lsJ}MWbhWe$J4qfhdokyZ05BqCw0b2$=<@R89Fq}~=^F_0v zHQ#f%@RI;fYvq@&MFV4oU+=I+M2_^FnF6%g<90SFPR4jn-p~jP z=^O!-FIgZ&nNSXkvJtq*Ta^mUR*~M8mfAC?B7^-Nr;%iT&_C}blwU2lz9MTl_V4C0 zYi?lWey*$+f>d?K1tXKlj^ypAj&KyEHoPX#60zTDvW*d}d?4g|dMvg4^wIoA!09AU z9otM-lVZR@YjN+Vh224q3TTxqOGgxvH8nZe&KGo5{q)2%+flyOkpQ7DLMF;%zrVfQ z^=~47Fsj>#?gC~~7ck2@hb18u`i#2XbZe|`o@^yFFi2EPp3Fm=vyUiX-+}h$mEw76 zx(jk&%3QxkCx}(4F>v_9ec~-$@EVv{hi51~fSh zgBSSiZtbY(4)YgI6+5qdeDo8aC0Z|&t*33S(|AlidHr|f6a?t0 zrXv*zRcm1XdQRyLKKv`Bu-|?SN`wM`fN7ODp8xnNhMyGXEs?=xxD5CR{A`^0&Q-5QNGGqkn{lEf3Aj1_FTR^-v}@XTb)2D63CgFout5V z7Q0dvCz}=HkbI|m6%C9Mu{4`*EeD&i0pcz?NX|>i2&*6`LW1bpH&;_?zYh!JFz$TV zNABbRU`>|#r@B%911;+?i1H+frd|-Ee>G-6-!Q1=#)v(-wYkFi^p*sF|ATZE>t!+mHO)+Ho0_&B~tu=gmatZrY zx%}@;AotuGX6S%3KHp?fkfe6BtHk5b=^P|j@ymh!_p)sw`^1ykmP6K$4=3sB2G_?H zHF)I`a|2AXZJAHfA2}F3VpMZBJE^CU3^+6R4;4Y~@!jlBcXWZ@?>DykC7+gM${d!y zRoPYs(;%Zsx4fXxIfsYFPeE_bGe;l@m1+6&<=EE&d(;U$8|QPzDJ19P z0Y^N|U1w`5uLD*{&TgIWKz**$(mF_(Ln+#(F+XyPuShb|5=v^K$D>n8)~9Z0zL;CWY@(B5AkN;s>h}GmImcwU7!aQH z(51h=19`op&Fo-YPbbDW97|cKs@*d-}U_Y2ez6#M}-M?(uhsowB8o%r(OZKidD!fi0y18jUW+r4)wmo!S5P za21rk<={a}-ECB0YNpw`dL2S*f$xn@5oU>a|&Yt_VkZLbS*>LSCVELvhL(mxA=MADSMXA?tywd&{Pv?n*HKW ze~O6X&ov7@qU6@`a85#DLk+&xbrk}Mua+lZRUJ|>Hj_U_T#I1jSiscvdwAtf|?DU52ibK zAYvB@QnE(b*h-TA2VuC}awv{eNdMUchl7=&T2Ze0g_SY4r?OnoQd$@OzDDi^P(*r> z5DmIeqpQAqCo|{hol#}9l*)A%O|I%18ej_an&42voK3S0imacZItJ6( zOtYOi%aJz!3x^WyjfXLUTb>@p1tr{ zozX*!7nmwm&yxoj`zkr5uoWP_eEwQ01Dcec*&m(GOuD;W`pP@XW@Hx%8Tf-_NzbPi znq=p$*c&cOYIm^vMUCy->$T-B#{^~{`q1TP5AQ2cuT}vRV5=^AUAsoUipqy z_9ef{8~&?&W7#E7FE-b9(z6JdV9WTkPPF06mVi8$w-G5#MXfY#T>&tcd zlF+EP@3T)4R`fJU6u*!@jBaxVKBTaum6QOkCPhbl1eL0?pGMC&9@Fd`6ODa0G6sbZ zg{6i!R8C5H5}Fe3|2$E(9<4;WyUvlt_T9rD$mER^b0yTrGtI6Fha)+JweqhF3ZhHr zNJ9pUlY1~%>HG-9`;y2;L>@hQ)SE=6^Lp1g(xk5z50Nq&rwf$6{krhFEscF)?8jy` zO=CoTLA9;K1^HQ0z?Nms7m%{EHdhnQ_MdT$JJ0f*FV}vL zHXNxhcm}b3@rwf~w9AbKS-mF3+G3~jx;iej;8)(hQja?Y>Ol9Z2zQzY0Tk>x=hJ4+ zM8SjFz-w?_akDT`oNNfSPqcn~iH9g&^+P(jlnf<<(G?aq(@f9QDv1n2!K`EPI3sQR z&($=SHeX8RlRR?p<_F6Nin0!F_VZEMpm@M>HOAR~YDBzH@D)W@35Q+(mzJ?F zLkya!M^v!4ARYm8ejn}=B6L&0&FiO#XlL8Dfw3zu+O_KrL3`#niQ?(udKj=W>g_b%!Up)}xUE_zK_T}zR0I?Z56+EA71HZ{B^3S>$A{G+uA#hf#XY9kifOw( z#2ABBr9^g)yB(R{FX&)LB@G8|AaL4)QBHg#WHyT~aw4#m#@ZD4yuI|Q*!&|h0H`a! zvPRxML1^j7zcc={BHKMVbcs|j<7Sz7-g3+#8PU0NbHpMP?))SBnhK!0>b;&!0OQ{7 z?owm$;?RhO?{A5{hQmIonghq47Y^}7YHb)1&~Ngz!5ab_~!Z_hD6 zv_e|dFmdUm;dFP5Nk8$LDQhz+Y-^-exUfT3ND3+iEmTUh4rx+kYikhO2Frmjz#pnj z`X*0n0`>#GvzZYJ;6MlkXqy!Mi1?#1{fBjv$93msQUqhedE+h)!i_wvI;`>nK`qDNA|7>gs=;lw9QeOwa(J|$u`@kpv-`SOv`BIW2{)< z|Ms!GGIG$VuN?K9Q{kGx9ke-3A+%HSWTW|{ooxFzvQJyB7eZe?v2D1N zx9`iXCi@)@w1&1UyIyq`xC?b$VeOVJbsTA|4W6tiQUh_gp}U0~-5-4>tdB)aS-pR^ z!cAvyc-thoOBF3SbJ^$_xrQo9EY$wPJpwAR(_`m>9fCamO177LXUtlqwFo%i-DH`n zfUt@|XK{n|FDduY8Xrkh%@DyouSX<9;dkvc4m{468lrHe$w=QytCgljBA;2yenBcI zgPm+71h`2a)yuwnz$8_#;@bdP?yG}l{s%6;O5#HY>zk*M3n_2cp-aU+RIp$!ddpT^ zXlFUY%c4gh{ZL6h1|r;#luKcu?#|Tzhpevvi?aFRMHEHAKTYyU&BZyE{AY%$ak}oH_A(&*nCI@Jd;m z2Paew!hGih&Td!InV_Q&KVJjEKR6i69DsJe1|}532*x0XUBiLH)wnyg2K3V`DyD#E z{vY=I;zpg|Hv@f2_wmIGY~+Y%gwmes;F}hBtrmwS7W<#eTZT;;7W!F;)*~vL-cWELfk>QN&X9=6r>=d!tA~5~)B${gPL$N>A7ag`Z*9Y}!GW zQuhU^&BJ&d;Cqe&t}Jr{I12LxFVr3#5M0TFl{`#)T3j%g-NCAFGW^pAx-`fZlIUSF z$NXwLjH863uj?Msb97WXNDlbmR_16&lQz>5uN)OfK$j3Hh3j80b@h&TrO0dLA)>f; zUFn8|cHC`v_0Yd<^0@R5Cy$=4f%A(yE5ZGb(_z-~9FJU7i}MH`esG@8!hS5($ABrJ z@KW9?4t5~gpH%EIiA{n?&$>5Q8Li{TvIJojb35D}4r%DhvJtBRCnoKGvENSDsoOdW zqtjy$P|wfDd6iBJm>kUFx|+a*fgPo|gBrk!wP?#;>>WMY9v5}hDFcZwxgLWDxhQAte~zJhk)jikDAN#qy`cG% zBoIv%-}d_do(zwe?eSh094qWWbKL?lo%Qtm3aB;fnU4j`Z)q)@Z>5Zizuz;3-K*mz#ACAbFvG6K<5yUCCfXspi@C`9>>gvE0K?Zd^Mrwi}Br3 z^?w-x$cy&lNQ<|DPO(pNK+0;b=|%J#tq(@jY{?jtt$Qj=muYSPp+?w5?isf7w=>gd z6W-PjO{~0;ad+)aWgySO6sG!DCTN9jeR>|hiMe69<(s%y=m?w_2#)0fD`4!Bqio;j zBq*FB*!(z7Kx9~iOzg1pg;&)9v)I0<$VU3vPA)O(7=*dt@ADx?ir(`h@#0Y&gSC5& z)b`5QZx^bs%h_Mm5q)t20`HyR68t0hdZbo1~|cjy`|9%!x1aHxnNa7tBIzG7{H@pxuOx z^|;^AL9?Im^L6)ToiDRKZO>rSz*fQjK~fQ6smAZemMTd3PE(tFjK8KG{(--laPjrl zD^<^vWsT-Kem)uTy%%RcUJz9;4Vr%5rvI${;l<*DCN3dSnGxKG#n31pD1fDZfosHiCQaw{SlUPMw@$7@J; zCU4&?1yOW*;ZG8B&yXfHA6=I*{tG7>8>KS4fl`Pp&xQzh9q?T*)1+DRR$7Kk6(sQlFgUkLP+YRL(hTh6Ac@mnM&?Elbg&#bf{6i;dta7 z#}+3-(!;pWERcM-4wjPW1BkzT*cGq<1G~u1LR+V{1@tdOghfU5zXX-~5KB}>%AI>N zmnL6}%_LLt#24GZGWRir64Wwkeb;uq~Uw)*SBH4m37$Eb2YWJ z1^BlPmM9dFZu!eK+GAqx!vcLF)8uZGZf$ z6!Mo?>d%>PxX`JQGZzYVb6MwMJLV3}5J>-{V}hXD+Y@DS!JRhA~3eT@OF#g1uJC z8K2o&#fe^T@_h9C$bfDyne~Prj@0<*f$03G#q;EI)AvdQF#a2D0xE!3pV0ddmw??<+Ej7(bNV8yF4+^+F-aR zva_2IcO8NmE-JAF-cv4OXl{Fj`v=u#>}ZAe~0C$@p{D^5bkcP z*EgePMV!$|F0rU$!3|!KP>ocB!3Xxk0!=>l(c3znGz_^OMO$+TUndsiCxpX03It1t zlMUdvDqY$N8XQf=5+n{Kx&5+l?&N`E*SeybJ%KDYBnZ(SQTjw^62~hPXR~|KTWgHwi*U}Ty zGWut{-oTG0ji#m{+Md6|2}k%IdJ>87Rk&ix0Q#Jp7u0eXSMOR6Qu9xq?QHC|^VxtqU2PL#&MKS2` zb@&%_a10nL-snWQp&rXcniz^-3}?TW$+ z%(Z(-RjQ#7_uH=0Ys@d6KVNY6V|BQumU^{ou^UWqr?_#JwQ=jv2Bd1J9qtq;lx+Ez z)O8m(IH@(==Rj7>D^$q3GsG`4i-hL7pUy8-HeAosUg6f_cO{pEw4Y z`e>Acc&lE1;36$RaAfk(fb7l7Ozwk`$W2U}gVphhL}J@{DPy(n3g=Q-vAZ*K(IA$! z=R2LVG&sUR&9T5|Ut;~L+Kve^yJg=Z5bmCz zF}cn}*OGO2?9+zi1Zyyg>#{!BmkBbM4rM2}3J7ysDWxYzZ#A>9trs4d@>z}Zp}OQZ z^+C8b93FHzt%1Cv!`@^*3sJrVzJLN=$AM>oOK<_{l?2j!rS?Z7)hnX~;aCqH_la;|dt#kO+&M^#ku+DEtO)a6z{h=yL zG2L!CtA=j@j$2N&(rtyfmzpt{|HcsQso@^bnpqc0H)vc>{%Tx&*ImZ%{a2!h28SaxJ2wR!#uwV*+;;UsR-cbePlOi8LvQzV)J~y1mGyu}O`Hc^ z=mO@JcN1cMDh@RbBU=4x7Y^iE}fs==i0n4JXrL!N9}jqVX!BOcBp+H-kDo zFg4e3kbdSe$-cV*U0YjA$) z2BOhK$xfTi@NK2T2EnxzhV(hQs(_E)k@JfNqRqUGh2^riV_W-q^-N{fpN~y`39{!$ z-szE@SVuz}0Azqa=hTm+=yU2{tw4e|`@B=hUbGLnBNMC^>=t3G z1_Nf;w{5~fKo2tz<-A@`;kTUbP3biCl;M+P*R7@pToF%^3)z8vSC2F`v zvE4}OHZZ7h;Ykf&Dqfd!;ZgF z$qN!W!fP=O6dFRKqN6P)_zNdm7((?6k*RhvPG@f*s)s28OAYFyf>l<8Ut|{#wtQ3@ zk+Q@1$$q{u;?ACH_iO^K7Wt=%LFjWPVur0H0$mP|cJTsqfUJp#KWVUkjc3JXe(LA- z{0`(z`HWbCa_39VQaJ_x_zrK=`v>G5WhhkzIBXf^2wN=O2(CLDQrK9hPY6w&M@9{_ z`dAvBy;8c%F3D8DMVe5+Y3HwBY`#!yq%HH3p{;$;c1N{}*G{M_S|??+09ojY%A$Ck zMvzjB`}7ANjO&+4vixMX?mkg43dmlypdqY_X{}3-P4npxd(z4P&X5Q05yp#+w2tb`=46Lfqv# zDa*q{7&TFs-FT9!ds1ZpTj+b*POONe_zafjg~=PK(3hFbJIsygEIs5(shx^(Z={k0 z0hY#GQNtUqHF&1|T(KpV&i+O>Du=?4H36eU`ziO$#|eBb&a;z=g`DHrIrfJo@5Q*Qqv#>6T^LVduE*r;%#V?$PEGa`_cZ!Q;@KKYi>B@jp~G6; zRpytV7Jv7vmK5Se1)VGwG0saO$s{~#7(jeHJ0x~rJ zm@gO;LScw8U}S`%(#0GaUNdPY4euJH?bFYESByKDiG5d{ki6IS>|}LLgk2v>Ex=3$ zGAwsTgf?#O+FGl@K+^RMjH*$?v{~R{-kb)JXQ#QDd8ZCtz4^~zIEeN!@d_(9cOh~S6?WfUF^mIG^bIw zoW17ZRL_V9^3`b5{?qSiwbN`8sH|d8UrJfXb+wHl`_FgJ^+X~Rv-zsF+=BvfnsQGFraG1rf$)V;% z_CQtt^N>gr6MD=_#6lkz#$)%K(>eCB*Fa5!e7b(- z4N>4;N%@RA2569NGv}u>=jW9MT1;kOe;hVJAv$KwSK|cMpkY@lh#cX)jxH}XAZMRlq!8O^ z-rqkd+As> z-Na(Ze*NQyJ??3djW>MbJnzJ41o0x?$^n%BL$ds{=*|2<be80if}jQ zr4TbLC$Hb*b0#; zs8#-ckwg((oF%$VruQ08)iST~7@&bUiI7b0!oqkZh{psKlbYOu!D~}dLT|vEd zuZKN=&+>sh{X3!Sdwy3i1lKIt?fLdWsc`r>5BVk+OI3oc{I{))lO)aO=psr-QJpq?vC-N69=v#LZ_NfNmE95#RfmE2;o(ZK%4u^xB&dY zMJ{vTh#_zQ-H+?}8Rm`f-UKlTPrFFz6Jfb#3+XlQ0gzCrNYoUt^pAJ?4-e%vJZp5k z(;Ei}3A%Q!2wjGNF-1h&E$vP|+3Y`)>82ok!hEA-gWXZWh2zl!qBY`IKp#X-#N52L z>#hsR4fU5?dSy4$R7IS88ENDFP`Z_kVc(P&9+fLE_9+)nMdNn&{Tu^MZ0)Wp^N4_$ z3lZG00q*R8_4?Yc-vBca)re4Ua#7T_8EV-RLMYcdgM*F)GSv*1paQ$qFdEhZI_Yl3 z;rqu19A!gCyOCjU5^;^SPsHWW@F-~Arp?vrGD~4HbsZ2(Ga4KeG3qvE?XS+OjKWk4 zgz)0$9^s*D)k0n#0WJWwY9BFup*dNgTk9M3ydMqd)a83BlOYnMWMnnR0xt@>SE0az zs0Kwxe1219=7K83rMr21Z#jag=eITS-x?$Yr2t<`=T`dQ~_ z|DlUPY$ah4{a+Qm5?477lJCMDB$h#JB!G%|!Sh{EqL*K3 zHNyXvfW=Su@ymt(%K%3Mc>yj|>%ZWO(F+RXQdg#-f^m&M88^W?x_Y(m5h8E3D|)a-nGOd!`uT5*ZGl=Uq==lK~ja-oB$|b z>&AFO$*XXlqTz*cP~4S5Ed+ERJ4&JACUGyaao1>zBNLbz-N9xcl0gQv6F{G+K!-(s zM#}}l&|%sKB>;l}mva}{7=A~22F}rNwv>P=-EGaZkI=~C^?%tdK}(J-T3bkrFDn0I`baWP1=JQtN1PpuKS}d*8n79lN)I;^)n&I6oBIjUahnAwOhz zx`8UrJzj0cw@VdsN<7TersEjih~pE07Q>5DFSR1t)<4qY+IORwJ4qoo+$}V87xZZ)%nVF(eyM0esTU-YY zpkY+83SD|E1={NB^DuIstaeQ_9qC<_i?!LO`E_F$^p^#;-$3h&fnOjqoZbzL2)|eG z&IesFi?tIZ-DBtM{;5;^ZT?2o^$8?P;YZy`tMw=?Uc`vu8V#@S5EV=jc z%^lu|f6V%rE-(V5XrMRv{3t+|KS%&+d75vMr#2mYvAuf zUNA6r`~&^01Di^v;LDsVY`jm|3b-4AAEa$1of4OkhXmAPf1K78ZE3n86fLx%27p60S9l1sH6O=7cP*GFs zc#K9sv!G1j&evzE?>GGXNTn89Z12xHq>95KHD54LcF)8i!;5qXPQc&fe}0C>LPCBb zq*_+>g+PV;Sq+hjzIbHq$~S(WDt}*+?g{|uj^1eFQ4%< zL0pk7?NdksW(Nm|cNc{j!<3DCFww=d;+Gn_5$+3 z6CQZ!)s!j&_q^Je^J6_0_HVg#{0<+Yt!fd#dYT#h>6c+IahXZ7$L^H2)_GQvua^)W zQHJjy4Y{cMZTypyiG5t8M+kf;!0~@>sv2qi%lru~wV{z8YseEm*Q<7|uf`8O`~sqY z1Dlok>4gIu2u$g<-}HE>^HM$!WEps@5zlXu(FH@R8(1tEv?T$oi+&i93wrn<__-(8 z;;#qWzWh03iaqPWU2>RCd#2<}Jt}cNRt&5o4E?hw0paE&xwwk=@vs0&R zTuBi2eXUopQ&-auK-r+R@RZ;)VD-d*z5pZwaJLRRFCP!7PI{I;2T(*TiS;f%exf!f z&;f}aW%uApapLTI9)<83iwyV7P28W%Bb*vuLxqltotBdiCy07+bc zTsY+~2qG}beDsarN><3V1bvY``r4i4<9{+38KvjbP~X1d$YaX)DS);7c>uPwEQP${ z8A=iqTbhONjD)CRL)CM!A}6`n?QF~rIR}#wiKA&ZBhqEC6{p_MNCVVy`7+XSF`Q@D z$R3S3@>+eMii=h!wGZ2%M13&kD6YfPJL)4RKGw(ElE@r=n49bnEh&RW$RZGDj8^)Y z&kca-5FY0-4$Zuhay&B@K0cpsj9}}H6TI@vE5aZ)nzk%F`q3E^XCI5$k6z?>s4Gk% zc3#yq2P&5x=^8QUb|hxzS(#-#0Ko73p}37SbRBKp1r(!;WHBf!c@B69b~tM=qRO+& z`27xkeW%wYz+LdHhJ{}s!$oc2&oHUr@O)&gnD3Adog(wMjM%rnmV&&o`#npmy?gV< zaN}m#_cq3znMer*tXj(|FAxn2@2&JqkcjSJ;_aM0mbY9Jq!4R1uCO&}jfn;jL+|uk zM(m@~nsZUQny&!b?{7BR0c-@+^e;&fR{fM)){+EeucLk`;k$()T!-mfpK&k}eJkiL zEv~*^Qpis@C)MVpe3axp*Wo1JVt#sNsd}Xt`(Xz?@5r+BN&T!1BPL>g)A*O5IQ(7v zF#kZjE?a}zx&PieHFuJCFY(F7SjoBd_q6+89JAK=QcMW=f6>;FVBuab3lw;O^nSc+ zV{d%D=!dN%KU9i~xJNo%Vzu$iB}owQ6hggURa(Y{oF z(X97TIlr#Hpst|4Ze=@=dd@`7ODAWhq+rIg$&0F5Ny|u!|4uv?$dhjjt=l=f8NkBz z?93mSfqg=3&JH7Ng$+gqM)Oz6v$E^)FnVHK1G>-Bt>mtLxixC%b>jb?k~T{(ot~VJ z_#7E$guA~L*UC9$!cD{NHBHis-NO3o9Hcb`q>(F(I(bc4(c+5qt}sFbPg7R6uLQWQ zDx`nB5wf`6@Z1p*E%2{k^Drk>v;&S5yq?>qt1;+LT?oyPaH}3N#O7DD_%qGA5A>f;dXaJOhe4_IzXo`_7UdSF1`&= zU?9)BN13ckdX!yMO5r^k7l?>350*xy$o(DF%V%M3L63HPqZygo?n!e=`bu-5QE$O% z`c5q2`Xgpz0({@8bPEfM&|*Ahb&6hos^}73Ld~8(BmeoP{5Dm4Z~u)u-kYkIqazc8 z*f$bi_7afxx|k9%yAN;|o0!^Y8JM4D9mD%06k{%){|j!@$7MFx&_1^r$%r5{; z2^Y3zz9f9~G%v=1;bkdIMNJ(3jbouZ&glL#obH5T9A*(dFjj^BHv@mik#8LExmJKz z!ibb?rp*CM8NE1{l+Wlej?i$L)V-FXOFGhUhb>Y#*b9*1=r5UA6nX7g&r+G%1nHTd za)FMsAltUwS%sHVzz`uwbqqs@P>O2a03>E>XD92$j!YByL#P&BV6Tm{5w%Aqn@~P$ zr}%#f*%HsN^!EN-(`{YSx=i5rMUaB2k)@`R{~4cQcWh*`kf5N~_pZ{YQ&=fpH)${S zF8I5gzfM8+m^(|)=cK&}-v}WWGeZtE*Uef=XSw|5tnifdbc27&d;p#5$y}tsDln1v z(mUeFr2{HmPNIc3yw!u?O!p>w2$85LummcdmhCzkXdq>7Mk{#!cbqM{INgfrpksq^%XaMRbwHdiUh;sb zzGhjZ)X3g4rmNxqYcC1f8-PIwWsw>!ZNqH2=K`6~K(OG|5)5v8A<_%FfZD%5MBl*R z+S&g%6iZrZ4$x}%^EToSJ76p*Yrc|RTmVDSDAAA9CDknAPue^=IcZh9BwE0gHyK@R zbIbRx}zlm5&v;7YRFEjTZ4gcK0QrtD$|aKF(ywDI-I)|7@BLZun;znbvC{Xf zk2H#VO5+IQLnaN&$~RL1`{r0Y=g{m8|7C+;^5eDepJP9|@KB(LO&c8L(vvN+Nc9Nw&ZnPR z{CnBR&|H|xfPwLLG8pdt?@s`W?j1*Ux5D9WYL^WH5|?V>#u8^EaimekMgr~UwTzca z*7NU;N+-w1$0f>Y^V+_!1ES7djA2NHGfByV?6MPj4PN{8A3scI;>PWsgv<+pc>q@b z>31`{cj+1f|Ef;av8%nqWHpr(5NY_QiUHnnkwU0Bk__0>U5Q*cWel_}ETP zI)WQz9cKe=FCG#5mnL~Ef)NBAQBs@JapNNWo^n8>1jNLe=_hF%E_=$_C%U|s_!Bcd znFz%R5wnnaU@H1*Twe%BnxQGUPoy!eaoGqXQp%|*`(!mZA0kF<9J@WC}XVIlLO>GL^-nBfQk(8KbZ79irkr%sm{ zBU$!<^dX&wd411K7z1+~CXn;2wnQN2fYERye@pYnL@xXF5s&gUWoG7%b2l}^GBoXf z%M07J->c?QV5=+dV(V;H{nW*f@$6*QV!5lu81W$Ym`c@a0qn$=cXeTt{`|ADv`S0} z$P`0+C!o--e7(Rl`QHZi+8GT@1Pm|q64#F5U{KD8{s{b^F2F4Z7hs7pclpDR$RF*! zQ_EeIlwkXDDl4V9LI)O42VWv>Si{-Nz(K5zzM2i8BN#4y)y_Vd-FXEuPN1vmwWGLU4=2qW%45*Pq~ z{`~nKAz+MIpgH+KGfkitZT_d5-?wgk1S-ybGBcW8UZq0qY=YqVsr9M9aBXB4q z!QOP*1OH35F*1C8#_Kj{+UX@$=|e)yG&9lNUDYFnmVn))4KCmYu(QywfaxT+n{`aD zY$EKJpLgz#+`^5YDJ%x_npj+@b+lg>p835iOfxaKO{W8WSnu;QoFS-~#i)zw<@cZGCl>aNB`h;c>1 zq)PM~$p~?~0Wj8aG2T!;pA?^f#&x1_rHBv+Wd66R#?W~p$Pwq_q~XZ;K{ITGcWfc1T>4+j1f$+aaA2u= z?BDHRI{&Dlj2G#uy;p|c(;4dOV!_xb`U0mL-_hC3u&G>e zzEGn?8d!|Jelu#GZol<_ZR*c{QSj>^Of!G?PjE2Iv^sE zcWv`YVJKwV0rCk?Z^rNqc2`Z$voQ`ujl3YiEBt{2<(45lCz;-m*|?T}5UrKR~1 zNuUiF7dLyD#UeK{s#v~s^6>CbiYQ4$K;Uo<>?|Mt7<8+#C$B5%qs~Ca^YN$|WpY?I zNfq7bhMkFSe6U%e5zwMk(NAczEd^)8Xs@G^8 z;xck+Nc{}AN{IbhAOR~1AH1y}Run*i_;_$uOg%EyR_EX}rO>=?=7ncRFIcf=OfBQF zVO-bjpd-q+KUm@&NA;9E3~5`B4L5(-JT}8enUb8mG>ViY52~`QZ`>i-s!v+qs7Cd! z?X2i$cNhv@iowcV8k`OvF96`5zmI(0uu%;GQ?RfhARFw$;E`R_<&4j&raqOFRoE6(dY6-f23qC-Tz1H}*v`5U1Bx`TfzoO!*wCGWvDtQhJ;wJHpnaV4hi2^k`Yem`~ibWX%$KWc>AW zKw_zB`bRZ{dp2YvUof9r`H4R*ed8L&u4wg(t+f!Ju`8%NnV(NflScn(L%cxX1arp2 zvCnm;S6~C*42X2CnN~-+-%_C(Job8T4w*l6`2@UB;1wW6+g z*6AA=7)6+9QIaI&jIY&hTA5;12!t$jn`RSDy$*5?CP~ABmfvlMN&2g)6XB$&SVrMX zh5CJVc_0bH|Lj3z7#3h1%+5=AR7f`PdX%3|-dpH&`kK{Js}UnQl4Xl}Le4v{L31oX?(o7{|ui6*;J3&fuUMd;G5)`Lm}L;CJX&4|hN-3GK^iat^W& zDi9mNDk>^O2`tN7$Jp{oK93Dx3}zat$d;`pJWi4D&H3Jp&0%X3U}aRAFMO9iMdCiH z6+Fxo>S8$2dePA5#gjns?|4ZhIg$r#xXBJC0ajY2`H%0?2V6Y%0Yh;C93V1ZBIPy6 zPvRdnY!|Ut+hEO0Ni7I`$NNA_^hR>oiqQozRu#0B`Di=EvHi;k&|klVZ=N?E99S+& zR%{1VZZ^Ue(T(FtbKd`&DGo6w#<^@}RIxd3Jv`B%NpVUJzT#=mMkp!& z^yax5UdD_XQ0t#45?SB7{#Y2-L|#(D$f zbRWCT_D0=L_ZS`1()`-|aWpiKk~N+Du{ ztd|KyA$|3+ZnmM#Js>9buFqNu)l67aW zlHdF@YN8$El(TW&wgfx7x2}t1v!a?qoVa>gJ$!Mvs4#*9W<&1km3obGxq!i zW`LkYabtbrFM*4-5ntF{8O>E|lLyMF{1f#Dep;vm7iK^Z=@1%H;`_qj4^Su}h z!Mg+j#Yo6fPcPDBawP84&Xz2IHIbOVSYZ2mas#r;_^^ldEACe)mLgT-?K> zxOEIZh-0wO>2SytwaW?pFera6e3SDg#vU*9Vc(Eg1?a-i;Uy_RLf@{8NyIRuZd=4u zxSV4m&|fb-O%~B+*!vg602Vw`RDw2;HVOalmtApb z)QW?Lj$SAc0ZJZs_S4aewqMCDpZTr$PnoBhft~-OZ*5K>444=B72{r!<&bS;uEAKS zPTj0Uf(x%suGW4}t;J1FyT!1599fIs9DfKiSCQ% z4QY7tVm~d4i_mo9jd%=xt_=sd1=&8Mx5KeUgZsbIDZiCi5*BB~(fIhLSeWTr^2PPi zrdUt_`Wg&j96uL*9fFMHn!32YLSkn!?~3$d{#@TJ)dQb9!Gy$SRqvLH zRP@1rU*Em>)wfSl_r8!QzgumMcR)yhOYOUFhu5A2Mts1!vTu8=j-7gk3ERW4`_dAB z%8P4CqQ#k4rWIydm1x#}clLvC z>3#!d<~$Yl=6i#s@vK}-o~!12j(5t_UscSCNPAK6<;GmvMeHPgg9ZttdgjZ6z4HI> z|8xqe+?R8Z5O|Jmm)J48RYs%K={EoxCw8!MX+-_=q+iMOUfMAFgC+ewGgwk>$4_%u zjCu7Qew)SiOe89l0g9`8FivpDhv~nIJjJSPdgSDEII>8nnjRW>t z`Y$QtrbKWjva@_4l3htR4FzSknTEDM?Jz0sHkFT86NPOKY(iJqNwI8usRu9JD5VgB zcoxL`(dECv7A#jL%+dc|np1}C7oVH|=i8(Ie5=U%zO}rnq1NYnp0Lwfg7}Z~h7;!eK$?e8AX}+ z=5%Sd_WalEjpNUZdTgSiUC7=z8ZHR&=#NIWGuvp*9HzbYoykc7RxYPIiIXa;_=Nx@ z?A;DY#*{nAZUL_VJNINT{$<3xj*R&%Cm7OhShshSf}nhBg?b~#+6NOZxH~pV+ZD4i zA?ngkRoW}vId-r6OHo~fd1XY8HHhPYH%I62$3w~+dxS@BwVeDN4vr^898 zmOJTjt9CV7g%z7S^wf2)o^Hx`w`o&k_>R%YYE<-OzcineTfJp7J}`V4^ci#8B>x%{ z)N#YWw*l=P&RlY`QWQlP?d^fI&@)0}Tn)W+<13uC& z(||257`H4gJgE04>9tf_w%+?SZCYnxf1-A|Lybw-b!+;~HH%J}G3)gv_3O0{3>S$~ za@D!CY70&eblMz@0-&~_h?D?@|b*1 zF&onLy?8ThfqrxGcry%k`u}{S%k`f(f4+~w950T99&hfQ!%@d;=R4E{Rdtj+e3gpr zkFV9~-Sk!oZ=IkK7VSjl)5B}7D z?UF&O5qc9rnB#q|^3U8HYXKi}Fv-~T~&I^}=pZ?VXV)FSt9 zf3Mhn7J%$^LjS5dG|_mbowPHJruk&>oKI_fT7UQCGZ#;jbV@Qm*P(^#Nqun|9In{D z34Y;+{sjQBJxe}6+@Q0dL&{f|RO}mMoo}97o}#*uD%G=zLrT9+x(vK8*U;{l=7Zw} z3nLg+5w`k2S3ZW(mm@md@T>DEx;)1Ctf0W?f7nveL~O1-2&Ye5;zha=M9fjJ+&7A> z#vOBLJ~4fL(E`;>WWLOgt)n(&@o!2Zw!11m_2?e_O=HX}Vl*x1()#yLYu1cl{J2{D z4&&4IOaLLMW)_mSX5rePA=`$RcDdo`Sli&3`u_YjQ28M3l-EBlNImY6wpLz#`1320 zq!2qb?9y)gJ8BxMs8!}6-&_3;P4vH6#z}gnbSk7(1is>|roE==^U9V}Rc)8_-f_h< z{t{aU4NvKjo3isS1MJ-JDJT8JNMkiJ6OD5 z#ikO58UIC+`sJ+9g0?H`l6v=3X_Q|Ss;2kDuK zWwa1}Y}X@_f)lr{yfZ`m^m$Mg*}5B~*glPc>@~WFX-navxrfK_>h)|xj}Y~CP|)V0 znx|+8wp1^!Se&mUTBh>_0SnHZ)S~AxU3d>P%#7eqIiWn_2Jk-D9eQl>oN=pt0!>#3$UnfNVQ(-UTy1!h` zYGxKVMoaVW_Qr7-Du;C%h47AFg2Oj89$XMK10{WD*;Ee^7kLm+|y5D4YW%5g~(rEUTghI;GMV${!-O=9~|@OIg=fAg6^ zosf{0elX_OI#^jK(9K>Li?r*vV!RP=XS|0=H?;6FMsC%rFFhhcy|iVvicz%Va8&c* zb;SpWcFap09+$p{J{_Rb;X28JuYTM%=Z48_Ra|6Nm;Y+R zBZ!(=iTAXC4o{CNors-ZSgW!HnOAWnDpM_ zqciutMYYDz*vOYmxF(2EWEzjFV2s)=lVQEG&;dtD(wMu3lS~tJerkJear@+Ibrf+^ zS&P2%!g8}|x+jpWhmD>Rb+e-1id)k$Z$)LBV^0i1oD)7{Z(+&S~Vi5tp z&`sYa;H!)bO)Q9V0;h6D@*EX9XxTF;L(l`Whxux)@@ACgyo6`Tk*9~t$E%Z*ZjSa* zC?xWTv&o*#jIy`s&@&6bcvC7S0hGSZd2-$8*#7X5eUKKj_z;4>AGj(|83k}d z-4oN2pZedrJSQAk&(Zj!vD8=zfl?w!T5!EdkNcFH#53Vrr9 ziR_s3_tW%8hnkx|K?aY$q&I~mN(RS-1xAb+Y)g`v8Mp(98{U9Fhvs*_h8JrjnD|p6 zdvXV*WwiKzre9fUSe+{13N>zqwAB`WfkqebuO1TF$9FQd+X)Uy$O;$B3RkS)Aoz4MA zy@B0>45v74s>8t!b`|w+kzDv!B7MF+I)jh(8Y`9NEw8K!_EfIA{u98|q@S{VkhU0k zWyNt7<=4HqQ1@eUQZyww{8mcx+|Vb@K|qjlNQ|o8&XPW#F6G=`whEF>`=sbXs#-)5xWwuBt;|OwZI>rSv)~Q>)Co zBePGYEK6D|G@5dm9nx%iItN^P1_1N6vH2Bb&`YKQ0GO6P7|aw=6BgSJy6X#+<4f}K z75WvJN`rYJQ5oNm(Slbe93J_t-9vaR<06>N;#>{v5ibRcfUW*iuVZIo)66U<8xO@?K00mC}nXXsStZZ=YR>cMa=GAE!l? zdCtv)wO=j|zdR9%lM5c&o$Fz9u`nqT%G8IHKeCIF+-d07?+;|aX)BxEB{Xm!H43M4 zfx=7bfPX^Fg~HYv3<&T$r{s?8JIKMHoQ(3AtHCL+@_0c$}Qn!k3NYxEWhxeFE(jpq?g zWPr>D>(VN(kp57uqesp2mFi8iN_=z16?2v9+^qgv&mdNN_wY}5>NTGMm`yA+2HK6QQPrZYs66g@MrF!rZ%;h$h5PXiF^ z;=b5iYPUM=AW$nUC=Je#S^A(GaiuPO7C_zedGMH+5yvQE=m*&di)SbLO1SoKZiszudI7v|hKr z>nI;0o`G`rt~!ci2Xs@sk)W?CJAza4%tIC%J{2zT5D8;Vm6hti_UN&3TUC%a^Z*0^ zc5f9`gW#8QC7Q?v~yQp*;AIo@(92 zenn3B@cN)Ion`z~`Rq%LZp70VfyV*I0(r^Z@><4jAW*!>o+MUf@-%(n79jVe1e+qb zJ<;OAY4wW z;j}Y)2V)d63c;ZKB|Cl|0S2%?XdIzm~AQ zUrj97+U3UmO<4Fy8rZH^M%tq~DeVSM^gdSfRtM^vtV=Igwisi}n~d?YB9@P*@C+6w zo++u^_8n<7j$M69CX*w|M26&z{$hnFT!^b6F=7^E%rjj4Wz~n^*In6~j5h-US;9;tg0 zeXEmj0f7Zt2nt$D(%08tJn3K*rnL@sBA1hI638!Od1=81!+n_(tM>RTp@Lzn zyWd84wg&6=#0e(g?~e(ctEt3JpXxo}X1ej~w&=w4xRMqddrbJ`3u6NnxBNuLFxv0r^> z@ud~GEVEf$;1A-MUI=_&ii{23hW7KFyg@1IhA|d; zK1kt+c}i8|XInW6;&6%uc6ED$VE6WiqCk1vm+l2R=r5)Bv+7v>kXc@85!~Mmm?-1c zsT!ZGth{60Qt4#AAkY~k-eIwJhqkP8eAbgW+j!b1KF{`TQ^)xDxReGWE`tC9#w)6& z(n3Gqr!W|Yon)&7reQh|Uw-Iq;j4>(0wht<*YpXu@D+WhMBg zNk&S3&~DzaDG0P%&8D9*bt}nrCJxLXKQ$0h7)6MCeh09Obk8YO$SxTd;dx@5v?gOt zSzsB#XQC`CysR_a`>Ta|(U~eY4>cJdCC{86?DxI^3Pl|(Jf%HR4%8YIn^pD}g|uMb ze;GG5Ehc4rcV_{^2GP||ECTo2Bo1Fr&QpdL%`eQ3Bv%ey`%oOdJu{P^)6w{zwOZ-H=Pkb6R~{J5$gCv(M7o)m0JH z*Q>zqe2vgq9I?BQH8pyf;r&|#mMUYubLZVZWYKEY%&=vI*C1x@;rl7#?USky?tVT? z8}{JN1=WEHA#=*xA#-Vm>W4MKrwZO85LMLYC{X*?QNhIObi-tEDwmG~Zt7wE`R(!z z2Uie!7*F==A2d@ml8V4gRS($XokD5M!67r=B;rh01G3)%jw)B{D73k5%Om-4D)2+{ zFdT&a<|;504(;Bk$j5&>AG@ij)?D~=Wbd7i?|{OI#C_SSuRC9lMrU=< z&KF8Dl!5rlQ-hDQUHd=y;R*7~jUVw^t_c^>VfxrP&*jndq8u-hWem@|u_T@pz^K&M z&{g-^+1+7a9En?ho-Z&SN6v{~cUU-#CKEba9UstzV=XO4^L%olZm!x4cc!8M*bjV> zlV&iLw7J1?B{5cVJ|OVatz_{k>D@7!l17;O8$uKdsFm8@Jh?uZ4=%09c?Px( zmXGoFpsES4o#j$5`yEI@OlOcnM`C<^{vBVld9e-)^+R0jm~D2T{P&5R=m8iJFFR|7Gy7>g&LfVQ^ zEW22He6Y&;n=kUSop47$|F6oMXFCFLPRv#U!Fl(|p=a^>SlAm5tDrL5u zDGak`n~rE%NC_5vv~RVOekbR}ltFtru^!A&+$&<|%`0O`uf0glu|=@QpEYtoq{aLNmuc3u{_c`w^u1SWC?`iDY}Z+bd`6X ze=G?gjUqq{rj_u=((i!ChWe|l-Q6iXyK+)%eKzy?kLMe8co`?hCSzC*Dr9#PTQcjV zST?Jk6q`5|>Q27kU{1PYH_+e)B;bfZXOY^OD9e^NO~yd)y(64SA@jPsksxmXId^hv zW;8Cf>D=2SKB_tGH9np>=#xj;QS66np9R+}fEfUg3V}_aD~zi=$_3!5>w6+=`a!-^ zq=bnG|0k*Gk4$1x+Q!e~*I#6$l}=ibknI$eml_f61lKTQTj5_E|MEkqd!p)LSm7|# z^?9M!WjM!Mz>zqx+yl~)0dTe4Ns zm?cVpoRn9$HP+?iL&;AAFd&0G-gzdAYn>?uDl2SSVtG)Vt-+fV(!B6Q->JX*%csKp zhVCiIn*y*#>3eSTmCk0$_^I3XyBoyFzN!HtKd1>vwiZaHRLG2-?)uwTxK|f?<_so> zwA#m!-|zX_gYe?&ANuRr=QlaG+q`u zcRJ@)JkuAw1Kdrj&>N}VFYne&wIp(9OfAf4p*_Xkw+%}1P)ncRA+^2`6O!Jl4!K}z z(H`Njm-;zk;mSjCD@tx(x8F87?#uqMu_OS~*(?2Ssu^gk+EKkfKSC&i`PY4pLzq%( zxwqf7?R7?URGY?F68cJu?Y}RVYGh2b8RaWz&aaeJchs{VGNcvA%YM?CW zUt2!=gx_!WLGlYJrt_bgP~d#Cr9Sq|yyZy~FWikA0(5r;)EwZ zQ&9d4d>*THt=K6k~tWuN54@%Yv}wO^^{-^ zp%iQVQA=52)`#6z!BZ!)lZEzNWzDqJiTs^gpAAwDyZxK~Kj%(Xv%iu%KL zqf-tn^sX7Yon$E1WK*LZq*8)FB*(}V_Fsyu_)AR*36ed}fetCb9$yEWTd#i3$(*{i z-}EtzxEyQS0C>m~VTHpIYbK}QQ54xkpx6I6P%uC<72iL_#GY`y8Q6)-P8QlotQntz zv&fh%awi}k)HwAYX4I_KH*Dfyqzf8bif$^8isr^VGFGr4G&tqK?u#>QZqf%sz)FFP zSYIywai}2Fc{43*8JN!_Y3B3w3de94E$cEXN(yc0Co5H2si*yqeh@5d6Ob1i&oy2r z#Mk}$L+Z?VJ_UCLLD^u1E(9VSm5NP$nv6R=TS>a6*9k3%PaYARB|SpkH$_U-N&>=dWAxo0BrnDuTbF%B{|M z!sn!VQQ+f9>YpJ-nOWKG^OUJ<%lK?bbgQRlB`|`s?@TkBCK~;m}>l$Jq&*)IWx`i#ZQWyzhBCz7bU~FIE488OcVCd6S{;iDR2oY1mS29EyZN8G;eI=Q!OFBYI91)K&2&Yd+zeFwB7Tl_ND0s#*-m15hDm&NbAHBF_E_2Y zst)$5v=mwBs!6l_yc}fK7vAjFADkM{!yl>y$&LJNyo+q;hBf5Fq0C|)?exil?Vq(P+U)YWknxq!5JKilwgQ}gub?g8H z0l3-+dsJ)sO&avH9w`uod|p$wor4(bpbxZ}szIFFCD0*5TN00soK5gYL`U8`>}Cf( zafZ>6m)P7!ht?!;2DI0V{TBfc`ZPc2YbKJ0N;4N3A!+ORR;O$0slhMS(^eeKk#6l~ z8j7>kV^ET1gEsfD0`^N-6DB^NG-k%>Oc9n(X%gdCL~{Pv{Ze?9&<2X>+V_`k|EM$u z^{~28MyMDS`YZo16+^m4OU-Z`rqXHl>xgq}hW}V;Jr;!u>Wq%0y<6)=q1Nn0U9mxT zC3Cg)w&54GbEASoC3CyzZe49cp}`t(SXns@M{#Slh&<~qgL3}Fx9G2p9VrCd$k{qO zF3F-i=Pk39^%&Ydp`MeT?N*uB#A@(4Wgfk*&dfR%LV%I&$I)Zeum8qQE{Eh<~m zQd5{GHxE$z98wQ5#w(BI`J?NMBgzBFvMlehq#_igCaX4yPPx;Q1-BidRQy(D`P;!M zdA@z@mE3UZ3xeE&OdBDd>z$e`VI_PE^43-wy)Jh4YOs6yT%OM#OvzC1k`|N6$T(C_ z$n`FKIwC-EWQ!oDw_8Z`{+vgE+fG26m3voH;+6YJ-U~SQQ|^a<*Ll60Qn7a+wOq0F z4YmW`p_;}j?*n^g=$_J<9H@BQV|Z970aUNlR#d0mJ8&>1fJi@f@c!nS?LL!#OL=%nE%LG~+BI@BE!g~qVS0bra8mH?;!NP{l-vW25WF9P_W$1%6peE)gKLAM$6DKRjp1z6!S`8!B~v zS|_zH9A#+6YO*rWsV+2Ob}s^z2*$Y%0$^jBod}?WnZYkXs8{jPPn46M7OnOX*ND*K zr~p z5MW92Ixur&fOc}BZngUgWBu5YNHXo%#deL>u3K@107KX(w7(BPmrA9?5~nkH*Y%J! zyOZAP?FkG*zXw~}@A8Kk(ap~Nz<`&PhH`@vs$vlaDsM*p#g1&t+8;mr(X0Q-C+Wo-QoF2(d62B4iS;k;Lu*Nt+o z+VZ*PBSh(KBkFRk$bCNytLl{B;@IDw3$(B}^F&OBSS3HF*!$@*G~kRWNMJz{{v?om zj-?B{*iBsMd6NsDmV(!bG(dls6p4{Ds$|0IKru4+xwM*A-Po@mJ6L$US!T-pQzl9k zpx6T&d7G1uj3k)8Ym6*oA~z?~dBOX`x!6+PcHzDiUYGMIajs?|h*7Le_Vr%Zhj}t_ zro8t$urialtQsEA)ceU(HX_dKnMj_4C}bh+7lxB`bdr;jhD0JP2b~iOncBX$?lCBNWIkU0p;j0Ga}^!m8) z{e2@H}n#`xRAaU5;r$hm0Yjc@MjO{0>z<3yZ41 zz@ccuWSkXY&-3|V5pQF}N9V-DUs3WL%(YjY`JIzDo|%y1V2c1Tbb*Q-uzL0cM>ZU0hHWG`~n zgjAzWUGgt}3VtCJs=iQ~y_sH58CyxYGuc81l4=WpQz-J;&(Zi9u~gj>F$v`g?tzEJ z3Ea=87h19)@1CVg$Fa(EA2Ln9z~S-6?t@BPHMF4;Q=%8MJLRRzrNSoFDK0|37r|t_ zaxo_AYHxa^Ug|;5vlb_iYC0I7ScTFO$FRXLM9`$ zUObZ{0nuwFq=5{_4?b}pjxO=m+&EWHA7yQ?*B)uy9W(dk&4f#yJ8~JtMc*hdeP$MJ zxmne#rN!nfCfe(6>Os(nQnFkNjuFdDPrErQUKdA(U+gO8-FnQW%hkxc+1=&JWz?w? zHE2mN;TdYR;t6dl-U!}&3O%+W@x;DEhnESvLh=ZGT6Yx@J)0+znCXZ|B*Z3`mWj;X zVBdvZL`2aiKf}P^hpTc|&>lSae4|)wssx*(9lC|#zK-08)S5r@QfYRxPdix@q?!;- zm}O49AO&&RX&67f7@u~8&}kCNz9S&&3@x7+U*Wr@dRNpg_?EA4uj}NZGHW|sNOYN- zGMsta($#!3HZXmg|A5U}Z|Nrs-b`R|A|7Z}VNs`Fy{o=dMbf)>gqRIT Date: Sat, 7 Jan 2023 09:20:52 +0000 Subject: [PATCH 012/196] Fix license page --- spec/{ => 2022.12}/license.rst | 2 +- spec/draft/license.rst | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) rename spec/{ => 2022.12}/license.rst (87%) create mode 100644 spec/draft/license.rst diff --git a/spec/license.rst b/spec/2022.12/license.rst similarity index 87% rename from spec/license.rst rename to spec/2022.12/license.rst index 8d4b6d1fd..06ec75dfc 100644 --- a/spec/license.rst +++ b/spec/2022.12/license.rst @@ -5,5 +5,5 @@ All content on this website and the corresponding `GitHub repository `__ is licensed under the following license: - .. include:: ../LICENSE + .. include:: ../../LICENSE :parser: myst_parser.sphinx_ diff --git a/spec/draft/license.rst b/spec/draft/license.rst new file mode 100644 index 000000000..06ec75dfc --- /dev/null +++ b/spec/draft/license.rst @@ -0,0 +1,9 @@ +License +======= + +All content on this website and the corresponding +`GitHub repository `__ is licensed +under the following license: + + .. include:: ../../LICENSE + :parser: myst_parser.sphinx_ From f06c5a0b1ad723cd8e1197f990769c2762269ead Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Sat, 7 Jan 2023 09:26:03 +0000 Subject: [PATCH 013/196] Update changelog refs --- spec/2022.12/changelog.rst | 2 +- spec/draft/changelog.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/2022.12/changelog.rst b/spec/2022.12/changelog.rst index e0993307d..701a3dbcd 100644 --- a/spec/2022.12/changelog.rst +++ b/spec/2022.12/changelog.rst @@ -1,5 +1,5 @@ Changelog per API standard version ================================== -.. include:: ../CHANGELOG.md +.. include:: ../../CHANGELOG.md :parser: myst_parser.sphinx_ diff --git a/spec/draft/changelog.rst b/spec/draft/changelog.rst index e0993307d..701a3dbcd 100644 --- a/spec/draft/changelog.rst +++ b/spec/draft/changelog.rst @@ -1,5 +1,5 @@ Changelog per API standard version ================================== -.. include:: ../CHANGELOG.md +.. include:: ../../CHANGELOG.md :parser: myst_parser.sphinx_ From 6eb8df3926370ae1368b262bb98b6c0932d854ad Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Sat, 7 Jan 2023 13:03:49 +0000 Subject: [PATCH 014/196] Standardise `dtype.__eq__` autodocs accross versions --- spec/2021.12/API_specification/data_types.rst | 2 +- spec/2022.12/API_specification/data_types.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/2021.12/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst index 49373a6f5..48a8bd1a0 100644 --- a/spec/2021.12/API_specification/data_types.rst +++ b/spec/2021.12/API_specification/data_types.rst @@ -100,7 +100,7 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: array_api +.. currentmodule:: array_api.data_types .. autosummary:: :toctree: generated diff --git a/spec/2022.12/API_specification/data_types.rst b/spec/2022.12/API_specification/data_types.rst index e9f6ff732..a9be88181 100644 --- a/spec/2022.12/API_specification/data_types.rst +++ b/spec/2022.12/API_specification/data_types.rst @@ -101,13 +101,13 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: array_api +.. currentmodule:: array_api.data_types .. autosummary:: :toctree: generated :template: method.rst - dtype.__eq__ + __eq__ .. _data-type-defaults: From 96a38c30c64cbcdb39e78d9f7162ebbcf4c46d22 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 18 Jan 2023 09:49:11 +0000 Subject: [PATCH 015/196] Minor grammar fixes Co-authored-by: Athan --- PACKAGE.md | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PACKAGE.md b/PACKAGE.md index 199c4e2a2..dc5079d2a 100644 --- a/PACKAGE.md +++ b/PACKAGE.md @@ -1,7 +1,7 @@ # Stubs for the array API standard -Documentation specific to singular Python objects in the spec (i.e. functions, -methods and attributes) are infact represented by stub objects in the package +Documentation specific to singular Python objects in the spec (i.e., functions, +methods and attributes) are in fact represented by stub objects in the package `array-api-stubs`. These stubs ultimately get rendered via the autodoc capabilities in Sphinx. diff --git a/README.md b/README.md index 96edb338e..529afdbb9 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ this array API standard. ## Building docs locally -The spec website comprises of multiple Sphinx docs (one for each spec version), +The spec website is comprised of multiple Sphinx docs (one for each spec version), all of which exist in `spec/` and rely on the modules found in `src/` (most notably `array_api_stubs`). To install these modules and the additional dependencies of the Sphinx docs, you can use @@ -35,7 +35,7 @@ $ sphinx-build spec/draft/ _site/draft/ ``` To build the whole website, which includes every version of -the spec, you can utilize the `make` commands defined in `spec/Makefile`, e.g. +the spec, you can utilize the `make` commands defined in `spec/Makefile`; e.g., ```sh $ make From 399cd772d86a404e8902533dff507d110743ebe9 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 18 Jan 2023 09:50:56 +0000 Subject: [PATCH 016/196] Update copyright date (after accidentally reverting it) --- src/_array_api_conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 161590fea..ca8d2aaed 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- project = 'Python array API standard' -copyright = '2020, Consortium for Python Data API Standards' +copyright = '2020-2022, Consortium for Python Data API Standards' author = 'Consortium for Python Data API Standards' # -- General configuration --------------------------------------------------- From 8d48911ce0c68c3952d84580c2b1760801285930 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 1 Feb 2023 08:45:40 +0000 Subject: [PATCH 017/196] CI: ensure make propagates errors and CircleCI fails on doc build failure This got broken in a recent change to the Makefile --- Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 77a848598..a48139ddc 100644 --- a/Makefile +++ b/Makefile @@ -12,12 +12,12 @@ clean: -find . -type d -name generated -exec rm -rf {} + build: - -mkdir -p $(BUILDDIR) - -cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" - -cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" - -cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" - -touch "$(BUILDDIR)/.nojekyll" - -sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) - -sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) - -cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" - -sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) + mkdir -p $(BUILDDIR) + cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" + cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" + cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" + touch "$(BUILDDIR)/.nojekyll" + sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) + sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) + cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" + sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) From 3d918783ac7f11cb5b31681b2badddeca81dc71e Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Wed, 1 Feb 2023 04:53:03 -0500 Subject: [PATCH 018/196] Add admonitions for new and changed APIs in 2022 version (#585) - Add version changed to functions that were modified for complex support in 2022 - Add version added to functions created in 2022 Co-authored-by: Ralf Gommers --- src/array_api_stubs/_draft/array_object.py | 67 +++++++++ .../_draft/creation_functions.py | 47 +++++++ .../_draft/data_type_functions.py | 21 +++ .../_draft/elementwise_functions.py | 129 ++++++++++++++++++ src/array_api_stubs/_draft/fft.py | 70 ++++++++++ .../_draft/indexing_functions.py | 5 + src/array_api_stubs/_draft/linalg.py | 107 ++++++++++++++- .../_draft/linear_algebra_functions.py | 18 ++- .../_draft/searching_functions.py | 6 + src/array_api_stubs/_draft/set_functions.py | 24 ++++ .../_draft/statistical_functions.py | 6 + .../_draft/utility_functions.py | 12 ++ 12 files changed, 510 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 89e5ee1c3..cf6adcf3c 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -136,9 +136,14 @@ def __abs__(self: array, /) -> array: out: array an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -157,9 +162,14 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -228,6 +238,9 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __complex__(self: array, /) -> complex: @@ -260,6 +273,8 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. - If ``self`` is a finite number, the result is ``self + 0j``. + + .. versionadded:: 2022.12 """ def __dlpack__( @@ -326,6 +341,11 @@ def __dlpack__( errors are raised when export fails for other reasons (e.g., incorrect arguments passed or out of memory). + Notes + ----- + + .. versionchanged:: 2022.12 + Added BufferError. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -401,6 +421,9 @@ def __float__(self: array, /) -> float: - If ``self`` is ``True``, the result is ``1``. - If ``self`` is ``False``, the result is ``0``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: @@ -551,6 +574,9 @@ def __int__(self: array, /) -> int: - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. - If ``self`` is ``NaN``, raise ``ValueError``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __invert__(self: array, /) -> array: @@ -671,6 +697,8 @@ def __matmul__(self: array, other: array, /) -> array: - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. - The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. @@ -682,6 +710,9 @@ def __matmul__(self: array, other: array, /) -> array: - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __mod__(self: array, other: Union[int, float, array], /) -> array: @@ -727,9 +758,14 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -749,8 +785,14 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + Notes + ----- + .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __neg__(self: array, /) -> array: @@ -773,9 +815,14 @@ def __neg__(self: array, /) -> array: out: array an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -813,9 +860,14 @@ def __pos__(self: array, /) -> array: out: array an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: @@ -839,9 +891,14 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -913,9 +970,14 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -939,9 +1001,14 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 3f577b542..8736efc29 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -97,6 +97,12 @@ def asarray( ------- out: array an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -179,6 +185,12 @@ def eye( ------- out: array an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -237,6 +249,12 @@ def full( ------- out: array an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -273,6 +291,12 @@ def full_like( ------- out: array an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -334,12 +358,17 @@ def linspace( out: array a one-dimensional array containing evenly spaced values. + Notes + ----- .. note:: While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. .. note:: As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -367,6 +396,12 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -395,6 +430,12 @@ def ones( ------- out: array an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -420,6 +461,12 @@ def ones_like( ------- out: array an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 0f557852b..571871f6d 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -36,6 +36,12 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: ------- out: array an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -97,6 +103,14 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: - **dtype**: dtype real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -129,6 +143,8 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: - **dtype**: dtype integer data type. + + .. versionadded:: 2022.12 """ @@ -167,6 +183,11 @@ def isdtype( ------- out: bool boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 6b2a46e24..74ef7e98d 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -52,6 +52,9 @@ def abs(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -118,6 +121,9 @@ def acos(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -189,6 +195,9 @@ def acosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -254,6 +263,9 @@ def add(x1: array, x2: array, /) -> array: - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -308,6 +320,9 @@ def asin(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -370,6 +385,9 @@ def asinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -419,6 +437,9 @@ def atan(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -541,6 +562,9 @@ def atanh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -709,6 +733,11 @@ def conj(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -753,6 +782,9 @@ def cos(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -813,6 +845,9 @@ def cosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -893,6 +928,9 @@ def divide(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -934,6 +972,9 @@ def equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -987,6 +1028,9 @@ def exp(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1043,6 +1087,9 @@ def expm1(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1192,6 +1239,11 @@ def imag(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -1226,6 +1278,9 @@ def isfinite(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1258,6 +1313,9 @@ def isinf(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1289,6 +1347,9 @@ def isnan(x: array, /) -> array: - If ``a`` or ``b`` is ``NaN``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1390,6 +1451,9 @@ def log(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1449,6 +1513,9 @@ def log1p(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1488,6 +1555,9 @@ def log2(x: array, /) -> array: \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1527,6 +1597,9 @@ def log10(x: array, /) -> array: \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1703,6 +1776,9 @@ def multiply(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1725,6 +1801,12 @@ def negative(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1764,6 +1846,9 @@ def not_equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1780,6 +1865,12 @@ def positive(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1847,6 +1938,9 @@ def pow(x1: array, x2: array, /) -> array: .. note:: Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1863,6 +1957,11 @@ def real(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -1958,6 +2057,9 @@ def round(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2002,6 +2104,9 @@ def sign(x: array, /) -> array: - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2045,6 +2150,9 @@ def sin(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2105,6 +2213,9 @@ def sinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2133,6 +2244,9 @@ def square(x: array, /) -> array: **Special cases** For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2189,6 +2303,9 @@ def sqrt(x: array, /) -> array: - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2209,6 +2326,12 @@ def subtract(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2252,6 +2375,9 @@ def tan(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2316,6 +2442,9 @@ def tanh(x: array, /) -> array: For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 2eb428b0c..7979095fe 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -44,6 +44,11 @@ def fft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -90,6 +95,11 @@ def ifft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -143,6 +153,11 @@ def fftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -196,6 +211,11 @@ def ifftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -242,6 +262,11 @@ def rfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -288,6 +313,11 @@ def irfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -341,6 +371,11 @@ def rfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -394,6 +429,11 @@ def irfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -437,6 +477,11 @@ def hfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -480,6 +525,11 @@ def ihfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -507,6 +557,11 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar ------- out: array an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -536,6 +591,11 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a ------- out: array an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -559,6 +619,11 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -580,6 +645,11 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index e76ce7484..d57dc91e5 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -23,6 +23,11 @@ def take(x: array, indices: array, /, *, axis: int) -> array: ------- out: array an array having the same data type as ``x``. The output array must have the same rank (i.e., number of dimensions) as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` whose size must equal the number of elements in ``indices``. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index b040251dd..20d1d54ff 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -38,6 +38,12 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: ------- out: array an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -66,9 +72,17 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. + **Raises** - - if provided an invalid ``axis``. - if the size of the axis over which to compute the cross product is not equal to ``3``. - if the size of the axis over which to compute the cross product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ @@ -87,6 +101,12 @@ def det(x: array, /) -> array: ------- out: array if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -154,9 +174,14 @@ def eigh(x: array, /) -> Tuple[array]: - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -192,9 +217,14 @@ def eigvalsh(x: array, /) -> array: out: array an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -224,6 +254,12 @@ def inv(x: array, /) -> array: ------- out: array an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -288,6 +324,12 @@ def matrix_norm( ------- out: array an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -306,6 +348,12 @@ def matrix_power(x: array, n: int, /) -> array: ------- out: array if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -326,6 +374,12 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a ------- out: array an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -348,6 +402,12 @@ def outer(x1: array, x2: array, /) -> array: ------- out: array a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -382,6 +442,12 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: ------- out: array an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -441,6 +507,12 @@ def qr( - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -490,6 +562,12 @@ def slogdet(x: array, /) -> Tuple[array, array]: - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -522,6 +600,12 @@ def solve(x1: array, x2: array, /) -> array: ------- out: array an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -571,6 +655,12 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -589,6 +679,12 @@ def svdvals(x: array, /) -> array: ------- out: array an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -653,6 +749,9 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -716,6 +815,12 @@ def vector_norm( ------- out: array an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index c8b6e50f8..9d949c067 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -32,6 +32,11 @@ def matmul(x1: array, x2: array, /) -> array: The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** @@ -40,6 +45,7 @@ def matmul(x1: array, x2: array, /) -> array: - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + """ @@ -101,6 +107,12 @@ def tensordot( ------- out: array an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -133,10 +145,14 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: out: array if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** - - if provided an invalid ``axis``. - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 9393ba71e..9dcc0f95c 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -75,6 +75,12 @@ def nonzero(x: array, /) -> Tuple[array, ...]: ------- out: Typle[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index dc95f58e8..661d3df90 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -38,6 +38,12 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -74,6 +80,12 @@ def unique_counts(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -110,6 +122,12 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -141,6 +159,12 @@ def unique_values(x: array, /) -> array: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 787faeeb9..93faaf31e 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -171,6 +171,9 @@ def prod( - If ``N`` is ``0``, the product is `1` (i.e., the empty product). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -265,6 +268,9 @@ def sum( - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index e70fe8aa6..64e5de297 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -33,6 +33,12 @@ def all( ------- out: array if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -68,6 +74,12 @@ def any( ------- out: array if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ From d8720324d5669099cfa24323b43f833274853a53 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 28 Feb 2023 12:34:02 +0000 Subject: [PATCH 019/196] Improvments to doc building with `make` (#587) --- .circleci/config.yml | 4 ++-- .github/workflows/pages.yml | 4 ++-- Makefile | 14 +++++++++----- README.md | 34 +++++++++++++++++++++++----------- doc-requirements.txt | 7 +++++++ pyproject.toml | 11 ----------- spec/2021.12/conf.py | 2 ++ spec/2022.12/conf.py | 2 ++ spec/draft/conf.py | 2 ++ 9 files changed, 49 insertions(+), 31 deletions(-) create mode 100644 doc-requirements.txt diff --git a/.circleci/config.yml b/.circleci/config.yml index cecae43c8..b35ab8506 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,8 +19,8 @@ jobs: name: build docs no_output_timeout: 25m command: | - pip install .[doc] - make + pip install -r doc-requirements.txt + make spec - store_artifacts: path: _site/ diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index e615135d3..b328abc11 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -76,14 +76,14 @@ jobs: # Install dependencies: - name: 'Install dependencies' run: | - pip install .[doc] + pip install -r doc-requirements.txt # Generate the documentation: - name: 'Build documentation' run: | # Turn warnings into errors and ensure .doctrees is not deployed: export SPHINXOPTS="-b html -WT --keep-going -d doctrees" - make + make spec # Configure Git: - name: 'Configure Git' diff --git a/Makefile b/Makefile index a48139ddc..d23e05218 100644 --- a/Makefile +++ b/Makefile @@ -3,15 +3,19 @@ SPHINXOPTS ?= -W --keep-going SOURCEDIR = spec BUILDDIR = _site -.PHONY: default clean build +.PHONY: default clean draft spec -default: clean build +default: clean spec clean: - -rm -rf $(BUILDDIR) - -find . -type d -name generated -exec rm -rf {} + + rm -rf $(BUILDDIR) + find . -type d -name generated -exec rm -rf {} + -build: +draft: + mkdir -p $(BUILDDIR) + sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) + +spec: mkdir -p $(BUILDDIR) cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" diff --git a/README.md b/README.md index 529afdbb9..6c32aec19 100644 --- a/README.md +++ b/README.md @@ -18,31 +18,43 @@ this array API standard. ## Building docs locally -The spec website is comprised of multiple Sphinx docs (one for each spec version), -all of which exist in `spec/` and rely on the modules found in `src/` (most -notably `array_api_stubs`). To install these modules and the additional -dependencies of the Sphinx docs, you can use +### Quickstart + +To install the local stubs and additional dependencies of the Sphinx docs, you +can use `pip install -r doc-requirements.txt`. Then just running `make` at the +root of the repository should build the whole spec website. ```sh -$ pip install -e .[doc] # ensure you install the dependencies extra "doc" +$ pip install -r doc-requirements.txt +$ make +$ ls _site/ +2021.12/ draft/ index.html latest/ versions.json ``` +### The nitty-gritty + +The spec website is comprised of multiple Sphinx docs (one for each spec version), +all of which exist in `spec/` and rely on the modules found in `src/` (most +notably `array_api_stubs`). For purposes of building the docs, these `src/` +modules do not need to be installed as they are added to the `sys.path` at +runtime. + To build specific versions of the spec, run `sphinx-build` on the respective folder in `spec/`, e.g. ```sh -$ sphinx-build spec/draft/ _site/draft/ +$ sphinx-build spec/2012.12/ _site/2012.12/ ``` -To build the whole website, which includes every version of -the spec, you can utilize the `make` commands defined in `spec/Makefile`; e.g., +Additionally, `make draft` aliases ```sh -$ make -$ ls _site/ -2021.12/ draft/ index.html latest/ versions.json +$ sphinx-build spec/draft/ _site/draft/ ``` +To build the whole website, which includes every version of the spec, you can +utilize `make spec`. + ## Making a spec release diff --git a/doc-requirements.txt b/doc-requirements.txt new file mode 100644 index 000000000..230413784 --- /dev/null +++ b/doc-requirements.txt @@ -0,0 +1,7 @@ +sphinx==4.3.0 +sphinx-material==0.0.30 +myst-parser +sphinx_markdown_tables +sphinx_copybutton +docutils<0.18 +sphinx-math-dollar diff --git a/pyproject.toml b/pyproject.toml index b8240a665..f39bf48b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,17 +14,6 @@ Source = "https://github.com/data-apis/array-api/" Documentation = "https://data-apis.org/array-api/" Homepage = "https://data-apis.org/" -[project.optional-dependencies] -doc = [ - "sphinx==4.3.0", - "sphinx-material==0.0.30", - "myst-parser", - "sphinx_markdown_tables", - "sphinx_copybutton", - "docutils<0.18", - "sphinx-math-dollar", -] - [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index d9ec5b030..04af8974d 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -1,4 +1,6 @@ import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2021_12 as stubs_mod from _array_api_conf import * diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py index e9d652d44..fd05b644e 100644 --- a/spec/2022.12/conf.py +++ b/spec/2022.12/conf.py @@ -1,4 +1,6 @@ import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2022_12 as stubs_mod from _array_api_conf import * diff --git a/spec/draft/conf.py b/spec/draft/conf.py index f3804e7ad..4a57229b2 100644 --- a/spec/draft/conf.py +++ b/spec/draft/conf.py @@ -1,4 +1,6 @@ import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _draft as stubs_mod from _array_api_conf import * From 3612edc171bb5838c9c7d8b68c5325ad0b6c70aa Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Wed, 8 Mar 2023 15:46:46 -0500 Subject: [PATCH 020/196] Add imag to elementwise functions table of contents (#603) --- spec/2022.12/API_specification/elementwise_functions.rst | 1 + spec/draft/API_specification/elementwise_functions.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/2022.12/API_specification/elementwise_functions.rst b/spec/2022.12/API_specification/elementwise_functions.rst index bc21e14b9..0e5fd0609 100644 --- a/spec/2022.12/API_specification/elementwise_functions.rst +++ b/spec/2022.12/API_specification/elementwise_functions.rst @@ -44,6 +44,7 @@ Objects in API floor_divide greater greater_equal + imag isfinite isinf isnan diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index bc21e14b9..0e5fd0609 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -44,6 +44,7 @@ Objects in API floor_divide greater greater_equal + imag isfinite isinf isnan From 94a24c8aa87f5cdfc9aa94ef845e63992d6bb018 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 14 Mar 2023 05:45:56 -0600 Subject: [PATCH 021/196] Make it clearer that the dtype kinds in isdtype are the string inputs (#610) --- .../_2022_12/data_type_functions.py | 14 +++++++------- src/array_api_stubs/_draft/data_type_functions.py | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/array_api_stubs/_2022_12/data_type_functions.py b/src/array_api_stubs/_2022_12/data_type_functions.py index 0f557852b..f3561b76f 100644 --- a/src/array_api_stubs/_2022_12/data_type_functions.py +++ b/src/array_api_stubs/_2022_12/data_type_functions.py @@ -148,13 +148,13 @@ def isdtype( - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: - - **bool**: boolean data types (e.g., ``bool``). - - **signed integer**: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). - - **unsigned integer**: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). - - **integral**: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. - - **real floating**: real-valued floating-point data types (e.g., ``float32``, ``float64``). - - **complex floating**: complex floating-point data types (e.g., ``complex64``, ``complex128``). - - **numeric**: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 571871f6d..700bffd90 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -164,13 +164,13 @@ def isdtype( - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: - - **bool**: boolean data types (e.g., ``bool``). - - **signed integer**: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). - - **unsigned integer**: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). - - **integral**: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. - - **real floating**: real-valued floating-point data types (e.g., ``float32``, ``float64``). - - **complex floating**: complex floating-point data types (e.g., ``complex64``, ``complex128``). - - **numeric**: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. From dc5e56d28521146f977f910cec3718dfd614de57 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 21 Mar 2023 18:20:29 +0000 Subject: [PATCH 022/196] Add a page on exceptions, and treat exceptions more consistently Closes gh-606 --- spec/draft/design_topics/exceptions.rst | 28 +++++++++++++++++++ spec/draft/design_topics/index.rst | 1 + .../_draft/manipulation_functions.py | 23 +++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 spec/draft/design_topics/exceptions.rst diff --git a/spec/draft/design_topics/exceptions.rst b/spec/draft/design_topics/exceptions.rst new file mode 100644 index 000000000..0a176c302 --- /dev/null +++ b/spec/draft/design_topics/exceptions.rst @@ -0,0 +1,28 @@ +.. _exceptions: + +Exceptions +========== + +This standard specifies expected syntax and semantics for a set of APIs. When +inputs to an API do not match what is expected, libraries may emit warnings, +raise exceptions, or misbehave in unexpected ways. In general it is not +possible to foresee or specify all the ways in which unexpected or invalid +inputs are provided. Therefore, this standard does not attempt to specify +exception or warning types to the extent needed in order to do exception +handling in a portable manner. In general, it is expected that array library +implementers follow `the guidance given by the documentation of the Python +language `__, and use either +fitting builtin exception or warning types that are appropriate for the +situation, or custom exceptions or warnings that derive from those builtin +ones. + +In specific cases, it may be useful to provide guidance to array library +authors regarding what an appropriate exception is. That guidance will be +phrased as *should* rather than *must* (typically in a *Raises* section), +because (a) there may be reasons for an implementer to deviate, and (b) more +often than not existing array library implementation already differ in their +choices and it may not be worth them breaking backwards compatibility in order +to comply with a "must" in this standard. + +In other cases, this standard will only specify that an exception should or +must be raised, but not mention what type of exception that is. diff --git a/spec/draft/design_topics/index.rst b/spec/draft/design_topics/index.rst index c8c5a0733..fa26359a7 100644 --- a/spec/draft/design_topics/index.rst +++ b/spec/draft/design_topics/index.rst @@ -11,6 +11,7 @@ Design topics & constraints device_support static_typing accuracy + exceptions complex_numbers C_API parallelism diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2d7179a8b..2a4b612f5 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -67,12 +67,17 @@ def expand_dims(x: array, /, *, axis: int = 0) -> array: x: array input array. axis: int - axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). An ``IndexError`` exception must be raised if provided an invalid ``axis`` position. + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). Returns ------- out: array an expanded output array having the same data type as ``x``. + + Raises + ------ + IndexError + If provided an invalid ``axis`` position, an ``IndexError`` should be raised. """ @@ -125,12 +130,18 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - boolean indicating whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying if possible, and may copy otherwise. Default: ``None``. Returns ------- out: array an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If ``copy=False`` and a copy would be necessary, a ``ValueError`` + should be raised. """ @@ -169,12 +180,18 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: x: array input array. axis: Union[int, Tuple[int, ...]] - axis (or axes) to squeeze. If a specified axis has a size greater than one, a ``ValueError`` must be raised. + axis (or axes) to squeeze. Returns ------- out: array an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If a specified axis has a size greater than one, i.e. it is not a + singleton dimension, a ``ValueError`` should be raised. """ From 371a4ed33d89bb23e5595d80b056d92d44257e4c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 21 Mar 2023 13:47:23 -0500 Subject: [PATCH 023/196] Add favicon (#612) Co-authored-by: Ralf Gommers --- doc-requirements.txt | 1 + pyproject.toml | 12 ++++++++++++ spec/_static/images/favicon.png | Bin 0 -> 5152 bytes src/_array_api_conf.py | 14 +++++++++++--- 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 spec/_static/images/favicon.png diff --git a/doc-requirements.txt b/doc-requirements.txt index 230413784..488aa3e81 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -3,5 +3,6 @@ sphinx-material==0.0.30 myst-parser sphinx_markdown_tables sphinx_copybutton +sphinx_favicon docutils<0.18 sphinx-math-dollar diff --git a/pyproject.toml b/pyproject.toml index f39bf48b9..b4f991c45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,18 @@ Source = "https://github.com/data-apis/array-api/" Documentation = "https://data-apis.org/array-api/" Homepage = "https://data-apis.org/" +[project.optional-dependencies] +doc = [ + "sphinx==4.3.0", + "sphinx-material==0.0.30", + "myst-parser", + "sphinx_markdown_tables", + "sphinx_copybutton", + "docutils<0.18", + "sphinx-math-dollar", + "sphinx-favicon", +] + [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" diff --git a/spec/_static/images/favicon.png b/spec/_static/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..49b7d9d6fa9e82e24c907c324f53df2dbf11a222 GIT binary patch literal 5152 zcmbtY_fr#quSW$bLueVLBCBOjt$?)1EVNA72(py2q_X!EW$#g;>?Io!s0`W277$Rj z4A~$BL}bY3`R=_x;QQ|7F8SQ$l1nb*ha^fzOXU_dD>WGz*)26yWxapc{g1l$>)~zbW<#cE?ToeIQggJlv(dA$wDxuFw~-+uW9(E@Ry6RL+0Ld6 zVD14&Xj4bllBofU$OT6q0z!p?4Y;{lrMN@20Ec@z$*g{H3O|91dkTqQlx`FCsK!sj z*F2$#U!lGmUs|tm{|rfPZT7!f*!?K}qVfB@`2NoD_OCAt*Z!sQA5ygyo2I9Pa768T zE#fYB+4s_Bfgen9b%pc3ja@_wYUn}tpAP)++X}Jw2<;&aruk^rjuTBBoHa%2#A>ID z_^aQS&H{^^yo1;sAhyv!9Ugt<()Q!uXR{d8AQGKrul~lzf6KBc%1jzV(B~1Xbkg5| z?etPEv%kPlTJfIY@;#?iB^$`e3&e0HSLhD)b1s%dPL}wsh07oyHxg@}x*~JQ3$lp! zv1aQn^i)N;coC->Lv8;9S3+_%xH z0%+Qj2;}e&wiSIKtkHOTD%q{!(Q=)GnW|R*k#{!R3L-A=#S$1kbLvdg0D;e#S3Q7z z4RRZmYT%`{HzT*=_u7$d?oeet<7s)(5^;glW)>Db0@G|fI@YC$!7Fx^fIZvG_kwnI zUQ#3j8t3Gf=Hjffq$#WdB37D1rkY#>oKcZdcPmWHblmI;o<)Pl2eIcJ6#Pcf@M2~q z4G=@`-*m~gKxF+puI{bsPe!9rt4Vcrbt@IJTJZ_UTLpt33!UKvX-$L`H3)oMtZQVJ zP%&!cGNl=sx^kz3Xg>Ht7Ew>n)x7|3fBM8vepbXn7^R)t>bQU5>cs$e8tu6Q>qU?d zdlgW0+JZKRG2P;{7ng6-`N0!hcJ~o^-(l1nMq*~_X@1c z{XD=EWc{Wm#58J)!D4H~H4Ml!EycMOXjDnP*6_*9!@MIad-cKcE$OR16fb5&Ey1%f z_jTY{DK+8m{1K1$`hftdvq8OP6Vf*kVdeMrWmwv53HzGAGdYW~*!@v)kX^}h-rmLq zQLIP$xiZU{NMndXaAVsKqW{xsbjCx{`Jm%|JxX#?amF?H?8fTxaAK{<%3a?lAGh0YUuO7?YoQ z#><#~|LDiWMh%hMlDkDL9=tNZ7eZD&z7XukC z*KftDvTreSe`HsMZf?cEYgC*(M+Hc_H(-hVVUZ=z=zQ@cMa7UUw;!oJzpEMHm0!PU zP>%QK^~DZSU7j8M;t&G&xNB(ssRj&tadmRwH;|$#SDJq?pEh4Sm}L%>p%qTn$f;N_ z=907~-VIwAvUv&DQ}fG+H=F))!n4)Bqrv-UT$ku`&J(w3wMcNSl0G6>t*yF5X_*sG z#5T7!T~P4w8c6!KLTp6&edAXE;4(AQUZQ$ZE`jdnXJ1Zm*Xviel@rw{`SiD3+udF! zX_-yVi;+>{osrB@uFo>K8nsQvhJnCKw zI&o7(y9N;M?}ObgR*8~%Vs9Db8+=9)^9>+5Y76_!SZhE2@*IPIau#pq^L$)M%>sJf zoV<7dII%}uXqC0#*Yi%=KJ18zV3fvn9--5;*!e#*LzC&Uryi4EiQ&CAP9G@cqPBCY zW5;4^cMZ5UUU1!1R@DUwf$?ptlm_3Y40BNq?4r9H25%+GibQ=Qk8-m5PX0=8=`=q} z8Roaw%2=r4*~k_YA&HMKT6fN`dE@OJq_yTsm5+C_>h(XzZi$r9`+^DdD@=J238JuZ zw(UG4sI_f9Y2@l;XWR&R5#^Pgh6-6{|0>~Qvv1lB*f!0uex+t?@MQd_atznzJ(7%? zG6GFGj1%rm)53cd2%%R)5Me(%Rzi))y8wHrSRDe2V``)}2|{5^tL^Fa8saR}DFRl^ z=%n=I54H@`(JM_j%PP+9J1XU(&#Bt+;9isCVjgb{lrc=~dOMKUdsP5f&`s@!b*h~n zYBm(la*8@{C$bod@{J+D#gqw`zSeorFjawGwbQ-QNRWaO%XzVV_26J_G280*R^g-o zn2<=h1g$Dpr^BBd823c{*hv0N^t}%ug}Hi%%OCW@(LSw9WZ~fD3G8tV#148>*@qjX z$*U}5p8|=npIwqH*9jMG%D1;P5aF>0QUClN>+THZ&diRw7ty3u6Is1$kXAf)Dg`&0J3WkRm2&ViD%>80L{{>C5cDtLFIe$}m&NtoZ(ft#8xc-+`^+ zYV9|scV&}D>AOsz&ZctL8>Bd(x`F_!+%@(^YEr#7*qV|m3 z&lbVZ3_tv75!)VJz185TT&n+gpaPLv03GJ+O<(SYVI1kITMEXLGxdZG7#A~bOrk-W zt+wpz0lbfPCbRaBni#w0ZDJVmr$j(YE$cAa7rc+=ht0Gm5O*z^K+D7n$Ej|-T%1Qe z{nyi{kISilJ0{jAos~9t)DMoXR=PFUXAkwbcvC^seOt6&(ay@KJdDRRUj)^O^xE^| ze&Xt#c*qvB{vI*X-TupKHmtDO?8E6RUmI4k+xE7Gq0vkRHr_Cmz=NQmt#w!eo@L*8tzf;~RESc1Sa6~%6Q0SVNXY!~PpwcOr zqEyYMEcu0j&HmG(p);BeN>QvaAzLI|=8zBtq;5xr0`S)iZrqp>1O?O2U_$v)cGStw z7?($|5@q)zr{tF3g=Gb%j)q?0gu@GzN^$COzYd5btIrLzZvl08LpI)T1W;bJ&uINw zJ8OJ5lgekvS~~1@aN%JcftX!UbhmtiqnD~O$=PR}Yp;%kyB-QYs&7}jC4806#NFKcn|;?wrV5TQ-{8pUl#K&6EI+M3rT{Qy|Qx=sN1GpbF`ElW3wY zUsv(PWS9dC6@$w)Mf)VY%BI=F!ErA7>U^8ons27&9?TPubj4pjShHg0F8@umQ=w2r zLbEivFld}%E37{e88BD9N!ME5Q$iu31F5Kt^cT9cXb1%dW74Vn&_G@#3 zOEJ8El8gV9PVeOU#%8L{Mf=#?n1(IbUULUWw-&fN05e#&>VFOcSqDdxv9?)@gjs0R z-!{buNuQ4h6>rqC2F_!g79=->F}7n&!5U2vd>N9(F-5qSI-_1pFBPWxrqq1st|3x+ ze$euRaB$(fC!rHrRYi4YSp5D-$=qKkt8X-f^V{#q`-#PMf*E>LJ=2ObDC@*gy^Ot( zoxf#gCHTk1bajRH25-;;I235|>y*Y+>2%fiOc-a4)(L&FMCEGb%u<($TGcP{=zB?! z^wItb<~#O32$CcRN%z*Hvqf$eY`Jo_T+*rMc5s9OGX{@6gw#SZCYM^E zXysI?bjbZ-_iHITNM7A``Frp0#@zcB0JBE)*>lC6BzzI_Nqc;5y>C9+*Q`lUVB=Gv zEJJjxP8C*?d=}y_zcNt-@nhEUq)&s%%9lST3}Dv%E*A3vkdL?mlKZ9tc_0-?`)dN8 zPbXkKmrqFK&wBf6tZ_GjuEn1sAn=hRH2>#j$jKQ|vxY3Xo4V6}Aw;a9qbQ zEnV+7|44O}GV5e|C=lEh7HLe&9Vpg(J-z zk_M`uzq5QQfA0u5N&#g!E-D9dg^Mazn-NRio0blI(&Gs4WwR<@>2YyM6i;S3JT~Zl z{ssH&i_bt*bxQFSmv`Kx>-pWZwXa_cE!Uls8h^65|J(DE8AZ8U8Hp{bklP{ZSphJI zg7mF5WT#2|U*8(`x5$ya*Bvkn*^^)DfxX!A5QrLKDGczsV`IoKZQV)FnA+*>Vf44e zwu-w|q2qZEfh%>ymWaBH>kr6XWk%93Ty_fLWbJC0R(*b11yr4ae;krNFiq&rUg?sb zoZ^1(OL=ZM)W>wyS7~i*Kl*p`dG_vC{-sDi^dxof$D$EA3Zbiz!D~=juJD2tg$WKP zJzw%C#YFNyaZQbxYbzxGok!$nU{p2j?%W`XTq$zHY^hwRN3`F;vpQO^Qk+?A z=t}_$v9Cp$;)vWn;wLo24ta4GxgIl$5O(pxRW8!4k!3}OCT7VR1?t>XpN0>o?lC-< zeMttjP(0g%W`!H~{OrXhZ_LH@s5-iUa$Nmpg*qWyuGay3;aHI);nGS7a!zhZMm#2| z_ZduPT_U(L?CQ&jh+L(pfEggkXXZ4QfMFKBt)prV|Iqy4!-Jwxl3D0k7G~@a0D30D z*(b=v7pf{Z6Z?jGBBlq@eew)k5F*x79qE#ZHqJW*5H4;4VLjc6)Kam8TWnn?zyU%} zj5~dF+|aYJ3pbAz6}PFM3A3N&VRzIOL&DvDr2Ocgd$XU_QfP-{ zlVE~ojJ@*^cLQyR`?OStc7g7TQ_*j0^+{W)7xJYTlm@XYZV@K^TF fj4S;lm+S^vx7AGCc+NcFza7=kTFRBEXTkpkp8ADl literal 0 HcmV?d00001 diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index ca8d2aaed..490d3a2aa 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -30,11 +30,12 @@ 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', - 'sphinx_markdown_tables', - 'sphinx_copybutton', 'sphinx.ext.autosummary', 'sphinx.ext.napoleon', 'sphinx.ext.autodoc', + 'sphinx_copybutton', + 'sphinx_favicon', + 'sphinx_markdown_tables', ] autosummary_generate = True @@ -176,7 +177,14 @@ todo_include_todos = True -#html_favicon = "images/favicon.ico" + +favicons = [ + { + "rel": "icon", + "sizes": "196x195", + "href": "images/favicon.png", + }, +] html_use_index = True html_domain_indices = True From 8a3e6bc6bcd0dde6a22a7127ac83bc6691250707 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 21 Mar 2023 13:49:07 -0500 Subject: [PATCH 024/196] Add `unstack` (#604) --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index 4f43f0835..fc0e752b9 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -28,3 +28,4 @@ Objects in API roll squeeze stack + unstack diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2d7179a8b..28ffbcff2 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -199,6 +199,24 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ +def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: + """ + Splits an array in a sequence of arrays along the given axis. + + Parameters + ---------- + x: array + input array. + axis: int + axis along which the array will be split. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: Tuple[array, ...] + tuple of slices along the given dimension. All the arrays have the same shape. + """ + + __all__ = [ "broadcast_arrays", "broadcast_to", @@ -210,4 +228,5 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> "roll", "squeeze", "stack", + "unstack", ] From d89e7a7b9739353afcf49951686f804fa372e3fe Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 27 Mar 2023 13:07:16 -0500 Subject: [PATCH 025/196] Backport versionadded and versionchanged annotations to 2022.12 spec --- src/array_api_stubs/_2022_12/array_object.py | 66 ++++++++++ .../_2022_12/creation_functions.py | 47 +++++++ .../_2022_12/data_type_functions.py | 21 +++ .../_2022_12/elementwise_functions.py | 122 ++++++++++++++++++ src/array_api_stubs/_2022_12/fft.py | 70 ++++++++++ src/array_api_stubs/_2022_12/linalg.py | 105 +++++++++++++++ .../_2022_12/linear_algebra_functions.py | 16 +++ .../_2022_12/searching_functions.py | 6 + src/array_api_stubs/_2022_12/set_functions.py | 24 ++++ .../_2022_12/statistical_functions.py | 6 + .../_2022_12/utility_functions.py | 12 ++ 11 files changed, 495 insertions(+) diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index 89e5ee1c3..6cac6033d 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -136,9 +136,14 @@ def __abs__(self: array, /) -> array: out: array an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -157,9 +162,14 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -228,6 +238,9 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __complex__(self: array, /) -> complex: @@ -260,6 +273,8 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. - If ``self`` is a finite number, the result is ``self + 0j``. + + .. versionadded:: 2022.12 """ def __dlpack__( @@ -326,6 +341,11 @@ def __dlpack__( errors are raised when export fails for other reasons (e.g., incorrect arguments passed or out of memory). + Notes + ----- + + .. versionchanged:: 2022.12 + Added BufferError. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -401,6 +421,9 @@ def __float__(self: array, /) -> float: - If ``self`` is ``True``, the result is ``1``. - If ``self`` is ``False``, the result is ``0``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: @@ -551,6 +574,9 @@ def __int__(self: array, /) -> int: - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. - If ``self`` is ``NaN``, raise ``ValueError``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __invert__(self: array, /) -> array: @@ -671,6 +697,8 @@ def __matmul__(self: array, other: array, /) -> array: - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. - The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. @@ -682,6 +710,9 @@ def __matmul__(self: array, other: array, /) -> array: - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __mod__(self: array, other: Union[int, float, array], /) -> array: @@ -727,9 +758,14 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -748,9 +784,14 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __neg__(self: array, /) -> array: @@ -773,9 +814,14 @@ def __neg__(self: array, /) -> array: out: array an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -794,9 +840,14 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __pos__(self: array, /) -> array: @@ -839,9 +890,14 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -913,9 +969,14 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -939,9 +1000,14 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py index 3f577b542..8736efc29 100644 --- a/src/array_api_stubs/_2022_12/creation_functions.py +++ b/src/array_api_stubs/_2022_12/creation_functions.py @@ -97,6 +97,12 @@ def asarray( ------- out: array an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -179,6 +185,12 @@ def eye( ------- out: array an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -237,6 +249,12 @@ def full( ------- out: array an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -273,6 +291,12 @@ def full_like( ------- out: array an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -334,12 +358,17 @@ def linspace( out: array a one-dimensional array containing evenly spaced values. + Notes + ----- .. note:: While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. .. note:: As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -367,6 +396,12 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -395,6 +430,12 @@ def ones( ------- out: array an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -420,6 +461,12 @@ def ones_like( ------- out: array an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/data_type_functions.py b/src/array_api_stubs/_2022_12/data_type_functions.py index f3561b76f..700bffd90 100644 --- a/src/array_api_stubs/_2022_12/data_type_functions.py +++ b/src/array_api_stubs/_2022_12/data_type_functions.py @@ -36,6 +36,12 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: ------- out: array an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -97,6 +103,14 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: - **dtype**: dtype real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -129,6 +143,8 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: - **dtype**: dtype integer data type. + + .. versionadded:: 2022.12 """ @@ -167,6 +183,11 @@ def isdtype( ------- out: bool boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index 6b2a46e24..b502e091b 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -52,6 +52,9 @@ def abs(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -118,6 +121,9 @@ def acos(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -189,6 +195,9 @@ def acosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -254,6 +263,9 @@ def add(x1: array, x2: array, /) -> array: - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -308,6 +320,9 @@ def asin(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -370,6 +385,9 @@ def asinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -419,6 +437,9 @@ def atan(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -541,6 +562,9 @@ def atanh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -709,6 +733,8 @@ def conj(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have the same data type as ``x``. + + .. versionadded:: 2022.12 """ @@ -753,6 +779,9 @@ def cos(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -813,6 +842,9 @@ def cosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -893,6 +925,9 @@ def divide(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -934,6 +969,9 @@ def equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -987,6 +1025,9 @@ def exp(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1043,6 +1084,9 @@ def expm1(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1192,6 +1236,8 @@ def imag(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + .. versionadded:: 2022.12 """ @@ -1226,6 +1272,9 @@ def isfinite(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1258,6 +1307,9 @@ def isinf(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1289,6 +1341,9 @@ def isnan(x: array, /) -> array: - If ``a`` or ``b`` is ``NaN``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1390,6 +1445,9 @@ def log(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1449,6 +1507,9 @@ def log1p(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1488,6 +1549,9 @@ def log2(x: array, /) -> array: \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1527,6 +1591,9 @@ def log10(x: array, /) -> array: \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1703,6 +1770,9 @@ def multiply(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1725,6 +1795,12 @@ def negative(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1764,6 +1840,9 @@ def not_equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1780,6 +1859,12 @@ def positive(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1847,6 +1932,9 @@ def pow(x1: array, x2: array, /) -> array: .. note:: Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1863,6 +1951,10 @@ def real(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + .. versionadded:: 2022.12 """ @@ -1958,6 +2050,9 @@ def round(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2002,6 +2097,9 @@ def sign(x: array, /) -> array: - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2045,6 +2143,9 @@ def sin(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2105,6 +2206,9 @@ def sinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2133,6 +2237,9 @@ def square(x: array, /) -> array: **Special cases** For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2189,6 +2296,9 @@ def sqrt(x: array, /) -> array: - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2209,6 +2319,12 @@ def subtract(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2252,6 +2368,9 @@ def tan(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2316,6 +2435,9 @@ def tanh(x: array, /) -> array: For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index 2eb428b0c..7979095fe 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -44,6 +44,11 @@ def fft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -90,6 +95,11 @@ def ifft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -143,6 +153,11 @@ def fftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -196,6 +211,11 @@ def ifftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -242,6 +262,11 @@ def rfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -288,6 +313,11 @@ def irfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -341,6 +371,11 @@ def rfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -394,6 +429,11 @@ def irfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -437,6 +477,11 @@ def hfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -480,6 +525,11 @@ def ihfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -507,6 +557,11 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar ------- out: array an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -536,6 +591,11 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a ------- out: array an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -559,6 +619,11 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -580,6 +645,11 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index b040251dd..3f6de3a58 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -38,6 +38,12 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: ------- out: array an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -65,6 +71,14 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: out: array an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** @@ -87,6 +101,12 @@ def det(x: array, /) -> array: ------- out: array if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -154,9 +174,14 @@ def eigh(x: array, /) -> Tuple[array]: - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -192,9 +217,14 @@ def eigvalsh(x: array, /) -> array: out: array an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -224,6 +254,12 @@ def inv(x: array, /) -> array: ------- out: array an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -288,6 +324,12 @@ def matrix_norm( ------- out: array an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -306,6 +348,12 @@ def matrix_power(x: array, n: int, /) -> array: ------- out: array if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -326,6 +374,12 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a ------- out: array an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -348,6 +402,12 @@ def outer(x1: array, x2: array, /) -> array: ------- out: array a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -382,6 +442,12 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: ------- out: array an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -441,6 +507,12 @@ def qr( - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -490,6 +562,12 @@ def slogdet(x: array, /) -> Tuple[array, array]: - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -522,6 +600,12 @@ def solve(x1: array, x2: array, /) -> array: ------- out: array an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -571,6 +655,12 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -589,6 +679,12 @@ def svdvals(x: array, /) -> array: ------- out: array an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -653,6 +749,9 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -716,6 +815,12 @@ def vector_norm( ------- out: array an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py index c8b6e50f8..6590d2146 100644 --- a/src/array_api_stubs/_2022_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2022_12/linear_algebra_functions.py @@ -32,6 +32,11 @@ def matmul(x1: array, x2: array, /) -> array: The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** @@ -101,6 +106,12 @@ def tensordot( ------- out: array an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -133,6 +144,11 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: out: array if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py index 9393ba71e..9dcc0f95c 100644 --- a/src/array_api_stubs/_2022_12/searching_functions.py +++ b/src/array_api_stubs/_2022_12/searching_functions.py @@ -75,6 +75,12 @@ def nonzero(x: array, /) -> Tuple[array, ...]: ------- out: Typle[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/set_functions.py b/src/array_api_stubs/_2022_12/set_functions.py index dc95f58e8..661d3df90 100644 --- a/src/array_api_stubs/_2022_12/set_functions.py +++ b/src/array_api_stubs/_2022_12/set_functions.py @@ -38,6 +38,12 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -74,6 +80,12 @@ def unique_counts(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -110,6 +122,12 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -141,6 +159,12 @@ def unique_values(x: array, /) -> array: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/statistical_functions.py b/src/array_api_stubs/_2022_12/statistical_functions.py index 787faeeb9..93faaf31e 100644 --- a/src/array_api_stubs/_2022_12/statistical_functions.py +++ b/src/array_api_stubs/_2022_12/statistical_functions.py @@ -171,6 +171,9 @@ def prod( - If ``N`` is ``0``, the product is `1` (i.e., the empty product). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -265,6 +268,9 @@ def sum( - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/utility_functions.py b/src/array_api_stubs/_2022_12/utility_functions.py index e70fe8aa6..64e5de297 100644 --- a/src/array_api_stubs/_2022_12/utility_functions.py +++ b/src/array_api_stubs/_2022_12/utility_functions.py @@ -33,6 +33,12 @@ def all( ------- out: array if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -68,6 +74,12 @@ def any( ------- out: array if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ From 73c7fcb0793a0a1f7c603bf444fb7e0ccab281fe Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Apr 2023 00:37:35 -0700 Subject: [PATCH 026/196] Apply suggestions from code review --- spec/draft/design_topics/exceptions.rst | 12 ++++++------ src/array_api_stubs/_draft/manipulation_functions.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/draft/design_topics/exceptions.rst b/spec/draft/design_topics/exceptions.rst index 0a176c302..570fe56e3 100644 --- a/spec/draft/design_topics/exceptions.rst +++ b/spec/draft/design_topics/exceptions.rst @@ -5,23 +5,23 @@ Exceptions This standard specifies expected syntax and semantics for a set of APIs. When inputs to an API do not match what is expected, libraries may emit warnings, -raise exceptions, or misbehave in unexpected ways. In general it is not +raise exceptions, or misbehave in unexpected ways. In general, it is not possible to foresee or specify all the ways in which unexpected or invalid inputs are provided. Therefore, this standard does not attempt to specify exception or warning types to the extent needed in order to do exception handling in a portable manner. In general, it is expected that array library implementers follow `the guidance given by the documentation of the Python -language `__, and use either -fitting builtin exception or warning types that are appropriate for the -situation, or custom exceptions or warnings that derive from those builtin +language `__, and either use +builtin exception or warning types that are appropriate for the +situation or use custom exceptions or warnings that derive from those builtin ones. In specific cases, it may be useful to provide guidance to array library authors regarding what an appropriate exception is. That guidance will be phrased as *should* rather than *must* (typically in a *Raises* section), because (a) there may be reasons for an implementer to deviate, and (b) more -often than not existing array library implementation already differ in their -choices and it may not be worth them breaking backwards compatibility in order +often than not, existing array library implementation already differ in their +choices, and it may not be worth them breaking backward compatibility in order to comply with a "must" in this standard. In other cases, this standard will only specify that an exception should or diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2a4b612f5..99a40057a 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -130,7 +130,7 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying if possible, and may copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. Returns ------- @@ -190,8 +190,8 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: Raises ------ ValueError - If a specified axis has a size greater than one, i.e. it is not a - singleton dimension, a ``ValueError`` should be raised. + If a specified axis has a size greater than one (i.e., it is not a + singleton dimension), a ``ValueError`` should be raised. """ From fcd54b380391e459ed9cb3449e4ce41a9e837243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Tue, 18 Apr 2023 17:09:15 -0600 Subject: [PATCH 027/196] Fix a typo in tensordot --- src/array_api_stubs/_draft/linear_algebra_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index 9d949c067..d9ac2437c 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -97,7 +97,7 @@ def tensordot( - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. .. note:: From 6dea842a0195da72e497b9a66cee3a0fe5243542 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Thu, 20 Apr 2023 17:28:26 -0500 Subject: [PATCH 028/196] Backport typo fix in tensordot (#624) --- src/array_api_stubs/_2021_12/linear_algebra_functions.py | 2 +- src/array_api_stubs/_2022_12/linear_algebra_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2021_12/linear_algebra_functions.py b/src/array_api_stubs/_2021_12/linear_algebra_functions.py index 30d09c254..a2defaf1b 100644 --- a/src/array_api_stubs/_2021_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2021_12/linear_algebra_functions.py @@ -75,7 +75,7 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. Returns ------- diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py index 6590d2146..110a19ce1 100644 --- a/src/array_api_stubs/_2022_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2022_12/linear_algebra_functions.py @@ -96,7 +96,7 @@ def tensordot( - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. .. note:: From 4d1372b85565101f4ddede1fa7ab4bdfc4680457 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 2 May 2023 11:29:57 -0500 Subject: [PATCH 029/196] Update all contributors (#618) --- .all-contributorsrc | 314 +++++++++++++++++++++++++++++++++++++++++++- README.md | 126 ++++++++++++------ 2 files changed, 396 insertions(+), 44 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3bacaeb2f..f7f25e7d4 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -171,9 +171,7 @@ "avatar_url": "https://avatars.githubusercontent.com/u/2626883?v=4", "profile": "https://www.linkedin.com/in/shengzha/", "contributions": [ - "ideas", - "review", - "talk" + "ideas" ] }, { @@ -308,6 +306,316 @@ "contributions": [ "ideas" ] + }, + { + "login": "lezcano", + "name": "Mario Lezcano Casado", + "avatar_url": "https://avatars.githubusercontent.com/u/3291265?v=4", + "profile": "https://github.com/lezcano", + "contributions": [ + "ideas" + ] + }, + { + "login": "BvB93", + "name": "Bas van Beek", + "avatar_url": "https://avatars.githubusercontent.com/u/43369155?v=4", + "profile": "https://github.com/BvB93", + "contributions": [ + "ideas" + ] + }, + { + "login": "seberg", + "name": "Sebastian Berg", + "avatar_url": "https://avatars.githubusercontent.com/u/61977?v=4", + "profile": "https://github.com/seberg", + "contributions": [ + "ideas" + ] + }, + { + "login": "IsaacBreen", + "name": "Isaac Breen", + "avatar_url": "https://avatars.githubusercontent.com/u/57783927?v=4", + "profile": "https://github.com/IsaacBreen", + "contributions": [ + "ideas" + ] + }, + { + "login": "kmaehashi", + "name": "Kenichi Maehashi", + "avatar_url": "https://avatars.githubusercontent.com/u/939877?v=4", + "profile": "https://github.com/kmaehashi", + "contributions": [ + "ideas" + ] + }, + { + "login": "cnpryer", + "name": "Chris Pryer", + "avatar_url": "https://avatars.githubusercontent.com/u/14341145?v=4", + "profile": "https://github.com/cnpryer", + "contributions": [ + "ideas" + ] + }, + { + "login": "tirthasheshpatel", + "name": "Tirth Patel", + "avatar_url": "https://avatars.githubusercontent.com/u/43181252?v=4", + "profile": "https://github.com/tirthasheshpatel", + "contributions": [ + "ideas" + ] + }, + { + "login": "kshitij12345", + "name": "Kshiteej K", + "avatar_url": "https://avatars.githubusercontent.com/u/19503980?v=4", + "profile": "https://github.com/kshitij12345", + "contributions": [ + "ideas" + ] + }, + { + "login": "AnirudhDagar", + "name": "Anirudh Dagar", + "avatar_url": "https://avatars.githubusercontent.com/u/23621655?v=4", + "profile": "https://anirudhdagar.ml/", + "contributions": [ + "ideas" + ] + }, + { + "login": "tomwhite", + "name": "Tom White", + "avatar_url": "https://avatars.githubusercontent.com/u/85085?v=4", + "profile": "http://tom-e-white.com/", + "contributions": [ + "ideas" + ] + }, + { + "login": "honno", + "name": "Matthew Barber", + "avatar_url": "https://avatars.githubusercontent.com/u/8246949?v=4", + "profile": "https://github.com/honno", + "contributions": [ + "ideas", + "content" + ] + }, + { + "login": "pmeier", + "name": "Philip Meier", + "avatar_url": "https://avatars.githubusercontent.com/u/6849766?v=4", + "profile": "https://github.com/pmeier", + "contributions": [ + "research", + "code" + ] + }, + { + "login": "Zac-HD", + "name": "Zac Hatfield-Dodds", + "avatar_url": "https://avatars.githubusercontent.com/u/12229877?v=4", + "profile": "https://github.com/Zac-HD", + "contributions": [ + "ideas", + "code" + ] + }, + { + "login": "djl11", + "name": "Daniel Lenton", + "avatar_url": "https://avatars.githubusercontent.com/u/22750088?v=4", + "profile": "https://github.com/djl11", + "contributions": [ + "code" + ] + }, + { + "login": "simonetgordon", + "name": "Simone G", + "avatar_url": "https://avatars.githubusercontent.com/u/74716948?v=4", + "profile": "https://github.com/simonetgordon", + "contributions": [ + "code", + "ideas" + ] + }, + { + "login": "tylerjereddy", + "name": "Tyler Reddy", + "avatar_url": "https://avatars.githubusercontent.com/u/7903078?v=4", + "profile": "https://github.com/tylerjereddy", + "contributions": [ + "ideas" + ] + }, + { + "login": "mattbarrett98", + "name": "Matt Barrett", + "avatar_url": "https://avatars.githubusercontent.com/u/83289589?v=4", + "profile": "https://github.com/mattbarrett98", + "contributions": [ + "ideas" + ] + }, + { + "login": "bicycleman15", + "name": "Jatin Prakash", + "avatar_url": "https://avatars.githubusercontent.com/u/47978882?v=4", + "profile": "https://github.com/bicycleman15", + "contributions": [ + "ideas" + ] + }, + { + "login": "Ishticode", + "name": "Ishtiaq Hussain", + "avatar_url": "https://avatars.githubusercontent.com/u/53497039?v=4", + "profile": "https://github.com/Ishticode", + "contributions": [ + "ideas" + ] + }, + { + "login": "sherry30", + "name": "sherry30", + "avatar_url": "https://avatars.githubusercontent.com/u/65318415?v=4", + "profile": "https://github.com/sherry30", + "contributions": [ + "ideas" + ] + }, + { + "login": "juaolobo", + "name": "João Lobo", + "avatar_url": "https://avatars.githubusercontent.com/u/49628984?v=4", + "profile": "https://github.com/juaolobo", + "contributions": [ + "ideas" + ] + }, + { + "login": "NeilGirdhar", + "name": "Neil Girdhar", + "avatar_url": "https://avatars.githubusercontent.com/u/730137?v=4", + "profile": "https://github.com/NeilGirdhar", + "contributions": [ + "ideas" + ] + }, + { + "login": "nstarman", + "name": "Nathaniel Starkman", + "avatar_url": "https://avatars.githubusercontent.com/u/8949649?v=4", + "profile": "https://github.com/nstarman", + "contributions": [ + "ideas" + ] + }, + { + "login": "jakirkham", + "name": "jakirkham", + "avatar_url": "https://avatars.githubusercontent.com/u/3019665?v=4", + "profile": "https://github.com/jakirkham", + "contributions": [ + "ideas" + ] + }, + { + "login": "RickSanchezStoic", + "name": "RickSanchezStoic", + "avatar_url": "https://avatars.githubusercontent.com/u/57310695?v=4", + "profile": "https://github.com/RickSanchezStoic", + "contributions": [ + "ideas" + ] + }, + { + "login": "tlambert03", + "name": "Talley Lambert", + "avatar_url": "https://avatars.githubusercontent.com/u/1609449?v=4", + "profile": "https://github.com/tlambert03", + "contributions": [ + "ideas" + ] + }, + { + "login": "jni", + "name": "Juan Nunez-Iglesias", + "avatar_url": "https://avatars.githubusercontent.com/u/492549?v=4", + "profile": "http://ilovesymposia.com/", + "contributions": [ + "ideas" + ] + }, + { + "login": "chkothe", + "name": "Christian Kothe", + "avatar_url": "https://avatars.githubusercontent.com/u/5318120?v=4", + "profile": "https://github.com/chkothe", + "contributions": [ + "ideas" + ] + }, + { + "login": "vnmabus", + "name": "Carlos Ramos Carreño", + "avatar_url": "https://avatars.githubusercontent.com/u/2364173?v=4", + "profile": "https://github.com/vnmabus", + "contributions": [ + "ideas" + ] + }, + { + "login": "gilfree", + "name": "Gilad", + "avatar_url": "https://avatars.githubusercontent.com/u/88031955?v=4", + "profile": "https://github.com/gilfree", + "contributions": [ + "ideas" + ] + }, + { + "login": "thomasjpfan", + "name": "Thomas J. Fan", + "avatar_url": "https://avatars.githubusercontent.com/u/5402633?v=4", + "profile": "https://github.com/thomasjpfan", + "contributions": [ + "ideas" + ] + }, + { + "login": "Conchylicultor", + "name": "Conchylicultor", + "avatar_url": "https://avatars.githubusercontent.com/u/9047355?v=4", + "profile": "http://e-pot.xyz/", + "contributions": [ + "ideas" + ] + }, + { + "login": "fcharras", + "name": "Franck Charras", + "avatar_url": "https://avatars.githubusercontent.com/u/29153872?v=4", + "profile": "https://github.com/fcharras", + "contributions": [ + "ideas" + ] + }, + { + "login": "kkraus14", + "name": "Keith Kraus", + "avatar_url": "https://avatars.githubusercontent.com/u/3665167?v=4", + "profile": "https://github.com/kkraus14", + "contributions": [ + "ideas" + ] } ], "contributorsPerLine": 7 diff --git a/README.md b/README.md index 6c32aec19..dbfee4cea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Array API standard -[![All Contributors](https://img.shields.io/badge/all_contributors-29-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-63-orange.svg?style=flat-square)](#contributors-) This repository contains documents, tooling and other content related to the @@ -151,45 +151,89 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Saul Shanabrook

🔧 🤔 🔬

Athan

🖋 🔣 🔧 🔬

Stephannie Jimenez Gacha

🔣 🖋 🔬

Aaron Meurer

🖋 ⚠️ 🔧

Tony Fast

🚧

Ralf Gommers

📝 💼 💻 🖋 📖 🔍 🚧 🤔 📆 📢

Travis E. Oliphant

💼 🔍 🤔

Leo Fang

👀 🤔 🖋

Tianqi Chen

🤔 👀

Stephan Hoyer

🤔 👀 💬

Alexandre Passos

🤔 👀

Paige Bailey

🔍

Adam Paszke

🤔 👀 📢

Andreas Mueller

🤔 👀

Sheng Zha

🤔 👀 📢

kkraus

🤔 👀 📢

Tom Augspurger

👀 💬

edloper

👀 💬

Areg Melik-Adamyan

👀 🔍

Oleksandr Pavlyk

👀 💬

tdimitri

🤔

Jack Pappas

🤔

Ashish Agarwal

👀 💬

Edward Z. Yang

🤔

Mike Ruberry

🤔

Eric Wieser

🤔

Carol Willing

🤔

Alex Rogozhnikov

🤔

Matthew Honnibal

🤔
Saul Shanabrook
Saul Shanabrook

🔧 🤔 🔬
Athan
Athan

🖋 🔣 🔧 🔬
Stephannie Jimenez Gacha
Stephannie Jimenez Gacha

🔣 🖋 🔬
Aaron Meurer
Aaron Meurer

🖋 ⚠️ 🔧
Tony Fast
Tony Fast

🚧
Ralf Gommers
Ralf Gommers

📝 💼 💻 🖋 📖 🔍 🚧 🤔 📆 📢
Travis E. Oliphant
Travis E. Oliphant

💼 🔍 🤔
Leo Fang
Leo Fang

👀 🤔 🖋
Tianqi Chen
Tianqi Chen

🤔 👀
Stephan Hoyer
Stephan Hoyer

🤔 👀 💬
Alexandre Passos
Alexandre Passos

🤔 👀
Paige Bailey
Paige Bailey

🔍
Adam Paszke
Adam Paszke

🤔 👀 📢
Andreas Mueller
Andreas Mueller

🤔 👀
Sheng Zha
Sheng Zha

🤔
kkraus
kkraus

🤔 👀 📢
Tom Augspurger
Tom Augspurger

👀 💬
edloper
edloper

👀 💬
Areg Melik-Adamyan
Areg Melik-Adamyan

👀 🔍
Oleksandr Pavlyk
Oleksandr Pavlyk

👀 💬
tdimitri
tdimitri

🤔
Jack Pappas
Jack Pappas

🤔
Ashish Agarwal
Ashish Agarwal

👀 💬
Edward Z. Yang
Edward Z. Yang

🤔
Mike Ruberry
Mike Ruberry

🤔
Eric Wieser
Eric Wieser

🤔
Carol Willing
Carol Willing

🤔
Alex Rogozhnikov
Alex Rogozhnikov

🤔
Matthew Honnibal
Matthew Honnibal

🤔
Mario Lezcano Casado
Mario Lezcano Casado

🤔
Bas van Beek
Bas van Beek

🤔
Sebastian Berg
Sebastian Berg

🤔
Isaac Breen
Isaac Breen

🤔
Kenichi Maehashi
Kenichi Maehashi

🤔
Chris Pryer
Chris Pryer

🤔
Tirth Patel
Tirth Patel

🤔
Kshiteej K
Kshiteej K

🤔
Anirudh Dagar
Anirudh Dagar

🤔
Tom White
Tom White

🤔
Matthew Barber
Matthew Barber

🤔 🖋
Philip Meier
Philip Meier

🔬 💻
Zac Hatfield-Dodds
Zac Hatfield-Dodds

🤔 💻
Daniel Lenton
Daniel Lenton

💻
Simone G
Simone G

💻 🤔
Tyler Reddy
Tyler Reddy

🤔
Matt Barrett
Matt Barrett

🤔
Jatin Prakash
Jatin Prakash

🤔
Ishtiaq Hussain
Ishtiaq Hussain

🤔
sherry30
sherry30

🤔
João Lobo
João Lobo

🤔
Neil Girdhar
Neil Girdhar

🤔
Nathaniel Starkman
Nathaniel Starkman

🤔
jakirkham
jakirkham

🤔
RickSanchezStoic
RickSanchezStoic

🤔
Talley Lambert
Talley Lambert

🤔
Juan Nunez-Iglesias
Juan Nunez-Iglesias

🤔
Christian Kothe
Christian Kothe

🤔
Carlos Ramos Carreño
Carlos Ramos Carreño

🤔
Gilad
Gilad

🤔
Thomas J. Fan
Thomas J. Fan

🤔
Conchylicultor
Conchylicultor

🤔
Franck Charras
Franck Charras

🤔
Keith Kraus
Keith Kraus

🤔
@@ -197,4 +241,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! \ No newline at end of file From accf8c20d8fae9b760e59a40ab43b556fd8410cb Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 2 May 2023 11:32:41 -0500 Subject: [PATCH 030/196] Fix `svd` function return dtype (#619) --- src/array_api_stubs/_2021_12/linalg.py | 4 ++-- src/array_api_stubs/_2022_12/linalg.py | 4 ++-- src/array_api_stubs/_draft/linalg.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 0749daf8e..230645439 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -364,7 +364,7 @@ def solve(x1: array, x2: array, /) -> array: an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. """ -def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: """ Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) ``x``, where ``U`` is a matrix (or a stack of matrices) with orthonormal columns, ``S`` is a vector of non-negative numbers (or stack of vectors), and ``Vh`` is a matrix (or a stack of matrices) with orthonormal rows. @@ -379,7 +379,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ------- .. NOTE: once complex numbers are supported, each square matrix must be Hermitian. - out: Union[array, Tuple[array, ...]] + out: Tuple[array, array, array] a namedtuple ``(U, S, Vh)`` whose - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index 3f6de3a58..c1ff64c3e 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -609,7 +609,7 @@ def solve(x1: array, x2: array, /) -> array: """ -def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: r""" Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. @@ -649,7 +649,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, Returns ------- - out: Union[array, Tuple[array, ...]] + out: Tuple[array, array, array] a namedtuple ``(U, S, Vh)`` whose - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 20d1d54ff..b03f6eb63 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -609,7 +609,7 @@ def solve(x1: array, x2: array, /) -> array: """ -def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: r""" Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. @@ -649,7 +649,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, Returns ------- - out: Union[array, Tuple[array, ...]] + out: Tuple[array, array, array] a namedtuple ``(U, S, Vh)`` whose - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. From d0353d9150db2b94ec807467fc5b8c8c882a6199 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:09:36 +0200 Subject: [PATCH 031/196] Modify function to remain in the same page if the version is changed --- spec/_static/javascripts/version_dropdown.js | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 spec/_static/javascripts/version_dropdown.js diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js new file mode 100644 index 000000000..df7a496e9 --- /dev/null +++ b/spec/_static/javascripts/version_dropdown.js @@ -0,0 +1,31 @@ +function add_custom_version_dropdown(json_loc, target_loc, text) { + + var dropdown = document.createElement("div"); + dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; + var button = document.createElement("button"); + button.className = "dropdownbutton"; + var content = document.createElement("div"); + content.className = "dropdown-content md-hero"; + dropdown.appendChild(button); + dropdown.appendChild(content); + console.log('*********'); + $.getJSON(json_loc, function(versions) { + for (var key in versions) { + if (versions.hasOwnProperty(key)) { + console.log(key, versions[key]); + var a = document.createElement("a"); + a.innerHTML = key; + a.title = key; + a.href = target_loc + versions[key] + "/{{ pagename }}.html"; + console.log('----', a.href); + content.appendChild(a); + } + } + }).done(function() { + button.innerHTML = text; + }).fail(function() { + button.innerHTML = "Other Versions Not Found"; + }).always(function() { + $(".navheader").append(dropdown); + }); +}; From 395f34246cd8392332a01b0c29f439ab5dc614a4 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:18:42 +0200 Subject: [PATCH 032/196] Rename function --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index df7a496e9..c9d5248d2 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,4 +1,4 @@ -function add_custom_version_dropdown(json_loc, target_loc, text) { +function add_version_dropdown(json_loc, target_loc, text) { var dropdown = document.createElement("div"); dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; From 4ab650d10b428b3010c13d8659bab09c95a86ced Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:33:01 +0200 Subject: [PATCH 033/196] Fix current url path --- spec/_static/javascripts/version_dropdown.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index c9d5248d2..5fe84e4cb 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -13,10 +13,12 @@ function add_version_dropdown(json_loc, target_loc, text) { for (var key in versions) { if (versions.hasOwnProperty(key)) { console.log(key, versions[key]); + var currentURL = window.location.href; + var path = currentURL.split( versions[key] )[ 1 ]; var a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = target_loc + versions[key] + "/{{ pagename }}.html"; + a.href = target_loc + versions[key] + path; console.log('----', a.href); content.appendChild(a); } From 4d941c9d425c59d37a7fd0b3718d6e7d042cb608 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:46:18 +0200 Subject: [PATCH 034/196] Fix URL --- spec/_static/javascripts/version_dropdown.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 5fe84e4cb..3a01a4695 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -10,15 +10,18 @@ function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(content); console.log('*********'); $.getJSON(json_loc, function(versions) { + var currentURL = window.location.href; + var path = currentURL.split( "_site" )[ 1 ]; + path = path.split('/'); + path = path.slice(1, path.length); + path = path.join('/'); for (var key in versions) { if (versions.hasOwnProperty(key)) { console.log(key, versions[key]); - var currentURL = window.location.href; - var path = currentURL.split( versions[key] )[ 1 ]; var a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = target_loc + versions[key] + path; + a.href = target_loc + versions[key] + "/" + path; console.log('----', a.href); content.appendChild(a); } From b8c053dd1cff1020fb961e1ba72ab66563c2c17a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:53:19 +0200 Subject: [PATCH 035/196] fix index --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 3a01a4695..097b27bd4 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -13,7 +13,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var currentURL = window.location.href; var path = currentURL.split( "_site" )[ 1 ]; path = path.split('/'); - path = path.slice(1, path.length); + path = path.slice(2, path.length); path = path.join('/'); for (var key in versions) { if (versions.hasOwnProperty(key)) { From 11dbf7834c3759c6643a13f8814db11273a1598d Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 02:08:44 +0200 Subject: [PATCH 036/196] Check if the page exists before assigning href --- spec/_static/javascripts/version_dropdown.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 097b27bd4..0093dfd64 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -21,9 +21,22 @@ function add_version_dropdown(json_loc, target_loc, text) { var a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = target_loc + versions[key] + "/" + path; - console.log('----', a.href); - content.appendChild(a); + var url = target_loc + versions[key]; + var http = new XMLHttpRequest(); + http.open('HEAD', url + "/" + path ); + http.onreadystatechange = function() { + if (this.readyState == this.DONE) { + callback(this.status != 404); + if(this.status != 404 ){ + a.href = url + "/" + path; + } + else { + a.href = url; + } + content.appendChild(a); + } + }; + http.send(); } } }).done(function() { From 5b1be4c00116cea291ca0efbfd1e79c52106b824 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 02:17:15 +0200 Subject: [PATCH 037/196] remove callback --- spec/_static/javascripts/version_dropdown.js | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 0093dfd64..db14796b4 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -26,7 +26,6 @@ function add_version_dropdown(json_loc, target_loc, text) { http.open('HEAD', url + "/" + path ); http.onreadystatechange = function() { if (this.readyState == this.DONE) { - callback(this.status != 404); if(this.status != 404 ){ a.href = url + "/" + path; } From 50424b86e49b2cbd31e2f04964ec734664076feb Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 02:24:18 +0200 Subject: [PATCH 038/196] change head to get --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index db14796b4..e0b10ee46 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -23,7 +23,7 @@ function add_version_dropdown(json_loc, target_loc, text) { a.title = key; var url = target_loc + versions[key]; var http = new XMLHttpRequest(); - http.open('HEAD', url + "/" + path ); + http.open('GET', url + "/" + path ); http.onreadystatechange = function() { if (this.readyState == this.DONE) { if(this.status != 404 ){ From 96b426f51ba016a12ae0068a0a0e6281fed67b40 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 14:38:17 +0200 Subject: [PATCH 039/196] Move appendChild --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e0b10ee46..ac375f426 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -32,10 +32,10 @@ function add_version_dropdown(json_loc, target_loc, text) { else { a.href = url; } - content.appendChild(a); } }; http.send(); + content.appendChild(a); } } }).done(function() { From a6157d04d7ec81aa4dfbc8635583a38eab5a3035 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 14:47:24 +0200 Subject: [PATCH 040/196] Add print --- spec/_static/javascripts/version_dropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index ac375f426..db5e0fa26 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -25,6 +25,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var http = new XMLHttpRequest(); http.open('GET', url + "/" + path ); http.onreadystatechange = function() { + console.log('%%%%', this); if (this.readyState == this.DONE) { if(this.status != 404 ){ a.href = url + "/" + path; From 7a4c0a494a2886e6a18fc1df98be6a485036a294 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 15:59:56 +0200 Subject: [PATCH 041/196] split function --- spec/_static/javascripts/version_dropdown.js | 34 +++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index db5e0fa26..a75ede5a2 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,5 +1,21 @@ -function add_version_dropdown(json_loc, target_loc, text) { +function assign_href( a ) { + var http = new XMLHttpRequest(); + http.open('GET', url + "/" + path ); + http.onreadystatechange = function() { + console.log('%%%%', this); + if (this.readyState == this.DONE) { + if(this.status != 404 ){ + a.href = url + "/" + path; + } + else { + a.href = url; + } + } + }; + http.send(); +} +function add_version_dropdown(json_loc, target_loc, text) { var dropdown = document.createElement("div"); dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; var button = document.createElement("button"); @@ -21,21 +37,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var a = document.createElement("a"); a.innerHTML = key; a.title = key; - var url = target_loc + versions[key]; - var http = new XMLHttpRequest(); - http.open('GET', url + "/" + path ); - http.onreadystatechange = function() { - console.log('%%%%', this); - if (this.readyState == this.DONE) { - if(this.status != 404 ){ - a.href = url + "/" + path; - } - else { - a.href = url; - } - } - }; - http.send(); + assign_href( a ); content.appendChild(a); } } From 24c1479baba16188ad756621d1c6c9ba0b1c312a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 16:10:21 +0200 Subject: [PATCH 042/196] fix missing variable --- spec/_static/javascripts/version_dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a75ede5a2..a2f72f23e 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,4 +1,4 @@ -function assign_href( a ) { +function assign_href( a, url, path ) { var http = new XMLHttpRequest(); http.open('GET', url + "/" + path ); http.onreadystatechange = function() { @@ -37,7 +37,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var a = document.createElement("a"); a.innerHTML = key; a.title = key; - assign_href( a ); + assign_href( a, target_loc + versions[key], path ); content.appendChild(a); } } From f649007e2aab3cd7ec203906fbadf478e016c79f Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 16:23:30 +0200 Subject: [PATCH 043/196] move print --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a2f72f23e..ccd33f214 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -2,9 +2,9 @@ function assign_href( a, url, path ) { var http = new XMLHttpRequest(); http.open('GET', url + "/" + path ); http.onreadystatechange = function() { - console.log('%%%%', this); if (this.readyState == this.DONE) { if(this.status != 404 ){ + console.log('%%%%', this); a.href = url + "/" + path; } else { From 45ae354a946543648b28da4fe58f50afa1e87de8 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 24 May 2023 22:44:36 -0600 Subject: [PATCH 044/196] Fix invalid escape sequences in some files (#632) These can be found with the command python -We:invalid -We::SyntaxWarning -m compileall -f -q src/ --- src/array_api_stubs/_2021_12/creation_functions.py | 2 +- src/array_api_stubs/_2021_12/elementwise_functions.py | 4 ++-- src/array_api_stubs/_2021_12/linalg.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index 3285a386d..4ee683cd9 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -29,7 +29,7 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None """ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: - """ + r""" Convert the input to an array. Parameters diff --git a/src/array_api_stubs/_2021_12/elementwise_functions.py b/src/array_api_stubs/_2021_12/elementwise_functions.py index 213ebe53e..bf831d304 100644 --- a/src/array_api_stubs/_2021_12/elementwise_functions.py +++ b/src/array_api_stubs/_2021_12/elementwise_functions.py @@ -598,7 +598,7 @@ def floor(x: array, /) -> array: """ def floor_divide(x1: array, x2: array, /) -> array: - """ + r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. .. note:: @@ -1390,4 +1390,4 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] \ No newline at end of file +__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 230645439..6a0348129 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -444,7 +444,7 @@ def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: - """ + r""" Computes the vector norm of a vector (or batch of vectors) ``x``. Parameters From 0d85fa73bb121bf8788134e2f0be9ad5a632d677 Mon Sep 17 00:00:00 2001 From: Felix Hirwa Nshuti Date: Wed, 31 May 2023 04:15:50 +0000 Subject: [PATCH 045/196] typo fix in abs rfc --- src/array_api_stubs/_2022_12/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index b502e091b..28768e9d9 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -30,7 +30,7 @@ def abs(x: array, /) -> array: Returns ------- out: array - an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). Notes ----- From aee9df3496dca02ce90295b56fd2afa50971fb52 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 30 May 2023 21:29:01 -0700 Subject: [PATCH 046/196] Fix type in absolute value return value description --- src/array_api_stubs/_draft/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 74ef7e98d..5f474e7c8 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -30,7 +30,7 @@ def abs(x: array, /) -> array: Returns ------- out: array - an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). Notes ----- From 18b776358c772d167d54780a795d9d356121ca3a Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 5 Jun 2023 19:01:32 -0600 Subject: [PATCH 047/196] Add missing dtype attribute to iinfo_object and finfo_object --- src/array_api_stubs/_2022_12/_types.py | 4 ++-- src/array_api_stubs/_draft/_types.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/_types.py b/src/array_api_stubs/_2022_12/_types.py index 4a60040d5..589606784 100644 --- a/src/array_api_stubs/_2022_12/_types.py +++ b/src/array_api_stubs/_2022_12/_types.py @@ -39,7 +39,7 @@ class finfo_object: max: float min: float smallest_normal: float - + dtype: dtype @dataclass class iinfo_object: @@ -47,7 +47,7 @@ class iinfo_object: bits: int max: int min: int - + dtype: dtype _T_co = TypeVar("_T_co", covariant=True) diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 4a60040d5..589606784 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -39,7 +39,7 @@ class finfo_object: max: float min: float smallest_normal: float - + dtype: dtype @dataclass class iinfo_object: @@ -47,7 +47,7 @@ class iinfo_object: bits: int max: int min: int - + dtype: dtype _T_co = TypeVar("_T_co", covariant=True) From 13121939aa54fdfa10b47ccedd08995619f9522e Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:18:14 -0500 Subject: [PATCH 048/196] Use fetch API --- spec/_static/javascripts/version_dropdown.js | 22 ++++++++------------ 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index ccd33f214..44cd26db5 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,18 +1,14 @@ function assign_href( a, url, path ) { - var http = new XMLHttpRequest(); - http.open('GET', url + "/" + path ); - http.onreadystatechange = function() { - if (this.readyState == this.DONE) { - if(this.status != 404 ){ - console.log('%%%%', this); - a.href = url + "/" + path; - } - else { - a.href = url; - } + const r = fetch( url + "/" + path ); + r.then( response => { + console.log('...', response); + if( response.ok ){ + a.href = url + "/" + path; } - }; - http.send(); + else { + a.href = url; + } + }); } function add_version_dropdown(json_loc, target_loc, text) { From 8ca2b0f39a405deca8b5474b41602377dd278d9e Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:28:59 -0500 Subject: [PATCH 049/196] add catch block --- spec/_static/javascripts/version_dropdown.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 44cd26db5..99511b2f7 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -5,9 +5,8 @@ function assign_href( a, url, path ) { if( response.ok ){ a.href = url + "/" + path; } - else { - a.href = url; - } + }).catch( error => { + a.href = url; }); } From 5c73a1a0e16a554e7a7e0c11fd9df78e50dae165 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:39:00 -0500 Subject: [PATCH 050/196] add url if status is not ok --- spec/_static/javascripts/version_dropdown.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 99511b2f7..e92ea9082 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -5,6 +5,9 @@ function assign_href( a, url, path ) { if( response.ok ){ a.href = url + "/" + path; } + else { + a.href = url; + } }).catch( error => { a.href = url; }); From bac4929259e2b0b7965bccdce0f04eff373e6d21 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:48:22 -0500 Subject: [PATCH 051/196] remove prints and point to the index file --- spec/_static/javascripts/version_dropdown.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e92ea9082..e3608ab88 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,15 +1,14 @@ function assign_href( a, url, path ) { const r = fetch( url + "/" + path ); r.then( response => { - console.log('...', response); if( response.ok ){ a.href = url + "/" + path; } else { - a.href = url; + a.href = url + "/index.html"; } }).catch( error => { - a.href = url; + a.href = url + "/index.html"; }); } @@ -22,7 +21,6 @@ function add_version_dropdown(json_loc, target_loc, text) { content.className = "dropdown-content md-hero"; dropdown.appendChild(button); dropdown.appendChild(content); - console.log('*********'); $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; var path = currentURL.split( "_site" )[ 1 ]; From 9c024950369254335e23aee26aa23d4235daa828 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 12:01:45 -0500 Subject: [PATCH 052/196] remove unused variable --- spec/_static/javascripts/version_dropdown.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e3608ab88..d255f8147 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,6 +1,5 @@ function assign_href( a, url, path ) { - const r = fetch( url + "/" + path ); - r.then( response => { + fetch( url + "/" + path ).then( response => { if( response.ok ){ a.href = url + "/" + path; } From 487fc3a0fb41550742a938d68f1e863e3cdbf828 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 8 Jul 2023 15:03:04 -0700 Subject: [PATCH 053/196] Use consistent style and remove console.log --- spec/_static/javascripts/version_dropdown.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d255f8147..9cfe8cc06 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,12 +1,11 @@ -function assign_href( a, url, path ) { - fetch( url + "/" + path ).then( response => { - if( response.ok ){ +function assign_href(a, url, path) { + fetch(url + "/" + path).then(response => { + if (response.ok){ a.href = url + "/" + path; - } - else { + } else { a.href = url + "/index.html"; } - }).catch( error => { + }).catch(error => { a.href = url + "/index.html"; }); } @@ -22,17 +21,16 @@ function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(content); $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; - var path = currentURL.split( "_site" )[ 1 ]; - path = path.split('/'); + var path = currentURL.split("_site")[1]; + path = path.split("/"); path = path.slice(2, path.length); - path = path.join('/'); + path = path.join("/"); for (var key in versions) { if (versions.hasOwnProperty(key)) { - console.log(key, versions[key]); var a = document.createElement("a"); a.innerHTML = key; a.title = key; - assign_href( a, target_loc + versions[key], path ); + assign_href(a, target_loc + versions[key], path); content.appendChild(a); } } From 44b35f6d240f68235d4e8dc0b70c8d6116ffd372 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 8 Jul 2023 15:03:25 -0700 Subject: [PATCH 054/196] Add space --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 9cfe8cc06..d43ddde52 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,6 +1,6 @@ function assign_href(a, url, path) { fetch(url + "/" + path).then(response => { - if (response.ok){ + if (response.ok) { a.href = url + "/" + path; } else { a.href = url + "/index.html"; From 41eb94ba794741edc07ae68ebee01961c90458a3 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 15:26:49 -0700 Subject: [PATCH 055/196] Ensure variable is defined --- spec/_static/javascripts/version_dropdown.js | 22 +++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d43ddde52..e4b79fd01 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -22,16 +22,18 @@ function add_version_dropdown(json_loc, target_loc, text) { $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; var path = currentURL.split("_site")[1]; - path = path.split("/"); - path = path.slice(2, path.length); - path = path.join("/"); - for (var key in versions) { - if (versions.hasOwnProperty(key)) { - var a = document.createElement("a"); - a.innerHTML = key; - a.title = key; - assign_href(a, target_loc + versions[key], path); - content.appendChild(a); + if (path) { + path = path.split("/"); + path = path.slice(2, path.length); + path = path.join("/"); + for (var key in versions) { + if (versions.hasOwnProperty(key)) { + var a = document.createElement("a"); + a.innerHTML = key; + a.title = key; + assign_href(a, target_loc + versions[key], path); + content.appendChild(a); + } } } }).done(function() { From 244796d37ce5dd00ae71cff3dea9730447058ad9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 15:31:34 -0700 Subject: [PATCH 056/196] Accommodate both the preview and deployed site --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e4b79fd01..ad54ff16b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -21,7 +21,7 @@ function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(content); $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; - var path = currentURL.split("_site")[1]; + var path = currentURL.split(/_site|array_api/)[1]; if (path) { path = path.split("/"); path = path.slice(2, path.length); From 5c124b81711ac51ff45963b5c698308e48d8f475 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:03:34 -0700 Subject: [PATCH 057/196] Refactor to use async/await and update URL manipulation logic --- spec/_static/javascripts/version_dropdown.js | 122 +++++++++++++++---- 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index ad54ff16b..0b12c8005 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,46 +1,114 @@ -function assign_href(a, url, path) { - fetch(url + "/" + path).then(response => { +/** +* Returns a URL corresponding to a versioned resource (if one exists). +* +* @private +* @param {string} url - base URL +* @param {string} path - resource path +* @returns {Promise} promise which resolves a resource URL +*/ +async function href(url, path) { + const defaultURL = url + "/index.html"; + url += "/" + path; + await fetch(url).then(onResponse).catch(onError); + + /** + * Success handler. + * + * @private + * @param {Object} response - response object + */ + function onResponse(response) { if (response.ok) { - a.href = url + "/" + path; - } else { - a.href = url + "/index.html"; + return url; } - }).catch(error => { - a.href = url + "/index.html"; - }); + return defaultURL; + } + + /** + * Error handler. + * + * @private + * @param {Error} error - error object + */ + function onError(error) { + return defaultURL; + } } -function add_version_dropdown(json_loc, target_loc, text) { - var dropdown = document.createElement("div"); +/** +* Adds a version dropdown menu with custom URL paths depending on the current page. +* +* @param {string} json_loc - JSON URL +* @param {string} target_loc - target URL +* @param {string} text - text +* @returns {Promise} promise which resolves upon adding a version menu +*/ +async function add_version_dropdown(json_loc, target_loc, text) { + const dropdown = document.createElement("div"); dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; - var button = document.createElement("button"); + + const button = document.createElement("button"); button.className = "dropdownbutton"; - var content = document.createElement("div"); + + const content = document.createElement("div"); content.className = "dropdown-content md-hero"; + dropdown.appendChild(button); dropdown.appendChild(content); - $.getJSON(json_loc, function(versions) { - var currentURL = window.location.href; - var path = currentURL.split(/_site|array_api/)[1]; + + await $.getJSON(json_loc, onVersions).done(onDone).fail(onFail).always(onAlways); + + /** + * Callback invoked upon successfully resolving a list of versions. + * + * @private + * @param {Object} versions - versions object + */ + async function onVersions(versions) { + const currentURL = window.location.href; + let path = currentURL.split(/_site|array_api/)[1]; if (path) { path = path.split("/"); path = path.slice(2, path.length); path = path.join("/"); - for (var key in versions) { - if (versions.hasOwnProperty(key)) { - var a = document.createElement("a"); - a.innerHTML = key; - a.title = key; - assign_href(a, target_loc + versions[key], path); - content.appendChild(a); - } + } else { + path = ""; + } + for (let key in versions) { + if (versions.hasOwnProperty(key)) { + let a = document.createElement("a"); + a.innerHTML = key; + a.title = key; + a.href = await href(target_loc + versions[key], path); + content.appendChild(a); } } - }).done(function() { + } + + /** + * Callback invoked upon resolving a JSON resource. + * + * @private + */ + function onDone() { button.innerHTML = text; - }).fail(function() { + } + + /** + * Callback invoked upon failing to resolve a JSON resource. + * + * @private + */ + function onFail() { button.innerHTML = "Other Versions Not Found"; - }).always(function() { + } + + /** + * Callback which is always invoked upon attempting to resolve a JSON resource. + * + * @private + */ + function onAlways() { $(".navheader").append(dropdown); - }); + } }; From e21b169eed58e70b2bc58f2acf6ddbc9044e9f72 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:29:49 -0700 Subject: [PATCH 058/196] Remove duplicate success callback --- spec/_static/javascripts/version_dropdown.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 0b12c8005..8a4371f97 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -56,15 +56,15 @@ async function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(button); dropdown.appendChild(content); - await $.getJSON(json_loc, onVersions).done(onDone).fail(onFail).always(onAlways); + await $.getJSON(json_loc).done(onDone).fail(onFail).always(onAlways); /** - * Callback invoked upon successfully resolving a list of versions. + * Callback invoked upon resolving a JSON resource. * * @private * @param {Object} versions - versions object */ - async function onVersions(versions) { + async function onDone(versions) { const currentURL = window.location.href; let path = currentURL.split(/_site|array_api/)[1]; if (path) { @@ -83,14 +83,6 @@ async function add_version_dropdown(json_loc, target_loc, text) { content.appendChild(a); } } - } - - /** - * Callback invoked upon resolving a JSON resource. - * - * @private - */ - function onDone() { button.innerHTML = text; } From 39d16db3a6ebc1cb595391d42d4d7558b26dbc46 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:33:51 -0700 Subject: [PATCH 059/196] Add comment --- spec/_static/javascripts/version_dropdown.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 8a4371f97..d126a6859 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -9,6 +9,8 @@ async function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; + + // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: await fetch(url).then(onResponse).catch(onError); /** From e4db25e4da0fcf358c821e845a3b5a9da6eb4909 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:34:36 -0700 Subject: [PATCH 060/196] Update function descriptions --- spec/_static/javascripts/version_dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d126a6859..c66d51c65 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -14,7 +14,7 @@ async function href(url, path) { await fetch(url).then(onResponse).catch(onError); /** - * Success handler. + * Callback invoked upon successfully resolving a resource. * * @private * @param {Object} response - response object @@ -27,7 +27,7 @@ async function href(url, path) { } /** - * Error handler. + * Callback invoked upon failing to resolve a resource. * * @private * @param {Error} error - error object From 52aa78da1106c294d6e3ee8de4eed98460467e93 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:35:42 -0700 Subject: [PATCH 061/196] Update function docs --- spec/_static/javascripts/version_dropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index c66d51c65..1772a561d 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -65,6 +65,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * * @private * @param {Object} versions - versions object + * @returns {Promise} promise which resolves upon processing version data */ async function onDone(versions) { const currentURL = window.location.href; From 6649c2013a31f8cbc6c80e5968a1f218b8de874d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:40:11 -0700 Subject: [PATCH 062/196] Add debug statement --- spec/_static/javascripts/version_dropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 1772a561d..645879283 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -68,6 +68,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @returns {Promise} promise which resolves upon processing version data */ async function onDone(versions) { + console.log(versions) const currentURL = window.location.href; let path = currentURL.split(/_site|array_api/)[1]; if (path) { From 3b32fe216021ab85f32ee9a54f102f9794d78d74 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:54:50 -0700 Subject: [PATCH 063/196] Add comments --- spec/_static/javascripts/version_dropdown.js | 29 ++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 645879283..a3d81751b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -6,12 +6,12 @@ * @param {string} path - resource path * @returns {Promise} promise which resolves a resource URL */ -async function href(url, path) { +function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: - await fetch(url).then(onResponse).catch(onError); + return fetch(url).then(onResponse).catch(onError); /** * Callback invoked upon successfully resolving a resource. @@ -68,9 +68,15 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @returns {Promise} promise which resolves upon processing version data */ async function onDone(versions) { - console.log(versions) + console.log(versions); + + // Resolve the current browser URL: const currentURL = window.location.href; + + // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): let path = currentURL.split(/_site|array_api/)[1]; + + // Extract the resource subpath: if (path) { path = path.split("/"); path = path.slice(2, path.length); @@ -78,15 +84,28 @@ async function add_version_dropdown(json_loc, target_loc, text) { } else { path = ""; } + // For each version, create an anchor element and attempt to resolve a given resource for that version... + const promises = []; + const el = []; for (let key in versions) { if (versions.hasOwnProperty(key)) { let a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = await href(target_loc + versions[key], path); - content.appendChild(a); + el.push(a); + promises.push(href(target_loc + versions[key], path)); } } + // Resolve all resource URLs: + const urls = await Promise.all(promises); + + // Append the version links to the dropdown menu: + for (let i = 0; i < urls.length; i++) { + let a = el[i]; + a.href = urls[i]; + content.appendChild(a); + } + // Set the button text: button.innerHTML = text; } From 74a2b1ac1a990d8390f04a7a212e77e4e5238bcf Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:55:55 -0700 Subject: [PATCH 064/196] Fix function description --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a3d81751b..6145549fc 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,5 +1,5 @@ /** -* Returns a URL corresponding to a versioned resource (if one exists). +* Returns a promise for resolving a URL corresponding to a versioned resource (if one exists). * * @private * @param {string} url - base URL From a8a3e51302b5243a85ce6c38b3b19269156c336d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:08:01 -0700 Subject: [PATCH 065/196] Add debug statements --- spec/_static/javascripts/version_dropdown.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 6145549fc..547df387a 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -58,7 +58,11 @@ async function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(button); dropdown.appendChild(content); - await $.getJSON(json_loc).done(onDone).fail(onFail).always(onAlways); + const p = $.getJSON(json_loc); + console.log(p); + + p.done(onDone).fail(onFail).always(onAlways); + await p; /** * Callback invoked upon resolving a JSON resource. @@ -115,6 +119,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @private */ function onFail() { + console.log("Failure"); button.innerHTML = "Other Versions Not Found"; } @@ -124,6 +129,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @private */ function onAlways() { + console.log("Always"); $(".navheader").append(dropdown); } }; From 02e31b4e3da96b6e83b485db54d170960dd7a809 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:15:58 -0700 Subject: [PATCH 066/196] Replace `done` with `then` --- spec/_static/javascripts/version_dropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 547df387a..cf290d24a 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -60,8 +60,8 @@ async function add_version_dropdown(json_loc, target_loc, text) { const p = $.getJSON(json_loc); console.log(p); - - p.done(onDone).fail(onFail).always(onAlways); + + p.then(onVersions).fail(onFail).always(onAlways); await p; /** @@ -71,7 +71,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @param {Object} versions - versions object * @returns {Promise} promise which resolves upon processing version data */ - async function onDone(versions) { + async function onVersions(versions) { console.log(versions); // Resolve the current browser URL: From 05435222a7cc584c8682bf0df7b4abc3c081eb3a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:24:23 -0700 Subject: [PATCH 067/196] Rearrange callback assignments --- spec/_static/javascripts/version_dropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index cf290d24a..8f1e170cc 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -61,8 +61,9 @@ async function add_version_dropdown(json_loc, target_loc, text) { const p = $.getJSON(json_loc); console.log(p); - p.then(onVersions).fail(onFail).always(onAlways); - await p; + p.fail(onFail).always(onAlways); + + await p.then(onVersions); /** * Callback invoked upon resolving a JSON resource. @@ -119,7 +120,6 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @private */ function onFail() { - console.log("Failure"); button.innerHTML = "Other Versions Not Found"; } From 281d236fc2a0dad068dc99bd9e271b0930ec164a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:34:40 -0700 Subject: [PATCH 068/196] Invoke `promise` method to return a deferred object's promise --- spec/_static/javascripts/version_dropdown.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 8f1e170cc..d5f85d1e5 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -61,9 +61,10 @@ async function add_version_dropdown(json_loc, target_loc, text) { const p = $.getJSON(json_loc); console.log(p); + p.then(onVersions); p.fail(onFail).always(onAlways); - await p.then(onVersions); + await p.promise(); /** * Callback invoked upon resolving a JSON resource. From 3350625bdcc27873da733067130bc9732bc9cb10 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:49:22 -0700 Subject: [PATCH 069/196] Refactor to use `fetch` --- spec/_static/javascripts/version_dropdown.js | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d5f85d1e5..d6083b018 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -58,13 +58,20 @@ async function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(button); dropdown.appendChild(content); - const p = $.getJSON(json_loc); - console.log(p); + const opts = { + 'method': 'GET' + }; + await fetch(json_loc, opts).then(onResponse).then(onVersions).catch(onError); - p.then(onVersions); - p.fail(onFail).always(onAlways); - - await p.promise(); + /** + * Callback invoked upon resolving a resource. + * + * @private + * @param {Object} response - response object + */ + function onResponse(response) { + return response.json(); + } /** * Callback invoked upon resolving a JSON resource. @@ -113,24 +120,20 @@ async function add_version_dropdown(json_loc, target_loc, text) { } // Set the button text: button.innerHTML = text; + + // Append dropdown: + $(".navheader").append(dropdown); } /** - * Callback invoked upon failing to resolve a JSON resource. + * Callback invoked upon failing to resolve a resource. * * @private */ function onFail() { button.innerHTML = "Other Versions Not Found"; - } - /** - * Callback which is always invoked upon attempting to resolve a JSON resource. - * - * @private - */ - function onAlways() { - console.log("Always"); + // Append dropdown: $(".navheader").append(dropdown); } }; From 1c32d2e363a573322b441a969018872ef96ba2f1 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:50:06 -0700 Subject: [PATCH 070/196] Fix function name --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d6083b018..4b0e79501 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -130,7 +130,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * * @private */ - function onFail() { + function onError() { button.innerHTML = "Other Versions Not Found"; // Append dropdown: From 6c3068f77cc304bc84cd384ea6bdca8251e122ff Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:34:03 -0700 Subject: [PATCH 071/196] Fix regular expression --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 4b0e79501..f9e5b2cfd 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -87,7 +87,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { const currentURL = window.location.href; // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): - let path = currentURL.split(/_site|array_api/)[1]; + let path = currentURL.split(/_site|array\-api/)[1]; // Extract the resource subpath: if (path) { From 48d926f3017d9614e4458e7e94d64d00c4c08ca8 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:37:17 -0700 Subject: [PATCH 072/196] Add debug statements --- spec/_static/javascripts/version_dropdown.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index f9e5b2cfd..a462ec93f 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -9,7 +9,7 @@ function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; - +console.log(url); // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: return fetch(url).then(onResponse).catch(onError); @@ -81,14 +81,12 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @returns {Promise} promise which resolves upon processing version data */ async function onVersions(versions) { - console.log(versions); - // Resolve the current browser URL: const currentURL = window.location.href; // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): let path = currentURL.split(/_site|array\-api/)[1]; - +console.log(path); // Extract the resource subpath: if (path) { path = path.split("/"); From 01e433ae653cff2da80518ee138beca274025112 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:45:49 -0700 Subject: [PATCH 073/196] Remove debug statements --- spec/_static/javascripts/version_dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a462ec93f..a7a859f6b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -9,7 +9,7 @@ function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; -console.log(url); + // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: return fetch(url).then(onResponse).catch(onError); @@ -86,7 +86,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): let path = currentURL.split(/_site|array\-api/)[1]; -console.log(path); + // Extract the resource subpath: if (path) { path = path.split("/"); From 4448b37741058d2c4c01e4056e775abdb7ab1637 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:51:57 -0700 Subject: [PATCH 074/196] Perform head request rather than request entire resource --- spec/_static/javascripts/version_dropdown.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a7a859f6b..4d7b7378b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -11,7 +11,10 @@ function href(url, path) { url += "/" + path; // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: - return fetch(url).then(onResponse).catch(onError); + const opts = { + 'method': 'HEAD' + }; + return fetch(url, opts).then(onResponse).catch(onError); /** * Callback invoked upon successfully resolving a resource. From 2056a94c6571d7c9ef15298d308b28fead1471dd Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 10 Jul 2023 07:57:41 -0700 Subject: [PATCH 075/196] Fix optional keyword argument in `take` signature (#644) This commit fixes the function signature for `take`. Namely, when an input array is one-dimensional, the `axis` kwarg is optional; when the array has more than one dimension, the `axis` kwarg is required. Unfortunately, the type signature cannot encode this duality, and we must rely on the specification text to clarify that the `axis` kwarg is required for arrays having ranks greater than unity. Ref: https://github.com/data-apis/array-api-compat/issues/34 --- src/array_api_stubs/_2022_12/indexing_functions.py | 4 ++-- src/array_api_stubs/_draft/indexing_functions.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/indexing_functions.py b/src/array_api_stubs/_2022_12/indexing_functions.py index e76ce7484..0cbad55ab 100644 --- a/src/array_api_stubs/_2022_12/indexing_functions.py +++ b/src/array_api_stubs/_2022_12/indexing_functions.py @@ -1,7 +1,7 @@ -from ._types import Union, array +from ._types import Union, Optional, array -def take(x: array, indices: array, /, *, axis: int) -> array: +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: """ Returns elements of an array along an axis. diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index d57dc91e5..3b218fdac 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -1,7 +1,7 @@ -from ._types import Union, array +from ._types import Union, Optional, array -def take(x: array, indices: array, /, *, axis: int) -> array: +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: """ Returns elements of an array along an axis. From bd1e695db7cbfc11b1d31bc4dd33171d7a83f035 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 13 Jul 2023 09:48:24 -0700 Subject: [PATCH 076/196] Add specification for moving array axes to new positions --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index fc0e752b9..7eb7fa8b0 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -23,6 +23,7 @@ Objects in API concat expand_dims flip + moveaxis permute_dims reshape roll diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index d62cd4f07..f71a75517 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -99,6 +99,26 @@ def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> """ +def moveaxis(x: array, source: Union[int, Tuple[int, ...]], destination: Union[int, Tuple[int, ...]], /) -> array: + """ + Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. + + Parameters + ---------- + x: array + input array. + source: Union[int, Tuple[int, ...]] + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + destination: Union[int, Tuple[int, ...]] + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + + Returns + ------- + out: array + an array containing reordered axes. The returned array must have the same data type as ``x``. + """ + + def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: """ Permutes the axes (dimensions) of an array ``x``. @@ -240,6 +260,7 @@ def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: "concat", "expand_dims", "flip", + "moveaxis", "permute_dims", "reshape", "roll", From 6a2dea289ec7d290c76a7fc03451105ab38831df Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sat, 15 Jul 2023 14:50:41 -0500 Subject: [PATCH 077/196] Fix documentation for constants Sphinx cannot find the docstring corresponding to a constant unless you point it to the exact file where it is, since it doesn't actually live on the object itself. See https://github.com/sphinx-doc/sphinx/issues/6495 Fixes #601 --- spec/2021.12/API_specification/constants.rst | 2 +- spec/2022.12/API_specification/constants.rst | 2 +- spec/draft/API_specification/constants.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/2021.12/API_specification/constants.rst b/spec/2021.12/API_specification/constants.rst index abe256533..71cb8688d 100644 --- a/spec/2021.12/API_specification/constants.rst +++ b/spec/2021.12/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: array_api +.. currentmodule:: array_api.constants .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2022.12/API_specification/constants.rst b/spec/2022.12/API_specification/constants.rst index abe256533..71cb8688d 100644 --- a/spec/2022.12/API_specification/constants.rst +++ b/spec/2022.12/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: array_api +.. currentmodule:: array_api.constants .. NOTE: please keep the functions in alphabetical order diff --git a/spec/draft/API_specification/constants.rst b/spec/draft/API_specification/constants.rst index abe256533..71cb8688d 100644 --- a/spec/draft/API_specification/constants.rst +++ b/spec/draft/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: array_api +.. currentmodule:: array_api.constants .. NOTE: please keep the functions in alphabetical order From 91c6163e8e24be9e98549a5681669ea97705de07 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 19 Jul 2023 13:33:51 -0500 Subject: [PATCH 078/196] Add custom css to avoid line-through decorations in Literal arguments --- spec/_static/css/custom.css | 3 +++ src/_array_api_conf.py | 1 + 2 files changed, 4 insertions(+) create mode 100644 spec/_static/css/custom.css diff --git a/spec/_static/css/custom.css b/spec/_static/css/custom.css new file mode 100644 index 000000000..35506ee5f --- /dev/null +++ b/spec/_static/css/custom.css @@ -0,0 +1,3 @@ +s { + text-decoration: inherit; +} \ No newline at end of file diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 490d3a2aa..e183082ec 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -211,3 +211,4 @@ def process_signature(app, what, name, obj, options, signature, return_annotatio def setup(app): app.connect("autodoc-process-signature", process_signature) + app.add_css_file('css/custom.css') From b08480f9dddca4f3a1cb4423424a12f0659b256d Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 19 Jul 2023 13:54:07 -0500 Subject: [PATCH 079/196] fix invalid latex in qr function API docstring --- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index c1ff64c3e..e0552f17a 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -473,7 +473,7 @@ def qr( where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. - The reduced QR decomposition equals with the complete QR decomposition when :math:`n \qeq m` (wide matrix). + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index b03f6eb63..3cec1770e 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -473,7 +473,7 @@ def qr( where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. - The reduced QR decomposition equals with the complete QR decomposition when :math:`n \qeq m` (wide matrix). + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. From b551155cb10f48dab6f45611395c28b18e16cd15 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 19 Jul 2023 15:56:18 -0700 Subject: [PATCH 080/196] Set Circle CI API token --- .github/workflows/preview.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 347dbfb8d..43d8c0b68 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -11,6 +11,7 @@ jobs: uses: larsoner/circleci-artifacts-redirector-action@master with: repo-token: ${{ secrets.GITHUB_TOKEN }} + api-token: ${{ secrets.CIRCLECI_TOKEN }} artifact-path: 0/_site/draft/index.html circleci-jobs: build_page job-title: Check the rendered docs here! From e72b3ca08cd7427f04f3f2093d832bf6c90c4a96 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Thu, 20 Jul 2023 04:18:15 -0500 Subject: [PATCH 081/196] Add version to the nav title (#662) --- spec/2021.12/conf.py | 4 ++++ spec/2022.12/conf.py | 3 +++ spec/draft/conf.py | 3 +++ 3 files changed, 10 insertions(+) diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index 04af8974d..cfbc80b25 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -6,4 +6,8 @@ from _array_api_conf import * release = "2021.12" + +nav_title = html_theme_options.get("nav_title") + " v{}".format(release) +html_theme_options.update({"nav_title": nav_title}) + sys.modules["array_api"] = stubs_mod diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py index fd05b644e..1831a0387 100644 --- a/spec/2022.12/conf.py +++ b/spec/2022.12/conf.py @@ -6,4 +6,7 @@ from _array_api_conf import * release = "2022.12" + +nav_title = html_theme_options.get("nav_title") + " v{}".format(release) +html_theme_options.update({"nav_title": nav_title}) sys.modules["array_api"] = stubs_mod diff --git a/spec/draft/conf.py b/spec/draft/conf.py index 4a57229b2..a93585fef 100644 --- a/spec/draft/conf.py +++ b/spec/draft/conf.py @@ -6,4 +6,7 @@ from _array_api_conf import * release = "DRAFT" + +nav_title = html_theme_options.get("nav_title") + " {}".format(release) +html_theme_options.update({"nav_title": nav_title}) sys.modules["array_api"] = stubs_mod From 825cec75215c179431f3eb2e733d836115bf237a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 26 Jul 2023 13:17:30 -0500 Subject: [PATCH 082/196] add device kwarg to astype API --- .../_draft/data_type_functions.py | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 700bffd90..857d82ab8 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -1,7 +1,19 @@ -from ._types import Union, Tuple, array, dtype, finfo_object, iinfo_object - - -def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: +from ._types import ( + Union, + Tuple, + array, + dtype, + finfo_object, + iinfo_object, + device, + Optional +) + + +def astype( + x: array, dtype: dtype, /, *, copy: bool = True, + device: Optional[device] = None +) -> array: """ Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. @@ -31,6 +43,8 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: desired data type. copy: bool specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + device: Optional[device] + device on which to place the created array. Default: ``None``. Returns ------- From 1d99f906adde4fe96d49338c6dbd713aa526e0b8 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 26 Jul 2023 17:19:00 -0500 Subject: [PATCH 083/196] clarify behavior when dtype=None in sum, prod and trace --- src/array_api_stubs/_draft/linalg.py | 9 +++++---- .../_draft/statistical_functions.py | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 3cec1770e..93711b13a 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -718,10 +718,11 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 93faaf31e..066da0da5 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -143,10 +143,11 @@ def prod( data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product. Default: ``None``. @@ -240,10 +241,11 @@ def sum( data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. From caca863cc228d14aa0a990084aaaf7a5a06175d9 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Thu, 27 Jul 2023 16:32:13 -0500 Subject: [PATCH 084/196] Add review changes Co-authored-by: Athan --- src/array_api_stubs/_draft/data_type_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 857d82ab8..726e6c8c4 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -44,7 +44,7 @@ def astype( copy: bool specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. device: Optional[device] - device on which to place the created array. Default: ``None``. + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. Returns ------- From 0fbbd5003d87849a6a0df73e7dc28cbe9f9acd60 Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Wed, 9 Aug 2023 13:11:54 -0400 Subject: [PATCH 085/196] Clarify types to allow None in indexing I believe that the indexing specification allow `None` in a selection tuple, but the current typing does not specify this. I have changed the signature for `__getitem__` but did not change `__setitem__`. I am not sure where it is documented if the indexing specification applies to both equally. --- src/array_api_stubs/_draft/array_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index cf6adcf3c..264f3a7b2 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -477,7 +477,7 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array ], /, ) -> array: @@ -488,7 +488,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns From 520d30cf04c96556f8589250c7f5c8479bd194c9 Mon Sep 17 00:00:00 2001 From: Lucas Colley <51488791+lucascolley@users.noreply.github.com> Date: Sat, 19 Aug 2023 00:58:40 +0100 Subject: [PATCH 086/196] Correct upper Cholesky description formula --- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index e0552f17a..a2207bb4c 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -18,7 +18,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: The upper Cholesky decomposition is defined similarly .. math:: - x = UU^{H} \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} where :math:`U` is an upper triangular matrix. diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 3cec1770e..29dd6849f 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -18,7 +18,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: The upper Cholesky decomposition is defined similarly .. math:: - x = UU^{H} \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} where :math:`U` is an upper triangular matrix. From caf1011e7b8254c2cb75d31dcfb31164eef5e39a Mon Sep 17 00:00:00 2001 From: Aaron Siddhartha Mondal Date: Thu, 7 Sep 2023 16:52:51 +0200 Subject: [PATCH 087/196] Use parameter name obj in asarray device doc (#681) The asarray creation function uses obj instead of x. --- src/array_api_stubs/_2021_12/creation_functions.py | 2 +- src/array_api_stubs/_2022_12/creation_functions.py | 2 +- src/array_api_stubs/_draft/creation_functions.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index 4ee683cd9..abfb38455 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -60,7 +60,7 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. device: Optional[device] - device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py index 8736efc29..42d6f9420 100644 --- a/src/array_api_stubs/_2022_12/creation_functions.py +++ b/src/array_api_stubs/_2022_12/creation_functions.py @@ -89,7 +89,7 @@ def asarray( If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. device: Optional[device] - device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 8736efc29..42d6f9420 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -89,7 +89,7 @@ def asarray( If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. device: Optional[device] - device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. From ba80d0aa194082bf23eb44dab4d3688b94943537 Mon Sep 17 00:00:00 2001 From: Nathaniel Starkman Date: Tue, 12 Sep 2023 04:01:37 -0400 Subject: [PATCH 088/196] Move `__all__` to PEP-8 recommended location (#683) Module level "dunders" (i.e. names with two leading and two trailing underscores) such as __all__, __author__, __version__, etc. should be placed after the module docstring but before any import statements except from __future__ imports. Python mandates that future-imports must appear in the module before any other code except docstrings. Signed-off-by: nstarman --- src/array_api_stubs/__init__.py | 1 - src/array_api_stubs/_draft/_types.py | 47 ++++--- src/array_api_stubs/_draft/array_object.py | 4 +- src/array_api_stubs/_draft/constants.py | 4 +- .../_draft/creation_functions.py | 40 +++--- .../_draft/data_type_functions.py | 6 +- src/array_api_stubs/_draft/data_types.py | 6 +- .../_draft/elementwise_functions.py | 126 +++++++++--------- src/array_api_stubs/_draft/fft.py | 35 +++-- .../_draft/indexing_functions.py | 5 +- src/array_api_stubs/_draft/linalg.py | 54 ++++---- .../_draft/linear_algebra_functions.py | 6 +- .../_draft/manipulation_functions.py | 30 ++--- .../_draft/searching_functions.py | 6 +- src/array_api_stubs/_draft/set_functions.py | 6 +- .../_draft/sorting_functions.py | 6 +- .../_draft/statistical_functions.py | 6 +- .../_draft/utility_functions.py | 6 +- 18 files changed, 197 insertions(+), 197 deletions(-) diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index b3c7f1976..4ac3783ef 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1,2 +1 @@ from . import _2021_12, _2022_12, _draft - diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 589606784..2a73dda24 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -6,6 +6,27 @@ """ from __future__ import annotations +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", +] + from dataclasses import dataclass from typing import ( Any, @@ -34,6 +55,7 @@ @dataclass class finfo_object: """Dataclass returned by `finfo`.""" + bits: int eps: float max: float @@ -41,14 +63,17 @@ class finfo_object: smallest_normal: float dtype: dtype + @dataclass class iinfo_object: """Dataclass returned by `iinfo`.""" + bits: int max: int min: int dtype: dtype + _T_co = TypeVar("_T_co", covariant=True) @@ -58,25 +83,3 @@ def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: def __len__(self, /) -> int: ... - - -__all__ = [ - "Any", - "List", - "Literal", - "NestedSequence", - "Optional", - "PyCapsule", - "SupportsBufferProtocol", - "SupportsDLPack", - "Tuple", - "Union", - "Sequence", - "array", - "device", - "dtype", - "ellipsis", - "finfo_object", - "iinfo_object", - "Enum", -] diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index cf6adcf3c..e5d34248c 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -1,5 +1,7 @@ from __future__ import annotations +__all__ = ["array"] + from ._types import ( array, dtype as Dtype, @@ -1059,5 +1061,3 @@ def to_device( array = _array - -__all__ = ["array"] diff --git a/src/array_api_stubs/_draft/constants.py b/src/array_api_stubs/_draft/constants.py index c7aaddc5e..c5735d09f 100644 --- a/src/array_api_stubs/_draft/constants.py +++ b/src/array_api_stubs/_draft/constants.py @@ -1,3 +1,5 @@ +__all__ = ["e", "inf", "nan", "newaxis", "pi"] + e = 2.718281828459045 """ IEEE 754 floating-point representation of Euler's constant. @@ -26,5 +28,3 @@ ``pi = 3.1415926535897932384626433...`` """ - -__all__ = ["e", "inf", "nan", "newaxis", "pi"] diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 42d6f9420..5e2bb44e6 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -1,3 +1,23 @@ +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] + + from ._types import ( List, NestedSequence, @@ -563,23 +583,3 @@ def zeros_like( out: array an array having the same shape as ``x`` and filled with zeros. """ - - -__all__ = [ - "arange", - "asarray", - "empty", - "empty_like", - "eye", - "from_dlpack", - "full", - "full_like", - "linspace", - "meshgrid", - "ones", - "ones_like", - "tril", - "triu", - "zeros", - "zeros_like", -] diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 700bffd90..a5e9895b2 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -1,3 +1,6 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + + from ._types import Union, Tuple, array, dtype, finfo_object, iinfo_object @@ -208,6 +211,3 @@ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: out: dtype the dtype resulting from an operation involving the input arrays and dtypes. """ - - -__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] diff --git a/src/array_api_stubs/_draft/data_types.py b/src/array_api_stubs/_draft/data_types.py index 614807414..d15f4a9f7 100644 --- a/src/array_api_stubs/_draft/data_types.py +++ b/src/array_api_stubs/_draft/data_types.py @@ -1,3 +1,6 @@ +__all__ = ["__eq__"] + + from ._types import dtype @@ -17,6 +20,3 @@ def __eq__(self: dtype, other: dtype, /) -> bool: out: bool a boolean indicating whether the data type objects are equal. """ - - -__all__ = ["__eq__"] diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 5f474e7c8..147eff9cd 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -1,3 +1,66 @@ +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "conj", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "real", + "remainder", + "round", + "sign", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] + + from ._types import array @@ -2477,66 +2540,3 @@ def trunc(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. """ - - -__all__ = [ - "abs", - "acos", - "acosh", - "add", - "asin", - "asinh", - "atan", - "atan2", - "atanh", - "bitwise_and", - "bitwise_left_shift", - "bitwise_invert", - "bitwise_or", - "bitwise_right_shift", - "bitwise_xor", - "ceil", - "conj", - "cos", - "cosh", - "divide", - "equal", - "exp", - "expm1", - "floor", - "floor_divide", - "greater", - "greater_equal", - "imag", - "isfinite", - "isinf", - "isnan", - "less", - "less_equal", - "log", - "log1p", - "log2", - "log10", - "logaddexp", - "logical_and", - "logical_not", - "logical_or", - "logical_xor", - "multiply", - "negative", - "not_equal", - "positive", - "pow", - "real", - "remainder", - "round", - "sign", - "sin", - "sinh", - "square", - "sqrt", - "subtract", - "tan", - "tanh", - "trunc", -] diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 7979095fe..4a59392d5 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -1,3 +1,20 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + from ._types import Tuple, Union, Sequence, array, Optional, Literal, device @@ -651,21 +668,3 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: .. versionadded:: 2022.12 """ - - -__all__ = [ - "fft", - "ifft", - "fftn", - "ifftn", - "rfft", - "irfft", - "rfftn", - "irfftn", - "hfft", - "ihfft", - "fftfreq", - "rfftfreq", - "fftshift", - "ifftshift", -] diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 3b218fdac..3f4c25215 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -1,3 +1,5 @@ +__all__ = ["take"] + from ._types import Union, Optional, array @@ -29,6 +31,3 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. versionadded:: 2022.12 """ - - -__all__ = ["take"] diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 29dd6849f..dc74cd239 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -1,3 +1,30 @@ +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] + + from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype from .constants import inf @@ -822,30 +849,3 @@ def vector_norm( .. versionchanged:: 2022.12 Added complex data type support. """ - - -__all__ = [ - "cholesky", - "cross", - "det", - "diagonal", - "eigh", - "eigvalsh", - "inv", - "matmul", - "matrix_norm", - "matrix_power", - "matrix_rank", - "matrix_transpose", - "outer", - "pinv", - "qr", - "slogdet", - "solve", - "svd", - "svdvals", - "tensordot", - "trace", - "vecdot", - "vector_norm", -] diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index d9ac2437c..a6f84e392 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -1,3 +1,6 @@ +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] + + from ._types import Tuple, Union, Sequence, array @@ -155,6 +158,3 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ - - -__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index d62cd4f07..74b62a689 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -1,3 +1,18 @@ +__all__ = [ + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "permute_dims", + "reshape", + "roll", + "squeeze", + "stack", + "unstack", +] + + from ._types import List, Optional, Tuple, Union, array @@ -232,18 +247,3 @@ def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: out: Tuple[array, ...] tuple of slices along the given dimension. All the arrays have the same shape. """ - - -__all__ = [ - "broadcast_arrays", - "broadcast_to", - "concat", - "expand_dims", - "flip", - "permute_dims", - "reshape", - "roll", - "squeeze", - "stack", - "unstack", -] diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 9dcc0f95c..e586a7656 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -1,3 +1,6 @@ +__all__ = ["argmax", "argmin", "nonzero", "where"] + + from ._types import Optional, Tuple, array @@ -102,6 +105,3 @@ def where(condition: array, x1: array, x2: array, /) -> array: out: array an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. """ - - -__all__ = ["argmax", "argmin", "nonzero", "where"] diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 661d3df90..394fa2b17 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -1,3 +1,6 @@ +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] + + from ._types import Tuple, array @@ -166,6 +169,3 @@ def unique_values(x: array, /) -> array: .. versionchanged:: 2022.12 Added complex data type support. """ - - -__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] diff --git a/src/array_api_stubs/_draft/sorting_functions.py b/src/array_api_stubs/_draft/sorting_functions.py index 3eb52c8ce..2dc4ac410 100644 --- a/src/array_api_stubs/_draft/sorting_functions.py +++ b/src/array_api_stubs/_draft/sorting_functions.py @@ -1,3 +1,6 @@ +__all__ = ["argsort", "sort"] + + from ._types import array @@ -53,6 +56,3 @@ def sort( out : array a sorted array. The returned array must have the same data type and shape as ``x``. """ - - -__all__ = ["argsort", "sort"] diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 93faaf31e..7648f1c3f 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -1,3 +1,6 @@ +__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] + + from ._types import Optional, Tuple, Union, array, dtype @@ -315,6 +318,3 @@ def var( - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). """ - - -__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index 64e5de297..81d8dca41 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -1,3 +1,6 @@ +__all__ = ["all", "any"] + + from ._types import Optional, Tuple, Union, array @@ -81,6 +84,3 @@ def any( .. versionchanged:: 2022.12 Added complex data type support. """ - - -__all__ = ["all", "any"] From 2e0723844cc4b789f0ec86dc474d6cfa9387262e Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Tue, 12 Sep 2023 09:03:24 +0100 Subject: [PATCH 089/196] Add lucascolley to all contributors (#682) --- .all-contributorsrc | 10 ++++++++++ README.md | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index f7f25e7d4..1e46cd5c1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -616,6 +616,16 @@ "contributions": [ "ideas" ] + }, + { + "login": "lucascolley", + "name": "Lucas Colley", + "avatar_url": "https://avatars.githubusercontent.com/u/51488791?v=4", + "profile": "https://github.com/lucascolley", + "contributions": [ + "maintenance", + "bug" + ] } ], "contributorsPerLine": 7 diff --git a/README.md b/README.md index dbfee4cea..4e72e269a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Array API standard -[![All Contributors](https://img.shields.io/badge/all_contributors-63-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-64-orange.svg?style=flat-square)](#contributors-) This repository contains documents, tooling and other content related to the @@ -233,6 +233,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Franck Charras
Franck Charras

🤔 Keith Kraus
Keith Kraus

🤔 + + Lucas Colley
Lucas Colley

🚧 🐛 + From 678f9eab5a593005e7bb80a46156c27b210cfcea Mon Sep 17 00:00:00 2001 From: Nathaniel Starkman Date: Fri, 15 Sep 2023 08:36:59 -0400 Subject: [PATCH 090/196] Add style checking with pre-commit + black, and a CI job (#684) Signed-off-by: nstarman --- .git-blame-ignore-revs | 2 +- .github/workflows/ci.yml | 46 ++++++ .github/workflows/pages.yml | 4 +- .pre-commit-config.yaml | 50 ++++++ CHANGELOG.md | 2 +- CODE_OF_CONDUCT.md | 2 +- README.md | 2 +- pyproject.toml | 3 + spec/2021.12/benchmark_suite.md | 2 +- spec/2021.12/conf.py | 1 + spec/2021.12/design_topics/accuracy.rst | 2 +- spec/2021.12/design_topics/parallelism.rst | 2 +- spec/2021.12/future_API_evolution.md | 2 +- spec/2021.12/usage_data.md | 4 +- spec/2021.12/use_cases.md | 2 +- spec/2022.12/benchmark_suite.md | 2 +- spec/2022.12/conf.py | 1 + spec/2022.12/design_topics/accuracy.rst | 2 +- .../2022.12/design_topics/complex_numbers.rst | 4 +- spec/2022.12/design_topics/parallelism.rst | 2 +- spec/2022.12/future_API_evolution.md | 2 +- spec/2022.12/usage_data.md | 4 +- spec/2022.12/use_cases.md | 2 +- spec/_static/css/custom.css | 2 +- spec/_templates/property.rst | 2 +- spec/draft/benchmark_suite.md | 2 +- spec/draft/conf.py | 1 + spec/draft/design_topics/accuracy.rst | 2 +- spec/draft/design_topics/complex_numbers.rst | 4 +- spec/draft/design_topics/parallelism.rst | 2 +- spec/draft/future_API_evolution.md | 2 +- spec/draft/usage_data.md | 4 +- spec/draft/use_cases.md | 2 +- src/_array_api_conf.py | 119 +++++++-------- src/array_api_stubs/_2021_12/_types.py | 59 ++++++-- src/array_api_stubs/_2021_12/array_object.py | 49 ++++-- src/array_api_stubs/_2021_12/constants.py | 6 +- .../_2021_12/creation_functions.py | 143 +++++++++++++++--- .../_2021_12/data_type_functions.py | 18 ++- src/array_api_stubs/_2021_12/data_types.py | 2 + .../_2021_12/elementwise_functions.py | 116 +++++++++++++- src/array_api_stubs/_2021_12/linalg.py | 79 +++++++++- .../_2021_12/linear_algebra_functions.py | 15 +- .../_2021_12/manipulation_functions.py | 36 ++++- .../_2021_12/searching_functions.py | 7 +- src/array_api_stubs/_2021_12/set_functions.py | 7 +- .../_2021_12/sorting_functions.py | 13 +- .../_2021_12/statistical_functions.py | 70 ++++++++- .../_2021_12/utility_functions.py | 21 ++- src/array_api_stubs/_2022_12/_types.py | 4 + 50 files changed, 767 insertions(+), 165 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .pre-commit-config.yaml diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 64a94ebe7..4fd6df5d4 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -4,4 +4,4 @@ # Move special cases to notes sections 816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 0a2fa71a32b924cc92718db29910a6cbbc5e9341 -931144e7d7d5c8b23393aa730ef28962a35b113b \ No newline at end of file +931144e7d7d5c8b23393aa730ef28962a35b113b diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..6d3ba5c27 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +#/ +# @license MIT +# +# Copyright (c) 2022 Python Data APIs Consortium. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#/ + +# Workflow name: +name: ci + +# Workflow triggers: +on: + pull_request: + push: + branches: [main,] + +# Workflow jobs: +jobs: + + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + - uses: pre-commit/action@v3.0.0 + - uses: pre-commit-ci/lite-action@v1.0.1 + if: always() diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index b328abc11..7576076ef 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -45,10 +45,10 @@ jobs: # Avoid running this workflow for forks and allow skipping CI: if: "github.repository == 'data-apis/array-api' && !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip github]')" - + # Define a sequence of job steps... steps: - + # Checkout the repository: - name: 'Checkout repository' uses: actions/checkout@v2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..7ec7f02a8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,50 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + # Prevent giant files from being committed. + - id: check-ast + # Simply check whether files parse as valid python. + - id: check-case-conflict + # Check for files with names that would conflict on a case-insensitive + # filesystem like MacOS HFS+ or Windows FAT. + - id: check-json + # Attempts to load all json files to verify syntax. + - id: check-merge-conflict + # Check for files that contain merge conflict strings. + - id: check-symlinks + # Checks for symlinks which do not point to anything. + - id: check-toml + # Attempts to load all TOML files to verify syntax. + - id: check-xml + # Attempts to load all xml files to verify syntax. + - id: check-yaml + # Attempts to load all yaml files to verify syntax. + exclude: ".*(.github.*)$" + - id: debug-statements + # Check for debugger imports and py37+ breakpoint() calls in python + # source. + - id: detect-private-key + # Checks for the existence of private keys. + - id: end-of-file-fixer + # Makes sure files end in a newline and only a newline. + - id: trailing-whitespace + # Trims trailing whitespace. + exclude_types: [python] + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: python-check-mock-methods + # Prevent common mistakes of assert mck.not_called(), assert + # mck.called_once_with(...) and mck.assert_called. + - id: text-unicode-replacement-char + # Forbid files which have a UTF-8 Unicode replacement character. + - id: python-check-blanket-noqa + # Enforce that all noqa annotations always occur with specific codes. + + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 23.7.0 + hooks: + - id: black diff --git a/CHANGELOG.md b/CHANGELOG.md index 002d4fec9..0897e4ea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -196,4 +196,4 @@ The following is a list of fixes and points of clarification with regard to the - `linspace`: conversion of `start` and `stop` should follow type promotion rules ([gh-568](https://github.com/data-apis/array-api/pull/568)) - `nonzero`: clarify that, for arrays having a boolean data type, non-zero elements are those elements which equal `True` ([gh-441](https://github.com/data-apis/array-api/pull/441)) - `trunc`: fix description ([gh-511](https://github.com/data-apis/array-api/pull/511)) -- `vecdot`: clarify broadcasting behavior ([gh-417](https://github.com/data-apis/array-api/pull/417) and [gh-473](https://github.com/data-apis/array-api/pull/473)) \ No newline at end of file +- `vecdot`: clarify broadcasting behavior ([gh-417](https://github.com/data-apis/array-api/pull/417) and [gh-473](https://github.com/data-apis/array-api/pull/473)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 3ceb0ad58..9e9419abe 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ Please note that the Consortium for Python Data API Standards has a Code of Conduct that we ask everyone to respect, see: -https://github.com/data-apis/.github/blob/master/CODE_OF_CONDUCT.md \ No newline at end of file +https://github.com/data-apis/.github/blob/master/CODE_OF_CONDUCT.md diff --git a/README.md b/README.md index 4e72e269a..fef3099ff 100644 --- a/README.md +++ b/README.md @@ -244,4 +244,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! \ No newline at end of file +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/pyproject.toml b/pyproject.toml index b4f991c45..57af04207 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,3 +29,6 @@ doc = [ [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 88 diff --git a/spec/2021.12/benchmark_suite.md b/spec/2021.12/benchmark_suite.md index da203cbf6..41066c6a4 100644 --- a/spec/2021.12/benchmark_suite.md +++ b/spec/2021.12/benchmark_suite.md @@ -1,3 +1,3 @@ # Benchmark suite -Adding a benchmark suite is planned in the future. \ No newline at end of file +Adding a benchmark suite is planned in the future. diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index cfbc80b25..9638670b4 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -1,5 +1,6 @@ import sys from pathlib import Path + sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2021_12 as stubs_mod diff --git a/spec/2021.12/design_topics/accuracy.rst b/spec/2021.12/design_topics/accuracy.rst index df417d546..8c97db698 100644 --- a/spec/2021.12/design_topics/accuracy.rst +++ b/spec/2021.12/design_topics/accuracy.rst @@ -74,4 +74,4 @@ This specification does not specify accuracy requirements for statistical functi Linear Algebra -------------- -This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2021.12/design_topics/parallelism.rst b/spec/2021.12/design_topics/parallelism.rst index 77d06c966..f013a9cf9 100644 --- a/spec/2021.12/design_topics/parallelism.rst +++ b/spec/2021.12/design_topics/parallelism.rst @@ -21,4 +21,4 @@ coordination of parallelization behavior in a stack of Python libraries are: Option (1) may possibly fit in a future version of this array API standard. `array-api issue 4 `_ contains -more detailed discussion on the topic of parallelism. \ No newline at end of file +more detailed discussion on the topic of parallelism. diff --git a/spec/2021.12/future_API_evolution.md b/spec/2021.12/future_API_evolution.md index 719b554e3..443f683d5 100644 --- a/spec/2021.12/future_API_evolution.md +++ b/spec/2021.12/future_API_evolution.md @@ -57,4 +57,4 @@ than Python package versioning. The frequency of releasing a new version of an API standard will likely be at regular intervals and on the order of one year, however no assumption on -frequency of new versions appearing must be made. \ No newline at end of file +frequency of new versions appearing must be made. diff --git a/spec/2021.12/usage_data.md b/spec/2021.12/usage_data.md index 7963333ff..c2dcd5d65 100644 --- a/spec/2021.12/usage_data.md +++ b/spec/2021.12/usage_data.md @@ -82,5 +82,5 @@ See the [`python-record-api`](https://github.com/data-apis/python-record-api) re Design and usage data support specification decision-making in the following ways. - Validate user stories to ensure that proposals satisfy existing needs. -- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). -- Inform technical design discussions to ensure that proposals are grounded in empirical data. \ No newline at end of file +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2021.12/use_cases.md b/spec/2021.12/use_cases.md index 50b6bd24d..26f7a529c 100644 --- a/spec/2021.12/use_cases.md +++ b/spec/2021.12/use_cases.md @@ -232,4 +232,4 @@ def check(x, y): # (this is different from Numpy, whose behaviour depends on # the *values* of the arguments -- see PyArray_CanCastArrayTo). self.assertEqual(got.dtype, x.dtype) -``` \ No newline at end of file +``` diff --git a/spec/2022.12/benchmark_suite.md b/spec/2022.12/benchmark_suite.md index da203cbf6..41066c6a4 100644 --- a/spec/2022.12/benchmark_suite.md +++ b/spec/2022.12/benchmark_suite.md @@ -1,3 +1,3 @@ # Benchmark suite -Adding a benchmark suite is planned in the future. \ No newline at end of file +Adding a benchmark suite is planned in the future. diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py index 1831a0387..e056bb7f2 100644 --- a/spec/2022.12/conf.py +++ b/spec/2022.12/conf.py @@ -1,5 +1,6 @@ import sys from pathlib import Path + sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2022_12 as stubs_mod diff --git a/spec/2022.12/design_topics/accuracy.rst b/spec/2022.12/design_topics/accuracy.rst index df417d546..8c97db698 100644 --- a/spec/2022.12/design_topics/accuracy.rst +++ b/spec/2022.12/design_topics/accuracy.rst @@ -74,4 +74,4 @@ This specification does not specify accuracy requirements for statistical functi Linear Algebra -------------- -This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2022.12/design_topics/complex_numbers.rst b/spec/2022.12/design_topics/complex_numbers.rst index da441499a..0eca79e91 100644 --- a/spec/2022.12/design_topics/complex_numbers.rst +++ b/spec/2022.12/design_topics/complex_numbers.rst @@ -27,7 +27,7 @@ Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer po In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. .. warning:: - All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. @@ -58,4 +58,4 @@ Valued-based Promotion According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. -By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. \ No newline at end of file +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/2022.12/design_topics/parallelism.rst b/spec/2022.12/design_topics/parallelism.rst index 77d06c966..f013a9cf9 100644 --- a/spec/2022.12/design_topics/parallelism.rst +++ b/spec/2022.12/design_topics/parallelism.rst @@ -21,4 +21,4 @@ coordination of parallelization behavior in a stack of Python libraries are: Option (1) may possibly fit in a future version of this array API standard. `array-api issue 4 `_ contains -more detailed discussion on the topic of parallelism. \ No newline at end of file +more detailed discussion on the topic of parallelism. diff --git a/spec/2022.12/future_API_evolution.md b/spec/2022.12/future_API_evolution.md index 719b554e3..443f683d5 100644 --- a/spec/2022.12/future_API_evolution.md +++ b/spec/2022.12/future_API_evolution.md @@ -57,4 +57,4 @@ than Python package versioning. The frequency of releasing a new version of an API standard will likely be at regular intervals and on the order of one year, however no assumption on -frequency of new versions appearing must be made. \ No newline at end of file +frequency of new versions appearing must be made. diff --git a/spec/2022.12/usage_data.md b/spec/2022.12/usage_data.md index 7963333ff..c2dcd5d65 100644 --- a/spec/2022.12/usage_data.md +++ b/spec/2022.12/usage_data.md @@ -82,5 +82,5 @@ See the [`python-record-api`](https://github.com/data-apis/python-record-api) re Design and usage data support specification decision-making in the following ways. - Validate user stories to ensure that proposals satisfy existing needs. -- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). -- Inform technical design discussions to ensure that proposals are grounded in empirical data. \ No newline at end of file +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2022.12/use_cases.md b/spec/2022.12/use_cases.md index 50b6bd24d..26f7a529c 100644 --- a/spec/2022.12/use_cases.md +++ b/spec/2022.12/use_cases.md @@ -232,4 +232,4 @@ def check(x, y): # (this is different from Numpy, whose behaviour depends on # the *values* of the arguments -- see PyArray_CanCastArrayTo). self.assertEqual(got.dtype, x.dtype) -``` \ No newline at end of file +``` diff --git a/spec/_static/css/custom.css b/spec/_static/css/custom.css index 35506ee5f..51c73f65c 100644 --- a/spec/_static/css/custom.css +++ b/spec/_static/css/custom.css @@ -1,3 +1,3 @@ s { text-decoration: inherit; -} \ No newline at end of file +} diff --git a/spec/_templates/property.rst b/spec/_templates/property.rst index baf31cea3..74062629f 100644 --- a/spec/_templates/property.rst +++ b/spec/_templates/property.rst @@ -2,4 +2,4 @@ {{ name.split('.')[-1] | underline }} -.. auto{{ objtype }}:: {{ objname }} \ No newline at end of file +.. auto{{ objtype }}:: {{ objname }} diff --git a/spec/draft/benchmark_suite.md b/spec/draft/benchmark_suite.md index da203cbf6..41066c6a4 100644 --- a/spec/draft/benchmark_suite.md +++ b/spec/draft/benchmark_suite.md @@ -1,3 +1,3 @@ # Benchmark suite -Adding a benchmark suite is planned in the future. \ No newline at end of file +Adding a benchmark suite is planned in the future. diff --git a/spec/draft/conf.py b/spec/draft/conf.py index a93585fef..d02568c35 100644 --- a/spec/draft/conf.py +++ b/spec/draft/conf.py @@ -1,5 +1,6 @@ import sys from pathlib import Path + sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _draft as stubs_mod diff --git a/spec/draft/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst index df417d546..8c97db698 100644 --- a/spec/draft/design_topics/accuracy.rst +++ b/spec/draft/design_topics/accuracy.rst @@ -74,4 +74,4 @@ This specification does not specify accuracy requirements for statistical functi Linear Algebra -------------- -This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/draft/design_topics/complex_numbers.rst b/spec/draft/design_topics/complex_numbers.rst index da441499a..0eca79e91 100644 --- a/spec/draft/design_topics/complex_numbers.rst +++ b/spec/draft/design_topics/complex_numbers.rst @@ -27,7 +27,7 @@ Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer po In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. .. warning:: - All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. @@ -58,4 +58,4 @@ Valued-based Promotion According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. -By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. \ No newline at end of file +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/draft/design_topics/parallelism.rst b/spec/draft/design_topics/parallelism.rst index 77d06c966..f013a9cf9 100644 --- a/spec/draft/design_topics/parallelism.rst +++ b/spec/draft/design_topics/parallelism.rst @@ -21,4 +21,4 @@ coordination of parallelization behavior in a stack of Python libraries are: Option (1) may possibly fit in a future version of this array API standard. `array-api issue 4 `_ contains -more detailed discussion on the topic of parallelism. \ No newline at end of file +more detailed discussion on the topic of parallelism. diff --git a/spec/draft/future_API_evolution.md b/spec/draft/future_API_evolution.md index 719b554e3..443f683d5 100644 --- a/spec/draft/future_API_evolution.md +++ b/spec/draft/future_API_evolution.md @@ -57,4 +57,4 @@ than Python package versioning. The frequency of releasing a new version of an API standard will likely be at regular intervals and on the order of one year, however no assumption on -frequency of new versions appearing must be made. \ No newline at end of file +frequency of new versions appearing must be made. diff --git a/spec/draft/usage_data.md b/spec/draft/usage_data.md index 7963333ff..c2dcd5d65 100644 --- a/spec/draft/usage_data.md +++ b/spec/draft/usage_data.md @@ -82,5 +82,5 @@ See the [`python-record-api`](https://github.com/data-apis/python-record-api) re Design and usage data support specification decision-making in the following ways. - Validate user stories to ensure that proposals satisfy existing needs. -- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). -- Inform technical design discussions to ensure that proposals are grounded in empirical data. \ No newline at end of file +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/draft/use_cases.md b/spec/draft/use_cases.md index 50b6bd24d..26f7a529c 100644 --- a/spec/draft/use_cases.md +++ b/spec/draft/use_cases.md @@ -232,4 +232,4 @@ def check(x, y): # (this is different from Numpy, whose behaviour depends on # the *values* of the arguments -- see PyArray_CanCastArrayTo). self.assertEqual(got.dtype, x.dtype) -``` \ No newline at end of file +``` diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index e183082ec..d3a136eaa 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -16,9 +16,9 @@ # -- Project information ----------------------------------------------------- -project = 'Python array API standard' -copyright = '2020-2022, Consortium for Python Data API Standards' -author = 'Consortium for Python Data API Standards' +project = "Python array API standard" +copyright = "2020-2022, Consortium for Python Data API Standards" +author = "Consortium for Python Data API Standards" # -- General configuration --------------------------------------------------- @@ -26,23 +26,23 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'myst_parser', - 'sphinx.ext.extlinks', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.autosummary', - 'sphinx.ext.napoleon', - 'sphinx.ext.autodoc', - 'sphinx_copybutton', - 'sphinx_favicon', - 'sphinx_markdown_tables', + "myst_parser", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinx.ext.autodoc", + "sphinx_copybutton", + "sphinx_favicon", + "sphinx_markdown_tables", ] autosummary_generate = True -autodoc_typehints = 'signature' +autodoc_typehints = "signature" add_module_names = False -napoleon_custom_sections = [('Returns', 'params_style')] -default_role = 'code' +napoleon_custom_sections = [("Returns", "params_style")] +default_role = "code" # nitpicky = True makes Sphinx warn whenever a cross-reference target can't be # found. @@ -50,30 +50,33 @@ # autodoc wants to make cross-references for every type hint. But a lot of # them don't actually refer to anything that we have a document for. nitpick_ignore = [ - ('py:class', 'collections.abc.Sequence'), - ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:class', "Union[int, float, Literal[inf, - inf]]"), - ('py:obj', "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:obj', "typing.Union[int, float, typing.Literal[inf, - inf]]"), - ('py:class', 'enum.Enum'), - ('py:class', 'ellipsis'), + ("py:class", "collections.abc.Sequence"), + ("py:class", "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), + ("py:class", "Union[int, float, Literal[inf, - inf]]"), + ( + "py:obj", + "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]", + ), + ("py:obj", "typing.Union[int, float, typing.Literal[inf, - inf]]"), + ("py:class", "enum.Enum"), + ("py:class", "ellipsis"), ] nitpick_ignore_regex = [ - ('py:class', '.*array'), - ('py:class', '.*device'), - ('py:class', '.*dtype'), - ('py:class', '.*NestedSequence'), - ('py:class', '.*SupportsBufferProtocol'), - ('py:class', '.*PyCapsule'), - ('py:class', '.*finfo_object'), - ('py:class', '.*iinfo_object'), + ("py:class", ".*array"), + ("py:class", ".*device"), + ("py:class", ".*dtype"), + ("py:class", ".*NestedSequence"), + ("py:class", ".*SupportsBufferProtocol"), + ("py:class", ".*PyCapsule"), + ("py:class", ".*finfo_object"), + ("py:class", ".*iinfo_object"), ] # In array_object.py we have to use aliased names for some types because they # would otherwise refer back to method objects of array autodoc_type_aliases = { - 'array': 'array', - 'Device': 'device', - 'Dtype': 'dtype', + "array": "array", + "Device": "device", + "Dtype": "dtype", } # Make autosummary show the signatures of functions in the tables using actual @@ -81,18 +84,19 @@ # just patch out the function that processes the signatures. See # https://github.com/sphinx-doc/sphinx/issues/10053. import sphinx.ext.autosummary as autosummary_mod -if hasattr(autosummary_mod, '_module'): + +if hasattr(autosummary_mod, "_module"): # It's a sphinx deprecated module wrapper object autosummary_mod = autosummary_mod._module autosummary_mod.mangle_signature = lambda sig, max_chars=30: sig # Add any paths that contain templates here, relative to this directory. -templates_path = ['../_templates'] +templates_path = ["../_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # MyST options myst_heading_anchors = 3 @@ -106,12 +110,12 @@ extensions.append("sphinx_material") html_theme_path = sphinx_material.html_theme_path() html_context = sphinx_material.get_html_context() -html_theme = 'sphinx_material' +html_theme = "sphinx_material" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['../_static'] +html_static_path = ["../_static"] # -- Material theme options (see theme.conf for more information) ------------ @@ -121,26 +125,20 @@ } html_theme_options = { - # Set the name of the project to appear in the navigation. - 'nav_title': f'Python array API standard', - + "nav_title": f"Python array API standard", # Set you GA account ID to enable tracking #'google_analytics_account': 'UA-XXXXX', - # Specify a base_url used to generate sitemap.xml. If not # specified, then no sitemap will be built. #'base_url': 'https://project.github.io/project', - # Set the color and the accent color (see # https://material.io/design/color/the-color-system.html) - 'color_primary': 'indigo', - 'color_accent': 'green', - + "color_primary": "indigo", + "color_accent": "green", # Set the repo location to get a badge with stats #'repo_url': 'https://github.com/project/project/', #'repo_name': 'Project', - "html_minify": False, "html_prettify": False, "css_minify": True, @@ -149,14 +147,12 @@ "touch_icon": "images/apple-icon-152x152.png", "theme_color": "#2196f3", "master_doc": False, - # Visible levels of the global TOC; -1 means unlimited - 'globaltoc_depth': 2, + "globaltoc_depth": 2, # If False, expand all TOC entries - 'globaltoc_collapse': True, + "globaltoc_collapse": True, # If True, show hidden TOC entries - 'globaltoc_includehidden': True, - + "globaltoc_includehidden": True, "nav_links": [ {"href": "index", "internal": True, "title": "Array API standard"}, { @@ -167,9 +163,8 @@ ], "heroes": { "index": "A common API for array and tensor Python libraries", - #"customization": "Configuration options to personalize your site.", + # "customization": "Configuration options to personalize your site.", }, - "version_dropdown": True, "version_json": "../versions.json", "table_classes": ["plain"], @@ -179,11 +174,11 @@ todo_include_todos = True favicons = [ - { - "rel": "icon", - "sizes": "196x195", - "href": "images/favicon.png", - }, + { + "rel": "icon", + "sizes": "196x195", + "href": "images/favicon.png", + }, ] html_use_index = True @@ -202,6 +197,7 @@ # -- Prettify type hints ----------------------------------------------------- r_type_prefix = re.compile(r"array_api(?:_stubs\._[a-z0-9_]+)?\._types\.") + def process_signature(app, what, name, obj, options, signature, return_annotation): if signature: signature = re.sub(r_type_prefix, "", signature) @@ -209,6 +205,7 @@ def process_signature(app, what, name, obj, options, signature, return_annotatio return_annotation = re.sub(r_type_prefix, "", return_annotation) return signature, return_annotation + def setup(app): app.connect("autodoc-process-signature", process_signature) - app.add_css_file('css/custom.css') + app.add_css_file("css/custom.css") diff --git a/src/array_api_stubs/_2021_12/_types.py b/src/array_api_stubs/_2021_12/_types.py index b55e8fb25..be81b40ae 100644 --- a/src/array_api_stubs/_2021_12/_types.py +++ b/src/array_api_stubs/_2021_12/_types.py @@ -7,18 +7,29 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Any, List, Literal, Optional, Sequence, Tuple, TypeVar, Union, Protocol +from typing import ( + Any, + List, + Literal, + Optional, + Sequence, + Tuple, + TypeVar, + Union, + Protocol, +) from enum import Enum -array = TypeVar('array') -device = TypeVar('device') -dtype = TypeVar('dtype') -SupportsDLPack = TypeVar('SupportsDLPack') -SupportsBufferProtocol = TypeVar('SupportsBufferProtocol') -PyCapsule = TypeVar('PyCapsule') +array = TypeVar("array") +device = TypeVar("device") +dtype = TypeVar("dtype") +SupportsDLPack = TypeVar("SupportsDLPack") +SupportsBufferProtocol = TypeVar("SupportsBufferProtocol") +PyCapsule = TypeVar("PyCapsule") # ellipsis cannot actually be imported from anywhere, so include a dummy here # to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 -ellipsis = TypeVar('ellipsis') +ellipsis = TypeVar("ellipsis") + @dataclass class finfo_object: @@ -28,6 +39,7 @@ class finfo_object: min: float smallest_normal: float + @dataclass class iinfo_object: bits: int @@ -37,11 +49,32 @@ class iinfo_object: _T_co = TypeVar("_T_co", covariant=True) + class NestedSequence(Protocol[_T_co]): - def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: ... - def __len__(self, /) -> int: ... + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: + ... + + def __len__(self, /) -> int: + ... -__all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', -'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', 'Sequence', -'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object', 'Enum'] +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", +] diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index ac6890f71..9aa7119d0 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -1,9 +1,20 @@ from __future__ import annotations -from ._types import (array, dtype as Dtype, device as Device, Optional, Tuple, - Union, Any, PyCapsule, Enum, ellipsis) - -class _array(): +from ._types import ( + array, + dtype as Dtype, + device as Device, + Optional, + Tuple, + Union, + Any, + PyCapsule, + Enum, + ellipsis, +) + + +class _array: def __init__(self) -> None: """ Initialize the attributes for the array object class. @@ -205,7 +216,9 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ - def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: + def __array_namespace__( + self: array, /, *, api_version: Optional[str] = None + ) -> Any: """ Returns an object that has all the array API functions on it. @@ -237,7 +250,9 @@ def __bool__(self: array, /) -> bool: a Python ``bool`` object representing the single element of the array. """ - def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: + def __dlpack__( + self: array, /, *, stream: Optional[Union[int, Any]] = None + ) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -435,7 +450,13 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. """ - def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: + def __getitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + /, + ) -> array: """ Returns ``self[key]``. @@ -877,7 +898,14 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ - def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: + def __setitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + value: Union[int, float, bool, array], + /, + ) -> None: """ Sets ``self[key]`` to ``value``. @@ -995,7 +1023,9 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ - def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: + def to_device( + self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None + ) -> array: """ Copy the array from the device on which it currently resides to the specified ``device``. @@ -1018,4 +1048,5 @@ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. """ + array = _array diff --git a/src/array_api_stubs/_2021_12/constants.py b/src/array_api_stubs/_2021_12/constants.py index 18c8ac761..c7aaddc5e 100644 --- a/src/array_api_stubs/_2021_12/constants.py +++ b/src/array_api_stubs/_2021_12/constants.py @@ -5,12 +5,12 @@ ``e = 2.71828182845904523536028747135266249775724709369995...`` """ -inf = float('inf') +inf = float("inf") """ IEEE 754 floating-point representation of (positive) infinity. """ -nan = float('nan') +nan = float("nan") """ IEEE 754 floating-point representation of Not a Number (``NaN``). """ @@ -27,4 +27,4 @@ ``pi = 3.1415926535897932384626433...`` """ -__all__ = ['e', 'inf', 'nan', 'newaxis', 'pi'] +__all__ = ["e", "inf", "nan", "newaxis", "pi"] diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index abfb38455..c7659d0df 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -1,7 +1,25 @@ -from ._types import (List, NestedSequence, Optional, SupportsBufferProtocol, Tuple, Union, array, - device, dtype) - -def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None, step: Union[int, float] = 1, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: +from ._types import ( + List, + NestedSequence, + Optional, + SupportsBufferProtocol, + Tuple, + Union, + array, + device, + dtype, +) + + +def arange( + start: Union[int, float], + /, + stop: Optional[Union[int, float]] = None, + step: Union[int, float] = 1, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. @@ -28,7 +46,15 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. """ -def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: + +def asarray( + obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], + /, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: r""" Convert the input to an array. @@ -70,7 +96,13 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr an array containing the data from ``obj``. """ -def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def empty( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns an uninitialized array having a specified `shape`. @@ -89,7 +121,10 @@ def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, an array containing uninitialized data. """ -def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def empty_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns an uninitialized array with the same ``shape`` as an input array ``x``. @@ -108,7 +143,16 @@ def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d an array having the same shape as ``x`` and containing uninitialized data. """ -def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def eye( + n_rows: int, + n_cols: Optional[int] = None, + /, + *, + k: int = 0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. @@ -131,6 +175,7 @@ def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Opti an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. """ + def from_dlpack(x: object, /) -> array: """ Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. @@ -151,7 +196,14 @@ def from_dlpack(x: object, /) -> array: The returned array may be either a copy or a view. See :ref:`data-interchange` for details. """ -def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def full( + shape: Union[int, Tuple[int, ...]], + fill_value: Union[int, float], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with ``fill_value``. @@ -176,7 +228,15 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d an array where every element is equal to ``fill_value``. """ -def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def full_like( + x: array, + /, + fill_value: Union[int, float], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. @@ -204,7 +264,17 @@ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dty an array having the same shape as ``x`` and where every element is equal to ``fill_value``. """ -def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, dtype: Optional[dtype] = None, device: Optional[device] = None, endpoint: bool = True) -> array: + +def linspace( + start: Union[int, float], + stop: Union[int, float], + /, + num: int, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + endpoint: bool = True, +) -> array: """ Returns evenly spaced numbers over a specified interval. @@ -240,7 +310,8 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. """ -def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: + +def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -266,7 +337,13 @@ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: Each returned array should have the same data type as the input arrays. """ -def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def ones( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with ones. @@ -285,7 +362,10 @@ def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, d an array containing ones. """ -def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def ones_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. @@ -304,6 +384,7 @@ def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[de an array having the same shape as ``x`` and filled with ones. """ + def tril(x: array, /, *, k: int = 0) -> array: """ Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. @@ -327,6 +408,7 @@ def tril(x: array, /, *, k: int = 0) -> array: an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. """ + def triu(x: array, /, *, k: int = 0) -> array: """ Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. @@ -350,7 +432,13 @@ def triu(x: array, /, *, k: int = 0) -> array: an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. """ -def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def zeros( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with zeros. @@ -369,7 +457,10 @@ def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, an array containing zeros. """ -def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def zeros_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. @@ -388,4 +479,22 @@ def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d an array having the same shape as ``x`` and filled with zeros. """ -__all__ = ['arange', 'asarray', 'empty', 'empty_like', 'eye', 'from_dlpack', 'full', 'full_like', 'linspace', 'meshgrid', 'ones', 'ones_like', 'tril', 'triu', 'zeros', 'zeros_like'] + +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] diff --git a/src/array_api_stubs/_2021_12/data_type_functions.py b/src/array_api_stubs/_2021_12/data_type_functions.py index 2356a8b2e..3567f783f 100644 --- a/src/array_api_stubs/_2021_12/data_type_functions.py +++ b/src/array_api_stubs/_2021_12/data_type_functions.py @@ -1,5 +1,6 @@ from ._types import List, Tuple, Union, array, dtype, finfo_object, iinfo_object + def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: """ Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. @@ -27,6 +28,7 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: an array having the specified data type. The returned array must have the same shape as ``x``. """ + def broadcast_arrays(*arrays: array) -> List[array]: """ Broadcasts one or more arrays against one another. @@ -42,6 +44,7 @@ def broadcast_arrays(*arrays: array) -> List[array]: a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. """ + def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: """ Broadcasts an array to a specified shape. @@ -59,6 +62,7 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: an array having a specified shape. Must have the same data type as ``x``. """ + def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: """ Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. @@ -76,6 +80,7 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. """ + def finfo(type: Union[dtype, array], /) -> finfo_object: """ Machine limits for floating-point data types. @@ -111,6 +116,7 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: smallest positive floating-point number with full precision. """ + def iinfo(type: Union[dtype, array], /) -> iinfo_object: """ Machine limits for integer data types. @@ -138,6 +144,7 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: smallest representable number. """ + def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: """ Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. @@ -156,4 +163,13 @@ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: the dtype resulting from an operation involving the input arrays and dtypes. """ -__all__ = ['astype', 'broadcast_arrays', 'broadcast_to', 'can_cast', 'finfo', 'iinfo', 'result_type'] + +__all__ = [ + "astype", + "broadcast_arrays", + "broadcast_to", + "can_cast", + "finfo", + "iinfo", + "result_type", +] diff --git a/src/array_api_stubs/_2021_12/data_types.py b/src/array_api_stubs/_2021_12/data_types.py index fd00521f1..9a0c24851 100644 --- a/src/array_api_stubs/_2021_12/data_types.py +++ b/src/array_api_stubs/_2021_12/data_types.py @@ -1,5 +1,6 @@ from ._types import dtype + def __eq__(self: dtype, other: dtype, /) -> bool: """ Computes the truth value of ``self == other`` in order to test for data type object equality. @@ -17,4 +18,5 @@ def __eq__(self: dtype, other: dtype, /) -> bool: a boolean indicating whether the data type objects are equal. """ + all = [__eq__] diff --git a/src/array_api_stubs/_2021_12/elementwise_functions.py b/src/array_api_stubs/_2021_12/elementwise_functions.py index bf831d304..2f4478aaa 100644 --- a/src/array_api_stubs/_2021_12/elementwise_functions.py +++ b/src/array_api_stubs/_2021_12/elementwise_functions.py @@ -1,5 +1,6 @@ from ._types import array + def abs(x: array, /) -> array: """ Calculates the absolute value for each element ``x_i`` of the input array ``x`` (i.e., the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign). @@ -26,6 +27,7 @@ def abs(x: array, /) -> array: an array containing the absolute value of each element in ``x``. The returned array must have the same data type as ``x``. """ + def acos(x: array, /) -> array: """ Calculates an implementation-dependent approximation of the principal value of the inverse cosine, having domain ``[-1, +1]`` and codomain ``[+0, +π]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. @@ -50,6 +52,7 @@ def acos(x: array, /) -> array: an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def acosh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the inverse hyperbolic cosine, having domain ``[+1, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -74,6 +77,7 @@ def acosh(x: array, /) -> array: an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def add(x1: array, x2: array, /) -> array: """ Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -116,6 +120,7 @@ def add(x1: array, x2: array, /) -> array: an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. """ + def asin(x: array, /) -> array: """ Calculates an implementation-dependent approximation of the principal value of the inverse sine, having domain ``[-1, +1]`` and codomain ``[-π/2, +π/2]`` for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. @@ -141,6 +146,7 @@ def asin(x: array, /) -> array: an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def asinh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the inverse hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. @@ -166,6 +172,7 @@ def asinh(x: array, /) -> array: an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def atan(x: array, /) -> array: """ Calculates an implementation-dependent approximation of the principal value of the inverse tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-π/2, +π/2]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. @@ -191,6 +198,7 @@ def atan(x: array, /) -> array: an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def atan2(x1: array, x2: array, /) -> array: """ Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. @@ -244,6 +252,7 @@ def atan2(x1: array, x2: array, /) -> array: """ + def atanh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the inverse hyperbolic tangent, having domain ``[-1, +1]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -271,6 +280,7 @@ def atanh(x: array, /) -> array: an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def bitwise_and(x1: array, x2: array, /) -> array: """ Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -288,6 +298,7 @@ def bitwise_and(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_left_shift(x1: array, x2: array, /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. @@ -305,6 +316,7 @@ def bitwise_left_shift(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_invert(x: array, /) -> array: """ Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. @@ -320,6 +332,7 @@ def bitwise_invert(x: array, /) -> array: an array containing the element-wise results. The returned array must have the same data type as ``x``. """ + def bitwise_or(x1: array, x2: array, /) -> array: """ Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -337,6 +350,7 @@ def bitwise_or(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_right_shift(x1: array, x2: array, /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. @@ -357,6 +371,7 @@ def bitwise_right_shift(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_xor(x1: array, x2: array, /) -> array: """ Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -374,6 +389,7 @@ def bitwise_xor(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def ceil(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. @@ -401,6 +417,7 @@ def ceil(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def cos(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the cosine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. @@ -426,6 +443,7 @@ def cos(x: array, /) -> array: an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def cosh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the hyperbolic cosine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. @@ -451,6 +469,7 @@ def cosh(x: array, /) -> array: an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def divide(x1: array, x2: array, /) -> array: """ Calculates the division for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -500,6 +519,7 @@ def divide(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -517,6 +537,7 @@ def equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def exp(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the exponential function, having domain ``[-infinity, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). @@ -542,6 +563,7 @@ def exp(x: array, /) -> array: an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def expm1(x: array, /) -> array: """ Calculates an implementation-dependent approximation to ``exp(x)-1``, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -570,6 +592,7 @@ def expm1(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def floor(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. @@ -597,6 +620,7 @@ def floor(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def floor_divide(x1: array, x2: array, /) -> array: r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. @@ -653,6 +677,7 @@ def floor_divide(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def greater(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -670,6 +695,7 @@ def greater(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def greater_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -687,6 +713,7 @@ def greater_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def isfinite(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if finite (i.e., not ``NaN`` and not equal to positive or negative infinity). @@ -702,6 +729,7 @@ def isfinite(x: array, /) -> array: an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is finite and ``False`` otherwise. The returned array must have a data type of ``bool``. """ + def isinf(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. @@ -717,6 +745,7 @@ def isinf(x: array, /) -> array: an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is either positive or negative infinity and ``False`` otherwise. The returned array must have a data type of ``bool``. """ + def isnan(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. @@ -732,6 +761,7 @@ def isnan(x: array, /) -> array: an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is ``NaN`` and ``False`` otherwise. The returned array should have a data type of ``bool``. """ + def less(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -749,6 +779,7 @@ def less(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def less_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -766,6 +797,7 @@ def less_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def log(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -791,6 +823,7 @@ def log(x: array, /) -> array: an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log1p(x: array, /) -> array: """ Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, having domain ``[-1, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -820,6 +853,7 @@ def log1p(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log2(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the base ``2`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -845,6 +879,7 @@ def log2(x: array, /) -> array: an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log10(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the base ``10`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -870,6 +905,7 @@ def log10(x: array, /) -> array: an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def logaddexp(x1: array, x2: array, /) -> array: """ Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -895,6 +931,7 @@ def logaddexp(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def logical_and(x1: array, x2: array, /) -> array: """ Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -915,6 +952,7 @@ def logical_and(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of `bool`. """ + def logical_not(x: array, /) -> array: """ Computes the logical NOT for each element ``x_i`` of the input array ``x``. @@ -933,6 +971,7 @@ def logical_not(x: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def logical_or(x1: array, x2: array, /) -> array: """ Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -953,6 +992,7 @@ def logical_or(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def logical_xor(x1: array, x2: array, /) -> array: """ Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -973,6 +1013,7 @@ def logical_xor(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def multiply(x1: array, x2: array, /) -> array: """ Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1007,6 +1048,7 @@ def multiply(x1: array, x2: array, /) -> array: an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. """ + def negative(x: array, /) -> array: """ Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. @@ -1025,6 +1067,7 @@ def negative(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def not_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1042,6 +1085,7 @@ def not_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def positive(x: array, /) -> array: """ Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. @@ -1057,6 +1101,7 @@ def positive(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def pow(x1: array, x2: array, /) -> array: """ Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. @@ -1108,6 +1153,7 @@ def pow(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def remainder(x1: array, x2: array, /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. @@ -1159,6 +1205,7 @@ def remainder(x1: array, x2: array, /) -> array: an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def round(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. @@ -1187,6 +1234,7 @@ def round(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def sign(x: array, /) -> array: """ Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. @@ -1208,6 +1256,7 @@ def sign(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def sin(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the sine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. @@ -1232,6 +1281,7 @@ def sin(x: array, /) -> array: an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def sinh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -1257,6 +1307,7 @@ def sinh(x: array, /) -> array: an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def square(x: array, /) -> array: """ Squares (``x_i * x_i``) each element ``x_i`` of the input array ``x``. @@ -1272,6 +1323,7 @@ def square(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def sqrt(x: array, /) -> array: """ Calculates the square root, having domain ``[0, +infinity]`` and codomain ``[0, +infinity]``, for each element ``x_i`` of the input array ``x``. After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). @@ -1297,6 +1349,7 @@ def sqrt(x: array, /) -> array: an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def subtract(x1: array, x2: array, /) -> array: """ Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). @@ -1314,6 +1367,7 @@ def subtract(x1: array, x2: array, /) -> array: an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. """ + def tan(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the tangent, having domain ``(-infinity, +infinity)`` and codomain ``(-infinity, +infinity)``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. @@ -1338,6 +1392,7 @@ def tan(x: array, /) -> array: an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def tanh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the hyperbolic tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. @@ -1363,6 +1418,7 @@ def tanh(x: array, /) -> array: an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def trunc(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the integer-valued number that is closest to but no greater than ``x_i``. @@ -1390,4 +1446,62 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] + +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "remainder", + "round", + "sign", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 6a0348129..4e4ba52b2 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -1,6 +1,7 @@ from ._types import Literal, Optional, Tuple, Union, Sequence, array from .constants import inf + def cholesky(x: array, /, *, upper: bool = False) -> array: """ Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symmetric positive-definite matrix (or a stack of matrices) ``x``, where ``L`` is a lower-triangular matrix or a stack of matrices (``U`` is an upper-triangular matrix or a stack of matrices). @@ -24,6 +25,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ + def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Returns the cross product of 3-element vectors. If ``x1`` and ``x2`` are multi-dimensional arrays (i.e., both have a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. @@ -43,6 +45,7 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. """ + def det(x: array, /) -> array: """ Returns the determinant of a square matrix (or a stack of square matrices) ``x``. @@ -58,6 +61,7 @@ def det(x: array, /) -> array: if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. """ + def diagonal(x: array, /, *, offset: int = 0) -> array: """ Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. @@ -81,6 +85,7 @@ def diagonal(x: array, /, *, offset: int = 0) -> array: an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. """ + def eigh(x: array, /) -> Tuple[array]: """ Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) ``x``, where ``Q`` is an orthogonal matrix (or a stack of matrices) and ``L`` is a vector (or a stack of vectors). @@ -113,6 +118,7 @@ def eigh(x: array, /) -> Tuple[array]: Eigenvalue sort order is left unspecified and is thus implementation-dependent. """ + def eigvalsh(x: array, /) -> array: """ Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) ``x``. @@ -140,6 +146,7 @@ def eigvalsh(x: array, /) -> array: Eigenvalue sort order is left unspecified and is thus implementation-dependent. """ + def inv(x: array, /) -> array: """ Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. @@ -155,12 +162,20 @@ def inv(x: array, /) -> array: an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ + def matmul(x1: array, x2: array, /) -> array: """ Alias for :func:`~array_api.matmul`. """ -def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: + +def matrix_norm( + x: array, + /, + *, + keepdims: bool = False, + ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro", +) -> array: """ Computes the matrix norm of a matrix (or a stack of matrices) ``x``. @@ -213,6 +228,7 @@ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def matrix_power(x: array, n: int, /) -> array: """ Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. @@ -230,6 +246,7 @@ def matrix_power(x: array, n: int, /) -> array: if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. """ + def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: """ Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). @@ -247,11 +264,13 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a an array containing the ranks. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). """ + def matrix_transpose(x: array, /) -> array: """ Alias for :func:`~array_api.matrix_transpose`. """ + def outer(x1: array, x2: array, /) -> array: """ Returns the outer product of two vectors ``x1`` and ``x2``. @@ -269,6 +288,7 @@ def outer(x1: array, x2: array, /) -> array: a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: """ Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. @@ -286,7 +306,10 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: an array containing the pseudo-inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). """ -def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tuple[array, array]: + +def qr( + x: array, /, *, mode: Literal["reduced", "complete"] = "reduced" +) -> Tuple[array, array]: """ Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where ``Q`` is an orthonormal matrix (or a stack of matrices) and ``R`` is an upper-triangular matrix (or a stack of matrices). @@ -316,6 +339,7 @@ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tupl Each returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def slogdet(x: array, /) -> Tuple[array, array]: """ Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. @@ -344,6 +368,7 @@ def slogdet(x: array, /) -> Tuple[array, array]: If a determinant is zero, then the corresponding ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to ``sign * exp(logsabsdet)`` (although, again, the result may be subject to numerical precision errors). """ + def solve(x1: array, x2: array, /) -> array: """ Returns the solution to the system of linear equations represented by the well-determined (i.e., full rank) linear matrix equation ``AX = B``. @@ -364,6 +389,7 @@ def solve(x1: array, x2: array, /) -> array: an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. """ + def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: """ Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) ``x``, where ``U`` is a matrix (or a stack of matrices) with orthonormal columns, ``S`` is a vector of non-negative numbers (or stack of vectors), and ``Vh`` is a matrix (or a stack of matrices) with orthonormal rows. @@ -389,6 +415,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array Each returned array must have the same floating-point data type as ``x``. """ + def svdvals(x: array, /) -> array: """ Returns the singular values of a matrix (or a stack of matrices) ``x``. @@ -404,11 +431,19 @@ def svdvals(x: array, /) -> array: an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have the same floating-point data type as ``x``. """ -def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: """ Alias for :func:`~array_api.tensordot`. """ + def trace(x: array, /, *, offset: int = 0) -> array: """ Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. @@ -438,12 +473,21 @@ def trace(x: array, /, *, offset: int = 0) -> array: The returned array must have the same data type as ``x``. """ + def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ Alias for :func:`~array_api.vecdot`. """ -def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: + +def vector_norm( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, + ord: Union[int, float, Literal[inf, -inf]] = 2, +) -> array: r""" Computes the vector norm of a vector (or batch of vectors) ``x``. @@ -494,4 +538,29 @@ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = No an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ -__all__ = ['cholesky', 'cross', 'det', 'diagonal', 'eigh', 'eigvalsh', 'inv', 'matmul', 'matrix_norm', 'matrix_power', 'matrix_rank', 'matrix_transpose', 'outer', 'pinv', 'qr', 'slogdet', 'solve', 'svd', 'svdvals', 'tensordot', 'trace', 'vecdot', 'vector_norm'] + +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] diff --git a/src/array_api_stubs/_2021_12/linear_algebra_functions.py b/src/array_api_stubs/_2021_12/linear_algebra_functions.py index a2defaf1b..0b5cbfdb7 100644 --- a/src/array_api_stubs/_2021_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2021_12/linear_algebra_functions.py @@ -1,5 +1,6 @@ from ._types import Tuple, Union, Sequence, array + def matmul(x1: array, x2: array, /) -> array: """ Computes the matrix product. @@ -37,6 +38,7 @@ def matmul(x1: array, x2: array, /) -> array: - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. """ + def matrix_transpose(x: array, /) -> array: """ Transposes a matrix (or a stack of matrices) ``x``. @@ -52,7 +54,14 @@ def matrix_transpose(x: array, /) -> array: an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. """ -def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: """ Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. @@ -83,6 +92,7 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Computes the (vector) dot product of two arrays. @@ -108,4 +118,5 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: - if the size of the axis over which to compute the dot product is not the same for both ``x1`` and ``x2``. """ -__all__ = ['matmul', 'matrix_transpose', 'tensordot', 'vecdot'] + +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] diff --git a/src/array_api_stubs/_2021_12/manipulation_functions.py b/src/array_api_stubs/_2021_12/manipulation_functions.py index 64c05db35..8ae359a3a 100644 --- a/src/array_api_stubs/_2021_12/manipulation_functions.py +++ b/src/array_api_stubs/_2021_12/manipulation_functions.py @@ -1,6 +1,9 @@ from ._types import List, Optional, Tuple, Union, array -def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0) -> array: + +def concat( + arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0 +) -> array: """ Joins a sequence of arrays along an existing axis. @@ -20,6 +23,7 @@ def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[i This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. """ + def expand_dims(x: array, /, *, axis: int = 0) -> array: """ Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. @@ -37,6 +41,7 @@ def expand_dims(x: array, /, *, axis: int = 0) -> array: an expanded output array having the same data type as ``x``. """ + def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: """ Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. @@ -54,6 +59,7 @@ def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. """ + def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: """ Permutes the axes (dimensions) of an array ``x``. @@ -71,7 +77,10 @@ def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: an array containing the axes permutation. The returned array must have the same data type as ``x``. """ -def reshape(x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None) -> array: + +def reshape( + x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None +) -> array: """ Reshapes an array without changing its data. @@ -90,7 +99,14 @@ def reshape(x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None) an output array having the same data type and elements as ``x``. """ -def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + +def roll( + x: array, + /, + shift: Union[int, Tuple[int, ...]], + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, +) -> array: """ Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. @@ -109,6 +125,7 @@ def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Unio an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. """ + def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: """ Removes singleton dimensions (axes) from ``x``. @@ -126,6 +143,7 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: an output array having the same data type and elements as ``x``. """ + def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: """ Joins a sequence of arrays along a new axis. @@ -146,4 +164,14 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. """ -__all__ = ['concat', 'expand_dims', 'flip', 'permute_dims', 'reshape', 'roll', 'squeeze', 'stack'] \ No newline at end of file + +__all__ = [ + "concat", + "expand_dims", + "flip", + "permute_dims", + "reshape", + "roll", + "squeeze", + "stack", +] diff --git a/src/array_api_stubs/_2021_12/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py index c2875adcc..14ebdd889 100644 --- a/src/array_api_stubs/_2021_12/searching_functions.py +++ b/src/array_api_stubs/_2021_12/searching_functions.py @@ -1,5 +1,6 @@ from ._types import Optional, Tuple, array + def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ Returns the indices of the maximum values along a specified axis. When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. @@ -19,6 +20,7 @@ def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. """ + def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ Returns the indices of the minimum values along a specified axis. When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. @@ -38,6 +40,7 @@ def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. """ + def nonzero(x: array, /) -> Tuple[array, ...]: """ Returns the indices of the array elements which are non-zero. @@ -58,6 +61,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. """ + def where(condition: array, x1: array, x2: array, /) -> array: """ Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. @@ -77,4 +81,5 @@ def where(condition: array, x1: array, x2: array, /) -> array: an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. """ -__all__ = ['argmax', 'argmin', 'nonzero', 'where'] + +__all__ = ["argmax", "argmin", "nonzero", "where"] diff --git a/src/array_api_stubs/_2021_12/set_functions.py b/src/array_api_stubs/_2021_12/set_functions.py index bd24e5323..eb5c1d951 100644 --- a/src/array_api_stubs/_2021_12/set_functions.py +++ b/src/array_api_stubs/_2021_12/set_functions.py @@ -1,5 +1,6 @@ from ._types import Tuple, array + def unique_all(x: array, /) -> Tuple[array, array, array, array]: """ Returns the unique elements of an input array ``x``, the first occurring indices for each unique element in ``x``, the indices from the set of unique elements that reconstruct ``x``, and the corresponding counts for each unique element in ``x``. @@ -39,6 +40,7 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_counts(x: array, /) -> Tuple[array, array]: """ Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. @@ -73,6 +75,7 @@ def unique_counts(x: array, /) -> Tuple[array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_inverse(x: array, /) -> Tuple[array, array]: """ Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. @@ -107,6 +110,7 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_values(x: array, /) -> array: """ Returns the unique elements of an input array ``x``. @@ -136,4 +140,5 @@ def unique_values(x: array, /) -> array: The order of unique elements is not specified and may vary between implementations. """ -__all__ = ['unique_all', 'unique_counts', 'unique_inverse', 'unique_values'] \ No newline at end of file + +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] diff --git a/src/array_api_stubs/_2021_12/sorting_functions.py b/src/array_api_stubs/_2021_12/sorting_functions.py index 715a3e817..59d3a3c68 100644 --- a/src/array_api_stubs/_2021_12/sorting_functions.py +++ b/src/array_api_stubs/_2021_12/sorting_functions.py @@ -1,6 +1,9 @@ from ._types import array -def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + +def argsort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: """ Returns the indices that sort an array ``x`` along a specified axis. @@ -21,7 +24,10 @@ def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bo an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. """ -def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + +def sort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: """ Returns a sorted copy of an input array ``x``. @@ -42,4 +48,5 @@ def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool a sorted array. The returned array must have the same data type and shape as ``x``. """ -__all__ = ['argsort', 'sort'] \ No newline at end of file + +__all__ = ["argsort", "sort"] diff --git a/src/array_api_stubs/_2021_12/statistical_functions.py b/src/array_api_stubs/_2021_12/statistical_functions.py index 4265f28f5..a436535f7 100644 --- a/src/array_api_stubs/_2021_12/statistical_functions.py +++ b/src/array_api_stubs/_2021_12/statistical_functions.py @@ -1,6 +1,13 @@ from ._types import Optional, Tuple, Union, array, dtype -def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def max( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the maximum value of the input array ``x``. @@ -28,7 +35,14 @@ def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. """ -def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def mean( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the arithmetic mean of the input array ``x``. @@ -57,7 +71,14 @@ def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, kee While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. """ -def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def min( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the minimum value of the input array ``x``. @@ -85,7 +106,15 @@ def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. """ -def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + +def prod( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: """ Calculates the product of input array ``x`` elements. @@ -127,7 +156,15 @@ def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dty if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. """ -def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + +def std( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: """ Calculates the standard deviation of the input array ``x``. @@ -158,7 +195,15 @@ def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. """ -def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + +def sum( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: """ Calculates the sum of the input array ``x``. @@ -200,7 +245,15 @@ def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtyp if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. """ -def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + +def var( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: """ Calculates the variance of the input array ``x``. @@ -232,4 +285,5 @@ def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. """ -__all__ = ['max', 'mean', 'min', 'prod', 'std', 'sum', 'var'] + +__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] diff --git a/src/array_api_stubs/_2021_12/utility_functions.py b/src/array_api_stubs/_2021_12/utility_functions.py index 79423f455..847182abd 100644 --- a/src/array_api_stubs/_2021_12/utility_functions.py +++ b/src/array_api_stubs/_2021_12/utility_functions.py @@ -1,6 +1,13 @@ from ._types import Optional, Tuple, Union, array -def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def all( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Tests whether all input array elements evaluate to ``True`` along a specified axis. @@ -25,7 +32,14 @@ def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. """ -def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def any( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Tests whether any input array element evaluates to ``True`` along a specified axis. @@ -50,4 +64,5 @@ def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. """ -__all__ = ['all', 'any'] + +__all__ = ["all", "any"] diff --git a/src/array_api_stubs/_2022_12/_types.py b/src/array_api_stubs/_2022_12/_types.py index 589606784..837a7806f 100644 --- a/src/array_api_stubs/_2022_12/_types.py +++ b/src/array_api_stubs/_2022_12/_types.py @@ -34,6 +34,7 @@ @dataclass class finfo_object: """Dataclass returned by `finfo`.""" + bits: int eps: float max: float @@ -41,14 +42,17 @@ class finfo_object: smallest_normal: float dtype: dtype + @dataclass class iinfo_object: """Dataclass returned by `iinfo`.""" + bits: int max: int min: int dtype: dtype + _T_co = TypeVar("_T_co", covariant=True) From 9dbdec0656c89e41ccbcc1d82723f293bcb8ff9f Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 15 Sep 2023 14:38:51 +0200 Subject: [PATCH 091/196] Add a git-blame-ignore-revs entry for style changes in previous commit --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 4fd6df5d4..3d9e87daa 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,5 +1,6 @@ # Migrate code style to Black 162034b12711dad54589c5dc9e75942695a7957f +678f9eab5a593005e7bb80a46156c27b210cfcea # Move special cases to notes sections 816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 From 149d340c77e3166a9e60a7ff75621769818780ca Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Tue, 19 Sep 2023 14:38:12 -0700 Subject: [PATCH 092/196] Fix lint error --- src/array_api_stubs/_draft/manipulation_functions.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2b6689647..4c2a4ab4a 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -115,7 +115,12 @@ def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> """ -def moveaxis(x: array, source: Union[int, Tuple[int, ...]], destination: Union[int, Tuple[int, ...]], /) -> array: +def moveaxis( + x: array, + source: Union[int, Tuple[int, ...]], + destination: Union[int, Tuple[int, ...]], + / +) -> array: """ Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. From f05c22fb42bd3c69b1589ef9c7162ebf33a12d09 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Tue, 19 Sep 2023 14:44:54 -0700 Subject: [PATCH 093/196] Fix index range --- src/array_api_stubs/_draft/manipulation_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 4c2a4ab4a..4bfeb1caa 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -129,9 +129,9 @@ def moveaxis( x: array input array. source: Union[int, Tuple[int, ...]] - Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. destination: Union[int, Tuple[int, ...]] - indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. Returns ------- From 8149b33b51bf2d7064bd72731d99ccc31e9cc265 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Tue, 19 Sep 2023 14:45:49 -0700 Subject: [PATCH 094/196] Fix lint error --- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 4bfeb1caa..2bc929134 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -119,7 +119,7 @@ def moveaxis( x: array, source: Union[int, Tuple[int, ...]], destination: Union[int, Tuple[int, ...]], - / + /, ) -> array: """ Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. From f7aa6805f598b810e596e296a1c0d5d4e51b70f9 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:12:28 -0700 Subject: [PATCH 095/196] Revert removed exported symbols --- src/array_api_stubs/_draft/data_type_functions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 8243d7986..2301fc196 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -1,3 +1,5 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + from ._types import ( Union, Tuple, From 430c96751b59ff33c3825b859f473ad1a3bbf58d Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:14:34 -0700 Subject: [PATCH 096/196] Update copy --- src/array_api_stubs/_draft/data_type_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 2301fc196..0f089c889 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -46,7 +46,7 @@ def astype( copy: bool specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. device: Optional[device] - device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. Returns ------- From c33c508114e0f846d6ede134bf679ad88e0ef5ca Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:16:51 -0700 Subject: [PATCH 097/196] Fix lint error --- src/array_api_stubs/_draft/data_type_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 0f089c889..11533f7f2 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -8,7 +8,7 @@ finfo_object, iinfo_object, device, - Optional + Optional, ) From 1c6c73c29a45eba6963981a77324c3dce66b16f4 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:18:14 -0700 Subject: [PATCH 098/196] Fix lint error --- src/array_api_stubs/_draft/data_type_functions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 11533f7f2..81d518807 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -13,8 +13,7 @@ def astype( - x: array, dtype: dtype, /, *, copy: bool = True, - device: Optional[device] = None + x: array, dtype: dtype, /, *, copy: bool = True, device: Optional[device] = None ) -> array: """ Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. From 8c42f02add07e6f4423335a4c71dd7f91b37cf84 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 19 Sep 2023 19:29:13 -0500 Subject: [PATCH 099/196] Allow negative axes in tensordot PR-URL: https://github.com/data-apis/array-api/pull/625 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/linear_algebra_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index a6f84e392..079a90ee6 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -92,7 +92,7 @@ def tensordot( Contracted axes (dimensions) must not be broadcasted. axes: Union[int, Tuple[Sequence[int], Sequence[int]]] - number of axes (dimensions) to contract or explicit sequences of axes (dimensions) for ``x1`` and ``x2``, respectively. + number of axes (dimensions) to contract or explicit sequences of axis (dimension) indices for ``x1`` and ``x2``, respectively. If ``axes`` is an ``int`` equal to ``N``, then contraction must be performed over the last ``N`` axes of ``x1`` and the first ``N`` axes of ``x2`` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. @@ -100,7 +100,7 @@ def tensordot( - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each index referred to in a sequence must be unique. If ``x1`` has rank (i.e, number of dimensions) ``N``, a valid ``x1`` axis must reside on the half-open interval ``[-N, N)``. If ``x2`` has rank ``M``, a valid ``x2`` axis must reside on the half-open interval ``[-M, M)``. .. note:: From 03886d61efdd0cb11302da8043d0aa65b3c03bbf Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Oct 2023 16:44:46 -0700 Subject: [PATCH 100/196] Add support for `copysign` to the specification PR-URL: https://github.com/data-apis/array-api/pull/693 --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 0e5fd0609..8048eb38a 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -34,6 +34,7 @@ Objects in API bitwise_xor ceil conj + copysign cos cosh divide diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 147eff9cd..faaa9213b 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -16,6 +16,7 @@ "bitwise_xor", "ceil", "conj", + "copysign", "cos", "cosh", "divide", @@ -804,6 +805,47 @@ def conj(x: array, /) -> array: """ +def copysign(x1: array, x2: array, /) -> array: + r""" + Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. + + Parameters + ---------- + x1: array + input array containing magnitudes. Should have a real-valued floating-point data type. + x2: array + input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``-0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``+0``, the result is ``|x1_i|``. + - If ``x2_i`` is greater than ``0``, the result is ``|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. + + If ``x1_i`` is ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + """ + + def cos(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. From 2bcf7c048f9f38f1529beddf7a6c0a9627cd5cfe Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Oct 2023 19:01:48 -0700 Subject: [PATCH 101/196] Add support for tiling an array to the specification PR-URL: https://github.com/data-apis/array-api/pull/692 Co-authored-by: Oleksandr Pavlyk --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index 7eb7fa8b0..680efb55f 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -29,4 +29,5 @@ Objects in API roll squeeze stack + tile unstack diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2bc929134..74538a8a3 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -10,6 +10,7 @@ "roll", "squeeze", "stack", + "tile", "unstack", ] @@ -257,6 +258,30 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ +def tile(x: array, repetitions: Tuple[int, ...], /): + """ + Constructs an array by tiling an input array. + + Parameters + ---------- + x: array + input array. + repetitions: Tuple[int, ...] + number of repetitions along each axis (dimension). + + Let ``N = len(x.shape)`` and ``M = len(repetitions)``. + + If ``N > M``, the function must prepend ones until all axes (dimensions) are specified (e.g., if ``x`` has shape ``(8,6,4,2)`` and ``repetitions`` is the tuple ``(3,3)``, then ``repetitions`` must be treated as ``(1,1,3,3)``). + + If ``N < M``, the function must prepend singleton axes (dimensions) to ``x`` until ``x`` has as many axes (dimensions) as ``repetitions`` specifies (e.g., if ``x`` has shape ``(4,2)`` and ``repetitions`` is the tuple ``(3,3,3,3)``, then ``x`` must be treated as if it has shape ``(1,1,4,2)``). + + Returns + ------- + out: array + a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + """ + + def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: """ Splits an array in a sequence of arrays along the given axis. From 0f64005c7af6cc1906f310e929d0b8fcac24fd41 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 5 Nov 2023 20:23:35 -0800 Subject: [PATCH 102/196] Backport type fixes to `__getitem__` to previous specification revisions PR-URL: https://github.com/data-apis/array-api/pull/687 Reviewed-by: Matthew Barber Ref: https://github.com/data-apis/array-api/pull/674 --- spec/draft/API_specification/indexing.rst | 3 +++ src/array_api_stubs/_2021_12/array_object.py | 9 +++++++-- src/array_api_stubs/_2022_12/array_object.py | 9 +++++++-- src/array_api_stubs/_draft/array_object.py | 9 +++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/spec/draft/API_specification/indexing.rst b/spec/draft/API_specification/indexing.rst index 6d5e77a5b..eb61c26d5 100644 --- a/spec/draft/API_specification/indexing.rst +++ b/spec/draft/API_specification/indexing.rst @@ -156,6 +156,9 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult .. note:: Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. + .. note:: + The constant ``newaxis`` is an alias of ``None`` and can thus be used in a similar manner as ``None``. + - Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. .. note:: diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index 9aa7119d0..528e0a286 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -453,7 +453,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, ], /, ) -> array: @@ -464,7 +469,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index 6cac6033d..b8f703996 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -477,7 +477,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, ], /, ) -> array: @@ -488,7 +493,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 2976b46b2..e934c0bec 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -479,7 +479,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, ], /, ) -> array: @@ -490,7 +495,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns From ab69aa240025ff1d52525ce3859b69ebfd6b7faf Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 16 Nov 2023 06:07:50 -0800 Subject: [PATCH 103/196] fix: correct typo in data type (#706) --- src/array_api_stubs/_2022_12/elementwise_functions.py | 2 +- src/array_api_stubs/_draft/elementwise_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index 28768e9d9..9139612e8 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -727,7 +727,7 @@ def conj(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex-floating point data type. + input array. Should have a complex floating-point data type. Returns ------- diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index faaa9213b..e3988a09f 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -791,7 +791,7 @@ def conj(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex-floating point data type. + input array. Should have a complex floating-point data type. Returns ------- From 267a41ce079481e25e4a8d3634184d636ea379b9 Mon Sep 17 00:00:00 2001 From: Christian Bourjau Date: Thu, 16 Nov 2023 16:31:43 +0100 Subject: [PATCH 104/196] Allow lazy implementations to raise from intrinsically eager functions (#652) --- src/array_api_stubs/_draft/array_object.py | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index e934c0bec..03d62590d 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -241,6 +241,10 @@ def __bool__(self: array, /) -> bool: For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + **Lazy implementations** + + The Python language requires the return value to be of type ``bool``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionchanged:: 2022.12 Added boolean and complex data type support. """ @@ -276,6 +280,10 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. - If ``self`` is a finite number, the result is ``self + 0j``. + **Lazy implementations** + + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionadded:: 2022.12 """ @@ -424,6 +432,10 @@ def __float__(self: array, /) -> float: - If ``self`` is ``True``, the result is ``1``. - If ``self`` is ``False``, the result is ``0``. + **Lazy implementations** + + The Python language requires the return value to be of type ``float``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionchanged:: 2022.12 Added boolean and complex data type support. """ @@ -544,6 +556,13 @@ def __index__(self: array, /) -> int: ------- out: int a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. """ def __int__(self: array, /) -> int: @@ -582,6 +601,13 @@ def __int__(self: array, /) -> int: - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. - If ``self`` is ``NaN``, raise ``ValueError``. + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionchanged:: 2022.12 Added boolean and complex data type support. """ From bbb40017c3c51fe9237c794424e889e21a325486 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 16 Nov 2023 17:42:16 +0100 Subject: [PATCH 105/196] Fix a minor formatting issue that `black` is unhappy about --- src/array_api_stubs/_draft/array_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 03d62590d..600e947e0 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -282,7 +282,7 @@ def __complex__(self: array, /) -> complex: **Lazy implementations** - The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. .. versionadded:: 2022.12 """ From 200d016ca8a61997f0da2f657cd4560ac098249d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 27 Nov 2023 10:56:46 +0100 Subject: [PATCH 106/196] Add a design topic page on lazy vs. eager implementations (#708) Follow-up to gh-652, which added notes to the specifications for `__bool__` & co on this topic. --- spec/draft/design_topics/index.rst | 1 + spec/draft/design_topics/lazy_eager.rst | 43 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 spec/draft/design_topics/lazy_eager.rst diff --git a/spec/draft/design_topics/index.rst b/spec/draft/design_topics/index.rst index fa26359a7..548eda90c 100644 --- a/spec/draft/design_topics/index.rst +++ b/spec/draft/design_topics/index.rst @@ -7,6 +7,7 @@ Design topics & constraints copies_views_and_mutation data_dependent_output_shapes + lazy_eager data_interchange device_support static_typing diff --git a/spec/draft/design_topics/lazy_eager.rst b/spec/draft/design_topics/lazy_eager.rst new file mode 100644 index 000000000..63297ac73 --- /dev/null +++ b/spec/draft/design_topics/lazy_eager.rst @@ -0,0 +1,43 @@ +.. _lazy-eager: + +Lazy vs. eager execution +======================== + +While the execution model for implementations is out of scope of this standard, +there are a few aspects of lazy (or graph-based) execution as contrasted to +eager execution that may have an impact on the prescribed semantics of +individual APIs, and will therefore show up in the API specification. + +One important difference is data-dependent or value-dependent behavior, as +described in :ref:`data-dependent-output-shapes`. Because such behavior is hard +to implement, implementers may choose to omit such APIs from their library. + +Another difference is when the Python language itself prescribes that a +specific type *must* be returned. For those cases, it is not possible to return +a lazy/delayed kind of object to avoid computing a value. This is the case for +five dunder methods: `__bool__`, `__int__`, `__float__`, `__complex__` and +`__index__`. Each implementation has only two choices when one of these methods +is called: + +1. Compute a value of the required type (a Python scalar of type `bool`, `int`, + `float` or `complex`), or +2. Raise an exception. + +When an implementation is 100% lazy, for example when it serializes a +computation graph, computing the value is not possible and hence such an +implementation has no choice but to raise an exception. For a "mostly lazy" +implementation, it may make sense to trigger execution instead - but it is not +required to, both choices are valid. + +A common code construct where this happens is conditional logic, e.g.:: + + vals = compute_something() + if all(vals): + # The if-statement will make Python call the __bool__ method + # on the result of `all(vals)`. + do_something_else() + +Note that the API does not contain control flow constructs, as of now, that +would allow avoiding the implicit `__bool__` call in the example above. The +only control flow-like function is `where`, but there's no function like `cond` +to replace an `if`-statement. From 5555d41466d8f326ba550ba293ab94fdefeae9ab Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 29 Nov 2023 21:20:16 -0800 Subject: [PATCH 107/196] Revise guidance to require a minimum upper bound for supported ranks PR-URL: https://github.com/data-apis/array-api/pull/702 Reviewed-by: Ralf Gommers Reviewed-by: Leo Fang --- spec/draft/API_specification/array_object.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/draft/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst index b15bbdc43..0fadf9fc5 100644 --- a/spec/draft/API_specification/array_object.rst +++ b/spec/draft/API_specification/array_object.rst @@ -7,7 +7,7 @@ Array object A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods. -Furthermore, a conforming implementation of the array API standard must support array objects of arbitrary rank ``N`` (i.e., number of dimensions), where ``N`` is greater than or equal to zero. +Furthermore, a conforming implementation of the array API standard must support, at minimum, array objects of rank (i.e., number of dimensions) ``0``, ``1``, ``2``, ``3``, and ``4`` and must explicitly document their maximum supported rank ``N``. .. note:: Conforming implementations must support zero-dimensional arrays. From f5d83044b3b6fcc96baeec24a99aacec8b1600d7 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 30 Nov 2023 02:02:50 -0800 Subject: [PATCH 108/196] Remove outdated content from Purpose and Scope document (#714) * Remove outdated content from Purpose and Scope document * Fix typo * Backport content updates to the 2022 revision --- spec/2022.12/purpose_and_scope.md | 7 +++---- spec/draft/purpose_and_scope.md | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/2022.12/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md index eee3c7f4c..38287f270 100644 --- a/spec/2022.12/purpose_and_scope.md +++ b/spec/2022.12/purpose_and_scope.md @@ -144,7 +144,7 @@ standard is shown in this diagram: _Rationale: execution is the domain of implementations. Attempting to specify execution behavior in a standard is likely to require much more fine-grained coordination between developers of implementations, and hence is likely to - become an obstable to adoption._ + become an obstacle to adoption._ 3. Non-Python API standardization (e.g., Cython or NumPy C APIs) @@ -153,14 +153,13 @@ standard is shown in this diagram: this point in time to standardize anything. See the [C API section](design_topics/C_API.md) for more details._ -4. Standardization of these dtypes is out of scope: bfloat16, complex, extended +4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. _Rationale: these dtypes aren't uniformly supported, and their inclusion at this point in time could put a significant implementation burden on libraries. It is expected that some of these dtypes - in particular - `bfloat16`, `complex64`, and `complex128` - will be included in a future - version of the standard._ + `bfloat16` - will be included in a future version of the standard._ 5. The following topics are out of scope: I/O, polynomials, error handling, testing routines, building and packaging related functionality, methods of diff --git a/spec/draft/purpose_and_scope.md b/spec/draft/purpose_and_scope.md index eee3c7f4c..38287f270 100644 --- a/spec/draft/purpose_and_scope.md +++ b/spec/draft/purpose_and_scope.md @@ -144,7 +144,7 @@ standard is shown in this diagram: _Rationale: execution is the domain of implementations. Attempting to specify execution behavior in a standard is likely to require much more fine-grained coordination between developers of implementations, and hence is likely to - become an obstable to adoption._ + become an obstacle to adoption._ 3. Non-Python API standardization (e.g., Cython or NumPy C APIs) @@ -153,14 +153,13 @@ standard is shown in this diagram: this point in time to standardize anything. See the [C API section](design_topics/C_API.md) for more details._ -4. Standardization of these dtypes is out of scope: bfloat16, complex, extended +4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. _Rationale: these dtypes aren't uniformly supported, and their inclusion at this point in time could put a significant implementation burden on libraries. It is expected that some of these dtypes - in particular - `bfloat16`, `complex64`, and `complex128` - will be included in a future - version of the standard._ + `bfloat16` - will be included in a future version of the standard._ 5. The following topics are out of scope: I/O, polynomials, error handling, testing routines, building and packaging related functionality, methods of From 5a145340fbe17b23aee4c7f2e5d753c64a454443 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 2 Dec 2023 08:36:50 -0800 Subject: [PATCH 109/196] Add `signbit` specification for determining whether a sign bit is set (#705) --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 8048eb38a..b3f08727b 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -69,6 +69,7 @@ Objects in API remainder round sign + signbit sin sinh square diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index e3988a09f..5ff0c45d6 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -51,6 +51,7 @@ "remainder", "round", "sign", + "signbit", "sin", "sinh", "square", @@ -2215,6 +2216,40 @@ def sign(x: array, /) -> array: """ +def signbit(x: array, /) -> array: + r""" + Determines whether the sign bit is set for each element ``x_i`` of the input array ``x``. + + The sign bit of a real-valued floating-point number ``x_i`` is set whenever ``x_i`` is either ``-0``, less than zero, or a signed ``NaN`` (i.e., a ``NaN`` value whose sign bit is ``1``). + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``+0``, the result is ``False``. + - If ``x_i`` is ``-0``, the result is ``True``. + - If ``x_i`` is ``+infinity``, the result is ``False``. + - If ``x_i`` is ``-infinity``, the result is ``True``. + - If ``x_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``False``. + - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + """ + + def sin(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. From 1fd3429eb1bfe3a62875404e4e5e45d01873dd3f Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 13 Dec 2023 21:01:22 -0800 Subject: [PATCH 110/196] Add specification for computing the cumulative sum PR-URL: https://github.com/data-apis/array-api/pull/653 --- .../statistical_functions.rst | 1 + .../_draft/statistical_functions.py | 60 ++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/statistical_functions.rst b/spec/draft/API_specification/statistical_functions.rst index 23cd2cb1d..20e02b3f9 100644 --- a/spec/draft/API_specification/statistical_functions.rst +++ b/spec/draft/API_specification/statistical_functions.rst @@ -18,6 +18,7 @@ Objects in API :toctree: generated :template: method.rst + cumulative_sum max mean min diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 92cdb5755..14952402c 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -1,9 +1,67 @@ -__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] +__all__ = ["cumulative_sum", "max", "mean", "min", "prod", "std", "sum", "var"] from ._types import Optional, Tuple, Union, array, dtype +def cumulative_sum( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative sum of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum by counting from the last dimension. + + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + dtype: Optional[dtype] + data type of the returned array. If ``None``, + + - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + + .. note:: + keyword argument is intended to help prevent data type overflows. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative sum. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative sum must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + """ + + def max( x: array, /, From bda9c4872f65d5420142d65269968e287bcc9d59 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 13 Dec 2023 21:06:13 -0800 Subject: [PATCH 111/196] Add note clarifying behavior for out-of-bounds indices in `take` PR-URL: https://github.com/data-apis/array-api/pull/701 --- src/array_api_stubs/_draft/indexing_functions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 3f4c25215..f3bf0fc14 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -16,6 +16,10 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: input array. indices: array array indices. The array must be one-dimensional and have an integer data type. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + axis: int axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. From 50ca6792b44aa3d10a31c696adbd03f815ffabac Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 13 Dec 2023 21:11:35 -0800 Subject: [PATCH 112/196] Add specifications for `maximum` and `minimum` Closes: https://github.com/data-apis/array-api/issues/667 PR-URL: https://github.com/data-apis/array-api/pull/713 --- .../elementwise_functions.rst | 2 + .../_draft/elementwise_functions.py | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index b3f08727b..7984d8e02 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -60,6 +60,8 @@ Objects in API logical_not logical_or logical_xor + maximum + minimum multiply negative not_equal diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 5ff0c45d6..3da5412ca 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -42,6 +42,8 @@ "logical_not", "logical_or", "logical_xor", + "maximum", + "minimum", "multiply", "negative", "not_equal", @@ -1820,6 +1822,66 @@ def logical_xor(x1: array, x2: array, /) -> array: """ +def maximum(x1: array, x2: array, /) -> array: + r""" + Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise maximum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + """ + + +def minimum(x1: array, x2: array, /) -> array: + r""" + Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise minimum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + """ + + def multiply(x1: array, x2: array, /) -> array: r""" Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. From 5c2423a96c9fd5113e405df88f2422f14cd978b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= <8431159+mtsokol@users.noreply.github.com> Date: Mon, 18 Dec 2023 21:27:33 +0100 Subject: [PATCH 113/196] Fix definition of complex inner product in `vecdot` (#723) PR-URL: https://github.com/data-apis/array-api/pull/723 Reviewed-by: Athan Reines --- src/array_api_stubs/_2022_12/linear_algebra_functions.py | 4 ++-- src/array_api_stubs/_draft/linear_algebra_functions.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py index 110a19ce1..d5329db76 100644 --- a/src/array_api_stubs/_2022_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2022_12/linear_algebra_functions.py @@ -122,9 +122,9 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as .. math:: - \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} a_i\overline{b_i} + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i - over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{b_i}` denotes the complex conjugate if :math:`b_i` is complex and the identity if :math:`b_i` is real-valued. + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. Parameters ---------- diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index 079a90ee6..96f082bd5 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -126,9 +126,9 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as .. math:: - \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} a_i\overline{b_i} + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i - over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{b_i}` denotes the complex conjugate if :math:`b_i` is complex and the identity if :math:`b_i` is real-valued. + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. Parameters ---------- From 72f86f37e51cd28183c6b25c6b0b6d81ff497856 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 11 Jan 2024 13:47:26 -0800 Subject: [PATCH 114/196] Add `searchsorted` to the specification (#699) --- .../API_specification/searching_functions.rst | 1 + .../_draft/searching_functions.py | 54 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/spec/draft/API_specification/searching_functions.rst b/spec/draft/API_specification/searching_functions.rst index 01ab4e82a..c952f1aad 100644 --- a/spec/draft/API_specification/searching_functions.rst +++ b/spec/draft/API_specification/searching_functions.rst @@ -23,4 +23,5 @@ Objects in API argmax argmin nonzero + searchsorted where diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index e586a7656..dda000e74 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -1,7 +1,7 @@ -__all__ = ["argmax", "argmin", "nonzero", "where"] +__all__ = ["argmax", "argmin", "nonzero", "searchsorted", "where"] -from ._types import Optional, Tuple, array +from ._types import Optional, Tuple, Literal, array def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: @@ -87,6 +87,56 @@ def nonzero(x: array, /) -> Tuple[array, ...]: """ +def searchsorted( + x1: array, + x2: array, + /, + *, + side: Literal["left", "right"] = "left", + sorter: Optional[array] = None, +) -> array: + """ + Finds the indices into ``x1`` such that, if the corresponding elements in ``x2`` were inserted before the indices, the order of ``x1``, when sorted in ascending order, would be preserved. + + Parameters + ---------- + x1: array + input array. Must be a one-dimensional array. Should have a real-valued data type. If ``sorter`` is ``None``, must be sorted in ascending order; otherwise, ``sorter`` must be an array of indices that sort ``x1`` in ascending order. + x2: array + array containing search values. Should have a real-valued data type. + side: Literal['left', 'right'] + argument controlling which index is returned if a value lands exactly on an edge. + + Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + + If ``side == 'left'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``0``. + + Otherwise, if ``side == 'right'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + + Default: ``'left'``. + sorter: Optional[array] + array of indices that sort ``x1`` in ascending order. The array must have the same shape as ``x1`` and have an integer data type. Default: ``None``. + + Returns + ------- + out: array + an array of indices with the same shape as ``x2``. The returned array must have the default array index data type. + + Notes + ----- + + For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. + + While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + """ + + def where(condition: array, x1: array, x2: array, /) -> array: """ Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. From 8fe8b0864ce0dd48cca1006accb684c34513783d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 11 Jan 2024 23:26:14 +0100 Subject: [PATCH 115/196] Fix sidebar contents under Extensions (#729) The problem was that the sidebar doesn't show the named pages in the toctree if that toctree is under a subheading in index.rst Closes gh-716 --- spec/draft/extensions/index.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/draft/extensions/index.rst b/spec/draft/extensions/index.rst index 30d9cfa90..3b9409954 100644 --- a/spec/draft/extensions/index.rst +++ b/spec/draft/extensions/index.rst @@ -24,11 +24,10 @@ the implementer, e.g. via a regular submodule that is imported under the The functions in an extension must adhere to the same conventions as those in the array API standard. See :ref:`api-specification`. - -Extensions ----------- +------------------------------------------------------------------------------ .. toctree:: + :caption: Extension modules: :maxdepth: 1 fourier_transform_functions From 7a56675105864d98cf43b65656f6c2edf93bd2d4 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 12 Jan 2024 10:41:22 +0100 Subject: [PATCH 116/196] Update DLPack content to address unsupported use cases (#709) Also extend the description of errors when DLPack cannot be supported --- spec/draft/design_topics/data_interchange.rst | 19 +++++++++++++++++++ .../_draft/creation_functions.py | 14 ++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/spec/draft/design_topics/data_interchange.rst b/spec/draft/design_topics/data_interchange.rst index 8686042c8..3b3040672 100644 --- a/spec/draft/design_topics/data_interchange.rst +++ b/spec/draft/design_topics/data_interchange.rst @@ -84,3 +84,22 @@ page gives a high-level specification for data exchange in Python using DLPack. are recommended to do so using the same syntax and semantics as outlined below. They are not required to return an array object from ``from_dlpack`` which conforms to this standard. + +Non-supported use cases +----------------------- + +Use of DLPack requires that the data can be represented by a strided, in-memory +layout on a single device. This covers usage by a large range of, but not all, +known and possible array libraries. Use cases that are not supported by DLPack +include: + +- Distributed arrays, i.e., the data residing on multiple nodes or devices, +- Sparse arrays, i.e., sparse representations where a data value (typically + zero) is implicit. + +There may be other reasons why it is not possible or desirable for an +implementation to materialize the array as strided data in memory. In such +cases, the implementation may raise a `BufferError` in the `__dlpack__` or +`__dlpack_device__` method. In case an implementation is never able to export +its array data via DLPack, it may omit `__dlpack__` and `__dlpack_device__` +completely, and hence `from_dlpack` may raise an `AttributeError`. diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 5e2bb44e6..69733a646 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -232,6 +232,20 @@ def from_dlpack(x: object, /) -> array: :class: note The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array + may raise ``BufferError`` when the data cannot be exported as DLPack + (e.g., incompatible dtype or strides). It may also raise other errors + when export fails for other reasons (e.g., not enough memory available + to materialize the data). ``from_dlpack`` must propagate such + exceptions. + AttributeError + If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present + on the input array. This may happen for libraries that are never able + to export their data with DLPack. """ From 6e320d01b60dc38e7119ed3e9d409a00818bbe0b Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 22 Jan 2024 12:07:38 -0800 Subject: [PATCH 117/196] Add `clip` to the specification PR-URL: https://github.com/data-apis/array-api/pull/715 --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 35 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 7984d8e02..f0b69cfcb 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -33,6 +33,7 @@ Objects in API bitwise_right_shift bitwise_xor ceil + clip conj copysign cos diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 3da5412ca..c71b6674b 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -15,6 +15,7 @@ "bitwise_right_shift", "bitwise_xor", "ceil", + "clip", "conj", "copysign", "cos", @@ -65,7 +66,7 @@ ] -from ._types import array +from ._types import Optional, Union, array def abs(x: array, /) -> array: @@ -775,6 +776,38 @@ def ceil(x: array, /) -> array: """ +def clip( + x: array, + /, + min: Optional[Union[int, float, array]] = None, + max: Optional[Union[int, float, array]] = None, +) -> array: + r""" + Clamps each element ``x_i`` of the input array ``x`` to the range ``[min, max]``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + min: Optional[Union[int, float, array]] + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + max: Optional[Union[int, float, array]] + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + + Returns + ------- + out: array + an array containing element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. + - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + """ + + def conj(x: array, /) -> array: """ Returns the complex conjugate for each element ``x_i`` of the input array ``x``. From 0cde841671d99fc2e028eea87cd13d6eea49704e Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 22 Jan 2024 21:30:09 +0100 Subject: [PATCH 118/196] Clarify guidance in the "function and method signatures" section The type annotations part was a little outdated. For the positional and keyword-only descriptions, improve the language to account for exceptions to the default design rules. Closes: #475 PR-URL: https://github.com/data-apis/array-api/pull/730 Reviewed-by: Athan Reines --- .../function_and_method_signatures.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/draft/API_specification/function_and_method_signatures.rst b/spec/draft/API_specification/function_and_method_signatures.rst index 86d0819a6..0eca2ac69 100644 --- a/spec/draft/API_specification/function_and_method_signatures.rst +++ b/spec/draft/API_specification/function_and_method_signatures.rst @@ -5,7 +5,7 @@ Function and method signatures Function signatures in this standard adhere to the following: -1. Positional parameters must be `positional-only `_ parameters. +1. Positional parameters should be `positional-only `_ parameters. Positional-only parameters have no externally-usable name. When a function accepting positional-only parameters is called, positional arguments are mapped to these parameters based solely on their order. @@ -20,7 +20,7 @@ Function signatures in this standard adhere to the following: namespace >= 3.8. Alternatively, they can add guidance to their users in the documentation to use the functions as if they were positional-only. -2. Optional parameters must be `keyword-only `_ arguments. +2. Optional parameters should be `keyword-only `_ arguments. *Rationale: this leads to more readable code, and it makes it easier to evolve an API over time by adding keywords without having to worry about @@ -30,8 +30,8 @@ Function signatures in this standard adhere to the following: is called ``x``. For functions that have multiple array parameters, those parameters are called ``xi`` with ``i = 1, 2, ...`` (i.e., ``x1``, ``x2``). -4. Type annotations are left out of the signatures themselves for readability; however, - they are added to individual parameter descriptions. For code which aims to +4. Signatures include type annotations. The type annotations are also added to + individual parameter and return value descriptions. For code which aims to adhere to the standard, adding type annotations is strongly recommended. A function signature and description will look like: @@ -57,3 +57,7 @@ A function signature and description will look like: Method signatures will follow the same conventions modulo the addition of ``self``. + +Note that there are a few exceptions to rules (1) and (2), in cases where +it enhances readability or use of the non-default form of the parameter in +question is commonly used in code written for existing array libraries. From 293512d35f8acccb55b184462505cdb1ab5d1a14 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 22 Jan 2024 23:22:28 +0100 Subject: [PATCH 119/196] Upgrade Sphinx version used in doc deployment (#735) * Upgrade Sphinx version used in doc deployment It was breaking with: ``` sphinx-build "spec/2021.12" "_site/2021.12" -W --keep-going Running Sphinx v4.3.0 Sphinx version error: The sphinxcontrib.applehelp extension used by this project needs at least Sphinx v5.0; it therefore cannot be built with this version. ``` * Fix some doc build warnings that broke in CI --- doc-requirements.txt | 3 +-- spec/2021.12/assumptions.md | 4 ++-- spec/2021.12/purpose_and_scope.md | 2 +- spec/2021.12/use_cases.md | 2 +- spec/2022.12/assumptions.md | 4 ++-- spec/2022.12/purpose_and_scope.md | 2 +- spec/2022.12/use_cases.md | 2 +- spec/draft/assumptions.md | 4 ++-- spec/draft/purpose_and_scope.md | 2 +- spec/draft/use_cases.md | 2 +- src/_array_api_conf.py | 2 ++ 11 files changed, 15 insertions(+), 14 deletions(-) diff --git a/doc-requirements.txt b/doc-requirements.txt index 488aa3e81..08ced9aa2 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -1,8 +1,7 @@ -sphinx==4.3.0 +sphinx==6.2.1 sphinx-material==0.0.30 myst-parser sphinx_markdown_tables sphinx_copybutton sphinx_favicon -docutils<0.18 sphinx-math-dollar diff --git a/spec/2021.12/assumptions.md b/spec/2021.12/assumptions.md index 3a90710ea..b11482c5a 100644 --- a/spec/2021.12/assumptions.md +++ b/spec/2021.12/assumptions.md @@ -26,7 +26,7 @@ of functions to be predictable from input dtypes only rather than input values. The only dependency that's assumed in this standard is that on Python itself. Python >= 3.8 is assumed, motivated by the use of positional-only parameters -(see [function and method signatures](API_specification/function_and_method_signatures.md)). +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). Importantly, array libraries are not assumed to be aware of each other, or of a common array-specific layer. The [use cases](use_cases.md) do not require @@ -39,7 +39,7 @@ for that is: Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared -memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.md)). +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). This can be done without a dependency though - only adherence to a protocol is enough. diff --git a/spec/2021.12/purpose_and_scope.md b/spec/2021.12/purpose_and_scope.md index 4678ba064..0debbc08a 100644 --- a/spec/2021.12/purpose_and_scope.md +++ b/spec/2021.12/purpose_and_scope.md @@ -151,7 +151,7 @@ standard is shown in this diagram: _Rationale: this is an important topic for some array-consuming libraries, but there is no widely shared C/Cython API and hence it doesn't make sense at this point in time to standardize anything. See - the [C API section](design_topics/C_API.md) for more details._ + the [C API section](design_topics/C_API.rst) for more details._ 4. Standardization of these dtypes is out of scope: bfloat16, complex, extended precision floating point, datetime, string, object and void dtypes. diff --git a/spec/2021.12/use_cases.md b/spec/2021.12/use_cases.md index 26f7a529c..e24aa50db 100644 --- a/spec/2021.12/use_cases.md +++ b/spec/2021.12/use_cases.md @@ -59,7 +59,7 @@ array implementation as a dependency. It's clear that SciPy functionality that relies on compiled extensions (C, C++, Cython, Fortran) directly can't easily be run on another array library -than NumPy (see [C API](design_topics/C_API.md) for more details about this topic). Pure Python +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python code can work though. There's two main possibilities: 1. Testing with another package, manually or in CI, and simply provide a list diff --git a/spec/2022.12/assumptions.md b/spec/2022.12/assumptions.md index 3a90710ea..b11482c5a 100644 --- a/spec/2022.12/assumptions.md +++ b/spec/2022.12/assumptions.md @@ -26,7 +26,7 @@ of functions to be predictable from input dtypes only rather than input values. The only dependency that's assumed in this standard is that on Python itself. Python >= 3.8 is assumed, motivated by the use of positional-only parameters -(see [function and method signatures](API_specification/function_and_method_signatures.md)). +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). Importantly, array libraries are not assumed to be aware of each other, or of a common array-specific layer. The [use cases](use_cases.md) do not require @@ -39,7 +39,7 @@ for that is: Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared -memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.md)). +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). This can be done without a dependency though - only adherence to a protocol is enough. diff --git a/spec/2022.12/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md index 38287f270..f375c9512 100644 --- a/spec/2022.12/purpose_and_scope.md +++ b/spec/2022.12/purpose_and_scope.md @@ -151,7 +151,7 @@ standard is shown in this diagram: _Rationale: this is an important topic for some array-consuming libraries, but there is no widely shared C/Cython API and hence it doesn't make sense at this point in time to standardize anything. See - the [C API section](design_topics/C_API.md) for more details._ + the [C API section](design_topics/C_API.rst) for more details._ 4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. diff --git a/spec/2022.12/use_cases.md b/spec/2022.12/use_cases.md index 26f7a529c..e24aa50db 100644 --- a/spec/2022.12/use_cases.md +++ b/spec/2022.12/use_cases.md @@ -59,7 +59,7 @@ array implementation as a dependency. It's clear that SciPy functionality that relies on compiled extensions (C, C++, Cython, Fortran) directly can't easily be run on another array library -than NumPy (see [C API](design_topics/C_API.md) for more details about this topic). Pure Python +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python code can work though. There's two main possibilities: 1. Testing with another package, manually or in CI, and simply provide a list diff --git a/spec/draft/assumptions.md b/spec/draft/assumptions.md index 3a90710ea..b11482c5a 100644 --- a/spec/draft/assumptions.md +++ b/spec/draft/assumptions.md @@ -26,7 +26,7 @@ of functions to be predictable from input dtypes only rather than input values. The only dependency that's assumed in this standard is that on Python itself. Python >= 3.8 is assumed, motivated by the use of positional-only parameters -(see [function and method signatures](API_specification/function_and_method_signatures.md)). +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). Importantly, array libraries are not assumed to be aware of each other, or of a common array-specific layer. The [use cases](use_cases.md) do not require @@ -39,7 +39,7 @@ for that is: Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared -memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.md)). +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). This can be done without a dependency though - only adherence to a protocol is enough. diff --git a/spec/draft/purpose_and_scope.md b/spec/draft/purpose_and_scope.md index 38287f270..f375c9512 100644 --- a/spec/draft/purpose_and_scope.md +++ b/spec/draft/purpose_and_scope.md @@ -151,7 +151,7 @@ standard is shown in this diagram: _Rationale: this is an important topic for some array-consuming libraries, but there is no widely shared C/Cython API and hence it doesn't make sense at this point in time to standardize anything. See - the [C API section](design_topics/C_API.md) for more details._ + the [C API section](design_topics/C_API.rst) for more details._ 4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. diff --git a/spec/draft/use_cases.md b/spec/draft/use_cases.md index 26f7a529c..e24aa50db 100644 --- a/spec/draft/use_cases.md +++ b/spec/draft/use_cases.md @@ -59,7 +59,7 @@ array implementation as a dependency. It's clear that SciPy functionality that relies on compiled extensions (C, C++, Cython, Fortran) directly can't easily be run on another array library -than NumPy (see [C API](design_topics/C_API.md) for more details about this topic). Pure Python +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python code can work though. There's two main possibilities: 1. Testing with another package, manually or in CI, and simply provide a list diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index d3a136eaa..9c5722f94 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -52,12 +52,14 @@ nitpick_ignore = [ ("py:class", "collections.abc.Sequence"), ("py:class", "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), + ("py:class", "int | float | ~typing.Literal[inf, -inf, 'fro', 'nuc'] | None"), ("py:class", "Union[int, float, Literal[inf, - inf]]"), ( "py:obj", "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]", ), ("py:obj", "typing.Union[int, float, typing.Literal[inf, - inf]]"), + ("py:class", "int | float | ~typing.Literal[inf, -inf]"), ("py:class", "enum.Enum"), ("py:class", "ellipsis"), ] From 95332bb71159cea68e15e7d20364a3e07060a402 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi <2190658+hameerabbasi@users.noreply.github.com> Date: Thu, 25 Jan 2024 13:59:59 +0100 Subject: [PATCH 120/196] Fix wording for comparison operators PR-URL: https://github.com/data-apis/array-api/pull/736 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- spec/2022.12/API_specification/array_object.rst | 3 ++- spec/draft/API_specification/array_object.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/2022.12/API_specification/array_object.rst b/spec/2022.12/API_specification/array_object.rst index b15bbdc43..45aec9b34 100644 --- a/spec/2022.12/API_specification/array_object.rst +++ b/spec/2022.12/API_specification/array_object.rst @@ -163,7 +163,8 @@ A conforming implementation of the array API standard must provide and support a - `operator.ne(x1, x2) `_ - `operator.__ne__(x1, x2) `_ -Comparison operators should be defined for arrays having any data type. +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). In-place Operators ~~~~~~~~~~~~~~~~~~ diff --git a/spec/draft/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst index 0fadf9fc5..f8a586ade 100644 --- a/spec/draft/API_specification/array_object.rst +++ b/spec/draft/API_specification/array_object.rst @@ -163,7 +163,8 @@ A conforming implementation of the array API standard must provide and support a - `operator.ne(x1, x2) `_ - `operator.__ne__(x1, x2) `_ -Comparison operators should be defined for arrays having any data type. +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). In-place Operators ~~~~~~~~~~~~~~~~~~ From 937d3b8e22ef42d2420a951cefe6ec28107f31bf Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 8 Feb 2024 06:14:02 -0700 Subject: [PATCH 121/196] Clarify specification guidance in FFT functions PR-URL: https://github.com/data-apis/array-api/pull/720 Closes: https://github.com/data-apis/array-api/issues/717 Closes: https://github.com/data-apis/array-api/issues/718 Ref: https://github.com/data-apis/array-api/pull/189 Co-authored-by: Leo Fang Co-authored-by: Athan Reines Reviewed-by: Leo Fang Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2022_12/fft.py | 297 +++++++++++++--------------- src/array_api_stubs/_draft/fft.py | 262 +++++++++++------------- 2 files changed, 253 insertions(+), 306 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index 7979095fe..f79aa155e 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -1,3 +1,20 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + from ._types import Tuple, Union, Sequence, array, Optional, Literal, device @@ -13,24 +30,22 @@ def fft( Computes the one-dimensional discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -43,7 +58,7 @@ def fft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -64,24 +79,22 @@ def ifft( Computes the one-dimensional inverse discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -94,7 +107,7 @@ def ifft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -107,8 +120,8 @@ def fftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -120,24 +133,19 @@ def fftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -152,7 +160,7 @@ def fftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -165,8 +173,8 @@ def ifftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -178,24 +186,19 @@ def ifftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -210,7 +213,7 @@ def ifftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -231,24 +234,22 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -261,7 +262,7 @@ def rfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -282,24 +283,22 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Should have a complex-valued floating-point data type. - n: int - length of the transformed axis of the **output**. If + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -312,11 +311,13 @@ def irfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + .. versionadded:: 2022.12 """ @@ -325,8 +326,8 @@ def rfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -339,23 +340,18 @@ def rfftn( ---------- x: array input array. Must have a real-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **input**. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -370,7 +366,7 @@ def rfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. Notes ----- @@ -383,8 +379,8 @@ def irfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -397,23 +393,18 @@ def irfftn( ---------- x: array input array. Should have a complex-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **output**. ``n=s[i]`` is also the number of input points used along the axis (dimension) ``i``, except for the last axis, where ``n=s[-1]//2+1`` points of the input are used. If + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - - ``n`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``n``. - - ``n`` is less than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``n``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array, except for the last axis which is trimmed to ``2*(m-1)``, where ``m`` is the length of the input along the axis. + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. - - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -428,11 +419,13 @@ def irfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. Notes ----- + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + .. versionadded:: 2022.12 """ @@ -451,19 +444,17 @@ def hfft( Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the **output**. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -476,7 +467,7 @@ def hfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -500,18 +491,16 @@ def ihfft( ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -524,7 +513,7 @@ def ihfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -535,9 +524,9 @@ def ihfft( def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies. + Computes the discrete Fourier transform sample frequencies. - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -556,7 +545,7 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar Returns ------- out: array - an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -567,9 +556,9 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -590,7 +579,7 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a Returns ------- out: array - an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -599,9 +588,9 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a """ -def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: """ - Shift the zero-frequency component to the center of the spectrum. + Shifts the zero-frequency component to the center of the spectrum. This function swaps half-spaces for all axes (dimensions) specified by ``axes``. @@ -612,13 +601,13 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- @@ -627,7 +616,9 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: """ -def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: """ Inverse of ``fftshift``. @@ -638,34 +629,16 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- .. versionadded:: 2022.12 """ - - -__all__ = [ - "fft", - "ifft", - "fftn", - "ifftn", - "rfft", - "irfft", - "rfftn", - "irfftn", - "hfft", - "ihfft", - "fftfreq", - "rfftfreq", - "fftshift", - "ifftshift", -] diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 4a59392d5..f79aa155e 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -30,24 +30,22 @@ def fft( Computes the one-dimensional discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -60,7 +58,7 @@ def fft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -81,24 +79,22 @@ def ifft( Computes the one-dimensional inverse discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -111,7 +107,7 @@ def ifft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -124,8 +120,8 @@ def fftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -137,24 +133,19 @@ def fftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -169,7 +160,7 @@ def fftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -182,8 +173,8 @@ def ifftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -195,24 +186,19 @@ def ifftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -227,7 +213,7 @@ def ifftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -248,24 +234,22 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -278,7 +262,7 @@ def rfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -299,24 +283,22 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Should have a complex-valued floating-point data type. - n: int - length of the transformed axis of the **output**. If + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -329,11 +311,13 @@ def irfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + .. versionadded:: 2022.12 """ @@ -342,8 +326,8 @@ def rfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -356,23 +340,18 @@ def rfftn( ---------- x: array input array. Must have a real-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **input**. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -387,7 +366,7 @@ def rfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. Notes ----- @@ -400,8 +379,8 @@ def irfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -414,23 +393,18 @@ def irfftn( ---------- x: array input array. Should have a complex-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **output**. ``n=s[i]`` is also the number of input points used along the axis (dimension) ``i``, except for the last axis, where ``n=s[-1]//2+1`` points of the input are used. If - - - ``n`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``n``. - - ``n`` is less than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``n``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array, except for the last axis which is trimmed to ``2*(m-1)``, where ``m`` is the length of the input along the axis. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -445,11 +419,13 @@ def irfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. Notes ----- + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + .. versionadded:: 2022.12 """ @@ -468,19 +444,17 @@ def hfft( Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the **output**. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -493,7 +467,7 @@ def hfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -517,18 +491,16 @@ def ihfft( ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -541,7 +513,7 @@ def ihfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -552,9 +524,9 @@ def ihfft( def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies. + Computes the discrete Fourier transform sample frequencies. - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -573,7 +545,7 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar Returns ------- out: array - an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -584,9 +556,9 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -607,7 +579,7 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a Returns ------- out: array - an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -616,9 +588,9 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a """ -def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: """ - Shift the zero-frequency component to the center of the spectrum. + Shifts the zero-frequency component to the center of the spectrum. This function swaps half-spaces for all axes (dimensions) specified by ``axes``. @@ -629,13 +601,13 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- @@ -644,7 +616,9 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: """ -def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: """ Inverse of ``fftshift``. @@ -655,13 +629,13 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- From 425e9eb4eeeaf9057b5f2e93168ff377ddb9775f Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 8 Feb 2024 16:17:52 -0500 Subject: [PATCH 122/196] Fix typo in FFT guidance PR-URL: https://github.com/data-apis/array-api/pull/743 Reviewed-by: Athan Reines Ref: https://github.com/data-apis/array-api/pull/720 --- src/array_api_stubs/_2022_12/fft.py | 4 ++-- src/array_api_stubs/_draft/fft.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index f79aa155e..901b8407b 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -234,7 +234,7 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- @@ -283,7 +283,7 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index f79aa155e..901b8407b 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -234,7 +234,7 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- @@ -283,7 +283,7 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- From 83420d21394e92b2fc92313f789f7b3d8c0c8c93 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 9 Feb 2024 01:23:41 +0100 Subject: [PATCH 123/196] Add versioning support to DLPack APIs (#602) * Add versioning support to DLPack APIs xref https://github.com/dmlc/dlpack/issues/116 * Address review comment, replace ">=2 years" by "from March 2025" * nit: re-order * improvements & fixes * Satisfy linter * Satisfy linter * Update src/array_api_stubs/_draft/array_object.py Co-authored-by: Sebastian Berg --------- Co-authored-by: Leo Fang Co-authored-by: Athan Co-authored-by: Sebastian Berg --- src/array_api_stubs/_draft/array_object.py | 102 +++++++++++++----- .../_draft/creation_functions.py | 5 + 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 600e947e0..9f8be2479 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -288,7 +288,11 @@ def __complex__(self: array, /) -> complex: """ def __dlpack__( - self: array, /, *, stream: Optional[Union[int, Any]] = None + self: array, + /, + *, + stream: Optional[Union[int, Any]] = None, + max_version: Optional[tuple[int, int]] = None, ) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -298,20 +302,14 @@ def __dlpack__( self: array array instance. stream: Optional[Union[int, Any]] - for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be a positive integer or ``-1``. If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. - - For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. - - - .. note:: - Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be an integer larger than or equal to ``-1`` (see below for allowed values on each platform). If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. + For other device types which do have a stream, queue, or similar synchronization/ordering mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. - Device-specific notes: + .. note:: + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. - - .. admonition:: CUDA - :class: note + Device-specific values of ``stream`` for CUDA: - ``None``: producer must assume the legacy default stream (default). - ``1``: the legacy default stream. @@ -319,24 +317,28 @@ def __dlpack__( - ``> 2``: stream number represented as a Python integer. - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. - - .. admonition:: ROCm - :class: note + Device-specific values of ``stream`` for ROCm: - ``None``: producer must assume the legacy default stream (default). - ``0``: the default stream. - ``> 2``: stream number represented as a Python integer. - Using ``1`` and ``2`` is not supported. - - .. admonition:: Tip - :class: important - - It is recommended that implementers explicitly handle streams. If - they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` - (ROCm) is preferred. ``None`` is a safe default for developers who do - not want to think about stream handling at all, potentially at the - cost of more synchronization than necessary. + .. admonition:: Tip + :class: important + + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronizations than necessary. + max_version: Optional[tuple[int, int]] + The maximum DLPack version that the *consumer* (i.e., the caller of + ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. + This method may return a capsule of version ``max_version`` (recommended + if it does support that), or of a different version. + This means the consumer must verify the version even when + `max_version` is passed. Returns ------- @@ -353,9 +355,61 @@ def __dlpack__( Notes ----- + The DLPack version scheme is SemVer, where the major DLPack versions + represent ABI breaks, and minor versions represent ABI-compatible additions + (e.g., new enum values for new data types or device types). + + The ``max_version`` keyword was introduced in v2023.12, and goes + together with the ``DLManagedTensorVersioned`` struct added in DLPack + 1.0. This keyword may not be used by consumers until a later time after + introduction, because producers may implement the support at a different + point in time. + + It is recommended for the producer to use this logic in the implementation + of ``__dlpack__``: + + .. code:: python + + if max_version is None: + # Keep and use the DLPack 0.X implementation + # Note: from March 2025 onwards (but ideally as late as + # possible), it's okay to raise BufferError here + else: + # We get to produce `DLManagedTensorVersioned` now. Note that + # our_own_dlpack_version is the max version that the *producer* + # supports and fills in the `DLManagedTensorVersioned::version` + # field + if max_version >= our_own_dlpack_version: + # Consumer understands us, just return a Capsule with our max version + elif max_version[0] == our_own_dlpack_version[0]: + # major versions match, we should still be fine here - + # return our own max version + else: + # if we're at a higher major version internally, did we + # keep an implementation of the older major version around? + # For example, if the producer is on DLPack 1.x and the consumer + # is 0.y, can the producer still export a capsule containing + # DLManagedTensor and not DLManagedTensorVersioned? + # If so, use that. Else, the producer should raise a BufferError + # here to tell users that the consumer's max_version is too + # old to allow the data exchange to happen. + + And this logic for the consumer in ``from_dlpack``: + + .. code:: python + + try: + x.__dlpack__(max_version=(1, 0)) + # if it succeeds, store info from the capsule named "dltensor_versioned", + # and need to set the name to "used_dltensor_versioned" when we're done + except TypeError: + x.__dlpack__() .. versionchanged:: 2022.12 Added BufferError. + + .. versionchanged:: 2023.12 + Added the ``max_version`` keyword. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 69733a646..d0f967717 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -246,6 +246,11 @@ def from_dlpack(x: object, /) -> array: If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present on the input array. This may happen for libraries that are never able to export their data with DLPack. + + Notes + ----- + See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in + order to handle DLPack versioning correctly. """ From a902944642a553b287a226711d380676c070940e Mon Sep 17 00:00:00 2001 From: Athan Date: Fri, 9 Feb 2024 00:17:51 -0800 Subject: [PATCH 124/196] Add note regarding copy behavior when moving to same device (#742) Closes: https://github.com/data-apis/array-api/issues/645 --- src/array_api_stubs/_draft/array_object.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 9f8be2479..5b412685e 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -1140,8 +1140,11 @@ def to_device( an array with the same data and data type as ``self`` and located on the specified ``device``. - .. note:: - If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. + Notes + ----- + + - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. + - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. """ From 2404c9968726f11be30047e903b613fa2031b9e9 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 13 Feb 2024 07:41:16 +0100 Subject: [PATCH 125/196] docs: reorganize data type specification guidance PR-URL: https://github.com/data-apis/array-api/pull/745 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- spec/draft/API_specification/data_types.rst | 198 ++++++++------------ 1 file changed, 78 insertions(+), 120 deletions(-) diff --git a/spec/draft/API_specification/data_types.rst b/spec/draft/API_specification/data_types.rst index a9be88181..5987dd322 100644 --- a/spec/draft/API_specification/data_types.rst +++ b/spec/draft/API_specification/data_types.rst @@ -5,109 +5,83 @@ Data Types Array API specification for supported data types. -A conforming implementation of the array API standard must provide and support the following data types. +A conforming implementation of the array API standard must provide and support +the following data types ("dtypes") in its array object, and as data type +objects in its main namespace under the specified names: + ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| dtype object | description | ++==============+============================================================================================================================================================================================+ +| bool | Boolean (``True`` or ``False``). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int8 | An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int16 | A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int32 | A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int64 | A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint8 | An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint16 | A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint32 | A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint64 | A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float32 | IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float64 | IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex64 | Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex128 | Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Data type objects must have the following methods (no attributes are required): -bool ----- - -Boolean (``True`` or ``False``). - -int8 ----- - -An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. - -int16 ------ - -A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. - -int32 ------ - -A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. - -int64 ------ - -A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. - -uint8 ------ - -An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. - -uint16 ------- - -A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. - -uint32 ------- - -A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. - -uint64 ------- - -A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. - -float32 -------- - -IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). - -float64 -------- +.. + NOTE: please keep the functions in alphabetical order -IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). +.. currentmodule:: array_api.data_types -complex64 ---------- +.. autosummary:: + :toctree: generated + :template: method.rst -Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). + __eq__ -complex128 ----------- -Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). +.. note:: + A conforming implementation of the array API standard may provide and + support additional data types beyond those described in this specification. + It may also support additional methods and attributes on dtype objects. .. note:: IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. -.. note:: - A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. - -.. _data-type-objects: -Data Type Objects ------------------ +Use of data type objects +------------------------ -Data types ("dtypes") are objects which are used as ``dtype`` specifiers in functions and methods (e.g., ``zeros((2, 3), dtype=float32)``). +Data type objects are used as ``dtype`` specifiers in functions and methods +(e.g., ``zeros((2, 3), dtype=float32)``), accessible as ``.dtype`` attribute on +arrays, and used in various casting and introspection functions (e.g., +``isdtype(x.dtype, 'integral')``). -.. note:: - A conforming implementation may add additional methods or attributes to data type objects beyond those described in this specification. +``dtype`` keywords in functions specify the data type of arrays returned from +functions or methods. ``dtype`` keywords are not required to affect the data +type used for intermediate calculations or results (e.g., implementors are free +to use a higher-precision data type when accumulating values for reductions, as +long as the returned array has the specified data type). .. note:: Implementations may provide other ways to specify data types (e.g., ``zeros((2, 3), dtype='f4')``) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. -A conforming implementation of the array API standard must provide and support data type objects having the following attributes and methods. - -Methods -~~~~~~~ - -.. - NOTE: please keep the functions in alphabetical order - -.. currentmodule:: array_api.data_types - -.. autosummary:: - :toctree: generated - :template: method.rst - - __eq__ +See :ref:`type-promotion` for specification guidance describing the rules governing the interaction of two or more data types or data type objects. .. _data-type-defaults: @@ -138,6 +112,7 @@ the library should clearly warn about this in its documentation. .. note:: The default data types should be clearly defined in a conforming library's documentation. + .. _data-type-categories: Data Type Categories @@ -145,41 +120,24 @@ Data Type Categories For the purpose of organizing functions within this specification, the following data type categories are defined. -.. note:: - Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. - - -Numeric Data Types -~~~~~~~~~~~~~~~~~~ - -``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. - -Real-valued Data Types -~~~~~~~~~~~~~~~~~~~~~~ - -``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. - -Integer Data Types -~~~~~~~~~~~~~~~~~~ - -``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. - -Floating-point Data Types -~~~~~~~~~~~~~~~~~~~~~~~~~ ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| data type category | dtypes | ++============================+========================================================================================================================================================+ +| Numeric | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Floating-point | ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued floating-point | ``float32`` and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Complex floating-point | ``complex64`` and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Boolean | ``bool``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ -``float32``, ``float64``, ``complex64``, and ``complex128``. -Real-valued Floating-point Data Types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``float32`` and ``float64``. - -Complex Floating-point Data Types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``complex64`` and ``complex128``. - -Boolean Data Types -~~~~~~~~~~~~~~~~~~ - -``bool``. +.. note:: + Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. From 72740507b478f014fb65156198534f8046fbe37f Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 13 Feb 2024 09:22:53 +0100 Subject: [PATCH 126/196] feat!: change default promotion behavior in summation APIs This commit modifies type promotion behavior in `sum`, `prod`, `cumulative_sum`, and `linalg.trace` when the input array has a floating-point data type. Previously, the specification required that conforming implementations upcast to the default floating-point data type when the input array data type was of a lower precision. This commit revises that guidance to require conforming libraries return an array having the same data type as the input array. This revision stems from feedback from implementing libraries, where the current status quo matches the changes in this commit, with little desire to change. As such, the specification is amended to match this reality. Closes: https://github.com/data-apis/array-api/issues/731 PR-URL: https://github.com/data-apis/array-api/pull/744 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/linalg.py | 15 ++---- .../_draft/statistical_functions.py | 50 ++++++------------- 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index d05b53a9f..c66258c7b 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -742,19 +742,12 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr Default: ``0``. dtype: Optional[dtype] - data type of the returned array. If ``None``, + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. - - .. note:: - keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. Returns ------- diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 14952402c..496440535 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -23,22 +23,14 @@ def cumulative_sum( axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum by counting from the last dimension. If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. - dtype: Optional[dtype] - data type of the returned array. If ``None``, - - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - .. note:: - keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. include_initial: bool boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. @@ -200,20 +192,14 @@ def prod( input array. Should have a numeric data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. - dtype: Optional[dtype] - data type of the returned array. If ``None``, - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product. Default: ``None``. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - .. note:: - This keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. keepdims: bool if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. @@ -298,20 +284,14 @@ def sum( input array. Should have a numeric data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. - dtype: Optional[dtype] - data type of the returned array. If ``None``, - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - .. note:: - keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. keepdims: bool if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. From 1745c88764934021a8cb0ac8cd2de43a3cec4a67 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 13 Feb 2024 01:46:11 -0700 Subject: [PATCH 127/196] feat!: restrict `axis` kwarg to negative integers in vecdot and cross This commit updates specification guidance in `vecdot` and `cross` to no longer explicitly support positive `axis` kwarg values. Previous specification guidance conflicts with NumPy gufuncs and restricting to negative integers removes ambiguity in determining over which axis to perform computation. This commit uses `should`, not `must`, to allow conforming libraries to support nonnegative `axis` values for backward compatibility. Closes: #724 Closes: #617 PR-URL: https://github.com/data-apis/array-api/pull/740 Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/linalg.py | 9 ++++----- src/array_api_stubs/_draft/linear_algebra_functions.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index c66258c7b..903f928d8 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -83,15 +83,15 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: Parameters ---------- x1: array - first input array. Must have a numeric data type. + first input array. Must have a numeric data type. The size of the axis over which the cross product is to be computed must be equal to 3. x2: array - second input array. Must be compatible with ``x1`` for all non-compute axes (see :ref:`broadcasting`). The size of the axis over which to compute the cross product must be the same size as the respective axis in ``x1``. Must have a numeric data type. + second input array. Must be broadcast compatible with ``x1`` along all axes other than the axis along which the cross-product is computed (see :ref:`broadcasting`). The size of the axis over which the cross product is to be computed must be equal to 3. Must have a numeric data type. .. note:: The compute axis (dimension) must not be broadcasted. axis: int - the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. Returns ------- @@ -110,8 +110,7 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: **Raises** - - if the size of the axis over which to compute the cross product is not equal to ``3``. - - if the size of the axis over which to compute the cross product is not the same (before broadcasting) for both ``x1`` and ``x2``. + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. """ diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index 96f082bd5..eea898a6b 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -141,7 +141,7 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: The contracted axis (dimension) must not be broadcasted. axis: int - axis over which to compute the dot product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the dot product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. Returns ------- From 474ec2b3eeedc4a6520e63df9601a2e4c6529a5a Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 14 Feb 2024 04:44:52 -0500 Subject: [PATCH 128/196] docs: clarify `s` and `axes` in FFT guidance Closes: https://github.com/data-apis/array-api/issues/747 PR-URL: https://github.com/data-apis/array-api/pull/746 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_2022_12/fft.py | 30 ++++++++++++++++++++--------- src/array_api_stubs/_draft/fft.py | 30 ++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index 901b8407b..bdd7a9c83 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -135,7 +135,7 @@ def fftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -143,9 +143,11 @@ def fftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -188,7 +190,7 @@ def ifftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -196,9 +198,11 @@ def ifftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -341,7 +345,7 @@ def rfftn( x: array input array. Must have a real-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -349,9 +353,11 @@ def rfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -394,7 +400,7 @@ def irfftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. @@ -402,9 +408,11 @@ def irfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -604,6 +612,8 @@ def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) - axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array @@ -632,6 +642,8 @@ def ifftshift( axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 901b8407b..bdd7a9c83 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -135,7 +135,7 @@ def fftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -143,9 +143,11 @@ def fftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -188,7 +190,7 @@ def ifftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -196,9 +198,11 @@ def ifftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -341,7 +345,7 @@ def rfftn( x: array input array. Must have a real-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -349,9 +353,11 @@ def rfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -394,7 +400,7 @@ def irfftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. @@ -402,9 +408,11 @@ def irfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -604,6 +612,8 @@ def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) - axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array @@ -632,6 +642,8 @@ def ifftshift( axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array From 71b01c1fbecf7e53fb9f7849b60ba2c2c44a6b73 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 14 Feb 2024 15:44:32 -0500 Subject: [PATCH 129/196] Support `copy` and `device` keywords in `from_dlpack` (#741) * support copy in from_dlpack * specify copy stream * allow 3-way copy arg to align all constructors * update to reflect the discussions * clairfy a bit and fix typos * sync the copy docs * clarify what's 'on CPU' * try to make linter happy * remove namespace leak clause, clean up, and add an example * make linter happy * fix Sphinx complaint about Enum * add/update v2023-specific notes on device * remove a note on kDLCPU --------- Co-authored-by: Ralf Gommers --- src/array_api_stubs/_draft/array_object.py | 51 +++++++++++++++++-- .../_draft/creation_functions.py | 46 +++++++++++++++-- 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 5b412685e..5017bf87c 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -293,6 +293,8 @@ def __dlpack__( *, stream: Optional[Union[int, Any]] = None, max_version: Optional[tuple[int, int]] = None, + dl_device: Optional[tuple[Enum, int]] = None, + copy: Optional[bool] = None, ) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -324,6 +326,12 @@ def __dlpack__( - ``> 2``: stream number represented as a Python integer. - Using ``1`` and ``2`` is not supported. + .. note:: + When ``dl_device`` is provided explicitly, ``stream`` must be a valid + construct for the specified device type. In particular, when ``kDLCPU`` + is in use, ``stream`` must be ``None`` and a synchronization must be + performed to ensure data safety. + .. admonition:: Tip :class: important @@ -333,12 +341,40 @@ def __dlpack__( not want to think about stream handling at all, potentially at the cost of more synchronizations than necessary. max_version: Optional[tuple[int, int]] - The maximum DLPack version that the *consumer* (i.e., the caller of + the maximum DLPack version that the *consumer* (i.e., the caller of ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. This method may return a capsule of version ``max_version`` (recommended if it does support that), or of a different version. This means the consumer must verify the version even when `max_version` is passed. + dl_device: Optional[tuple[enum.Enum, int]] + the DLPack device type. Default is ``None``, meaning the exported capsule + should be on the same device as ``self`` is. When specified, the format + must be a 2-tuple, following that of the return value of :meth:`array.__dlpack_device__`. + If the device type cannot be handled by the producer, this function must + raise ``BufferError``. + + The v2023.12 standard only mandates that a compliant library should offer a way for + ``__dlpack__`` to return a capsule referencing an array whose underlying memory is + accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). + If a copy must be made to enable this support but ``copy`` is set to ``False``, the + function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this + API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the + function must always copy (performed by the producer). If ``False``, the + function must never copy, and raise a ``BufferError`` in case a copy is + deemed necessary (e.g. if a cross-device data movement is requested, and + it is not possible without a copy). If ``None``, the function must reuse + the existing memory buffer if possible and copy otherwise. Default: ``None``. + + When a copy happens, the ``DLPACK_FLAG_BITMASK_IS_COPIED`` flag must be set. + + .. note:: + If a copy happens, and if the consumer-provided ``stream`` and ``dl_device`` + can be understood by the producer, the copy must be performed over ``stream``. Returns ------- @@ -394,22 +430,25 @@ def __dlpack__( # here to tell users that the consumer's max_version is too # old to allow the data exchange to happen. - And this logic for the consumer in ``from_dlpack``: + And this logic for the consumer in :func:`~array_api.from_dlpack`: .. code:: python try: - x.__dlpack__(max_version=(1, 0)) + x.__dlpack__(max_version=(1, 0), ...) # if it succeeds, store info from the capsule named "dltensor_versioned", # and need to set the name to "used_dltensor_versioned" when we're done except TypeError: - x.__dlpack__() + x.__dlpack__(...) + + This logic is also applicable to handling of the new ``dl_device`` and ``copy`` + keywords. .. versionchanged:: 2022.12 Added BufferError. .. versionchanged:: 2023.12 - Added the ``max_version`` keyword. + Added the ``max_version``, ``dl_device``, and ``copy`` keywords. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -436,6 +475,8 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: METAL = 8 VPI = 9 ROCM = 10 + CUDA_MANAGED = 13 + ONE_API = 14 """ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index d0f967717..dec09db0c 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -214,7 +214,13 @@ def eye( """ -def from_dlpack(x: object, /) -> array: +def from_dlpack( + x: object, + /, + *, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: """ Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. @@ -222,11 +228,22 @@ def from_dlpack(x: object, /) -> array: ---------- x: object input (array) object. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``x`` supports DLPack, the output array must be on the same device as ``x``. Default: ``None``. + + The v2023.12 standard only mandates that a compliant library should offer a way for ``from_dlpack`` to return an array + whose underlying memory is accessible to the Python interpreter, when the corresponding ``device`` is provided. If the + array library does not support such cases at all, the function must raise ``BufferError``. If a copy must be made to + enable this support but ``copy`` is set to ``False``, the function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy, and raise ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse the existing memory buffer if possible and copy otherwise. Default: ``None``. Returns ------- out: array - an array containing the data in `x`. + an array containing the data in ``x``. .. admonition:: Note :class: note @@ -238,7 +255,7 @@ def from_dlpack(x: object, /) -> array: BufferError The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array may raise ``BufferError`` when the data cannot be exported as DLPack - (e.g., incompatible dtype or strides). It may also raise other errors + (e.g., incompatible dtype, strides, or device). It may also raise other errors when export fails for other reasons (e.g., not enough memory available to materialize the data). ``from_dlpack`` must propagate such exceptions. @@ -246,11 +263,34 @@ def from_dlpack(x: object, /) -> array: If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present on the input array. This may happen for libraries that are never able to export their data with DLPack. + ValueError + If data exchange is possible via an explicit copy but ``copy`` is set to ``False``. Notes ----- See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in order to handle DLPack versioning correctly. + + A way to move data from two array libraries to the same device (assumed supported by both libraries) in + a library-agnostic fashion is illustrated below: + + .. code:: python + + def func(x, y): + xp_x = x.__array_namespace__() + xp_y = y.__array_namespace__() + + # Other functions than `from_dlpack` only work if both arrays are from the same library. So if + # `y` is from a different one than `x`, let's convert `y` into an array of the same type as `x`: + if not xp_x == xp_y: + y = xp_x.from_dlpack(y, copy=True, device=x.device) + + # From now on use `xp_x.xxxxx` functions, as both arrays are from the library `xp_x` + ... + + + .. versionchanged:: 2023.12 + Added device and copy support. """ From cc11aa344d8dab03345acb563f37c25583af151a Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Feb 2024 15:37:07 -0800 Subject: [PATCH 130/196] Add Array API inspection utilities (#689) --- spec/draft/API_specification/index.rst | 1 + spec/draft/API_specification/inspection.rst | 40 +++++ spec/draft/design_topics/device_support.rst | 29 ++-- src/_array_api_conf.py | 4 + src/array_api_stubs/_draft/__init__.py | 1 + src/array_api_stubs/_draft/_types.py | 59 +++++++ src/array_api_stubs/_draft/info.py | 170 ++++++++++++++++++++ 7 files changed, 290 insertions(+), 14 deletions(-) create mode 100644 spec/draft/API_specification/inspection.rst create mode 100644 src/array_api_stubs/_draft/info.py diff --git a/spec/draft/API_specification/index.rst b/spec/draft/API_specification/index.rst index 603131ab9..ffc3d3775 100644 --- a/spec/draft/API_specification/index.rst +++ b/spec/draft/API_specification/index.rst @@ -29,6 +29,7 @@ A conforming implementation of the array API standard must provide and support t function_and_method_signatures indexing indexing_functions + inspection linear_algebra_functions manipulation_functions searching_functions diff --git a/spec/draft/API_specification/inspection.rst b/spec/draft/API_specification/inspection.rst new file mode 100644 index 000000000..04691e712 --- /dev/null +++ b/spec/draft/API_specification/inspection.rst @@ -0,0 +1,40 @@ +Inspection +========== + + Array API specification for namespace inspection utilities. + +A conforming implementation of the array API standard must provide and support the following functions and associated inspection APIs. + + +Objects in API +-------------- + +.. currentmodule:: array_api.info + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + __array_namespace_info__ + + +Inspection APIs +--------------- + +In the namespace (or class) returned by ``__array_namespace_info__``, a conforming implementation of the array API standard must provide and support the following functions (or methods) for programmatically querying data type and device support, capabilities, and other specification-defined implementation-specific behavior, as documented in the functions described below. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + capabilities + default_device + default_dtypes + devices + dtypes diff --git a/spec/draft/design_topics/device_support.rst b/spec/draft/design_topics/device_support.rst index 29f0789bb..593b0b9fa 100644 --- a/spec/draft/design_topics/device_support.rst +++ b/spec/draft/design_topics/device_support.rst @@ -39,7 +39,7 @@ into library code which may have to do the following: Syntax for device assignment ---------------------------- -The array API will offer the following syntax for device assignment and +The array API provides the following syntax for device assignment and cross-device data transfer: 1. A ``.device`` property on the array object, which returns a ``Device`` object @@ -52,19 +52,20 @@ cross-device data transfer: 3. A ``.to_device`` method on the array object to copy an array to a different device. .. note:: - In the current API standard, the only way to obtain a ``Device`` object is from the - ``.device`` property on the array object. The standard does **not** include a universal - ``Device`` object recognized by all compliant libraries. Accordingly, the standard does - not provide a means of instantiating a ``Device`` object to point to a specific physical or - logical device. - - The choice to not include a standardized ``Device`` object may be revisited in a future revision of this standard. - - For array libraries which concern themselves with multi-device support, including CPU and GPU, - they are free to expose a library-specific device object (e.g., for creating an - array on a particular device). While a library-specific device object can be used as input to - ``to_device``, beware that this will mean non-portability as code will be specific to - that library. + The current API standard does **not** include a universal ``Device`` object + recognized by all compliant libraries. Accordingly, the standard does not + provide a means of instantiating a ``Device`` object to point to a specific + physical or logical device. + + The choice to not include a standardized ``Device`` object may be revisited + in a future revision of this standard. + + For array libraries which concern themselves with multi-device support, + including CPU and GPU, they are free to expose a library-specific device + object (e.g., for creating an array on a particular device). While a + library-specific device object can be used as input to ``to_device``, beware + that this will mean non-portability as code will be specific to that + library. Semantics --------- diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 9c5722f94..9233df3c4 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -72,6 +72,10 @@ ("py:class", ".*PyCapsule"), ("py:class", ".*finfo_object"), ("py:class", ".*iinfo_object"), + ("py:class", ".*Info"), + ("py:class", ".*Capabilities"), + ("py:class", ".*DefaultDataTypes"), + ("py:class", ".*DataTypes"), ] # In array_object.py we have to use aliased names for some types because they # would otherwise refer back to method objects of array diff --git a/src/array_api_stubs/_draft/__init__.py b/src/array_api_stubs/_draft/__init__.py index 12b6d9fbb..8415f2765 100644 --- a/src/array_api_stubs/_draft/__init__.py +++ b/src/array_api_stubs/_draft/__init__.py @@ -16,6 +16,7 @@ from .utility_functions import * from . import linalg from . import fft +from . import info __array_api_version__: str = "YYYY.MM" diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 2a73dda24..7c3d903d7 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -25,6 +25,10 @@ "finfo_object", "iinfo_object", "Enum", + "DefaultDataTypes", + "DataTypes", + "Capabilities", + "Info", ] from dataclasses import dataclass @@ -35,6 +39,7 @@ Optional, Sequence, Tuple, + TypedDict, TypeVar, Union, Protocol, @@ -83,3 +88,57 @@ def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: def __len__(self, /) -> int: ... + + +class Info(Protocol): + """Namespace returned by `__array_namespace_info__`.""" + + def capabilities(self) -> Capabilities: + ... + + def default_device(self) -> device: + ... + + def default_dtypes(self, *, device: Optional[device]) -> DefaultDataTypes: + ... + + def devices(self) -> List[device]: + ... + + def dtypes( + self, *, device: Optional[device], kind: Optional[Union[str, Tuple[str, ...]]] + ) -> DataTypes: + ... + + +DefaultDataTypes = TypedDict( + "DefaultDataTypes", + { + "real floating": dtype, + "complex floating": dtype, + "integral": dtype, + "indexing": dtype, + }, +) +DataTypes = TypedDict( + "DataTypes", + { + "bool": dtype, + "float32": dtype, + "float64": dtype, + "complex64": dtype, + "complex128": dtype, + "int8": dtype, + "int16": dtype, + "int32": dtype, + "int64": dtype, + "uint8": dtype, + "uint16": dtype, + "uint32": dtype, + "uint64": dtype, + }, + total=False, +) +Capabilities = TypedDict( + "Capabilities", {"boolean indexing": bool, "data-dependent shapes": bool} +) diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py new file mode 100644 index 000000000..f70418405 --- /dev/null +++ b/src/array_api_stubs/_draft/info.py @@ -0,0 +1,170 @@ +__all__ = [ + "__array_namespace_info__", + "capabilities", + "default_device", + "default_dtypes", + "devices", + "dtypes", +] + +from ._types import ( + Optional, + Union, + Tuple, + List, + device, + dtype, + DefaultDataTypes, + DataTypes, + Capabilities, + Info, +) + + +def __array_namespace_info__() -> Info: + """ + Returns a namespace with Array API namespace inspection utilities. + + Returns + ------- + out: Info + An object containing Array API namespace inspection utilities. + + Notes + ----- + + The returned object may be either a namespace or a class, so long as an Array API user can access inspection utilities as follows: + + :: + + info = xp.__array_namespace_info__() + info.capabilities() + info.devices() + info.dtypes() + info.default_dtypes() + # ... + """ + + +def capabilities() -> Capabilities: + """ + Returns a dictionary of array library capabilities. + + The dictionary must contain the following keys: + + - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + + Returns + ------- + out: Capabilities + a dictionary of array library capabilities. + """ + + +def default_device() -> device: + """ + Returns the default device. + + Returns + ------- + out: device + an object corresponding to the default device. + """ + + +def default_dtypes( + *, + device: Optional[device] = None, +) -> DefaultDataTypes: + """ + Returns a dictionary containing default data types. + + The dictionary must have the following keys: + + - `"real floating"`: default real floating-point data type. + - `"complex floating"`: default complex floating-point data type. + - `"integral"`: default integral data type. + - `"indexing"`: default array index data type. + + Dictionary values must be the corresponding data type object. + + Parameters + ---------- + device: Optional[device] + device for which to return default data types. If ``device`` is ``None``, the returned data types must be the default data types for the current device; otherwise, the returned data types must be default data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the default data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the default data types for the default device. + + Returns + ------- + out: DefaultDataTypes + a dictionary containing the default data type for respective data type kinds. + """ + + +def dtypes( + *, + device: Optional[device] = None, + kind: Optional[Union[str, Tuple[str, ...]]] = None, +) -> DataTypes: + """ + Returns a dictionary of supported *Array API* data types. + + .. note:: + While specification-conforming array libraries may support additional data types which are not present in this specification, data types which are not present in this specification should not be included in the returned dictionary. + + .. note:: + Specification-conforming array libraries must only return supported data types having expected properties as described in :ref:`data-types`. For example, if a library decides to alias ``float32`` as ``float64``, that library must not include ``float64`` in the dictionary of supported data types. + + Parameters + ---------- + kind: Optional[Union[str, Tuple[str, ...]]] + data type kind. + + - If ``kind`` is ``None``, the function must return a dictionary containing all supported Array API data types. + + - If ``kind`` is a string, the function must return a dictionary containing the data types belonging to the specified data type kind. The following data type kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of data type kinds, and the function must return a dictionary containing the data types belonging to at least one of the specified data type kinds. + + Default: ``None``. + device: Optional[device] + device for which to return supported data types. If ``device`` is ``None``, the returned data types must be the supported data types for the current device; otherwise, the returned data types must be supported data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the supported data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the supported data types for the default device. + + Returns + ------- + out: DataTypes + a dictionary containing supported data types. + + .. note:: + Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + """ + + +def devices() -> List[device]: + """ + Returns a list of supported devices which are available at runtime. + + Returns + ------- + out: List[device] + a list of supported devices. + + Notes + ----- + + Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + """ From ba787e3aaa75d41bcafa59ddc0915f61b483a403 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 16 Feb 2024 17:32:18 +0100 Subject: [PATCH 131/196] Add recommendation on what to do with DLPack read-only flag (#749) This is a follow-up to the discussion in gh-191. It's a recommendation rather than a hard requirement to allow implementers some choice. That said, this is how things worked in practice before DLPack 1.0 as well, since there was no flag to represent read-only. Experience with JAX showed that exposing shared memory was preferred by users over raising or always making a copy of the data on the producer side. --- src/array_api_stubs/_draft/array_object.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 5017bf87c..2a33a60ae 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -444,6 +444,12 @@ def __dlpack__( This logic is also applicable to handling of the new ``dl_device`` and ``copy`` keywords. + DLPack 1.0 added a flag to indicate that the array is read-only + (``DLPACK_FLAG_BITMASK_READ_ONLY``). A consumer that does not support + read-only arrays should ignore this flag (this is preferred over + raising an exception; the user is then responsible for ensuring the + memory isn't modified). + .. versionchanged:: 2022.12 Added BufferError. From bc48a1a3f73a64fdc6677f361bff11ee2baf7f97 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 21 Feb 2024 12:18:13 -0800 Subject: [PATCH 132/196] Add `hypot` specification for computing the square root of the sum of squares (#703) --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index f0b69cfcb..4919cff98 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -46,6 +46,7 @@ Objects in API floor_divide greater greater_equal + hypot imag isfinite isinf diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index c71b6674b..ee6ea27f3 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -28,6 +28,7 @@ "floor_divide", "greater", "greater_equal", + "hypot", "imag", "isfinite", "isinf", @@ -1367,6 +1368,51 @@ def greater_equal(x1: array, x2: array, /) -> array: """ +def hypot(x1: array, x2: array, /) -> array: + r""" + Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + The value computed by this function may be interpreted as the length of the hypotenuse of a right-angled triangle with sides of length ``x1_i`` and ``x2_i``, the distance of a point ``(x1_i, x2_i)`` from the origin ``(0, 0)``, or the magnitude of a complex number ``x1_i + x2_i * 1j``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``+infinity`` or ``-infinity`` and ``x2_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x2_i`` is ``+infinity`` or ``-infinity`` and ``x1_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x2_i)``. + - If ``x2_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x1_i)``. + - If ``x1_i`` is a finite number or ``NaN`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is a finite number or ``NaN`` and ``x1_i`` is ``NaN``, the result is ``NaN``. + - Underflow may only occur when both arguments are subnormal and the correct result is also subnormal. + + For real-valued floating-point operands, ``hypot(x1, x2)`` must equal ``hypot(x2, x1)``, ``hypot(x1, -x2)``, ``hypot(-x1, x2)``, and ``hypot(-x1, -x2)``. + + .. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, conforming implementations may vary in their support for subnormal numbers. + """ + + def imag(x: array, /) -> array: """ Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. From 6e9c48720fcde6941d48596e134c869c011a6a65 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 21 Feb 2024 23:18:27 -0800 Subject: [PATCH 133/196] docs: add note concerning signed zeros (#751) --- .../_draft/elementwise_functions.py | 14 ++++++----- .../_draft/statistical_functions.py | 24 +++++++++---------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index ee6ea27f3..4dc0c949f 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -1905,9 +1905,6 @@ def maximum(x1: array, x2: array, /) -> array: r""" Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x1: array @@ -1923,6 +1920,10 @@ def maximum(x1: array, x2: array, /) -> array: Notes ----- + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, @@ -1935,9 +1936,6 @@ def minimum(x1: array, x2: array, /) -> array: r""" Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x1: array @@ -1953,6 +1951,10 @@ def minimum(x1: array, x2: array, /) -> array: Notes ----- + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 496440535..2304ece80 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -64,12 +64,6 @@ def max( """ Calculates the maximum value of the input array ``x``. - .. note:: - When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). - - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x: array @@ -87,6 +81,12 @@ def max( Notes ----- + When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, @@ -144,12 +144,6 @@ def min( """ Calculates the minimum value of the input array ``x``. - .. note:: - When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). - - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x: array @@ -167,6 +161,12 @@ def min( Notes ----- + When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, From 11273e62fbfbc17b2a2f61535520ea3e34d71d52 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 22 Feb 2024 12:40:28 -0800 Subject: [PATCH 134/196] docs: clarify shape of `values` and order of `counts` (#752) --- src/array_api_stubs/_draft/set_functions.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 394fa2b17..25a897355 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -34,10 +34,10 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: out: Tuple[array, array, array, array] a namedtuple ``(values, indices, inverse_indices, counts)`` whose - - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. - - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of a flattened ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. - third element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and must have the default array index data type. - - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The returned array must have same shape as ``values`` and must have the default array index data type. + - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. .. note:: The order of unique elements is not specified and may vary between implementations. @@ -78,8 +78,8 @@ def unique_counts(x: array, /) -> Tuple[array, array]: out: Tuple[array, array] a namedtuple `(values, counts)` whose - - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. - - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The returned array must have same shape as ``values`` and must have the default array index data type. + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. .. note:: The order of unique elements is not specified and may vary between implementations. @@ -120,7 +120,7 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: out: Tuple[array, array] a namedtuple ``(values, inverse_indices)`` whose - - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. - second element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and have the default array index data type. .. note:: @@ -158,7 +158,7 @@ def unique_values(x: array, /) -> array: Returns ------- out: array - an array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. + a one-dimensional array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. .. note:: The order of unique elements is not specified and may vary between implementations. From 9d200ea3478a27bc3e93e3543a73369cfdc60ec0 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 22 Feb 2024 12:40:58 -0800 Subject: [PATCH 135/196] Add `repeat` to the specification (#690) --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index 680efb55f..395c1c3e2 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -25,6 +25,7 @@ Objects in API flip moveaxis permute_dims + repeat reshape roll squeeze diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 74538a8a3..4d7a17dda 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -6,6 +6,7 @@ "flip", "moveaxis", "permute_dims", + "repeat", "reshape", "roll", "squeeze", @@ -159,6 +160,53 @@ def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: """ +def repeat( + x: array, + repeats: Union[int, array], + /, + *, + axis: Optional[int] = None, +) -> array: + """ + Repeats each element of an array a specified number of times on a per-element basis. + + .. admonition:: Data-dependent output shape + :class: important + + When ``repeats`` is an array, the shape of the output array for this function depends on the data values in the ``repeats`` array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing the values in ``repeats``. Accordingly, such libraries may choose to omit support for ``repeats`` arrays; however, conforming implementations must support providing a literal ``int``. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array containing elements to repeat. + repeats: Union[int, array] + the number of repetitions for each element. + + If ``axis`` is ``None``, let ``N = prod(x.shape)`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(N,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(N,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape `(N,)`. + + If ``axis`` is not ``None``, let ``M = x.shape[axis]`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(M,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(M,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape ``(M,)``. + + If ``repeats`` is an array, the array must have an integer data type. + + .. note:: + For specification-conforming array libraries supporting hardware acceleration, providing an array for ``repeats`` may cause device synchronization due to an unknown output shape. For those array libraries where synchronization concerns are applicable, conforming array libraries are advised to include a warning in their documentation regarding potential performance degradation when ``repeats`` is an array. + + axis: Optional[int] + the axis (dimension) along which to repeat elements. If ``axis`` is `None`, the function must flatten the input array ``x`` and then repeat elements of the flattened input array and return the result as a one-dimensional output array. A flattened input array must be flattened in row-major, C-style order. Default: ``None``. + + Returns + ------- + out: array + an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + """ + + def reshape( x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None ) -> array: From cb44271dda95468e596fe7dcd0c08462bc7e0d60 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 25 Feb 2024 23:54:19 -0800 Subject: [PATCH 136/196] docs: add changelog for v2023.12 specification revision PR-URL: https://github.com/data-apis/array-api/pull/754 Reviewed-by: Athan Reines --- CHANGELOG.md | 132 ++++++++++++++++++ .../_2022_12/indexing_functions.py | 2 +- src/array_api_stubs/_draft/array_object.py | 25 +++- .../_draft/creation_functions.py | 3 + .../_draft/data_type_functions.py | 3 + .../_draft/elementwise_functions.py | 12 ++ src/array_api_stubs/_draft/fft.py | 27 ++++ .../_draft/indexing_functions.py | 5 +- src/array_api_stubs/_draft/info.py | 27 ++++ src/array_api_stubs/_draft/linalg.py | 12 +- .../_draft/linear_algebra_functions.py | 12 +- .../_draft/manipulation_functions.py | 20 +++ .../_draft/searching_functions.py | 2 + src/array_api_stubs/_draft/set_functions.py | 12 ++ .../_draft/statistical_functions.py | 14 ++ 15 files changed, 298 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0897e4ea5..eace3f0a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,138 @@ This changelog is organized by specification version and notes all changes with respect to the previous version. Within the section for a specific version (e.g., v2022.12), separate sections are used for (a) changes to existing APIs and requirements, (b) new APIs and new requirements, and (c) errata. +## v2023.12 + +### Updates + +> Updates to existing APIs and requirements. + +#### Normative + +- Clarify expectations concerning exception handling ([gh-613](https://github.com/data-apis/array-api/pull/613)) +- Clarify that the constant `newaxis` is an alias of `None` ([gh-687](https://github.com/data-apis/array-api/pull/687)) +- Add design discussion on lazy versus eager implementations ([gh-708](https://github.com/data-apis/array-api/pull/708)) +- Revise guidance to require a minimum upper bound for supported ranks ([gh-702](https://github.com/data-apis/array-api/pull/702)) +- Relax design requirements for positional and keyword-only arguments ([gh-730](https://github.com/data-apis/array-api/pull/730)) +- Add recommendation to `__dlpack__` for handling read-only arrays ([gh-749](https://github.com/data-apis/array-api/pull/749)) + +#### APIs + +- `__bool__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__complex__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__dlpack__`: add `max_version` keyword argument to support versioning ([gh-602](https://github.com/data-apis/array-api/pull/602)) +- `__dlpack__`: add `dl_device` and `copy` keyword arguments ([gh-741](https://github.com/data-apis/array-api/pull/741)) +- `__float__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__index__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__int__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `astype`: add support for an optional `device` keyword argument ([gh-665](https://github.com/data-apis/array-api/pull/665)) +- `from_dlpack`: require exceptions to address unsupported use cases ([gh-709](https://github.com/data-apis/array-api/pull/709)) +- `from_dlpack`: add support for `copy` and `device` keywords ([gh-741](https://github.com/data-apis/array-api/pull/741)) +- `max`: clarify that the order of signed zeros is unspecified ([gh-751](https://github.com/data-apis/array-api/pull/751)) +- `min`: clarify that the order of signed zeros is unspecified ([gh-751](https://github.com/data-apis/array-api/pull/751)) +- `take`: explicitly leave out-of-bounds behavior unspecified ([gh-701](https://github.com/data-apis/array-api/pull/701)) +- `tensordot`: allow negative axes ([gh-625](https://github.com/data-apis/array-api/pull/625)) +- `to_device`: clarify behavior when a provided `device` object corresponds to the same device on which an array instance resides ([gh-742](https://github.com/data-apis/array-api/pull/742)) +- `unique_all`: clarify the shape of the array containing unique values and the order of returned counts ([gh-752](https://github.com/data-apis/array-api/pull/752)) +- `unique_counts`: clarify the shape of the array containing unique values and the order of returned counts ([gh-752](https://github.com/data-apis/array-api/pull/752)) +- `unique_inverse`: clarify the shape of the array containing unique values ([gh-752](https://github.com/data-apis/array-api/pull/752)) +- `unique_values`: clarify the shape of the returned array ([gh-752](https://github.com/data-apis/array-api/pull/752)) + +#### Extensions + +> Updates to APIs and requirements included as part of specification extensions. + +- `fft.*`: clarify behavior of the `n` and `s` keyword arguments and the expected output array shape ([gh-720](https://github.com/data-apis/array-api/pull/720) and [gh-746](https://github.com/data-apis/array-api/pull/746); backported to v2022.12 revision of Array API specification) + +* * * + +### Additions + +> New APIs and requirements added to the specification. + +#### APIs + +The following APIs were added to the specification: + +- `__array_namespace_info__`: namespace with Array API namespace inspection utilities ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `clip`: clamp each element of an input array to a specified range ([gh-715](https://github.com/data-apis/array-api/pull/715)) +- `copysign`: compose a floating-point value with the magnitude of a `x1_i` and the sign of `x2_i` ([gh-693](https://github.com/data-apis/array-api/pull/693)) +- `cumulative_sum`: calculate the cumulative sum ([gh-653](https://github.com/data-apis/array-api/pull/653)) +- `hypot`: compute the square root of the sum of squares for each element in an array ([gh-703](https://github.com/data-apis/array-api/pull/703)) +- `maximum`: compute the maximum value for each element of an array relative to the respective element in another array ([gh-713](https://github.com/data-apis/array-api/pull/713)) +- `minimum`: compute the minimum value for each element of an array relative to the respective element in another array ([gh-713](https://github.com/data-apis/array-api/pull/713)) +- `moveaxis`: move array axes to new positions, while leaving other axes in their original positions ([gh-656](https://github.com/data-apis/array-api/pull/656)) +- `repeat`: repeat each element of an array a specified number of times ([gh-690](https://github.com/data-apis/array-api/pull/690)) +- `searchsorted`: find the indices into `x1` such that, if the corresponding elements in `x2` were inserted before the indices, the order of `x1`, when sorted in ascending order, would be preserved ([gh-699](https://github.com/data-apis/array-api/pull/699)) +- `signbit`: determine whether the sign bit is set for each element of an array ([gh-705](https://github.com/data-apis/array-api/pull/705)) +- `tile`: construct an array by tiling an input array ([gh-692](https://github.com/data-apis/array-api/pull/692)) +- `unstack`: split an array into a sequence of arrays along a given axis ([gh-604](https://github.com/data-apis/array-api/pull/604)) + +#### Inspection APIs + +The following inspection APIs were added to the specification: + +- `capabilities`: return a dictionary of array library capabilities ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `default_device`: return the default device ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `default_dtypes`: return a dictionary containing default data types ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `dtypes`: return a dictionary support Array API data types ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `devices`: return a list of supported devices ([gh-689](https://github.com/data-apis/array-api/pull/689)) + +* * * + +### Breaking Changes + +The following is a list of breaking changes relative to the previous version of the specification: + +- `prod`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) +- `sum`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) +- `vecdot`: only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) + +#### Extensions + +The following is a list of breaking changes in specification extensions relative to the previous version of the specification: + +- `fft.fft`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.fftn`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.hfft`: require the input array to have a complex-valued floating-point data type and require that the output array have a real-valued data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.ifft`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.ifftn`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.irfft`: require the output array have a real-valued floating-point data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.irfftn`: require the output array have a real-valued floating-point data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.fftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.rfftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `linalg.cross`: broadcast only along non-compute axes and only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) +- `linalg.trace`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) + +* * * + +### Errata + +The following is a list of fixes and points of clarification with regard to the previous version of the specification: + +- `__getitem__`: clarify typing to allow `None` in indexing ([gh-674](https://github.com/data-apis/array-api/pull/674) and [gh-687](https://github.com/data-apis/array-api/pull/687)) +- `__ge__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `__gt__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `__le__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `__lt__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `abs`: fix typo in return value description ([gh-633](https://github.com/data-apis/array-api/pull/633)) +- `asarray`: fix typo in `device` keyword argument description ([gh-681](https://github.com/data-apis/array-api/pull/681)) +- `conj`: fix typo in parameter description ([gh-706](https://github.com/data-apis/array-api/pull/706)) +- `finfo_object`: fix missing `dtype` attribute ([gh-639](https://github.com/data-apis/array-api/pull/639)) +- `fft.*`: fix various typing issues ([gh-720](https://github.com/data-apis/array-api/pull/720)) +- `iinfo_object`: fix missing `dtype` attribute ([gh-639](https://github.com/data-apis/array-api/pull/639)) +- `linalg.qr`: fix typo in function description ([gh-661](https://github.com/data-apis/array-api/pull/661)) +- `linalg.cholesky`: fix typo in function description ([gh-677](https://github.com/data-apis/array-api/pull/677)) +- `linalg.svd`: fix return type ([gh-619](https://github.com/data-apis/array-api/pull/619)) +- `prod`: clarify type promotion behavior when `dtype=None` ([gh-666](https://github.com/data-apis/array-api/pull/666)) +- `sum`: clarify type promotion behavior when `dtype=None` ([gh-666](https://github.com/data-apis/array-api/pull/666)) +- `take`: fix typing for optional `axis` keyword argument ([gh-644](https://github.com/data-apis/array-api/pull/644)) +- `tensordot`: fix typo in parameter description ([gh-622](https://github.com/data-apis/array-api/pull/622)) +- `trace`: clarify type promotion behavior when `dtype=None` ([gh-666](https://github.com/data-apis/array-api/pull/666)) +- `vecdot`: fix definition of complex inner product ([gh-723](https://github.com/data-apis/array-api/pull/723)) + +* * * + ## v2022.12 ### Updates diff --git a/src/array_api_stubs/_2022_12/indexing_functions.py b/src/array_api_stubs/_2022_12/indexing_functions.py index 0cbad55ab..5dd74461d 100644 --- a/src/array_api_stubs/_2022_12/indexing_functions.py +++ b/src/array_api_stubs/_2022_12/indexing_functions.py @@ -14,7 +14,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: input array. indices: array array indices. The array must be one-dimensional and have an integer data type. - axis: int + axis: Optional[int] axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 2a33a60ae..6dd70c278 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -247,6 +247,9 @@ def __bool__(self: array, /) -> bool: .. versionchanged:: 2022.12 Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __complex__(self: array, /) -> complex: @@ -285,6 +288,9 @@ def __complex__(self: array, /) -> complex: The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __dlpack__( @@ -451,10 +457,13 @@ def __dlpack__( memory isn't modified). .. versionchanged:: 2022.12 - Added BufferError. + Added BufferError. .. versionchanged:: 2023.12 - Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + + .. versionchanged:: 2023.12 + Added recommendation for handling read-only arrays. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -539,6 +548,9 @@ def __float__(self: array, /) -> float: .. versionchanged:: 2022.12 Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: @@ -664,6 +676,9 @@ def __index__(self: array, /) -> int: **Lazy implementations** The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __int__(self: array, /) -> int: @@ -711,6 +726,9 @@ def __int__(self: array, /) -> int: .. versionchanged:: 2022.12 Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __invert__(self: array, /) -> array: @@ -1192,6 +1210,9 @@ def to_device( - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. + + .. versionchanged:: 2023.12 + Clarified behavior when a provided ``device`` object corresponds to the device on which an array instance resides. """ diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index dec09db0c..6de79268e 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -289,6 +289,9 @@ def func(x, y): ... + .. versionchanged:: 2023.12 + Required exceptions to address unsupported use cases. + .. versionchanged:: 2023.12 Added device and copy support. """ diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 81d518807..e12d349c6 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -57,6 +57,9 @@ def astype( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Added device keyword argument support. """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 4dc0c949f..4462329d6 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -806,6 +806,8 @@ def clip( - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + + .. versionadded:: 2023.12 """ @@ -880,6 +882,8 @@ def copysign(x1: array, x2: array, /) -> array: - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + + .. versionadded:: 2023.12 """ @@ -1410,6 +1414,8 @@ def hypot(x1: array, x2: array, /) -> array: IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, conforming implementations may vary in their support for subnormal numbers. + + .. versionadded:: 2023.12 """ @@ -1929,6 +1935,8 @@ def maximum(x1: array, x2: array, /) -> array: For floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 """ @@ -1960,6 +1968,8 @@ def minimum(x1: array, x2: array, /) -> array: For floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 """ @@ -2390,6 +2400,8 @@ def signbit(x: array, /) -> array: - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index bdd7a9c83..4e8131c8b 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -64,6 +64,9 @@ def fft( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -113,6 +116,9 @@ def ifft( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -168,6 +174,9 @@ def fftn( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -223,6 +232,9 @@ def ifftn( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -323,6 +335,9 @@ def irfft( - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. """ @@ -435,6 +450,9 @@ def irfftn( - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. """ @@ -481,6 +499,9 @@ def hfft( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. """ @@ -559,6 +580,9 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. """ @@ -593,6 +617,9 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. """ diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index f3bf0fc14..35066a4a2 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -20,7 +20,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. note:: This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - axis: int + axis: Optional[int] axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. @@ -34,4 +34,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Out-of-bounds behavior is explicitly left unspecified. """ diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index f70418405..b755ca2c0 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -43,6 +43,8 @@ def __array_namespace_info__() -> Info: info.dtypes() info.default_dtypes() # ... + + .. versionadded: 2023.12 """ @@ -59,6 +61,11 @@ def capabilities() -> Capabilities: ------- out: Capabilities a dictionary of array library capabilities. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -70,6 +77,11 @@ def default_device() -> device: ------- out: device an object corresponding to the default device. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -101,6 +113,11 @@ def default_dtypes( ------- out: DefaultDataTypes a dictionary containing the default data type for respective data type kinds. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -151,6 +168,11 @@ def dtypes( .. note:: Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -167,4 +189,9 @@ def devices() -> List[device]: ----- Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + + Notes + ----- + + .. versionadded: 2023.12 """ diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 903f928d8..0950e6937 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -102,15 +102,18 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: Notes ----- + **Raises** + + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + .. versionchanged:: 2022.12 Added support for broadcasting. .. versionchanged:: 2022.12 Added complex data type support. - **Raises** - - - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + .. versionchanged:: 2023.12 + Restricted broadcasting to only non-compute axes and required that ``axis`` be a negative integer. """ @@ -772,6 +775,9 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. """ diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index eea898a6b..da4c97743 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -116,6 +116,9 @@ def tensordot( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Allow negative axes. """ @@ -151,10 +154,13 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: Notes ----- - .. versionchanged:: 2022.12 - Added complex data type support. - **Raises** - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted ``axis`` to only negative integers. """ diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 4d7a17dda..87f9511b0 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -139,6 +139,11 @@ def moveaxis( ------- out: array an array containing reordered axes. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2023.12 """ @@ -204,6 +209,11 @@ def repeat( ------- out: array an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + + Notes + ----- + + .. versionadded:: 2023.12 """ @@ -327,6 +337,11 @@ def tile(x: array, repetitions: Tuple[int, ...], /): ------- out: array a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + + Notes + ----- + + .. versionadded:: 2023.12 """ @@ -345,4 +360,9 @@ def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: ------- out: Tuple[array, ...] tuple of slices along the given dimension. All the arrays have the same shape. + + Notes + ----- + + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index dda000e74..029459b9a 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -134,6 +134,8 @@ def searchsorted( For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 25a897355..5b7e9a56c 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -47,6 +47,9 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. """ @@ -89,6 +92,9 @@ def unique_counts(x: array, /) -> Tuple[array, array]: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. """ @@ -131,6 +137,9 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior. """ @@ -168,4 +177,7 @@ def unique_values(x: array, /) -> array: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required that the output array must be one-dimensional. """ diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 2304ece80..9d3563e26 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -51,6 +51,8 @@ def cumulative_sum( **Special Cases** For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionadded:: 2023.12 """ @@ -92,6 +94,9 @@ def max( For floating-point operands, - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. """ @@ -172,6 +177,9 @@ def min( For floating-point operands, - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. """ @@ -222,6 +230,9 @@ def prod( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. """ @@ -314,6 +325,9 @@ def sum( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. """ From fbc9ddec2f0366df069901a1d99580b5791f8772 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:04:18 -0800 Subject: [PATCH 137/196] build: create new release --- .DS_Store | Bin 0 -> 6148 bytes LICENSE | 2 +- Makefile | 3 +- .../API_specification/array_object.rst | 308 ++ .../API_specification/broadcasting.rst | 128 + spec/2023.12/API_specification/constants.rst | 26 + .../API_specification/creation_functions.rst | 36 + .../API_specification/data_type_functions.rst | 26 + spec/2023.12/API_specification/data_types.rst | 143 + .../elementwise_functions.rst | 84 + .../function_and_method_signatures.rst | 63 + spec/2023.12/API_specification/index.rst | 41 + spec/2023.12/API_specification/indexing.rst | 208 ++ .../API_specification/indexing_functions.rst | 23 + spec/2023.12/API_specification/inspection.rst | 40 + .../linear_algebra_functions.rst | 23 + .../manipulation_functions.rst | 34 + .../API_specification/searching_functions.rst | 27 + .../API_specification/set_functions.rst | 24 + .../API_specification/sorting_functions.rst | 31 + .../statistical_functions.rst | 28 + .../API_specification/type_promotion.rst | 148 + .../API_specification/utility_functions.rst | 22 + spec/2023.12/API_specification/version.rst | 22 + spec/2023.12/assumptions.md | 77 + spec/2023.12/benchmark_suite.md | 3 + spec/2023.12/changelog.rst | 5 + spec/2023.12/conf.py | 13 + spec/2023.12/design_topics/C_API.rst | 94 + spec/2023.12/design_topics/accuracy.rst | 77 + .../2023.12/design_topics/complex_numbers.rst | 61 + .../copies_views_and_mutation.rst | 77 + .../data_dependent_output_shapes.rst | 15 + .../design_topics/data_interchange.rst | 105 + spec/2023.12/design_topics/device_support.rst | 112 + spec/2023.12/design_topics/exceptions.rst | 28 + spec/2023.12/design_topics/index.rst | 18 + spec/2023.12/design_topics/lazy_eager.rst | 43 + spec/2023.12/design_topics/parallelism.rst | 24 + spec/2023.12/design_topics/static_typing.rst | 50 + .../fourier_transform_functions.rst | 45 + spec/2023.12/extensions/index.rst | 34 + .../extensions/linear_algebra_functions.rst | 116 + spec/2023.12/future_API_evolution.md | 60 + spec/2023.12/index.rst | 37 + spec/2023.12/license.rst | 9 + spec/2023.12/purpose_and_scope.md | 470 +++ spec/2023.12/usage_data.md | 86 + spec/2023.12/use_cases.md | 235 ++ spec/2023.12/verification_test_suite.md | 62 + spec/_ghpages/versions.json | 1 + src/.DS_Store | Bin 0 -> 6148 bytes src/_array_api_conf.py | 2 +- src/array_api_stubs/_2023_12/__init__.py | 25 + src/array_api_stubs/_2023_12/_types.py | 144 + src/array_api_stubs/_2023_12/array_object.py | 1219 ++++++++ src/array_api_stubs/_2023_12/constants.py | 30 + .../_2023_12/creation_functions.py | 647 ++++ .../_2023_12/data_type_functions.py | 228 ++ src/array_api_stubs/_2023_12/data_types.py | 22 + .../_2023_12/elementwise_functions.py | 2774 +++++++++++++++++ src/array_api_stubs/_2023_12/fft.py | 683 ++++ .../_2023_12/indexing_functions.py | 40 + src/array_api_stubs/_2023_12/info.py | 197 ++ src/array_api_stubs/_2023_12/linalg.py | 850 +++++ .../_2023_12/linear_algebra_functions.py | 166 + .../_2023_12/manipulation_functions.py | 368 +++ .../_2023_12/searching_functions.py | 159 + src/array_api_stubs/_2023_12/set_functions.py | 183 ++ .../_2023_12/sorting_functions.py | 58 + .../_2023_12/statistical_functions.py | 374 +++ .../_2023_12/utility_functions.py | 86 + src/array_api_stubs/__init__.py | 2 +- 73 files changed, 11700 insertions(+), 4 deletions(-) create mode 100644 .DS_Store create mode 100644 spec/2023.12/API_specification/array_object.rst create mode 100644 spec/2023.12/API_specification/broadcasting.rst create mode 100644 spec/2023.12/API_specification/constants.rst create mode 100644 spec/2023.12/API_specification/creation_functions.rst create mode 100644 spec/2023.12/API_specification/data_type_functions.rst create mode 100644 spec/2023.12/API_specification/data_types.rst create mode 100644 spec/2023.12/API_specification/elementwise_functions.rst create mode 100644 spec/2023.12/API_specification/function_and_method_signatures.rst create mode 100644 spec/2023.12/API_specification/index.rst create mode 100644 spec/2023.12/API_specification/indexing.rst create mode 100644 spec/2023.12/API_specification/indexing_functions.rst create mode 100644 spec/2023.12/API_specification/inspection.rst create mode 100644 spec/2023.12/API_specification/linear_algebra_functions.rst create mode 100644 spec/2023.12/API_specification/manipulation_functions.rst create mode 100644 spec/2023.12/API_specification/searching_functions.rst create mode 100644 spec/2023.12/API_specification/set_functions.rst create mode 100644 spec/2023.12/API_specification/sorting_functions.rst create mode 100644 spec/2023.12/API_specification/statistical_functions.rst create mode 100644 spec/2023.12/API_specification/type_promotion.rst create mode 100644 spec/2023.12/API_specification/utility_functions.rst create mode 100644 spec/2023.12/API_specification/version.rst create mode 100644 spec/2023.12/assumptions.md create mode 100644 spec/2023.12/benchmark_suite.md create mode 100644 spec/2023.12/changelog.rst create mode 100644 spec/2023.12/conf.py create mode 100644 spec/2023.12/design_topics/C_API.rst create mode 100644 spec/2023.12/design_topics/accuracy.rst create mode 100644 spec/2023.12/design_topics/complex_numbers.rst create mode 100644 spec/2023.12/design_topics/copies_views_and_mutation.rst create mode 100644 spec/2023.12/design_topics/data_dependent_output_shapes.rst create mode 100644 spec/2023.12/design_topics/data_interchange.rst create mode 100644 spec/2023.12/design_topics/device_support.rst create mode 100644 spec/2023.12/design_topics/exceptions.rst create mode 100644 spec/2023.12/design_topics/index.rst create mode 100644 spec/2023.12/design_topics/lazy_eager.rst create mode 100644 spec/2023.12/design_topics/parallelism.rst create mode 100644 spec/2023.12/design_topics/static_typing.rst create mode 100644 spec/2023.12/extensions/fourier_transform_functions.rst create mode 100644 spec/2023.12/extensions/index.rst create mode 100644 spec/2023.12/extensions/linear_algebra_functions.rst create mode 100644 spec/2023.12/future_API_evolution.md create mode 100644 spec/2023.12/index.rst create mode 100644 spec/2023.12/license.rst create mode 100644 spec/2023.12/purpose_and_scope.md create mode 100644 spec/2023.12/usage_data.md create mode 100644 spec/2023.12/use_cases.md create mode 100644 spec/2023.12/verification_test_suite.md create mode 100644 src/.DS_Store create mode 100644 src/array_api_stubs/_2023_12/__init__.py create mode 100644 src/array_api_stubs/_2023_12/_types.py create mode 100644 src/array_api_stubs/_2023_12/array_object.py create mode 100644 src/array_api_stubs/_2023_12/constants.py create mode 100644 src/array_api_stubs/_2023_12/creation_functions.py create mode 100644 src/array_api_stubs/_2023_12/data_type_functions.py create mode 100644 src/array_api_stubs/_2023_12/data_types.py create mode 100644 src/array_api_stubs/_2023_12/elementwise_functions.py create mode 100644 src/array_api_stubs/_2023_12/fft.py create mode 100644 src/array_api_stubs/_2023_12/indexing_functions.py create mode 100644 src/array_api_stubs/_2023_12/info.py create mode 100644 src/array_api_stubs/_2023_12/linalg.py create mode 100644 src/array_api_stubs/_2023_12/linear_algebra_functions.py create mode 100644 src/array_api_stubs/_2023_12/manipulation_functions.py create mode 100644 src/array_api_stubs/_2023_12/searching_functions.py create mode 100644 src/array_api_stubs/_2023_12/set_functions.py create mode 100644 src/array_api_stubs/_2023_12/sorting_functions.py create mode 100644 src/array_api_stubs/_2023_12/statistical_functions.py create mode 100644 src/array_api_stubs/_2023_12/utility_functions.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cb2845bfd45fe0b2d4e5d60af22acccb797086ac GIT binary patch literal 6148 zcmeH~F$w}f3`G;&V!>uh%V|7-Hy9Q@ffo=|Y(z!TdXDZ-CJ3(9BJu;tpJXO1`-+{7 zh-iP?&P6&AY2l_avoJ74-pEzXvXjkybvYhR$31FRAH`W)!#f%5$2NroNPq-LfCNb3 zhX~lc4QnS=8A*TyNZ?7pz7Gj*nnO!f|8yYu2mozRcEj3d323qcG>4X|sK7L)2aQ(s zF~sWL4oz_`hnA|fT{MOdjVG&3F)*#|q6rC1vkLuHq@&4g1L!&>UK-q5|WOfMZ}Ffv*yH E03NCmz5oCK literal 0 HcmV?d00001 diff --git a/LICENSE b/LICENSE index e861ffccf..fb491e886 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2022 Consortium for Python Data API Standards contributors +Copyright (c) 2020-2024 Consortium for Python Data API Standards contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index d23e05218..51e1fbf76 100644 --- a/Makefile +++ b/Makefile @@ -23,5 +23,6 @@ spec: touch "$(BUILDDIR)/.nojekyll" sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) - cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" + sphinx-build "$(SOURCEDIR)/2023.12" "$(BUILDDIR)/2023.12" $(SPHINXOPTS) + cp -r "$(BUILDDIR)/2023.12" "$(BUILDDIR)/latest" sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/spec/2023.12/API_specification/array_object.rst b/spec/2023.12/API_specification/array_object.rst new file mode 100644 index 000000000..f8a586ade --- /dev/null +++ b/spec/2023.12/API_specification/array_object.rst @@ -0,0 +1,308 @@ +.. _array-object: + +Array object +============ + + Array API specification for array object attributes and methods. + +A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods. + +Furthermore, a conforming implementation of the array API standard must support, at minimum, array objects of rank (i.e., number of dimensions) ``0``, ``1``, ``2``, ``3``, and ``4`` and must explicitly document their maximum supported rank ``N``. + +.. note:: + Conforming implementations must support zero-dimensional arrays. + + Apart from array object attributes, such as ``ndim``, ``device``, and ``dtype``, all operations in this standard return arrays (or tuples of arrays), including those operations, such as ``mean``, ``var``, and ``std``, from which some common array libraries (e.g., NumPy) return scalar values. + + *Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value.* + +------------------------------------------------- + +.. _operators: + +Operators +--------- + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. + +Arithmetic Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. + +- ``+x``: :meth:`.array.__pos__` + + - `operator.pos(x) `_ + - `operator.__pos__(x) `_ + +- `-x`: :meth:`.array.__neg__` + + - `operator.neg(x) `_ + - `operator.__neg__(x) `_ + +- `x1 + x2`: :meth:`.array.__add__` + + - `operator.add(x1, x2) `_ + - `operator.__add__(x1, x2) `_ + +- `x1 - x2`: :meth:`.array.__sub__` + + - `operator.sub(x1, x2) `_ + - `operator.__sub__(x1, x2) `_ + +- `x1 * x2`: :meth:`.array.__mul__` + + - `operator.mul(x1, x2) `_ + - `operator.__mul__(x1, x2) `_ + +- `x1 / x2`: :meth:`.array.__truediv__` + + - `operator.truediv(x1,x2) `_ + - `operator.__truediv__(x1, x2) `_ + +- `x1 // x2`: :meth:`.array.__floordiv__` + + - `operator.floordiv(x1, x2) `_ + - `operator.__floordiv__(x1, x2) `_ + +- `x1 % x2`: :meth:`.array.__mod__` + + - `operator.mod(x1, x2) `_ + - `operator.__mod__(x1, x2) `_ + +- `x1 ** x2`: :meth:`.array.__pow__` + + - `operator.pow(x1, x2) `_ + - `operator.__pow__(x1, x2) `_ + +Arithmetic operators should be defined for arrays having real-valued data types. + +Array Operators +~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. + +- `x1 @ x2`: :meth:`.array.__matmul__` + + - `operator.matmul(x1, x2) `_ + - `operator.__matmul__(x1, x2) `_ + +The matmul ``@`` operator should be defined for arrays having real-valued data types. + +Bitwise Operators +~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. + +- `~x`: :meth:`.array.__invert__` + + - `operator.inv(x) `_ + - `operator.invert(x) `_ + - `operator.__inv__(x) `_ + - `operator.__invert__(x) `_ + +- `x1 & x2`: :meth:`.array.__and__` + + - `operator.and(x1, x2) `_ + - `operator.__and__(x1, x2) `_ + +- `x1 | x2`: :meth:`.array.__or__` + + - `operator.or(x1, x2) `_ + - `operator.__or__(x1, x2) `_ + +- `x1 ^ x2`: :meth:`.array.__xor__` + + - `operator.xor(x1, x2) `_ + - `operator.__xor__(x1, x2) `_ + +- `x1 << x2`: :meth:`.array.__lshift__` + + - `operator.lshift(x1, x2) `_ + - `operator.__lshift__(x1, x2) `_ + +- `x1 >> x2`: :meth:`.array.__rshift__` + + - `operator.rshift(x1, x2) `_ + - `operator.__rshift__(x1, x2) `_ + +Bitwise operators should be defined for arrays having integer and boolean data types. + +Comparison Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. + +- `x1 < x2`: :meth:`.array.__lt__` + + - `operator.lt(x1, x2) `_ + - `operator.__lt__(x1, x2) `_ + +- `x1 <= x2`: :meth:`.array.__le__` + + - `operator.le(x1, x2) `_ + - `operator.__le__(x1, x2) `_ + +- `x1 > x2`: :meth:`.array.__gt__` + + - `operator.gt(x1, x2) `_ + - `operator.__gt__(x1, x2) `_ + +- `x1 >= x2`: :meth:`.array.__ge__` + + - `operator.ge(x1, x2) `_ + - `operator.__ge__(x1, x2) `_ + +- `x1 == x2`: :meth:`.array.__eq__` + + - `operator.eq(x1, x2) `_ + - `operator.__eq__(x1, x2) `_ + +- `x1 != x2`: :meth:`.array.__ne__` + + - `operator.ne(x1, x2) `_ + - `operator.__ne__(x1, x2) `_ + +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + +In-place Operators +~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. + +An in-place operation must not change the data type or shape of the in-place array as a result of :ref:`type-promotion` or :ref:`broadcasting`. + +An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1 = x1 + x2``. + +.. note:: + In-place operators must be supported as discussed in :ref:`copyview-mutability`. + +Arithmetic Operators +"""""""""""""""""""" + +- ``+=``. May be implemented via ``__iadd__``. +- ``-=``. May be implemented via ``__isub__``. +- ``*=``. May be implemented via ``__imul__``. +- ``/=``. May be implemented via ``__itruediv__``. +- ``//=``. May be implemented via ``__ifloordiv__``. +- ``**=``. May be implemented via ``__ipow__``. +- ``%=``. May be implemented via ``__imod__``. + +Array Operators +""""""""""""""" + +- ``@=``. May be implemented via ``__imatmul__``. + +Bitwise Operators +""""""""""""""""" + +- ``&=``. May be implemented via ``__iand__``. +- ``|=``. May be implemented via ``__ior__``. +- ``^=``. May be implemented via ``__ixor__``. +- ``<<=``. May be implemented via ``__ilshift__``. +- ``>>=``. May be implemented via ``__irshift__``. + +Reflected Operators +~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. + +The results of applying reflected operators must match their non-reflected equivalents. + +.. note:: + All operators for which ``array scalar`` is implemented must have an equivalent reflected operator implementation. + +Arithmetic Operators +"""""""""""""""""""" + +- ``__radd__`` +- ``__rsub__`` +- ``__rmul__`` +- ``__rtruediv__`` +- ``__rfloordiv__`` +- ``__rpow__`` +- ``__rmod__`` + +Array Operators +""""""""""""""" + +- ``__rmatmul__`` + +Bitwise Operators +""""""""""""""""" + +- ``__rand__`` +- ``__ror__`` +- ``__rxor__`` +- ``__rlshift__`` +- ``__rrshift__`` + +------------------------------------------------- + +.. currentmodule:: array_api + +Attributes +---------- +.. + NOTE: please keep the attributes in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.dtype + array.device + array.mT + array.ndim + array.shape + array.size + array.T + +------------------------------------------------- + +Methods +------- +.. + NOTE: please keep the methods in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.__abs__ + array.__add__ + array.__and__ + array.__array_namespace__ + array.__bool__ + array.__complex__ + array.__dlpack__ + array.__dlpack_device__ + array.__eq__ + array.__float__ + array.__floordiv__ + array.__ge__ + array.__getitem__ + array.__gt__ + array.__index__ + array.__int__ + array.__invert__ + array.__le__ + array.__lshift__ + array.__lt__ + array.__matmul__ + array.__mod__ + array.__mul__ + array.__ne__ + array.__neg__ + array.__or__ + array.__pos__ + array.__pow__ + array.__rshift__ + array.__setitem__ + array.__sub__ + array.__truediv__ + array.__xor__ + array.to_device diff --git a/spec/2023.12/API_specification/broadcasting.rst b/spec/2023.12/API_specification/broadcasting.rst new file mode 100644 index 000000000..abb3ed222 --- /dev/null +++ b/spec/2023.12/API_specification/broadcasting.rst @@ -0,0 +1,128 @@ +.. _broadcasting: + +Broadcasting +============ + + Array API specification for broadcasting semantics. + +Overview +-------- + +**Broadcasting** refers to the automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +Broadcasting facilitates user ergonomics by encouraging users to avoid unnecessary copying of array data and can **potentially** enable more memory-efficient element-wise operations through vectorization, reduced memory consumption, and cache locality. + +Algorithm +--------- + +Given an element-wise operation involving two compatible arrays, an array having a singleton dimension (i.e., a dimension whose size is one) is broadcast (i.e., virtually repeated) across an array having a corresponding non-singleton dimension. + +If two arrays are of unequal rank, the array having a lower rank is promoted to a higher rank by (virtually) prepending singleton dimensions until the number of dimensions matches that of the array having a higher rank. + +The results of the element-wise operation must be stored in an array having a shape determined by the following algorithm. + +#. Let ``A`` and ``B`` both be arrays. + +#. Let ``shape1`` be a tuple describing the shape of array ``A``. + +#. Let ``shape2`` be a tuple describing the shape of array ``B``. + +#. Let ``N1`` be the number of dimensions of array ``A`` (i.e., the result of ``len(shape1)``). + +#. Let ``N2`` be the number of dimensions of array ``B`` (i.e., the result of ``len(shape2)``). + +#. Let ``N`` be the maximum value of ``N1`` and ``N2`` (i.e., the result of ``max(N1, N2)``). + +#. Let ``shape`` be a temporary list of length ``N`` for storing the shape of the result array. + +#. Let ``i`` be ``N-1``. + +#. Repeat, while ``i >= 0`` + + #. Let ``n1`` be ``N1 - N + i``. + + #. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. + + #. Let ``n2`` be ``N2 - N + i``. + + #. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. + + #. If ``d1 == 1``, then set the ``i``\th element of ``shape`` to ``d2``. + + #. Else, if ``d2 == 1``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, if ``d1 == d2``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, throw an exception. + + #. Set ``i`` to ``i-1``. + +#. Let ``tuple(shape)`` be the shape of the result array. + +Examples +~~~~~~~~ + +The following examples demonstrate the application of the broadcasting algorithm for two compatible arrays. + +:: + + A (4d array): 8 x 1 x 6 x 1 + B (3d array): 7 x 1 x 5 + --------------------------------- + Result (4d array): 8 x 7 x 6 x 5 + A (2d array): 5 x 4 + B (1d array): 1 + ------------------------- + Result (2d array): 5 x 4 + A (2d array): 5 x 4 + B (1d array): 4 + ------------------------- + Result (2d array): 5 x 4 + A (3d array): 15 x 3 x 5 + B (3d array): 15 x 1 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 1 + ------------------------------ + Result (3d array): 15 x 3 x 5 + + +The following examples demonstrate array shapes which do **not** broadcast. + +:: + + A (1d array): 3 + B (1d array): 4 # dimension does not match + + A (2d array): 2 x 1 + B (3d array): 8 x 4 x 3 # second dimension does not match + + A (3d array): 15 x 3 x 5 + B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended + +In-place Semantics +------------------ + +As implied by the broadcasting algorithm, in-place element-wise operations (including ``__setitem__``) must not change the shape of the in-place array as a result of broadcasting. Such operations should only be supported in the case where the right-hand operand can broadcast to the shape of the left-hand operand, after any indexing operations are performed. + +For example: + +:: + + x = empty((2, 3, 4)) + a = empty((1, 3, 4)) + + # This is OK. The shape of a, (1, 3, 4), can broadcast to the shape of x[...], (2, 3, 4) + x[...] = a + + # This is not allowed. The shape of a, (1, 3, 4), can NOT broadcast to the shape of x[1, ...], (3, 4) + x[1, ...] = a diff --git a/spec/2023.12/API_specification/constants.rst b/spec/2023.12/API_specification/constants.rst new file mode 100644 index 000000000..71cb8688d --- /dev/null +++ b/spec/2023.12/API_specification/constants.rst @@ -0,0 +1,26 @@ +Constants +========= + + Array API specification for constants. + +A conforming implementation of the array API standard must provide and support the following constants adhering to the following conventions. + +- Each constant must have a Python floating-point data type (i.e., ``float``) and be provided as a Python scalar value. + +Objects in API +-------------- + +.. currentmodule:: array_api.constants + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + + e + inf + nan + newaxis + pi diff --git a/spec/2023.12/API_specification/creation_functions.rst b/spec/2023.12/API_specification/creation_functions.rst new file mode 100644 index 000000000..ff5c06368 --- /dev/null +++ b/spec/2023.12/API_specification/creation_functions.rst @@ -0,0 +1,36 @@ +Creation Functions +================== + + Array API specification for creating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + arange + asarray + empty + empty_like + eye + from_dlpack + full + full_like + linspace + meshgrid + ones + ones_like + tril + triu + zeros + zeros_like diff --git a/spec/2023.12/API_specification/data_type_functions.rst b/spec/2023.12/API_specification/data_type_functions.rst new file mode 100644 index 000000000..d42968c7b --- /dev/null +++ b/spec/2023.12/API_specification/data_type_functions.rst @@ -0,0 +1,26 @@ +Data Type Functions +=================== + + Array API specification for data type functions. + +A conforming implementation of the array API standard must provide and support the following data type functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + astype + can_cast + finfo + iinfo + isdtype + result_type diff --git a/spec/2023.12/API_specification/data_types.rst b/spec/2023.12/API_specification/data_types.rst new file mode 100644 index 000000000..5987dd322 --- /dev/null +++ b/spec/2023.12/API_specification/data_types.rst @@ -0,0 +1,143 @@ +.. _data-types: + +Data Types +========== + + Array API specification for supported data types. + +A conforming implementation of the array API standard must provide and support +the following data types ("dtypes") in its array object, and as data type +objects in its main namespace under the specified names: + ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| dtype object | description | ++==============+============================================================================================================================================================================================+ +| bool | Boolean (``True`` or ``False``). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int8 | An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int16 | A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int32 | A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int64 | A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint8 | An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint16 | A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint32 | A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint64 | A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float32 | IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float64 | IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex64 | Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex128 | Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Data type objects must have the following methods (no attributes are required): + +.. + NOTE: please keep the functions in alphabetical order + +.. currentmodule:: array_api.data_types + +.. autosummary:: + :toctree: generated + :template: method.rst + + __eq__ + + +.. note:: + A conforming implementation of the array API standard may provide and + support additional data types beyond those described in this specification. + It may also support additional methods and attributes on dtype objects. + +.. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. + + +Use of data type objects +------------------------ + +Data type objects are used as ``dtype`` specifiers in functions and methods +(e.g., ``zeros((2, 3), dtype=float32)``), accessible as ``.dtype`` attribute on +arrays, and used in various casting and introspection functions (e.g., +``isdtype(x.dtype, 'integral')``). + +``dtype`` keywords in functions specify the data type of arrays returned from +functions or methods. ``dtype`` keywords are not required to affect the data +type used for intermediate calculations or results (e.g., implementors are free +to use a higher-precision data type when accumulating values for reductions, as +long as the returned array has the specified data type). + +.. note:: + Implementations may provide other ways to specify data types (e.g., ``zeros((2, 3), dtype='f4')``) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. + +See :ref:`type-promotion` for specification guidance describing the rules governing the interaction of two or more data types or data type objects. + + +.. _data-type-defaults: + +Default Data Types +------------------ + +A conforming implementation of the array API standard must define the following default data types. + +- a default real-valued floating-point data type (either ``float32`` or ``float64``). +- a default complex floating-point data type (either ``complex64`` or ``complex128``). +- a default integer data type (either ``int32`` or ``int64``). +- a default array index data type (either ``int32`` or ``int64``). + +The default real-valued floating-point and complex floating-point data types must be the same across platforms. + +The default complex floating-point point data type should match the default real-valued floating-point data type. For example, if the default real-valued floating-point data type is ``float32``, the default complex floating-point data type must be ``complex64``. If the default real-valued floating-point data type is ``float64``, the default complex floating-point data type must be ``complex128``. + +The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. + +The default array index data type may be ``int32`` on 32-bit platforms, but the default should be ``int64`` otherwise. + +Note that it is possible that a library supports multiple devices, with not all +those device types supporting the same data types. In this case, the default +integer or floating-point data types may vary with device. If that is the case, +the library should clearly warn about this in its documentation. + +.. note:: + The default data types should be clearly defined in a conforming library's documentation. + + +.. _data-type-categories: + +Data Type Categories +-------------------- + +For the purpose of organizing functions within this specification, the following data type categories are defined. + ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| data type category | dtypes | ++============================+========================================================================================================================================================+ +| Numeric | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Floating-point | ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued floating-point | ``float32`` and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Complex floating-point | ``complex64`` and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Boolean | ``bool``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +.. note:: + Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. diff --git a/spec/2023.12/API_specification/elementwise_functions.rst b/spec/2023.12/API_specification/elementwise_functions.rst new file mode 100644 index 000000000..4919cff98 --- /dev/null +++ b/spec/2023.12/API_specification/elementwise_functions.rst @@ -0,0 +1,84 @@ +.. _element-wise-functions: + +Element-wise Functions +====================== + + Array API specification for element-wise functions. + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + abs + acos + acosh + add + asin + asinh + atan + atan2 + atanh + bitwise_and + bitwise_left_shift + bitwise_invert + bitwise_or + bitwise_right_shift + bitwise_xor + ceil + clip + conj + copysign + cos + cosh + divide + equal + exp + expm1 + floor + floor_divide + greater + greater_equal + hypot + imag + isfinite + isinf + isnan + less + less_equal + log + log1p + log2 + log10 + logaddexp + logical_and + logical_not + logical_or + logical_xor + maximum + minimum + multiply + negative + not_equal + positive + pow + real + remainder + round + sign + signbit + sin + sinh + square + sqrt + subtract + tan + tanh + trunc diff --git a/spec/2023.12/API_specification/function_and_method_signatures.rst b/spec/2023.12/API_specification/function_and_method_signatures.rst new file mode 100644 index 000000000..0eca2ac69 --- /dev/null +++ b/spec/2023.12/API_specification/function_and_method_signatures.rst @@ -0,0 +1,63 @@ +.. _function-and-method-signatures: + +Function and method signatures +============================== + +Function signatures in this standard adhere to the following: + +1. Positional parameters should be `positional-only `_ parameters. + Positional-only parameters have no externally-usable name. When a function + accepting positional-only parameters is called, positional arguments are + mapped to these parameters based solely on their order. + + *Rationale: existing libraries have incompatible conventions, and using names + of positional parameters is not normal/recommended practice.* + + .. note:: + + Positional-only parameters are only available in Python >= 3.8. Libraries + still supporting 3.7 or 3.6 may consider making the API standard-compliant + namespace >= 3.8. Alternatively, they can add guidance to their users in the + documentation to use the functions as if they were positional-only. + +2. Optional parameters should be `keyword-only `_ arguments. + + *Rationale: this leads to more readable code, and it makes it easier to + evolve an API over time by adding keywords without having to worry about + keyword order.* + +3. For functions that have a single positional array parameter, that parameter + is called ``x``. For functions that have multiple array parameters, those + parameters are called ``xi`` with ``i = 1, 2, ...`` (i.e., ``x1``, ``x2``). + +4. Signatures include type annotations. The type annotations are also added to + individual parameter and return value descriptions. For code which aims to + adhere to the standard, adding type annotations is strongly recommended. + +A function signature and description will look like: + +:: + + funcname(x1, x2, /, *, key1=-1, key2=None) -> out: + Parameters + + x1 : array + description + x2 : array + description + key1 : int + description + key2 : Optional[str] + description + + Returns + + out : array + description + + +Method signatures will follow the same conventions modulo the addition of ``self``. + +Note that there are a few exceptions to rules (1) and (2), in cases where +it enhances readability or use of the non-default form of the parameter in +question is commonly used in code written for existing array libraries. diff --git a/spec/2023.12/API_specification/index.rst b/spec/2023.12/API_specification/index.rst new file mode 100644 index 000000000..ffc3d3775 --- /dev/null +++ b/spec/2023.12/API_specification/index.rst @@ -0,0 +1,41 @@ +.. _api-specification: + +API specification +================= + +A conforming implementation of the array API standard must provide and support the APIs and behavior detailed in this specification while adhering to the following conventions. + +- When a function signature includes a `/`, positional parameters must be `positional-only `_ parameters. See :ref:`function-and-method-signatures`. +- When a function signature includes a `*`, optional parameters must be `keyword-only `_ arguments. See :ref:`function-and-method-signatures`. +- Broadcasting semantics must follow the semantics defined in :ref:`broadcasting`. +- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. +- Functions may only be required for a subset of input data types. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in :ref:`accuracy`. + + +.. toctree:: + :caption: API specification + :maxdepth: 3 + + array_object + broadcasting + constants + creation_functions + data_type_functions + data_types + elementwise_functions + function_and_method_signatures + indexing + indexing_functions + inspection + linear_algebra_functions + manipulation_functions + searching_functions + set_functions + sorting_functions + statistical_functions + type_promotion + utility_functions + version diff --git a/spec/2023.12/API_specification/indexing.rst b/spec/2023.12/API_specification/indexing.rst new file mode 100644 index 000000000..eb61c26d5 --- /dev/null +++ b/spec/2023.12/API_specification/indexing.rst @@ -0,0 +1,208 @@ +.. _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. Let ``n`` be the axis (dimension) size. + +- An integer index must be an object satisfying `operator.index `_ (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 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:: + 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]``. + + .. note:: + 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``. + +- Colons ``:`` must be used for `slices `_: ``start:stop:step``, where ``start`` is inclusive and ``stop`` is exclusive. + + .. note:: + The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. + +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``). 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. + +:: + + A[:] + A[i:] + A[:j] + A[i:k] + A[::] + A[i::] + A[:j:] + A[::k] + A[i:j:] + A[i::k] + A[:j:k] + A[i::k] + A[i:j:k] + +.. note:: + Slice syntax can be equivalently achieved using the Python built-in `slice() `_ API. From the perspective of ``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 + +:: + + i, i+k, i+2k, i+3k, ..., i+(m-1)k + +where + +:: + + m = q + r + +and ``q`` and ``r`` (``r != 0``) are the quotient and remainder obtained by dividing ``j-i`` by ``k`` + +:: + + j - i = qk + r + +such that + +:: + + j > i + (m-1)k + +.. note:: + 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:: + 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``. +- 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``. + +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``. + +- 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:: + This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where ``0:100`` and ``0:10`` are equivalent on a list of length ``10``. + +The following ranges for the start and stop values of a slice must be supported. Let ``n`` be the axis (dimension) size being sliced. For a slice ``i:j:k``, the behavior specified above should be implemented for the following: + +- ``i`` or ``j`` omitted (``None``). +- ``-n <= i <= n``. +- For ``k > 0`` or ``k`` omitted (``None``), ``-n <= j <= n``. +- For ``k < 0``, ``-n - 1 <= j <= max(0, n - 1)``. + +The behavior outside of these bounds is unspecified. + +.. note:: + *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 (consistent with Python* ``list`` *slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +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``. + +- 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, ``A[(exp1, exp2, ..., expN)]`` is equivalent to ``A[exp1, exp2, ..., expN]``; the latter is syntactic sugar for the former. + + Accordingly, if ``A`` has rank ``1``, then ``A[(2:10,)]`` must be equivalent to ``A[2:10]``. If ``A`` has rank ``2``, then ``A[(2:10, :)]`` must be equivalent to ``A[2:10, :]``. And so on and so forth. + +- 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+i+1``, 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 must 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``. + + .. note:: + When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. + +- Providing a slice must retain array dimensions (i.e., the array rank must remain the same; ``rank(A) == rank(A[:])``). + +- 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 ``IndexError`` exception must be raised if more than one ellipsis is provided. + +- Providing an empty tuple or an ellipsis to an array of rank ``0`` must result in an array of the same rank (i.e., if ``A`` has rank ``0``, ``A == A[()]`` and ``A == A[...]``). + + .. note:: + This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. + +- Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. + + .. note:: + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. + + .. note:: + The constant ``newaxis`` is an alias of ``None`` and can thus be used in a similar manner as ``None``. + +- Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. + + .. note:: + Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. + + To perform flat indexing, use ``reshape(x, (-1,))[integer]``. + +- An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions (excluding ``None``) is greater than ``N``. + + .. 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 +---------------------- + +.. admonition:: Data-dependent output shape + :class: admonition important + + For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See :ref:`data-dependent-output-shapes` section for more details. + +An array must support indexing where the **sole index** is an ``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)``. + + .. note:: + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~array_api.expand_dims`. + +- 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:: + 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``) 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``. + +Return Values +------------- + +The result of an indexing operation (e.g., multi-axis indexing, boolean array indexing, etc) must be an array of the same data type as the indexed array. + +.. note:: + The specified return value behavior includes indexing operations which return a single value (e.g., accessing a single element within a one-dimensional array). diff --git a/spec/2023.12/API_specification/indexing_functions.rst b/spec/2023.12/API_specification/indexing_functions.rst new file mode 100644 index 000000000..aef298566 --- /dev/null +++ b/spec/2023.12/API_specification/indexing_functions.rst @@ -0,0 +1,23 @@ +.. _indexing-functions: + +Indexing Functions +=================== + + Array API specification for functions for indexing arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + take diff --git a/spec/2023.12/API_specification/inspection.rst b/spec/2023.12/API_specification/inspection.rst new file mode 100644 index 000000000..04691e712 --- /dev/null +++ b/spec/2023.12/API_specification/inspection.rst @@ -0,0 +1,40 @@ +Inspection +========== + + Array API specification for namespace inspection utilities. + +A conforming implementation of the array API standard must provide and support the following functions and associated inspection APIs. + + +Objects in API +-------------- + +.. currentmodule:: array_api.info + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + __array_namespace_info__ + + +Inspection APIs +--------------- + +In the namespace (or class) returned by ``__array_namespace_info__``, a conforming implementation of the array API standard must provide and support the following functions (or methods) for programmatically querying data type and device support, capabilities, and other specification-defined implementation-specific behavior, as documented in the functions described below. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + capabilities + default_device + default_dtypes + devices + dtypes diff --git a/spec/2023.12/API_specification/linear_algebra_functions.rst b/spec/2023.12/API_specification/linear_algebra_functions.rst new file mode 100644 index 000000000..04d36f50a --- /dev/null +++ b/spec/2023.12/API_specification/linear_algebra_functions.rst @@ -0,0 +1,23 @@ +Linear Algebra Functions +======================== + + Array API specification for linear algebra functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + matmul + matrix_transpose + tensordot + vecdot diff --git a/spec/2023.12/API_specification/manipulation_functions.rst b/spec/2023.12/API_specification/manipulation_functions.rst new file mode 100644 index 000000000..395c1c3e2 --- /dev/null +++ b/spec/2023.12/API_specification/manipulation_functions.rst @@ -0,0 +1,34 @@ +Manipulation Functions +====================== + + Array API specification for manipulating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + broadcast_arrays + broadcast_to + concat + expand_dims + flip + moveaxis + permute_dims + repeat + reshape + roll + squeeze + stack + tile + unstack diff --git a/spec/2023.12/API_specification/searching_functions.rst b/spec/2023.12/API_specification/searching_functions.rst new file mode 100644 index 000000000..c952f1aad --- /dev/null +++ b/spec/2023.12/API_specification/searching_functions.rst @@ -0,0 +1,27 @@ +.. _searching-functions: + +Searching Functions +=================== + + Array API specification for functions for searching arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argmax + argmin + nonzero + searchsorted + where diff --git a/spec/2023.12/API_specification/set_functions.rst b/spec/2023.12/API_specification/set_functions.rst new file mode 100644 index 000000000..addf31e1f --- /dev/null +++ b/spec/2023.12/API_specification/set_functions.rst @@ -0,0 +1,24 @@ +Set Functions +============= + + Array API specification for creating and operating on sets. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + unique_all + unique_counts + unique_inverse + unique_values diff --git a/spec/2023.12/API_specification/sorting_functions.rst b/spec/2023.12/API_specification/sorting_functions.rst new file mode 100644 index 000000000..ad3af8857 --- /dev/null +++ b/spec/2023.12/API_specification/sorting_functions.rst @@ -0,0 +1,31 @@ +Sorting Functions +================= + + Array API specification for sorting functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. note:: + + For floating-point input arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. + + Implementations may choose to sort signed zeros (``-0 < +0``) or may choose to rely solely on value equality (``==``). + + Implementations may choose to sort NaNs (e.g., to the end or to the beginning of a returned array) or leave them in-place. Should an implementation sort NaNs, the sorting convention should be clearly documented in the conforming implementation's documentation. + + While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argsort + sort diff --git a/spec/2023.12/API_specification/statistical_functions.rst b/spec/2023.12/API_specification/statistical_functions.rst new file mode 100644 index 000000000..20e02b3f9 --- /dev/null +++ b/spec/2023.12/API_specification/statistical_functions.rst @@ -0,0 +1,28 @@ +Statistical Functions +===================== + + Array API specification for statistical functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cumulative_sum + max + mean + min + prod + std + sum + var diff --git a/spec/2023.12/API_specification/type_promotion.rst b/spec/2023.12/API_specification/type_promotion.rst new file mode 100644 index 000000000..339b90e45 --- /dev/null +++ b/spec/2023.12/API_specification/type_promotion.rst @@ -0,0 +1,148 @@ +.. _type-promotion: + +Type Promotion Rules +==================== + + Array API specification for type promotion rules. + +Type promotion rules can be understood at a high level from the following diagram: + +.. image:: ../../_static/images/dtype_promotion_lattice.png + :target: Type promotion diagram + +*Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* + +Rules +----- + +A conforming implementation of the array API standard must implement the following type promotion rules governing the common result type for two **array** operands during an arithmetic operation. + +A conforming implementation of the array API standard may support additional type promotion rules beyond those described in this specification. + +.. note:: + Type codes are used here to keep tables readable; they are not part of the standard. In code, use the data type objects specified in :ref:`data-types` (e.g., ``int16`` rather than ``'i2'``). + +.. + Note: please keep table columns aligned + +The following type promotion tables specify the casting behavior for operations involving two array operands. When more than two array operands participate, application of the promotion tables is associative (i.e., the result does not depend on operand order). + +Signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | i1 | i2 | i4 | i8 | ++========+====+====+====+====+ +| **i1** | i1 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i2** | i2 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i4** | i4 | i4 | i4 | i8 | ++--------+----+----+----+----+ +| **i8** | i8 | i8 | i8 | i8 | ++--------+----+----+----+----+ + +where + +- **i1**: 8-bit signed integer (i.e., ``int8``) +- **i2**: 16-bit signed integer (i.e., ``int16``) +- **i4**: 32-bit signed integer (i.e., ``int32``) +- **i8**: 64-bit signed integer (i.e., ``int64``) + +Unsigned integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | u1 | u2 | u4 | u8 | ++========+====+====+====+====+ +| **u1** | u1 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u2** | u2 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u4** | u4 | u4 | u4 | u8 | ++--------+----+----+----+----+ +| **u8** | u8 | u8 | u8 | u8 | ++--------+----+----+----+----+ + +where + +- **u1**: 8-bit unsigned integer (i.e., ``uint8``) +- **u2**: 16-bit unsigned integer (i.e., ``uint16``) +- **u4**: 32-bit unsigned integer (i.e., ``uint32``) +- **u8**: 64-bit unsigned integer (i.e., ``uint64``) + +Mixed unsigned and signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+ +| | u1 | u2 | u4 | ++========+====+====+====+ +| **i1** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i2** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i4** | i4 | i4 | i8 | ++--------+----+----+----+ +| **i8** | i8 | i8 | i8 | ++--------+----+----+----+ + +Floating-point type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++---------+-----+-----+-----+-----+ +| | f4 | f8 | c8 | c16 | ++=========+=====+=====+=====+=====+ +| **f4** | f4 | f8 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **f8** | f8 | f8 | c16 | c16 | ++---------+-----+-----+-----+-----+ +| **c8** | c8 | c16 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **c16** | c16 | c16 | c16 | c16 | ++---------+-----+-----+-----+-----+ + +where + +- **f4**: single-precision (32-bit) floating-point number (i.e., ``float32``) +- **f8**: double-precision (64-bit) floating-point number (i.e., ``float64``) +- **c8**: single-precision complex floating-point number (i.e., ``complex64``) + composed of two single-precision (32-bit) floating-point numbers +- **c16**: double-precision complex floating-point number (i.e., ``complex128``) + composed of two double-precision (64-bit) floating-point numbers + + +Notes +~~~~~ + +- Type promotion rules must apply when determining the common result type for two **array** operands during an arithmetic operation, regardless of array dimension. Accordingly, zero-dimensional arrays must be subject to the same type promotion rules as dimensional arrays. +- Type promotion of non-numerical data types to numerical data types is unspecified (e.g., ``bool`` to ``intxx`` or ``floatxx``). + +.. note:: + Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. + +Mixing arrays with Python scalars +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using Python scalars (i.e., instances of ``bool``, ``int``, ``float``, ``complex``) together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with the array data type: + +- a Python ``bool`` for a ``bool`` array data type. +- a Python ``int`` within the bounds of the given data type for integer array :ref:`data-types`. +- a Python ``int`` or ``float`` for real-valued floating-point array data types. +- a Python ``int``, ``float``, or ``complex`` for complex floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to zero-dimensional array with the same data type as that of the array used in the expression. +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +.. note:: + Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. + + Similarly, behavior is not specified when mixing a Python ``complex`` and an array with a real-valued data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. + + Behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. diff --git a/spec/2023.12/API_specification/utility_functions.rst b/spec/2023.12/API_specification/utility_functions.rst new file mode 100644 index 000000000..5105fa3df --- /dev/null +++ b/spec/2023.12/API_specification/utility_functions.rst @@ -0,0 +1,22 @@ +Utility Functions +================= + + Array API specification for utility functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + all + any diff --git a/spec/2023.12/API_specification/version.rst b/spec/2023.12/API_specification/version.rst new file mode 100644 index 000000000..346395d9a --- /dev/null +++ b/spec/2023.12/API_specification/version.rst @@ -0,0 +1,22 @@ +Version +======= + + Array API specification for versioning. + +A conforming implementation of the array API standard must provide a `__array_api_version__` attribute - see :ref:`api-versioning` for details. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + :nosignatures: + + __array_api_version__ diff --git a/spec/2023.12/assumptions.md b/spec/2023.12/assumptions.md new file mode 100644 index 000000000..b11482c5a --- /dev/null +++ b/spec/2023.12/assumptions.md @@ -0,0 +1,77 @@ +(Assumptions)= + +# Assumptions + +## Hardware and software environments + +No assumptions on a specific hardware environment are made. It must be possible +to create an array library adhering to this standard that runs (efficiently) on +a variety of different hardware: CPUs with different architectures, GPUs, +distributed systems and TPUs and other emerging accelerators. + +The same applies to software environments: it must be possible to create an +array library adhering to this standard that runs efficiently independent of +what compilers, build-time or run-time execution environment, or distribution +and install method is employed. Parallel execution, JIT compilation, and +delayed (lazy) evaluation must all be possible. + +The variety of hardware and software environments puts _constraints_ on choices +made in the API standard. For example, JIT compilers may require output dtypes +of functions to be predictable from input dtypes only rather than input values. + + +(assumptions-dependencies)= + +## Dependencies + +The only dependency that's assumed in this standard is that on Python itself. +Python >= 3.8 is assumed, motivated by the use of positional-only parameters +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). + +Importantly, array libraries are not assumed to be aware of each other, or of +a common array-specific layer. The [use cases](use_cases.md) do not require +such a dependency, and building and evolving an array library is easier without +such a coupling. Facilitation support of multiple array types in downstream +libraries is an important use case however, the assumed dependency structure +for that is: + +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) + +Array libraries may know how to interoperate with each other, for example by +constructing their own array type from that of another library or by shared +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). +This can be done without a dependency though - only adherence to a protocol is +enough. + +Array-consuming libraries will have to depend on one or more array libraries. +That could be a "soft dependency" though, meaning retrieving an array library +namespace from array instances that are passed in, but not explicitly doing +`import arraylib_name`. + + +## Backwards compatibility + +The assumption made during creation of this standard is that libraries are +constrained by backwards compatibility guarantees to their users, and are +likely unwilling to make significant backwards-incompatible changes for the +purpose of conforming to this standard. Therefore it is assumed that the +standard will be made available in a new namespace within each library, or the +library will provide a way to retrieve a module or module-like object that +adheres to this standard. See {ref}`how-to-adopt-this-api` for more details. + + +## Production code & interactive use + +It is assumed that the primary use case is writing production code, for example +in array-consuming libraries. As a consequence, making it easy to ensure that +code is written as intended and has unambiguous semantics is preferred - and +clear exceptions must be raised otherwise. + +It is also assumed that this does not significantly detract from the +interactive user experience. However, in case existing libraries differ in +behavior, the more strict version of that behavior is typically preferred. A +good example is array inputs to functions - while NumPy accepts lists, tuples, +generators, and anything else that could be turned into an array, most other +libraries only accept their own array types. This standard follows the latter choice. +It is likely always possible to put a thin "interactive use convenience layer" +on top of a more strict behavior. diff --git a/spec/2023.12/benchmark_suite.md b/spec/2023.12/benchmark_suite.md new file mode 100644 index 000000000..41066c6a4 --- /dev/null +++ b/spec/2023.12/benchmark_suite.md @@ -0,0 +1,3 @@ +# Benchmark suite + +Adding a benchmark suite is planned in the future. diff --git a/spec/2023.12/changelog.rst b/spec/2023.12/changelog.rst new file mode 100644 index 000000000..701a3dbcd --- /dev/null +++ b/spec/2023.12/changelog.rst @@ -0,0 +1,5 @@ +Changelog per API standard version +================================== + +.. include:: ../../CHANGELOG.md + :parser: myst_parser.sphinx_ diff --git a/spec/2023.12/conf.py b/spec/2023.12/conf.py new file mode 100644 index 000000000..f1bee91d4 --- /dev/null +++ b/spec/2023.12/conf.py @@ -0,0 +1,13 @@ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) + +from array_api_stubs import _2023_12 as stubs_mod +from _array_api_conf import * + +release = "2023.12" + +nav_title = html_theme_options.get("nav_title") + " v{}".format(release) +html_theme_options.update({"nav_title": nav_title}) +sys.modules["array_api"] = stubs_mod diff --git a/spec/2023.12/design_topics/C_API.rst b/spec/2023.12/design_topics/C_API.rst new file mode 100644 index 000000000..6a44596b0 --- /dev/null +++ b/spec/2023.12/design_topics/C_API.rst @@ -0,0 +1,94 @@ +.. _C-API: + +C API +===== + +Use of a C API is out of scope for this array API, as mentioned in :ref:`Scope`. +There are a lot of libraries that do use such an API - in particular via Cython code +or via direct usage of the NumPy C API. When the maintainers of such libraries +want to use this array API standard to support multiple types of arrays, they +need a way to deal with that issue. This section aims to provide some guidance. + +The assumption in the rest of this section is that performance matters for the library, +and hence the goal is to make other array types work without converting to a +``numpy.ndarray`` or another particular array type. If that's not the case (e.g. for a +visualization package), then other array types can simply be handled by converting +to the supported array type. + +.. note:: + Often a zero-copy conversion to ``numpy.ndarray`` is possible, at least for CPU arrays. + If that's the case, this may be a good way to support other array types. + The main difficulty in that case will be getting the return array type right - however, + this standard does provide a Python-level API for array construction that should allow + doing this. A relevant question is if it's possible to know with + certainty that a conversion will be zero-copy. This may indeed be + possible, see :ref:`data-interchange`. + + +Example situations for C/Cython usage +------------------------------------- + +Situation 1: a Python package that is mostly pure Python, with a limited number of Cython extensions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include Statsmodels, scikit-bio and QuTiP + +Main strategy: documentation. The functionality using Cython code will not support other array types (or only with conversion to/from ``numpy.ndarray``), which can be documented per function. + + +Situation 2: a Python package that contains a lot of Cython code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include scikit-learn and scikit-image + +Main strategy: add support for other array types *per submodule*. This keeps it manageable to explain to the user which functionality does and doesn't have support. + +Longer term: specific support for particular array types (e.g. ``cupy.ndarray`` can be supported with Python-only code via ``cupy.ElementwiseKernel``). + + +Situation 3: a Python package that uses the NumPy or Python C API directly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include SciPy and Astropy + +Strategy: similar to *situation 2*, but the number of submodules that can support all array types may be limited. + + +Device support +-------------- + +Supporting non-CPU array types in code using the C API or Cython seems problematic, +this almost inevitably will require custom device-specific code (e.g., CUDA, ROCm) or +something like JIT compilation with Numba. + + +Other longer-term approaches +---------------------------- + +Further Python API standardization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There may be cases where it makes sense to standardize additional sets of +functions, because they're important enough that array libraries tend to +reimplement them. An example of this may be *special functions*, as provided +by ``scipy.special``. Bessel and gamma functions for example are commonly +reimplemented by array libraries. This may avoid having to drop into a +particular implementation that does use a C API (e.g., one can then rely on +``arraylib.special.gamma`` rather than having to use ``scipy.special.gamma``). + +HPy +~~~ + +`HPy `_ is a new project that will provide a higher-level +C API and ABI than CPython offers. A Cython backend targeting HPy will be provided as well. + +- Better PyPy support +- Universal ABI - single binary for all supported Python versions +- Cython backend generating HPy rather than CPython code + +HPy isn't quite ready for mainstream usage today, but once it is it may +help make supporting multiple array libraries or adding non-CPU device +support to Cython more feasible. diff --git a/spec/2023.12/design_topics/accuracy.rst b/spec/2023.12/design_topics/accuracy.rst new file mode 100644 index 000000000..8c97db698 --- /dev/null +++ b/spec/2023.12/design_topics/accuracy.rst @@ -0,0 +1,77 @@ +.. _accuracy: + +Accuracy +======== + + Array API specification for minimum accuracy requirements. + +Arithmetic Operations +--------------------- + +The results of element-wise arithmetic operations + +- ``+`` +- ``-`` +- ``*`` +- ``/`` +- ``%`` + +including the corresponding element-wise array APIs defined in this standard + +- add +- subtract +- multiply +- divide + +for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., ties rounded toward the nearest value with an even least significant bit). + +Mathematical Functions +---------------------- + +This specification does **not** precisely define the behavior of the following functions + +- acos +- acosh +- asin +- asinh +- atan +- atan2 +- atanh +- cos +- cosh +- exp +- expm1 +- log +- log1p +- log2 +- log10 +- pow +- sin +- sinh +- tan +- tanh + +except to require specific results for certain argument values that represent boundary cases of interest. + +.. note:: + To help readers identify functions lacking precisely defined accuracy behavior, this specification uses the phrase "implementation-dependent approximation" in function descriptions. + +For other argument values, these functions should compute approximations to the results of respective mathematical functions; however, this specification recognizes that array libraries may be constrained by underlying hardware and/or seek to optimize performance over absolute accuracy and, thus, allows some latitude in the choice of approximation algorithms. + +Although the specification leaves the choice of algorithms to the implementation, this specification recommends (but does not specify) that implementations use the approximation algorithms for IEEE 754-2019 arithmetic contained in `FDLIBM `_, the freely distributable mathematical library from Sun Microsystems, or some other comparable IEEE 754-2019 compliant mathematical library. + +.. note:: + With exception of a few mathematical functions, returning results which are indistinguishable from correctly rounded infinitely precise results is difficult, if not impossible, to achieve due to the algorithms involved, the limits of finite-precision, and error propagation. However, this specification recognizes that numerical accuracy alignment among array libraries is desirable in order to ensure portability and reproducibility. Accordingly, for each mathematical function, the specification test suite includes test values which span a function's domain and reports the average and maximum deviation from either a designated standard implementation (e.g., an arbitrary precision arithmetic implementation) or an average computed across a subset of known array library implementations. Such reporting aids users who need to know how accuracy varies among libraries and developers who need to check the validity of their implementations. + +Statistical Functions +--------------------- + +This specification does not specify accuracy requirements for statistical functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +.. note:: + In order for an array library to pass the specification test suite, an array library's statistical function implementations must satisfy certain bare-minimum accuracy requirements (e.g., accurate summation of a small set of positive integers). Unfortunately, imposing more rigorous accuracy requirements is not possible without severely curtailing possible implementation algorithms and unduly increasing implementation complexity. + +Linear Algebra +-------------- + +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2023.12/design_topics/complex_numbers.rst b/spec/2023.12/design_topics/complex_numbers.rst new file mode 100644 index 000000000..0eca79e91 --- /dev/null +++ b/spec/2023.12/design_topics/complex_numbers.rst @@ -0,0 +1,61 @@ +.. _complex-numbers: + +Complex Numbers +=============== + +The Complex Plane +----------------- + +Mathematically, equality comparison between complex numbers depends on the choice of topology. For example, the complex plane has a continuum of infinities; however, when the complex plane is projected onto the surface of a sphere (a stereographic projection commonly referred to as the *Riemann sphere*), infinities coalesce into a single *point at infinity*, thus modeling the extended complex plane. For the former, the value :math:`\infty + 3j` is distinct from (i.e., does not equal) :math:`\infty + 4j`, while, for the latter, :math:`\infty + 3j` does equal :math:`\infty + 4j`. + +Modeling complex numbers as a Riemann sphere conveys certain mathematical niceties (e.g., well-behaved division by zero and preservation of the identity :math:`\frac{1}{\frac{1}{z}} = z`); however, translating the model to IEEE 754 floating-point operations can lead to some unexpected results. For example, according to IEEE 754, :math:`+\infty` and :math:`-\infty` are distinct values; hence, for equality comparison, if :math:`x = +\infty` and :math:`y = -\infty`, then :math:`x \neq y`. In contrast, if we convert :math:`x` and :math:`y` to their complex number equivalents :math:`x = +\infty + 0j` and :math:`y = -\infty + 0j` and then interpret within the context of the extended complex plane, we arrive at the opposite result; namely, :math:`x = y`. + +In short, given the constraints of floating-point arithmetic and the subtleties of signed zeros, infinities, NaNs, and their interaction, crafting a specification which always yields intuitive results and satisfies all use cases involving complex numbers is not possible. Instead, this specification attempts to follow precedent (e.g., C99, Python, Julia, NumPy, and elsewhere), while also minimizing surprise. The result is an imperfect balance in which certain APIs may appear to embrace the one-infinity model found in C/C++ for algebraic operations involving complex numbers (e.g., considering :math:`\infty + \operatorname{NaN}\ j` to be infinite, irrespective of the imaginary component's value, including NaN), while other APIs may rely on the complex plane with its multiplicity of infinities (e.g., in transcendental functions). Accordingly, consumers of this specification should expect that certain results involving complex numbers for one operation may not be wholly consistent with results involving complex numbers for another operation. + + +.. _branch-cuts: + +Branch Cuts +----------- + +In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. + +For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. + +Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. + +In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. + +.. warning:: + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. + + +.. _complex-number-ordering: + +Complex Number Ordering +----------------------- + +Given a set :math:`\{a_1, \ldots, a_n\}`, an order relation must satisfy the following properties: + +1. **Reflexive**: for any :math:`a` in the set, :math:`a \leq a`. +2. **Transitive**: for any :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`b \leq c`, then :math:`a \leq c`. +3. **Antisymmetric**: for any :math:`a` and :math:`b` in the set, if :math:`a \leq b` and :math:`b \leq a`, then :math:`a = b`. +4. **Total Order**: in addition to the *partial order* established by 1-3, for any :math:`a` and :math:`b` in the set, either :math:`a \leq b` or :math:`b \leq a` (or both). +5. **Compatible with Addition**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b`, then :math:`a + c \leq b + c`. +6. **Compatible with Multiplication**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`0 \leq c`, then :math:`ac \leq bc`. + +Defining an order relation for complex numbers which satisfies all six properties defined above is not possible. Accordingly, this specification does not require that a conforming implementation of the array API standard adopt any specific complex number order relation. + +In order to satisfy backward compatibility guarantees, conforming implementations of the array API standard may choose to define an ordering for complex numbers (e.g., lexicographic); however, consumers of the array API standard should **not** assume that complex number ordering is consistent between implementations or even supported. + +If a conforming implementation chooses to define an ordering for complex numbers, the ordering must be clearly documented. + + +Valued-based Promotion +---------------------- + +According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. + +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/2023.12/design_topics/copies_views_and_mutation.rst b/spec/2023.12/design_topics/copies_views_and_mutation.rst new file mode 100644 index 000000000..52be1c805 --- /dev/null +++ b/spec/2023.12/design_topics/copies_views_and_mutation.rst @@ -0,0 +1,77 @@ +.. _copyview-mutability: + +Copy-view behaviour and mutability +================================== + +.. admonition:: Mutating views + :class: important + + Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may be either a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. + +Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically +have the concept of a "view", meaning an array containing data in memory that +belongs to another array (i.e. a different "view" on the original data). +Views are useful for performance reasons - not copying data to a new location +saves memory and is faster than copying - but can also affect the semantics +of code. This happens when views are combined with *mutating* operations. +This simple example illustrates that: + +.. code-block:: python + + x = ones(1) + y = x[:] # `y` *may* be a view on the data of `x` + y -= 1 # if `y` is a view, this modifies `x` + +Code as simple as the above example will not be portable between array +libraries - for NumPy/PyTorch/CuPy/MXNet ``x`` will contain the value ``0``, +while for TensorFlow/JAX/Dask it will contain the value ``1``. The combination +of views and mutability is fundamentally problematic here if the goal is to +be able to write code with unambiguous semantics. + +Views are necessary for getting good performance out of the current strided +array libraries. It is not always clear however when a library will return a +view, and when it will return a copy. This API standard does not attempt to +specify this - libraries can do either. + +There are several types of operations that do in-place mutation of data +contained in arrays. These include: + +1. Inplace operators (e.g. ``*=``) +2. Item assignment (e.g. ``x[0] = 1``) +3. Slice assignment (e.g., ``x[:2, :] = 3``) +4. The `out=` keyword present in some strided array libraries (e.g. ``sin(x, out=y)``) + +Libraries like TensorFlow and JAX tend to support inplace operators, provide +alternative syntax for item and slice assignment (e.g. an ``update_index`` +function or ``x.at[idx].set(y)``), and have no need for ``out=``. + +A potential solution could be to make views read-only, or use copy-on-write +semantics. Both are hard to implement and would present significant issues +for backwards compatibility for current strided array libraries. Read-only +views would also not be a full solution, given that mutating the original +(base) array will also result in ambiguous semantics. Hence this API standard +does not attempt to go down this route. + +Both inplace operators and item/slice assignment can be mapped onto +equivalent functional expressions (e.g. ``x[idx] = val`` maps to +``x.at[idx].set(val)``), and given that both inplace operators and item/slice +assignment are very widely used in both library and end user code, this +standard chooses to include them. + +The situation with ``out=`` is slightly different - it's less heavily used, and +easier to avoid. It's also not an optimal API, because it mixes an +"efficiency of implementation" consideration ("you're allowed to do this +inplace") with the semantics of a function ("the output _must_ be placed into +this array). There are libraries that do some form of tracing or abstract +interpretation over a language that does not support mutation (to make +analysis easier); in those cases implementing ``out=`` with correct handling of +views may even be impossible to do. There's alternatives, for example the +donated arguments in JAX or working buffers in LAPACK, that allow the user to +express "you _may_ overwrite this data, do whatever is fastest". Given that +those alternatives aren't widely used in array libraries today, this API +standard chooses to (a) leave out ``out=``, and (b) not specify another method +of reusing arrays that are no longer needed as buffers. + +This leaves the problem of the initial example - with this API standard it +remains possible to write code that will not work the same for all array +libraries. This is something that the user must be careful about. diff --git a/spec/2023.12/design_topics/data_dependent_output_shapes.rst b/spec/2023.12/design_topics/data_dependent_output_shapes.rst new file mode 100644 index 000000000..43daa9765 --- /dev/null +++ b/spec/2023.12/design_topics/data_dependent_output_shapes.rst @@ -0,0 +1,15 @@ +.. _data-dependent-output-shapes: + +Data-dependent output shapes +============================ + +Array libraries which build computation graphs commonly employ static analysis that relies upon known shapes. For example, JAX requires known array sizes when compiling code, in order to perform static memory allocation. Functions and operations which are value-dependent present difficulties for such libraries, as array sizes cannot be inferred ahead of time without also knowing the contents of the respective arrays. + +While value-dependent functions and operations are not impossible to implement for array libraries which build computation graphs, this specification does not want to impose an undue burden on such libraries and permits omission of value-dependent operations. All other array libraries are expected, however, to implement the value-dependent operations included in this specification in order to be array specification compliant. + +Value-dependent operations are demarcated in this specification using an admonition similar to the following: + +.. admonition:: Data-dependent output shape + :class: important + + The shape of the output array for this function/operation depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function/operation difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. diff --git a/spec/2023.12/design_topics/data_interchange.rst b/spec/2023.12/design_topics/data_interchange.rst new file mode 100644 index 000000000..3b3040672 --- /dev/null +++ b/spec/2023.12/design_topics/data_interchange.rst @@ -0,0 +1,105 @@ +.. _data-interchange: + +Data interchange mechanisms +=========================== + +This section discusses the mechanism to convert one type of array into another. +As discussed in the :ref:`assumptions-dependencies ` section, +*functions* provided by an array library are not expected to operate on +*array types* implemented by another library. Instead, the array can be +converted to a "native" array type. + +The interchange mechanism must offer the following: + +1. Data access via a protocol that describes the memory layout of the array + in an implementation-independent manner. + + *Rationale: any number of libraries must be able to exchange data, and no + particular package must be needed to do so.* + +2. Support for all dtypes in this API standard (see :ref:`data-types`). + +3. Device support. It must be possible to determine on what device the array + that is to be converted lives. + + *Rationale: there are CPU-only, GPU-only, and multi-device array types; + it's best to support these with a single protocol (with separate + per-device protocols it's hard to figure out unambiguous rules for which + protocol gets used, and the situation will get more complex over time + as TPU's and other accelerators become more widely available).* + +4. Zero-copy semantics where possible, making a copy only if needed (e.g. + when data is not contiguous in memory). + + *Rationale: performance.* + +5. A Python-side and a C-side interface, the latter with a stable C ABI. + + *Rationale: all prominent existing array libraries are implemented in + C/C++, and are released independently from each other. Hence a stable C + ABI is required for packages to work well together.* + +DLPack: An in-memory tensor structure +------------------------------------- + +The best candidate for this protocol is +`DLPack `_, and hence that is what this +standard has chosen as the primary/recommended protocol. Note that the +``asarray`` function also supports the Python buffer protocol (CPU-only) to +support libraries that already implement buffer protocol support. + +.. note:: + The main alternatives to DLPack are device-specific methods: + + - The `buffer protocol `_ on CPU + - ``__cuda_array_interface__`` for CUDA, specified in the Numba documentation + `here `_ + (Python-side only at the moment) + + An issue with device-specific protocols are: if two libraries both + support multiple device types, in which order should the protocols be + tried? A growth in the number of protocols to support each time a new + device gets supported by array libraries (e.g. TPUs, AMD GPUs, emerging + hardware accelerators) also seems undesirable. + + In addition to the above argument, it is also clear from adoption + patterns that DLPack has the widest support. The buffer protocol, despite + being a lot older and standardized as part of Python itself via PEP 3118, + hardly has any support from array libraries. CPU interoperability is + mostly dealt with via the NumPy-specific ``__array__`` (which, when called, + means the object it is attached to must return a ``numpy.ndarray`` + containing the data the object holds). + + See the `RFC to adopt DLPack `_ + for discussion that preceded the adoption of DLPack. + +DLPack's documentation can be found at: https://dmlc.github.io/dlpack/latest/. + +The `Python specification of DLPack `__ +page gives a high-level specification for data exchange in Python using DLPack. + +.. note:: + DLPack is a standalone protocol/project and can therefore be used outside of + this standard. Python libraries that want to implement only DLPack support + are recommended to do so using the same syntax and semantics as outlined + below. They are not required to return an array object from ``from_dlpack`` + which conforms to this standard. + +Non-supported use cases +----------------------- + +Use of DLPack requires that the data can be represented by a strided, in-memory +layout on a single device. This covers usage by a large range of, but not all, +known and possible array libraries. Use cases that are not supported by DLPack +include: + +- Distributed arrays, i.e., the data residing on multiple nodes or devices, +- Sparse arrays, i.e., sparse representations where a data value (typically + zero) is implicit. + +There may be other reasons why it is not possible or desirable for an +implementation to materialize the array as strided data in memory. In such +cases, the implementation may raise a `BufferError` in the `__dlpack__` or +`__dlpack_device__` method. In case an implementation is never able to export +its array data via DLPack, it may omit `__dlpack__` and `__dlpack_device__` +completely, and hence `from_dlpack` may raise an `AttributeError`. diff --git a/spec/2023.12/design_topics/device_support.rst b/spec/2023.12/design_topics/device_support.rst new file mode 100644 index 000000000..593b0b9fa --- /dev/null +++ b/spec/2023.12/design_topics/device_support.rst @@ -0,0 +1,112 @@ +.. _device-support: + +Device support +============== + +For libraries that support execution on more than a single hardware device - e.g. CPU and GPU, or multiple GPUs - it is important to be able to control on which device newly created arrays get placed and where execution happens. Attempting to be fully implicit doesn't always scale well to situations with multiple GPUs. + +Existing libraries employ one or more of these three methods to exert such control over data placement: + +1. A global default device, which may be fixed or user-switchable. +2. A context manager to control device assignment within its scope. +3. Local control for data allocation target device via explicit keywords, and a method to transfer arrays to another device. + +Libraries differ in how execution is controlled, via a context manager or with the convention that execution takes place on the same device where all argument arrays are allocated. And they may or may not allow mixing arrays on different devices via implicit data transfers. + +This standard chooses to add support for method 3 (local control), with the convention that execution takes place on the same device where all argument arrays are allocated. The rationale for choosing method 3 is because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see :ref:`device-out-of-scope` for details. + +Intended usage +-------------- + +The intended usage for the device support in the current version of the +standard is *device handling in library code*. The assumed pattern is that +users create arrays (for which they can use all the relevant device syntax +that the library they use provides), and that they then pass those arrays +into library code which may have to do the following: + +- Create new arrays on the same device as an array that's passed in. +- Determine whether two input arrays are present on the same device or not. +- Move an array from one device to another. +- Create output arrays on the same device as the input arrays. +- Pass on a specified device to other library code. + +.. note:: + Given that there is not much that's currently common in terms of + device-related syntax between different array libraries, the syntax included + in the standard is kept as minimal as possible while enabling the + above-listed use cases. + +Syntax for device assignment +---------------------------- + +The array API provides the following syntax for device assignment and +cross-device data transfer: + +1. A ``.device`` property on the array object, which returns a ``Device`` object + representing the device the data in the array is stored on, and supports + comparing devices for equality with ``==`` and ``!=`` within the same library + (e.g., by implementing ``__eq__``); comparing device objects from different + libraries is out of scope). +2. A ``device=None`` keyword for array creation functions, which takes an + instance of a ``Device`` object. +3. A ``.to_device`` method on the array object to copy an array to a different device. + +.. note:: + The current API standard does **not** include a universal ``Device`` object + recognized by all compliant libraries. Accordingly, the standard does not + provide a means of instantiating a ``Device`` object to point to a specific + physical or logical device. + + The choice to not include a standardized ``Device`` object may be revisited + in a future revision of this standard. + + For array libraries which concern themselves with multi-device support, + including CPU and GPU, they are free to expose a library-specific device + object (e.g., for creating an array on a particular device). While a + library-specific device object can be used as input to ``to_device``, beware + that this will mean non-portability as code will be specific to that + library. + +Semantics +--------- + +Handling devices is complex, and some frameworks have elaborate policies for +handling device placement. Therefore this section only gives recommendations, +rather than hard requirements: + +- Respect explicit device assignment (i.e. if the input to the ``device=`` keyword is not ``None``, guarantee that the array is created on the given device, and raise an exception otherwise). +- Preserve device assignment as much as possible (e.g. output arrays from a function are expected to be on the same device as input arrays to the function). +- Raise an exception if an operation involves arrays on different devices (i.e. avoid implicit data transfer between devices). +- Use a default for ``device=None`` which is consistent between functions within the same library. +- If a library has multiple ways of controlling device placement, the most explicit method should have the highest priority. For example: + + 1. If ``device=`` keyword is specified, that always takes precedence + + 2. If ``device=None``, then use the setting from a context manager, if set. + + 3. If no context manager was used, then use the global default device/strategy + +.. _device-out-of-scope: + +Out of scope for device support +------------------------------- + +Individual libraries may offers APIs for one or more of the following topics, +however those are out of scope for this standard: + +- Identifying a specific physical or logical device across libraries +- Setting a default device globally +- Stream/queue control +- Distributed allocation +- Memory pinning +- A context manager for device control + +.. note:: + A context manager for controlling the default device is present in most existing array + libraries (NumPy being the exception). There are concerns with using a + context manager however. A context manager can be tricky to use at a high + level, since it may affect library code below function calls (non-local + effects). See, e.g., `this PyTorch issue `_ + for a discussion on a good context manager API. + + Adding a context manager may be considered in a future version of this API standard. diff --git a/spec/2023.12/design_topics/exceptions.rst b/spec/2023.12/design_topics/exceptions.rst new file mode 100644 index 000000000..570fe56e3 --- /dev/null +++ b/spec/2023.12/design_topics/exceptions.rst @@ -0,0 +1,28 @@ +.. _exceptions: + +Exceptions +========== + +This standard specifies expected syntax and semantics for a set of APIs. When +inputs to an API do not match what is expected, libraries may emit warnings, +raise exceptions, or misbehave in unexpected ways. In general, it is not +possible to foresee or specify all the ways in which unexpected or invalid +inputs are provided. Therefore, this standard does not attempt to specify +exception or warning types to the extent needed in order to do exception +handling in a portable manner. In general, it is expected that array library +implementers follow `the guidance given by the documentation of the Python +language `__, and either use +builtin exception or warning types that are appropriate for the +situation or use custom exceptions or warnings that derive from those builtin +ones. + +In specific cases, it may be useful to provide guidance to array library +authors regarding what an appropriate exception is. That guidance will be +phrased as *should* rather than *must* (typically in a *Raises* section), +because (a) there may be reasons for an implementer to deviate, and (b) more +often than not, existing array library implementation already differ in their +choices, and it may not be worth them breaking backward compatibility in order +to comply with a "must" in this standard. + +In other cases, this standard will only specify that an exception should or +must be raised, but not mention what type of exception that is. diff --git a/spec/2023.12/design_topics/index.rst b/spec/2023.12/design_topics/index.rst new file mode 100644 index 000000000..548eda90c --- /dev/null +++ b/spec/2023.12/design_topics/index.rst @@ -0,0 +1,18 @@ +Design topics & constraints +=========================== + +.. toctree:: + :caption: Design topics & constraints + :maxdepth: 1 + + copies_views_and_mutation + data_dependent_output_shapes + lazy_eager + data_interchange + device_support + static_typing + accuracy + exceptions + complex_numbers + C_API + parallelism diff --git a/spec/2023.12/design_topics/lazy_eager.rst b/spec/2023.12/design_topics/lazy_eager.rst new file mode 100644 index 000000000..63297ac73 --- /dev/null +++ b/spec/2023.12/design_topics/lazy_eager.rst @@ -0,0 +1,43 @@ +.. _lazy-eager: + +Lazy vs. eager execution +======================== + +While the execution model for implementations is out of scope of this standard, +there are a few aspects of lazy (or graph-based) execution as contrasted to +eager execution that may have an impact on the prescribed semantics of +individual APIs, and will therefore show up in the API specification. + +One important difference is data-dependent or value-dependent behavior, as +described in :ref:`data-dependent-output-shapes`. Because such behavior is hard +to implement, implementers may choose to omit such APIs from their library. + +Another difference is when the Python language itself prescribes that a +specific type *must* be returned. For those cases, it is not possible to return +a lazy/delayed kind of object to avoid computing a value. This is the case for +five dunder methods: `__bool__`, `__int__`, `__float__`, `__complex__` and +`__index__`. Each implementation has only two choices when one of these methods +is called: + +1. Compute a value of the required type (a Python scalar of type `bool`, `int`, + `float` or `complex`), or +2. Raise an exception. + +When an implementation is 100% lazy, for example when it serializes a +computation graph, computing the value is not possible and hence such an +implementation has no choice but to raise an exception. For a "mostly lazy" +implementation, it may make sense to trigger execution instead - but it is not +required to, both choices are valid. + +A common code construct where this happens is conditional logic, e.g.:: + + vals = compute_something() + if all(vals): + # The if-statement will make Python call the __bool__ method + # on the result of `all(vals)`. + do_something_else() + +Note that the API does not contain control flow constructs, as of now, that +would allow avoiding the implicit `__bool__` call in the example above. The +only control flow-like function is `where`, but there's no function like `cond` +to replace an `if`-statement. diff --git a/spec/2023.12/design_topics/parallelism.rst b/spec/2023.12/design_topics/parallelism.rst new file mode 100644 index 000000000..f013a9cf9 --- /dev/null +++ b/spec/2023.12/design_topics/parallelism.rst @@ -0,0 +1,24 @@ +Parallelism +=========== + +Parallelism is mostly, but not completely, an execution or runtime concern +rather than an API concern. Execution semantics are out of scope for this API +standard, and hence won't be discussed further here. The API related part +involves how libraries allow users to exercise control over the parallelism +they offer, such as: + +- Via environment variables. This is the method of choice for BLAS libraries and libraries using OpenMP. +- Via a keyword to individual functions or methods. Examples include the ``n_jobs`` keyword used in scikit-learn and the ``workers`` keyword used in SciPy. +- Build-time settings to enable a parallel or distributed backend. +- Via letting the user set chunk sizes. Dask uses this approach. + +When combining multiple libraries, one has to deal with auto-parallelization +semantics and nested parallelism. Two things that could help improve the +coordination of parallelization behavior in a stack of Python libraries are: + +1. A common API pattern for enabling parallelism +2. A common library providing a parallelization layer + +Option (1) may possibly fit in a future version of this array API standard. +`array-api issue 4 `_ contains +more detailed discussion on the topic of parallelism. diff --git a/spec/2023.12/design_topics/static_typing.rst b/spec/2023.12/design_topics/static_typing.rst new file mode 100644 index 000000000..26a1fb901 --- /dev/null +++ b/spec/2023.12/design_topics/static_typing.rst @@ -0,0 +1,50 @@ +Static typing +============= + +Good support for static typing both in array libraries and array-consuming +code is desirable. Therefore the exact type or set of types for each +parameter, keyword and return value is specified for functions and methods - +see :ref:`function-and-method-signatures`. That section specifies arrays +simply as ``array``; what that means is dealt with in this section. + +Introducing type annotations in libraries became more relevant only when +Python 2.7 support was dropped at the start of 2020. As a consequence, using +type annotations with array libraries is largely still a work in progress. +This version of the API standard does not deal with trying to type *array +properties* like shape, dimensionality or dtype, because that's not a solved +problem in individual array libraries yet. + +An ``array`` type annotation can mean either the type of one specific array +object, or some superclass or typing Protocol - as long as it is consistent +with the array object specified in :ref:`array-object`. To illustrate by +example: + +.. code-block:: python + + # `Array` is a particular class in the library + def sin(x: Array, / ...) -> Array: + ... + +and + +.. code-block:: python + + # There's some base class `_BaseArray`, and there may be multiple + # array subclasses inside the library + A = TypeVar('A', bound=_BaseArray) + def sin(x: A, / ...) -> A: + ... + +should both be fine. There may be other variations possible. Also note that +this standard does not require that input and output array types are the same +(they're expected to be defined in the same library though). Given that +array libraries don't have to be aware of other types of arrays defined in +other libraries (see :ref:`assumptions-dependencies`), this should be enough +for a single array library. + +That said, an array-consuming library aiming to support multiple array types +may need more - for example a protocol to enable structural subtyping. This +API standard currently takes the position that it does not provide any +reference implementation or package that can or should be relied on at +runtime, hence no such protocol is defined here. This may be dealt with in a +future version of this standard. diff --git a/spec/2023.12/extensions/fourier_transform_functions.rst b/spec/2023.12/extensions/fourier_transform_functions.rst new file mode 100644 index 000000000..170ae390b --- /dev/null +++ b/spec/2023.12/extensions/fourier_transform_functions.rst @@ -0,0 +1,45 @@ +Fourier transform Functions +=========================== + + Array API specification for Fourier transform functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``fft``. + +If implemented, this ``fft`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'fft'): + >>> # Use `xp.fft` + + +Objects in API +-------------- + +A conforming implementation of this ``fft`` extension must provide and support the following functions. + +.. currentmodule:: array_api.fft + +.. + NOTE: please keep the functions and their inverse together + +.. autosummary:: + :toctree: generated + :template: method.rst + + fft + ifft + fftn + ifftn + rfft + irfft + rfftn + irfftn + hfft + ihfft + fftfreq + rfftfreq + fftshift + ifftshift diff --git a/spec/2023.12/extensions/index.rst b/spec/2023.12/extensions/index.rst new file mode 100644 index 000000000..3b9409954 --- /dev/null +++ b/spec/2023.12/extensions/index.rst @@ -0,0 +1,34 @@ +.. _extensions: + +Extensions +========== + +Extensions are coherent sets of functionality that are commonly implemented +across array libraries. Each array library supporting this standard may, but is +not required to, implement an extension. If an extension is supported, it +must be accessible inside the main array API supporting namespace as a separate +namespace. + +Extension module implementors must aim to provide all functions and other +public objects in an extension. The rationale for this is that downstream usage +can then check whether or not the extension is present (using ``hasattr(xp, +'extension_name')`` should be enough), and can then assume that functions are +implemented. This in turn makes it also easy for array-consuming libraries to +document which array libraries they support - e.g., "all libraries implementing +the array API standard and its linear algebra extension". + +The mechanism through which the extension namespace is made available is up to +the implementer, e.g. via a regular submodule that is imported under the +``linalg`` name, or via a module-level ``__getattr__``. + +The functions in an extension must adhere to the same conventions as those in +the array API standard. See :ref:`api-specification`. + +------------------------------------------------------------------------------ + +.. toctree:: + :caption: Extension modules: + :maxdepth: 1 + + fourier_transform_functions + linear_algebra_functions diff --git a/spec/2023.12/extensions/linear_algebra_functions.rst b/spec/2023.12/extensions/linear_algebra_functions.rst new file mode 100644 index 000000000..6759b2260 --- /dev/null +++ b/spec/2023.12/extensions/linear_algebra_functions.rst @@ -0,0 +1,116 @@ +.. _linear-algebra-extension: + +Linear Algebra Extension +======================== + + Array API specification for linear algebra functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``linalg``. + +If implemented, this ``linalg`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'linalg'): + >>> # Use `xp.linalg` + + +Design Principles +----------------- + +A principal goal of this specification is to standardize commonly implemented interfaces among array libraries. While this specification endeavors to avoid straying too far from common practice, this specification does, with due restraint, seek to address design decisions arising more from historical accident than first principles. This is especially true for linear algebra APIs, which have arisen and evolved organically over time and have often been tied to particular underlying implementations (e.g., to BLAS and LAPACK). + +Accordingly, the standardization process affords the opportunity to reduce interface complexity among linear algebra APIs by inferring and subsequently codifying common design themes, thus allowing more consistent APIs. What follows is the set of design principles governing the APIs which follow: + +1. **Batching**: if an operation is explicitly defined in terms of matrices (i.e., two-dimensional arrays), then the associated interface should support "batching" (i.e., the ability to perform the operation over a "stack" of matrices). Example operations include: + + - ``inv``: computing the multiplicative inverse of a square matrix. + - ``cholesky``: performing Cholesky decomposition. + - ``matmul``: performing matrix multiplication. + +2. **Data types**: if an operation requires decimal operations and :ref:`type-promotion` semantics are undefined (e.g., as is the case for mixed-kind promotions), then the associated interface should be specified as being restricted to floating-point data types. While the specification uses the term "SHOULD" rather than "MUST", a conforming implementation of the array API standard should only ignore the restriction provided overly compelling reasons for doing so. Example operations which should be limited to floating-point data types include: + + - ``inv``: computing the multiplicative inverse. + - ``slogdet``: computing the natural logarithm of the absolute value of the determinant. + - ``norm``: computing the matrix or vector norm. + + Certain operations are solely comprised of multiplications and additions. Accordingly, associated interfaces need not be restricted to floating-point data types. However, careful consideration should be given to overflow, and use of floating-point data types may be more prudent in practice. Example operations include: + + - ``matmul``: performing matrix multiplication. + - ``trace``: computing the sum along the diagonal. + - ``cross``: computing the vector cross product. + + Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: + + - ``matrix_transpose``: computing the transpose. + - ``diagonal``: returning the diagonal. + +3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. + + In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: + + - ``eig``: computing both eigenvalues and eignvectors. + - ``eigvals``: computing only eigenvalues. + +4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. + + Historically, at a time when all array computing happened on CPUs, BLAS and LAPACK underpinned most numerical computing libraries and environments. Naturally, language and library abstractions catered to the parameterization of those libraries, often exposing low-level implementation details verbatim in their higher-level interfaces, even if such choices would be considered poor or ill-advised by today's standards (e.g., NumPy's use of `UPLO` in `eigh`). However, the present day is considerably different. While still important, BLAS and LAPACK no longer hold a monopoly over linear algebra operations, especially given the proliferation of devices and hardware on which such operations must be performed. Accordingly, interfaces must be conservative in the parameterization they support in order to best ensure universality. Such conservatism applies even to performance optimization parameters afforded by certain hardware. + +5. **Orthogonality**: an interface should have clearly defined and delineated functionality which, ideally, has no overlap with the functionality of other interfaces in the specification. Providing multiple interfaces which can all perform the same operation creates unnecessary confusion regarding interface applicability (i.e., which interface is best at which time) and decreases readability of both library and user code. Where overlap is possible, the specification must be parsimonious in the number of interfaces, ensuring that each interface provides a unique and compelling abstraction. Examples of related interfaces which provide distinct levels of abstraction (and generality) include: + + - ``vecdot``: computing the dot product of two vectors. + - ``matmul``: performing matrix multiplication (including between two vectors and thus the dot product). + - ``tensordot``: computing tensor contractions (generalized sum-products). + - ``einsum``: expressing operations in terms of Einstein summation convention, including dot products and tensor contractions. + + The above can be contrasted with, e.g., NumPy, which provides the following interfaces for computing the dot product or related operations: + + - ``dot``: dot product, matrix multiplication, and tensor contraction. + - ``inner``: dot product. + - ``vdot``: dot product with flattening and complex conjugation. + - ``multi_dot``: chained dot product. + - ``tensordot``: tensor contraction. + - ``matmul``: matrix multiplication (dot product for two vectors). + - ``einsum``: Einstein summation convention. + + where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. + +.. currentmodule:: array_api.linalg + +Objects in API +-------------- + +A conforming implementation of this ``linalg`` extension must provide and support the following functions. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cholesky + cross + det + diagonal + eigh + eigvalsh + inv + matmul + matrix_norm + matrix_power + matrix_rank + matrix_transpose + outer + pinv + qr + slogdet + solve + svd + svdvals + tensordot + trace + vecdot + vector_norm diff --git a/spec/2023.12/future_API_evolution.md b/spec/2023.12/future_API_evolution.md new file mode 100644 index 000000000..443f683d5 --- /dev/null +++ b/spec/2023.12/future_API_evolution.md @@ -0,0 +1,60 @@ +(future-API-evolution)= + +# Future API standard evolution + +## Scope extensions + +Proposals for scope extensions in a future version of the API standard will follow +the process documented at https://github.com/data-apis/governance/blob/master/process_document.md + +In summary, proposed new APIs go through several maturity stages, and will only be +accepted in a future version of this API standard once they have reached the "Final" +maturity stage, which means multiple array libraries have compliant implementations +and real-world experience from use of those implementations is available. + + +## Backwards compatibility + +Functions, objects, keywords and specified behavior are added to this API standard +only if those are already present in multiple existing array libraries, and if there is +data that those APIs are used. Therefore it is highly unlikely that future versions +of this standard will make backwards-incompatible changes. + +The aim is for future versions to be 100% backwards compatible with older versions. +Any exceptions must have strong rationales and be clearly documented in the updated +API specification. + + +(api-versioning)= + +## Versioning + +This API standard uses the following versioning scheme: + +- The version is date-based, in the form `yyyy.mm` (e.g., `2020.12`). +- The version shall not include a standard way to do `alpha`/`beta`/`rc` or + `.post`/`.dev` type versions. + _Rationale: that's for Python packages, not for a standard._ +- The version must be made available at runtime via an attribute + `__array_api_version__` by a compliant implementation, in `'yyyy.mm'` format + as a string, in the namespace that implements the API standard. + _Rationale: dunder version strings are the standard way of doing this._ + +No utilities for dealing with version comparisons need to be provided; given +the format simple string comparisons with Python operators (`=-`, `<`, `>=`, +etc.) will be enough. + +```{note} + +Rationale for the `yyyy.mm` versioning scheme choice: +the API will be provided as part of a library, which already has a versioning +scheme (typically PEP 440 compliant and in the form `major.minor.bugfix`), +and a way to access it via `module.__version__`. The API standard version is +completely independent from the package version. Given the standardization +process, it resembles a C/C++ versioning scheme (e.g. `C99`, `C++14`) more +than Python package versioning. +``` + +The frequency of releasing a new version of an API standard will likely be at +regular intervals and on the order of one year, however no assumption on +frequency of new versions appearing must be made. diff --git a/spec/2023.12/index.rst b/spec/2023.12/index.rst new file mode 100644 index 000000000..3e51cc68e --- /dev/null +++ b/spec/2023.12/index.rst @@ -0,0 +1,37 @@ +Python array API standard +========================= + +Contents +-------- + +.. toctree:: + :caption: Context + :maxdepth: 1 + + purpose_and_scope + use_cases + assumptions + +.. toctree:: + :caption: API + :maxdepth: 1 + + design_topics/index + future_API_evolution + API_specification/index + extensions/index + +.. toctree:: + :caption: Methodology and Usage + :maxdepth: 1 + + usage_data + verification_test_suite + benchmark_suite + +.. toctree:: + :caption: Other + :maxdepth: 1 + + changelog + license diff --git a/spec/2023.12/license.rst b/spec/2023.12/license.rst new file mode 100644 index 000000000..06ec75dfc --- /dev/null +++ b/spec/2023.12/license.rst @@ -0,0 +1,9 @@ +License +======= + +All content on this website and the corresponding +`GitHub repository `__ is licensed +under the following license: + + .. include:: ../../LICENSE + :parser: myst_parser.sphinx_ diff --git a/spec/2023.12/purpose_and_scope.md b/spec/2023.12/purpose_and_scope.md new file mode 100644 index 000000000..f375c9512 --- /dev/null +++ b/spec/2023.12/purpose_and_scope.md @@ -0,0 +1,470 @@ +# Purpose and scope + +## Introduction + +Python users have a wealth of choice for libraries and frameworks for +numerical computing, data science, machine learning, and deep learning. New +frameworks pushing forward the state of the art in these fields are appearing +every year. One unintended consequence of all this activity and creativity +has been fragmentation in multidimensional array (a.k.a. tensor) libraries - +which are the fundamental data structure for these fields. Choices include +NumPy, Tensorflow, PyTorch, Dask, JAX, CuPy, MXNet, Xarray, and others. + +The APIs of each of these libraries are largely similar, but with enough +differences that it's quite difficult to write code that works with multiple +(or all) of these libraries. This array API standard aims to address that +issue, by specifying an API for the most common ways arrays are constructed +and used. + +Why not simply pick an existing API and bless that as the standard? In short, +because there are often good reasons for the current inconsistencies between +libraries. The most obvious candidate for that existing API is NumPy. However +NumPy was not designed with non-CPU devices, graph-based libraries, or JIT +compilers in mind. Other libraries often deviate from NumPy for good +(necessary) reasons. Choices made in this API standard are often the same +ones NumPy makes, or close to it, but are different where necessary to make +sure all existing array libraries can adopt this API. + + +### This API standard + +This document aims to standardize functionality that exists in most/all array +libraries and either is commonly used or is needed for +consistency/completeness. Usage is determined via analysis of downstream +libraries, see {ref}`usage-data`. An example of consistency is: there are +functional equivalents for all Python operators (including the rarely used +ones). + +Beyond usage and consistency, there's a set of use cases that inform the API +design to ensure it's fit for a wide range of users and situations - see +{ref}`use-cases`. + +A question that may arise when reading this document is: _"what about +functionality that's not present in this document?_ This: + +- means that there is no guarantee the functionality is present in libraries + adhering to the standard +- does _not_ mean that that functionality is unimportant +- may indicate that that functionality, if present in a particular array + library, is unlikely to be present in all other libraries + +### History + +The first library for numerical and scientific computing in Python was +Numeric, developed in the mid-1990s. In the early 2000s a second, similar +library, Numarray, was created. In 2005 NumPy was written, superceding both +Numeric and Numarray and resolving the fragmentation at that time. For +roughly a decade, NumPy was the only widely used array library. Over the past +~5 years, mainly due to the emergence of new hardware and the rise of deep +learning, many other libraries have appeared, leading to more severe +fragmentation. Concepts and APIs in newer libraries were often inspired by +(or copied from) those in older ones - and then changed or improved upon to +fit new needs and use cases. Individual library authors discussed ideas, +however there was never (before this array API standard) a serious attempt +to coordinate between all libraries to avoid fragmentation and arrive at a +common API standard. + +The idea for this array API standard grew gradually out of many conversations +between maintainers during 2019-2020. It quickly became clear that any +attempt to write a new "reference library" to fix the current fragmentation +was infeasible - unlike in 2005, there are now too many different use cases +and too many stakeholders, and the speed of innovation is too high. In May +2020 an initial group of maintainers was assembled in the [Consortium for +Python Data API Standards](https://data-apis.org/) to start drafting a +specification for an array API that could be adopted by each of the existing +array and tensor libraries. That resulted in this document, describing that +API. + + +(Scope)= + +## Scope (includes out-of-scope / non-goals) + +This section outlines what is in scope and out of scope for this API standard. + +### In scope + +The scope of the array API standard includes: + +- Functionality which needs to be included in an array library for it to adhere + to this standard. +- Names of functions, methods, classes and other objects. +- Function signatures, including type annotations. +- Semantics of functions and methods. I.e. expected outputs including precision + for and dtypes of numerical results. +- Semantics in the presence of `nan`'s, `inf`'s, empty arrays (i.e. arrays + including one or more dimensions of size `0`). +- Casting rules, broadcasting, indexing +- Data interchange. I.e. protocols to convert one type of array into another + type, potentially sharing memory. +- Device support. + +Furthermore, meta-topics included in this standard include: + +- Use cases for the API standard and assumptions made in it +- API standard adoption +- API standard versioning +- Future API standard evolution +- Array library and API standard versioning +- Verification of API standard conformance + +The concrete set of functionality that is in scope for this version of the +standard is shown in this diagram: + +![Scope of array API](../_static/images/scope_of_array_API.png) + + +**Goals** for the API standard include: + +- Make it possible for array-consuming libraries to start using multiple types + of arrays as inputs. +- Enable more sharing and reuse of code built on top of the core functionality + in the API standard. +- For authors of new array libraries, provide a concrete API that can be + adopted as is, rather than each author having to decide what to borrow from + where and where to deviate. +- Make the learning curve for users less steep when they switch from one array + library to another one. + + +### Out of scope + +1. Implementations of the standard are out of scope. + + _Rationale: the standard will consist of a document and an accompanying test + suite with which the conformance of an implementation can be verified. Actual + implementations will live in array libraries; no reference implementation is + planned._ + +2. Execution semantics are out of scope. This includes single-threaded vs. + parallel execution, task scheduling and synchronization, eager vs. delayed + evaluation, performance characteristics of a particular implementation of the + standard, and other such topics. + + _Rationale: execution is the domain of implementations. Attempting to specify + execution behavior in a standard is likely to require much more fine-grained + coordination between developers of implementations, and hence is likely to + become an obstacle to adoption._ + +3. Non-Python API standardization (e.g., Cython or NumPy C APIs) + + _Rationale: this is an important topic for some array-consuming libraries, + but there is no widely shared C/Cython API and hence it doesn't make sense at + this point in time to standardize anything. See + the [C API section](design_topics/C_API.rst) for more details._ + +4. Standardization of these dtypes is out of scope: bfloat16, extended + precision floating point, datetime, string, object and void dtypes. + + _Rationale: these dtypes aren't uniformly supported, and their inclusion at + this point in time could put a significant implementation burden on + libraries. It is expected that some of these dtypes - in particular + `bfloat16` - will be included in a future version of the standard._ + +5. The following topics are out of scope: I/O, polynomials, error handling, + testing routines, building and packaging related functionality, methods of + binding compiled code (e.g., `cffi`, `ctypes`), subclassing of an array + class, masked arrays, and missing data. + + _Rationale: these topics are not core functionality for an array library, + and/or are too tied to implementation details._ + +6. NumPy (generalized) universal functions, i.e. ufuncs and gufuncs. + + _Rationale: these are NumPy-specific concepts, and are mostly just a + particular way of building regular functions with a few extra + methods/properties._ + +7. Behaviour for unexpected/invalid input to functions and methods. + + _Rationale: there are a huge amount of ways in which users can provide + invalid or unspecified input to functionality in the standard. Exception + types or other resulting behaviour cannot be completely covered and would + be hard to make consistent between libraries._ + + +**Non-goals** for the API standard include: + +- Making array libraries identical so they can be merged. + + _Each library will keep having its own particular strength, whether it's + offering functionality beyond what's in the standard, performance advantages + for a given use case, specific hardware or software environment support, or + more._ + +- Implement a backend or runtime switching system to be able to switch from one + array library to another with a single setting or line of code. + + _This may be feasible, however it's assumed that when an array-consuming + library switches from one array type to another, some testing and possibly + code adjustment for performance or other reasons may be needed._ + +- Making it possible to mix multiple array libraries in function calls. + + _Most array libraries do not know about other libraries, and the functions + they implement may try to convert "foreign" input, or raise an exception. + This behaviour is hard to specify; ensuring only a single array type is + used is best left to the end user._ + + +### Implications of in/out of scope + +If something is out of scope and therefore will not be part of (the current +version of) the API standard, that means that there are no guarantees that that +functionality works the same way, or even exists at all, across the set of +array libraries that conform to the standard. It does _not_ imply that this +functionality is less important or should not be used. + + +## Stakeholders + +Arrays are fundamental to scientific computing, data science, and machine +learning and deep learning. Hence there are many stakeholders for an array API +standard. The _direct_ stakeholders of this standard are **authors/maintainers of +Python array libraries**. There are many more types of _indirect_ stakeholders +though, including: + +- maintainers of libraries and other programs which depend on array libraries + (called "array-consuming libraries" in the rest of this document) +- authors of non-Python array libraries +- developers of compilers and runtimes with array-specific functionality +- end users + +Libraries that are being actively considered - in terms of current behaviour and +API surface - during the creation of the first version of this standard +include: + +- [NumPy](https://numpy.org) +- [TensorFlow](https://www.tensorflow.org/) +- [PyTorch](https://pytorch.org/) +- [MXNet](https://numpy.mxnet.io/) +- [JAX](https://github.com/google/jax) +- [Dask](https://dask.org/) +- [CuPy](https://cupy.chainer.org/) + +Other Python array libraries that are currently under active development and +could adopt this API standard include: + +- [xarray](https://xarray.pydata.org/) +- [PyData/Sparse](https://sparse.pydata.org) +- [Weld](https://github.com/weld-project/weld) +- [Bohrium](https://bohrium.readthedocs.io/) +- [Arkouda](https://github.com/mhmerrill/arkouda) +- [Legate](https://research.nvidia.com/publication/2019-11_Legate-NumPy%3A-Accelerated) + +There are a huge amount of array-consuming libraries; some of the most +prominent ones that are being taken into account - in terms of current array +API usage or impact of design decisions on them - include (this list is likely +to grow it over time): + +- [Pandas](https://pandas.pydata.org/) +- [SciPy](https://github.com/scipy/scipy) +- [scikit-learn](https://scikit-learn.org/) +- [Matplotlib](https://matplotlib.org/) +- [scikit-image](https://scikit-image.org/) +- [NetworkX](https://networkx.github.io/) + +Array libraries in other languages, some of which may grow a Python API in the +future or have taken inspiration from NumPy or other array libraries, include: + +- [Xtensor](https://xtensor.readthedocs.io) (C++, cross-language) +- [XND](https://xnd.io/) (C, cross-language) +- [stdlib](https://stdlib.io/) (JavaScript) +- [rust-ndarray](https://github.com/rust-ndarray/ndarray) (Rust) +- [rray](https://github.com/r-lib/rray) (R) +- [ND4J](https://github.com/deeplearning4j/nd4j) (JVM) +- [NumSharp](https://github.com/SciSharp/NumSharp) (C#) + +Compilers, runtimes, and dispatching layers for which this API standard may be +relevant: + +- [Cython](https://cython.org/) +- [Numba](http://numba.pydata.org/) +- [Pythran](https://pythran.readthedocs.io/en/latest/) +- [Transonic](https://transonic.readthedocs.io) +- [ONNX](https://onnx.ai/) +- [Apache TVM](https://tvm.apache.org/) +- [MLIR](https://mlir.llvm.org/) +- [TACO](https://github.com/tensor-compiler/taco) +- [unumpy](https://github.com/Quansight-Labs/unumpy) +- [einops](https://github.com/arogozhnikov/einops) +- [Apache Arrow](https://arrow.apache.org/) + + + +## How to read this document + +For guidance on how to read and understand the type annotations included in this specification, consult the Python [documentation](https://docs.python.org/3/library/typing.html). + + +(how-to-adopt-this-api)= + +## How to adopt this API + +Most (all) existing array libraries will find something in this API standard +that is incompatible with a current implementation, and that they cannot +change due to backwards compatibility concerns. Therefore we expect that each +of those libraries will want to offer a standard-compliant API in a _new +namespace_. The question then becomes: how does a user access this namespace? + +The simplest method is: document the import to use to directly access the +namespace (e.g. `import package_name.array_api`). This has two issues though: + +1. Array-consuming libraries that want to support multiple array libraries + then have to explicitly import each library. +2. It is difficult to _version_ the array API standard implementation (see + {ref}`api-versioning`). + +To address both issues, a uniform way must be provided by a conforming +implementation to access the API namespace, namely a [method on the array +object](array.__array_namespace__): + +``` +xp = x.__array_namespace__() +``` + +The method must take one keyword, `api_version=None`, to make it possible to +request a specific API version: + +``` +xp = x.__array_namespace__(api_version='2020.10') +``` + +The `xp` namespace must contain all functionality specified in +{ref}`api-specification`. The namespace may contain other functionality; however, +including additional functionality is not recommended as doing so may hinder +portability and inter-operation of array libraries within user code. + +### Checking an array object for Compliance + +Array-consuming libraries are likely to want a mechanism for determining +whether a provided array is specification compliant. The recommended approach +to check for compliance is by checking whether an array object has an +`__array_namespace__` attribute, as this is the one distinguishing feature of +an array-compliant object. + +Checking for an `__array_namespace__` attribute can be implemented as a small +utility function similar to the following. + +```python +def is_array_api_obj(x): + return hasattr(x, '__array_namespace__') +``` + +```{note} +Providing a "reference library" on which people depend is out-of-scope for +the standard. Hence the standard cannot, e.g., provide an array ABC from +which libraries can inherit to enable an `isinstance` check. However, note +that the `numpy.array_api` implementation aims to provide a reference +implementation with only the behavior specified in this standard - it may +prove useful for verifying one is writing portable code. +``` + +### Discoverability of conforming implementations + +It may be useful to have a way to discover all packages in a Python +environment which provide a conforming array API implementation, and the +namespace that that implementation resides in. +To assist array-consuming libraries which need to create arrays originating +from multiple conforming array implementations, or developers who want to perform +for example cross-library testing, libraries may provide an +{pypa}`entry point ` in order to make an array API +namespace discoverable. + +:::{admonition} Optional feature +Given that entry points typically require build system & package installer +specific implementation, this standard chooses to recommend rather than +mandate providing an entry point. +::: + +The following code is an example for how one can discover installed +conforming libraries: + +```python +from importlib.metadata import entry_points + +try: + eps = entry_points()['array_api'] + ep = next(ep for ep in eps if ep.name == 'package_name') +except TypeError: + # The dict interface for entry_points() is deprecated in py3.10, + # supplanted by a new select interface. + ep = entry_points(group='array_api', name='package_name') + +xp = ep.load() +``` + +An entry point must have the following properties: + +- **group**: equal to `array_api`. +- **name**: equal to the package name. +- **object reference**: equal to the array API namespace import path. + + +* * * + +## Conformance + +A conforming implementation of the array API standard must provide and support +all the functions, arguments, data types, syntax, and semantics described in +this specification. + +A conforming implementation of the array API standard may provide additional +values, objects, properties, data types, and functions beyond those described +in this specification. + +Libraries which aim to provide a conforming implementation but haven't yet +completed such an implementation may, and are encouraged to, provide details on +the level of (non-)conformance. For details on how to do this, see +[Verification - measuring conformance](verification_test_suite.md). + + +* * * + +## Terms and Definitions + +For the purposes of this specification, the following terms and definitions apply. + + + +**array**: +a (usually fixed-size) multidimensional container of items of the same type and size. + +**axis**: +an array dimension. + +**branch cut**: +a curve in the complex plane across which a given complex function fails to be continuous. + +**broadcast**: +automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +**compatible**: +two arrays whose dimensions are compatible (i.e., where the size of each dimension in one array is either equal to one or to the size of the corresponding dimension in a second array). + +**element-wise**: +an operation performed element-by-element, in which individual array elements are considered in isolation and independently of other elements within the same array. + +**matrix**: +a two-dimensional array. + +**rank**: +number of array dimensions (not to be confused with the number of linearly independent columns of a matrix). + +**shape**: +a tuple of `N` non-negative integers that specify the sizes of each dimension and where `N` corresponds to the number of dimensions. + +**singleton dimension**: +a dimension whose size is one. + +**vector**: +a one-dimensional array. + +* * * + +## Normative References + +The following referenced documents are indispensable for the application of this specification. + +- __IEEE 754-2019: IEEE Standard for Floating-Point Arithmetic.__ Institute of Electrical and Electronic Engineers, New York (2019). +- Scott Bradner. 1997. "Key words for use in RFCs to Indicate Requirement Levels". RFC 2119. doi:[10.17487/rfc2119](https://tools.ietf.org/html/rfc2119). diff --git a/spec/2023.12/usage_data.md b/spec/2023.12/usage_data.md new file mode 100644 index 000000000..c2dcd5d65 --- /dev/null +++ b/spec/2023.12/usage_data.md @@ -0,0 +1,86 @@ +(usage-data)= + +# Usage Data + +> Summary of existing array API design and usage. + +## Introduction + +With rare exception, technical standardization ("standardization") occurs neither in a vacuum nor from first principles. Instead, standardization finds its origins in two or more, sometimes competing, implementations differing in design and behavior. These differences introduce friction as those (e.g., downstream end-users and library authors) who operate at higher levels of abstraction must either focus on an implementation subset (e.g., only NumPy-like array libraries) or accommodate variation through increased complexity (e.g., if NumPy array, call method `.foo()`; else if Dask array, call method `.bar()`). + +Standardization aspires to reduce this friction and is a process which codifies that which is common, while still encouraging experimentation and innovation. Through the process of standardization, implementations can align around a subset of established practices and channel development resources toward that which is new and novel. In short, standardization aims to thwart reinventing the proverbial wheel. + +A foundational step in standardization is articulating a subset of established practices and defining those practices in unambiguous terms. To this end, the standardization process must approach the problem from two directions: **design** and **usage**. The former direction seeks to understand + +- current implementation design (APIs, names, signatures, classes, and objects) +- current implementation semantics (calling conventions and behavior) + +while the latter direction seeks to quantify API + +- consumers (e.g., which downstream libraries utilize an API?) +- usage frequency (e.g., how often is an API consumed?) +- consumption patterns (e.g., which optional arguments are provided and in what context?) + +By analyzing both design and usage, the standardization process grounds specification decisions in empirical data and analysis. + +## Design + +To understand API design, standardization follows the following process. + +- Identify a representative sample of commonly used Python array libraries (e.g., NumPy, Dask Array, CuPy, MXNet, JAX, TensorFlow, and PyTorch). +- Acquire public APIs (e.g., by analyzing module exports and scraping public documentation). +- Unify and standardize public API data representation for subsequent analysis. +- Extract commonalities and differences by analyzing the intersection and complement of available APIs. +- Derive a common API subset suitable for standardization (based on prevalence and ease of implementation), where such a subset may include attribute names, method names, and positional and keyword arguments. +- Leverage usage data to validate API need and to inform naming conventions, supported data types, and/or optional arguments. +- Summarize findings and provide tooling for additional analysis and exploration. + +See the [`array-api-comparison`](https://github.com/data-apis/array-api-comparison) +repository for design data and summary analysis. + +## Usage + +To understand usage patterns, standardization follows the following process. + +- Identify a representative sample of commonly used Python libraries ("downstream libraries") which consume the subset of array libraries identified during design analysis (e.g., pandas, Matplotlib, SciPy, Xarray, scikit-learn, and scikit-image). +- Instrument downstream libraries in order to record Python array API calls. +- Collect traces while running downstream library test suites. +- Transform trace data into structured data (e.g., as JSON) for subsequent analysis. +- Generate empirical APIs based on provided arguments and associated types, noting which downstream library called which empirical API and at what frequency. +- Derive a single inferred API which unifies the individual empirical API calling semantics. +- Organize API results in human-readable form as type definition files. +- Compare the inferred API to the documented API. + +The following is an inferred API for `numpy.arange`. The docstring includes the number of lines of code that invoked this function for each downstream library when running downstream library test suites. + +```python +def arange( + _0: object, + /, + *_args: object, + dtype: Union[type, str, numpy.dtype, None] = ..., + step: Union[int, float] = ..., + stop: int = ..., +): + """ + usage.dask: 347 + usage.matplotlib: 359 + usage.pandas: 894 + usage.sample-usage: 4 + usage.scipy: 1173 + usage.skimage: 174 + usage.sklearn: 373 + usage.xarray: 666 + """ + ... +``` + +See the [`python-record-api`](https://github.com/data-apis/python-record-api) repository for source code, usage data, and analysis. To perform a similar analysis on additional downstream libraries, including those not publicly released, see the published PyPI [package](https://pypi.org/project/record_api/). + +## Use in Decision-Making + +Design and usage data support specification decision-making in the following ways. + +- Validate user stories to ensure that proposals satisfy existing needs. +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2023.12/use_cases.md b/spec/2023.12/use_cases.md new file mode 100644 index 000000000..e24aa50db --- /dev/null +++ b/spec/2023.12/use_cases.md @@ -0,0 +1,235 @@ +(use-cases)= + +# Use cases + +Use cases inform the requirements for, and design choices made in, this array +API standard. This section first discusses what types of use cases are +considered, and then works out a few concrete use cases in more detail. + +## Types of use cases + +- Packages that depend on a specific array library currently, and would like + to support multiple of them (e.g. for GPU or distributed array support, for + improved performance, or for reaching a wider user base). +- Writing new libraries/tools that wrap multiple array libraries. +- Projects that implement new types of arrays with, e.g., hardware-specific + optimizations or auto-parallelization behavior, and need an API to put on + top that is familiar to end users. +- End users that want to switch from one library to another without learning + about all the small differences between those libraries. + + +## Concrete use cases + +- {ref}`use-case-scipy` +- {ref}`use-case-einops` +- {ref}`use-case-xtensor` +- {ref}`use-case-numba` + + +(use-case-scipy)= + +### Use case 1: add hardware accelerator and distributed support to SciPy + +When surveying a representative set of advanced users and research software +engineers in 2019 (for [this NSF proposal](https://figshare.com/articles/Mid-Scale_Research_Infrastructure_-_The_Scientific_Python_Ecosystem/8009441)), +the single most common pain point brought up about SciPy was performance. + +SciPy heavily relies on NumPy (its only non-optional runtime dependency). +NumPy provides an array implementation that's in-memory, CPU-only and +single-threaded. Common performance-related wishes users have are: + +- parallel algorithms (can be multi-threaded or multiprocessing based) +- support for distributed arrays (with Dask in particular) +- support for GPUs and other hardware accelerators (shortened to just "GPU" + in the rest of this use case) + +Some parallelism can be supported in SciPy, it has a `workers` keyword +(similar to scikit-learn's `n_jobs` keyword) that allows specifying to use +parallelism in some algorithms. However SciPy itself will not directly start +depending on a GPU or distributed array implementation, or contain (e.g.) +CUDA code - that's not maintainable given the resources for development. +_However_, there is a way to provide distributed or GPU support. Part of the +solution is provided by NumPy's "array protocols" (see [gh-1](https://github.com/data-apis/array-api/issues/1)), that allow +dispatching to other array implementations. The main problem then becomes how +to know whether this will work with a particular distributed or GPU array +implementation - given that there are zero other array implementations that +are even close to providing full NumPy compatibility - without adding that +array implementation as a dependency. + +It's clear that SciPy functionality that relies on compiled extensions (C, +C++, Cython, Fortran) directly can't easily be run on another array library +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python +code can work though. There's two main possibilities: + +1. Testing with another package, manually or in CI, and simply provide a list + of functionality that is found to work. Then make ad-hoc fixes to expand + the set that works. +2. Start relying on a well-defined subset of the NumPy API (or a new + NumPy-like API), for which compatibility is guaranteed. + +Option (2) seems strongly preferable, and that "well-defined subset" is _what +an API standard should provide_. Testing will still be needed, to ensure there +are no critical corner cases or bugs between array implementations, however +that's then a very tractable task. + +As a concrete example, consider the spectral analysis functions in `scipy.signal`. +All of those functions (e.g., `periodogram`, `spectrogram`, `csd`, `welch`, `stft`, +`istft`) are pure Python - with the exception of `lombscargle` which is ~40 +lines of Cython - and uses NumPy function calls, array attributes and +indexing. The beginning of each function could be changed to retrieve the +module that implements the array API standard for the given input array type, +and then functions from that module could be used instead of NumPy functions. + +If the user has another array type, say a CuPy or PyTorch array `x` on their +GPU, doing: +``` +from scipy import signal + +signal.welch(x) +``` +will result in: +``` +# For CuPy +ValueError: object __array__ method not producing an array + +# For PyTorch +TypeError: can't convert cuda:0 device type tensor to numpy. +``` +and therefore the user will have to explicitly convert to and from a +`numpy.ndarray` (which is quite inefficient): +``` +# For CuPy +x_np = cupy.asnumpy(x) +freq, Pxx = (cupy.asarray(res) for res in signal.welch(x_np)) + +# For PyTorch +x_np = x.cpu().numpy() +# Note: ends up with tensors on CPU, may still have to move them back +freq, Pxx = (torch.tensor(res) for res in signal.welch(x_np)) +``` +This code will look a little different for each array library. The end goal +here is to be able to write this instead as: +``` +freq, Pxx = signal.welch(x) +``` +and have `freq`, `Pxx` be arrays of the same type and on the same device as `x`. + +```{note} + +This type of use case applies to many other libraries, from scikit-learn +and scikit-image to domain-specific libraries like AstroPy and +scikit-bio, to code written for a single purpose or user. +``` + +(use-case-einops)= + +### Use case 2: simplify einops by removing the backend system + +[einops](https://github.com/arogozhnikov/einops) is a library that provides flexible tensor operations and supports many array libraries (NumPy, TensorFlow, PyTorch, CuPy, MXNet, JAX). +Most of the code in `einops` is: + +- [einops.py](https://github.com/arogozhnikov/einops/blob/master/einops/einops.py) + contains the functions it offers as public API (`rearrange`, `reduce`, `repeat`). +- [_backends.py](https://github.com/arogozhnikov/einops/blob/master/einops/_backends.py) + contains the glue code needed to support that many array libraries. + +The amount of code in each of those two files is almost the same (~550 LoC each). +The typical pattern in `einops.py` is: +``` +def some_func(x): + ... + backend = get_backend(x) + shape = backend.shape(x) + result = backend.reduce(x) + ... +``` +With a standard array API, the `_backends.py` glue layer could almost completely disappear, +because the purpose it serves (providing a unified interface to array operations from each +of the supported backends) is already addressed by the array API standard. +Hence the complete `einops` code base could be close to 50% smaller, and easier to maintain or add to. + +```{note} + +Other libraries that have a similar backend system to support many array libraries +include [TensorLy](https://github.com/tensorly/tensorly), the (now discontinued) +multi-backend version of [Keras](https://github.com/keras-team/keras), +[Unumpy](https://github.com/Quansight-Labs/unumpy) and +[EagerPy](https://github.com/jonasrauber/eagerpy). Many end users and +organizations will also have such glue code - it tends to be needed whenever +one tries to support multiple array types in a single API. +``` + + +(use-case-xtensor)= + +### Use case 3: adding a Python API to xtensor + +[xtensor](https://github.com/xtensor-stack/xtensor) is a C++ array library +that is NumPy-inspired and provides lazy arrays. It has Python (and Julia and R) +bindings, however it does not have a Python array API. + +Xtensor aims to follow NumPy closely, however it only implements a subset of functionality +and documents some API differences in +[Notable differences with NumPy](https://xtensor.readthedocs.io/en/latest/numpy-differences.html). + +Note that other libraries document similar differences, see for example +[this page for JAX](https://jax.readthedocs.io/en/latest/jax.numpy.html) and +[this page for TensorFlow](https://www.tensorflow.org/guide/tf_numpy). + +Each time an array library author designs a new API, they have to choose (a) +what subset of NumPy makes sense to implement, and (b) where to deviate +because NumPy's API for a particular function is suboptimal or the semantics +don't fit their execution model. + +This array API standard aims to provide an API that can be readily adopted, +without having to make the above-mentioned choices. + +```{note} + +XND is another array library, written in C, that still needs a Python API. +Array implementations in other languages are often in a similar situation, +and could translate this array API standard 1:1 to their language. +``` + + +(use-case-numba)= + +### Use case 4: make JIT compilation of array computations easier and more robust + +[Numba](https://github.com/numba/numba) is a Just-In-Time (JIT) compiler for +numerical functions in Python; it is NumPy-aware. [PyPy](https://pypy.org) +is an implementation of Python with a JIT at its core; its NumPy support relies +on running NumPy itself through a compatibility layer (`cpyext`), while a +previous attempt to implement NumPy support directly was unsuccessful. + +Other array libraries may have an internal JIT (e.g., TensorFlow, PyTorch, +JAX, MXNet) or work with an external JIT like +[XLA](https://www.tensorflow.org/xla) or [VTA](https://tvm.apache.org/docs/vta/index.html). + +Numba currently has to jump through some hoops to accommodate NumPy's casting rules +and may not attain full compatibility with NumPy in some cases - see, e.g., +[this](https://github.com/numba/numba/issues/4749) or +[this](https://github.com/numba/numba/issues/5907) example issue regarding (array) scalar +return values. + +An [explicit suggestion from a Numba developer](https://twitter.com/esc___/status/1295389487485333505) +for this array API standard was: + +> for JIT compilers (e.g. Numba) it will be important, that the type of the + returned value(s) depends only on the *types* of the input but not on the + *values*. + +A concrete goal for this use case is to have better matching between +JIT-compiled and non-JIT execution. Here is an example from the Numba code +base, the need for which should be avoided in the future: + +``` +def check(x, y): + got = cfunc(x, y) + np.testing.assert_array_almost_equal(got, pyfunc(x, y)) + # Check the power operation conserved the input's dtype + # (this is different from Numpy, whose behaviour depends on + # the *values* of the arguments -- see PyArray_CanCastArrayTo). + self.assertEqual(got.dtype, x.dtype) +``` diff --git a/spec/2023.12/verification_test_suite.md b/spec/2023.12/verification_test_suite.md new file mode 100644 index 000000000..cbe770e48 --- /dev/null +++ b/spec/2023.12/verification_test_suite.md @@ -0,0 +1,62 @@ +# Verification - test suite + +## Measuring conformance + +In addition to the specification documents, a test suite is being developed to +aid library developers check conformance to the spec. **NOTE: The test suite +is still a work in progress.** It can be found at +. + +It is important to note that while the aim of the array API test suite is to +cover as much of the spec as possible, there are necessarily some aspects of +the spec that are not covered by the test suite, typically because they are +impossible to effectively test. Furthermore, if the test suite appears to +diverge in any way from what the spec documents say, this should be considered +a bug in the test suite. The specification is the ground source of truth. + +## Running the tests + +To run the tests, first clone the [test suite +repo](https://github.com/data-apis/array-api-tests), and install the testing +dependencies, + + pip install pytest hypothesis + +or + + conda install pytest hypothesis + +as well as the array libraries that you want to test. To run the tests, you +need to specify the array library that is to be tested. There are two ways to +do this. One way is to set the `ARRAY_API_TESTS_MODULE` environment variable. +For example + + ARRAY_API_TESTS_MODULE=numpy pytest + +Alternatively, edit the `array_api_tests/_array_module.py` file and change the +line + +```py +array_module = None +``` + +to + +```py +import numpy as array_module +``` + +(replacing `numpy` with the array module namespace to be tested). + +In either case, the tests should be run with the `pytest` command. + +Aside from the two testing dependencies (`pytest` and `hypothesis`), the test +suite has no dependencies. In particular, it does not depend on any specific +array libraries such as NumPy. All tests are run using only the array library +that is being tested, comparing results against the behavior as defined in the +spec. The test suite is designed to be standalone so that it can easily be vendored. + +See the +[README](https://github.com/data-apis/array-api-tests/blob/master/README.md) +in the test suite repo for more information about how to run and interpret the +test suite results. diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json index ad38507bb..04777bd78 100644 --- a/spec/_ghpages/versions.json +++ b/spec/_ghpages/versions.json @@ -1,6 +1,7 @@ { "2021.12": "2021.12", "2022.12": "2022.12", + "2023.12": "2023.12", "latest": "latest", "draft": "draft" } diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..dd19daea5d1a7b84e37b40dd1eb49bfc451dd50b GIT binary patch literal 6148 zcmeHKOG-mQ5UkcL0xrzbzd)!;&mE;Ee}t(zyiRW?uaiBQ}gHU6T7I45$QbR6ZhEQ9WTW5%(>U(?D*S^_)rPCZTp zSWi@x0#abCz-4Y1-v96DC+7b#NjoVZ1^$%+He0P%OTJR|*2&9xuWj@Py4QTu-M9`4 nL$qUJv}10(9p6Mz)-_-Ac`qCigU)==iTX3(y2zx!Un}qfHa!=x literal 0 HcmV?d00001 diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 9233df3c4..ec5d56d58 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- project = "Python array API standard" -copyright = "2020-2022, Consortium for Python Data API Standards" +copyright = "2020-2024, Consortium for Python Data API Standards" author = "Consortium for Python Data API Standards" # -- General configuration --------------------------------------------------- diff --git a/src/array_api_stubs/_2023_12/__init__.py b/src/array_api_stubs/_2023_12/__init__.py new file mode 100644 index 000000000..8415f2765 --- /dev/null +++ b/src/array_api_stubs/_2023_12/__init__.py @@ -0,0 +1,25 @@ +"""Function stubs and API documentation for the array API standard.""" + +from .array_object import * +from .constants import * +from .creation_functions import * +from .data_type_functions import * +from . import data_types as dtype +from .elementwise_functions import * +from .indexing_functions import * +from .linear_algebra_functions import * +from .manipulation_functions import * +from .searching_functions import * +from .set_functions import * +from .sorting_functions import * +from .statistical_functions import * +from .utility_functions import * +from . import linalg +from . import fft +from . import info + + +__array_api_version__: str = "YYYY.MM" +""" +String representing the version of the array API specification which the conforming implementation adheres to. +""" diff --git a/src/array_api_stubs/_2023_12/_types.py b/src/array_api_stubs/_2023_12/_types.py new file mode 100644 index 000000000..7c3d903d7 --- /dev/null +++ b/src/array_api_stubs/_2023_12/_types.py @@ -0,0 +1,144 @@ +""" +Types for type annotations used in the array API standard. + +The type variables should be replaced with the actual types for a given +library, e.g., for NumPy TypeVar('array') would be replaced with ndarray. +""" +from __future__ import annotations + +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", + "DefaultDataTypes", + "DataTypes", + "Capabilities", + "Info", +] + +from dataclasses import dataclass +from typing import ( + Any, + List, + Literal, + Optional, + Sequence, + Tuple, + TypedDict, + TypeVar, + Union, + Protocol, +) +from enum import Enum + +array = TypeVar("array") +device = TypeVar("device") +dtype = TypeVar("dtype") +SupportsDLPack = TypeVar("SupportsDLPack") +SupportsBufferProtocol = TypeVar("SupportsBufferProtocol") +PyCapsule = TypeVar("PyCapsule") +# ellipsis cannot actually be imported from anywhere, so include a dummy here +# to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 +ellipsis = TypeVar("ellipsis") + + +@dataclass +class finfo_object: + """Dataclass returned by `finfo`.""" + + bits: int + eps: float + max: float + min: float + smallest_normal: float + dtype: dtype + + +@dataclass +class iinfo_object: + """Dataclass returned by `iinfo`.""" + + bits: int + max: int + min: int + dtype: dtype + + +_T_co = TypeVar("_T_co", covariant=True) + + +class NestedSequence(Protocol[_T_co]): + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: + ... + + def __len__(self, /) -> int: + ... + + +class Info(Protocol): + """Namespace returned by `__array_namespace_info__`.""" + + def capabilities(self) -> Capabilities: + ... + + def default_device(self) -> device: + ... + + def default_dtypes(self, *, device: Optional[device]) -> DefaultDataTypes: + ... + + def devices(self) -> List[device]: + ... + + def dtypes( + self, *, device: Optional[device], kind: Optional[Union[str, Tuple[str, ...]]] + ) -> DataTypes: + ... + + +DefaultDataTypes = TypedDict( + "DefaultDataTypes", + { + "real floating": dtype, + "complex floating": dtype, + "integral": dtype, + "indexing": dtype, + }, +) +DataTypes = TypedDict( + "DataTypes", + { + "bool": dtype, + "float32": dtype, + "float64": dtype, + "complex64": dtype, + "complex128": dtype, + "int8": dtype, + "int16": dtype, + "int32": dtype, + "int64": dtype, + "uint8": dtype, + "uint16": dtype, + "uint32": dtype, + "uint64": dtype, + }, + total=False, +) +Capabilities = TypedDict( + "Capabilities", {"boolean indexing": bool, "data-dependent shapes": bool} +) diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py new file mode 100644 index 000000000..6dd70c278 --- /dev/null +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -0,0 +1,1219 @@ +from __future__ import annotations + +__all__ = ["array"] + +from ._types import ( + array, + dtype as Dtype, + device as Device, + Optional, + Tuple, + Union, + Any, + PyCapsule, + Enum, + ellipsis, +) + + +class _array: + def __init__(self: array) -> None: + """Initialize the attributes for the array object class.""" + + @property + def dtype(self: array) -> Dtype: + """ + Data type of the array elements. + + Returns + ------- + out: dtype + array data type. + """ + + @property + def device(self: array) -> Device: + """ + Hardware device the array data resides on. + + Returns + ------- + out: device + a ``device`` object (see :ref:`device-support`). + """ + + @property + def mT(self: array) -> array: + """ + Transpose of a matrix (or a stack of matrices). + + If an array instance has fewer than two dimensions, an error should be raised. + + Returns + ------- + out: array + array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape ``(..., M, N)``, the returned array must have shape ``(..., N, M)``). The returned array must have the same data type as the original array. + """ + + @property + def ndim(self: array) -> int: + """ + Number of array dimensions (axes). + + Returns + ------- + out: int + number of array dimensions (axes). + """ + + @property + def shape(self: array) -> Tuple[Optional[int], ...]: + """ + Array dimensions. + + Returns + ------- + out: Tuple[Optional[int], ...] + array dimensions. An array dimension must be ``None`` if and only if a dimension is unknown. + + + .. note:: + For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; ``A[:, B > 0]``) and thus cannot be statically resolved without knowing array contents. + + .. note:: + The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. + """ + + @property + def size(self: array) -> Optional[int]: + """ + Number of elements in an array. + + .. note:: + This must equal the product of the array's dimensions. + + Returns + ------- + out: Optional[int] + number of elements in an array. The returned value must be ``None`` if and only if one or more array dimensions are unknown. + + + .. note:: + For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. + """ + + @property + def T(self: array) -> array: + """ + Transpose of the array. + + The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. + + Returns + ------- + out: array + two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. + + + .. note:: + Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional ``permute_dims`` interface found in this specification. + """ + + def __abs__(self: array, /) -> array: + """ + Calculates the absolute value for each element of an array instance. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __add__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the sum for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance (augend array). Should have a numeric data type. + other: Union[int, float, array] + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __and__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i & other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. + """ + + def __array_namespace__( + self: array, /, *, api_version: Optional[str] = None + ) -> Any: + """ + Returns an object that has all the array API functions on it. + + Parameters + ---------- + self: array + array instance. + api_version: Optional[str] + string representing the version of the array API specification to be returned, in ``'YYYY.MM'`` form, for example, ``'2020.10'``. If it is ``None``, it should return the namespace corresponding to latest version of the array API specification. If the given version is invalid or not implemented for the given module, an error should be raised. Default: ``None``. + + Returns + ------- + out: Any + an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. + """ + + def __bool__(self: array, /) -> bool: + """ + Converts a zero-dimensional array to a Python ``bool`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: bool + a Python ``bool`` object representing the single element of the array. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``True``. + - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``bool``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __complex__(self: array, /) -> complex: + """ + Converts a zero-dimensional array to a Python ``complex`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: complex + a Python ``complex`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1+0j``. + - If ``self`` is ``False``, the result is ``0+0j``. + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. + - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. + - If ``self`` is a finite number, the result is ``self + 0j``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __dlpack__( + self: array, + /, + *, + stream: Optional[Union[int, Any]] = None, + max_version: Optional[tuple[int, int]] = None, + dl_device: Optional[tuple[Enum, int]] = None, + copy: Optional[bool] = None, + ) -> PyCapsule: + """ + Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. + + Parameters + ---------- + self: array + array instance. + stream: Optional[Union[int, Any]] + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be an integer larger than or equal to ``-1`` (see below for allowed values on each platform). If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. + + For other device types which do have a stream, queue, or similar synchronization/ordering mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + + .. note:: + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + + Device-specific values of ``stream`` for CUDA: + + - ``None``: producer must assume the legacy default stream (default). + - ``1``: the legacy default stream. + - ``2``: the per-thread default stream. + - ``> 2``: stream number represented as a Python integer. + - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. + + Device-specific values of ``stream`` for ROCm: + + - ``None``: producer must assume the legacy default stream (default). + - ``0``: the default stream. + - ``> 2``: stream number represented as a Python integer. + - Using ``1`` and ``2`` is not supported. + + .. note:: + When ``dl_device`` is provided explicitly, ``stream`` must be a valid + construct for the specified device type. In particular, when ``kDLCPU`` + is in use, ``stream`` must be ``None`` and a synchronization must be + performed to ensure data safety. + + .. admonition:: Tip + :class: important + + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronizations than necessary. + max_version: Optional[tuple[int, int]] + the maximum DLPack version that the *consumer* (i.e., the caller of + ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. + This method may return a capsule of version ``max_version`` (recommended + if it does support that), or of a different version. + This means the consumer must verify the version even when + `max_version` is passed. + dl_device: Optional[tuple[enum.Enum, int]] + the DLPack device type. Default is ``None``, meaning the exported capsule + should be on the same device as ``self`` is. When specified, the format + must be a 2-tuple, following that of the return value of :meth:`array.__dlpack_device__`. + If the device type cannot be handled by the producer, this function must + raise ``BufferError``. + + The v2023.12 standard only mandates that a compliant library should offer a way for + ``__dlpack__`` to return a capsule referencing an array whose underlying memory is + accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). + If a copy must be made to enable this support but ``copy`` is set to ``False``, the + function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this + API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the + function must always copy (performed by the producer). If ``False``, the + function must never copy, and raise a ``BufferError`` in case a copy is + deemed necessary (e.g. if a cross-device data movement is requested, and + it is not possible without a copy). If ``None``, the function must reuse + the existing memory buffer if possible and copy otherwise. Default: ``None``. + + When a copy happens, the ``DLPACK_FLAG_BITMASK_IS_COPIED`` flag must be set. + + .. note:: + If a copy happens, and if the consumer-provided ``stream`` and ``dl_device`` + can be understood by the producer, the copy must be performed over ``stream``. + + Returns + ------- + capsule: PyCapsule + a DLPack capsule for the array. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + Implementations should raise ``BufferError`` when the data cannot + be exported as DLPack (e.g., incompatible dtype or strides). Other + errors are raised when export fails for other reasons (e.g., incorrect + arguments passed or out of memory). + + Notes + ----- + The DLPack version scheme is SemVer, where the major DLPack versions + represent ABI breaks, and minor versions represent ABI-compatible additions + (e.g., new enum values for new data types or device types). + + The ``max_version`` keyword was introduced in v2023.12, and goes + together with the ``DLManagedTensorVersioned`` struct added in DLPack + 1.0. This keyword may not be used by consumers until a later time after + introduction, because producers may implement the support at a different + point in time. + + It is recommended for the producer to use this logic in the implementation + of ``__dlpack__``: + + .. code:: python + + if max_version is None: + # Keep and use the DLPack 0.X implementation + # Note: from March 2025 onwards (but ideally as late as + # possible), it's okay to raise BufferError here + else: + # We get to produce `DLManagedTensorVersioned` now. Note that + # our_own_dlpack_version is the max version that the *producer* + # supports and fills in the `DLManagedTensorVersioned::version` + # field + if max_version >= our_own_dlpack_version: + # Consumer understands us, just return a Capsule with our max version + elif max_version[0] == our_own_dlpack_version[0]: + # major versions match, we should still be fine here - + # return our own max version + else: + # if we're at a higher major version internally, did we + # keep an implementation of the older major version around? + # For example, if the producer is on DLPack 1.x and the consumer + # is 0.y, can the producer still export a capsule containing + # DLManagedTensor and not DLManagedTensorVersioned? + # If so, use that. Else, the producer should raise a BufferError + # here to tell users that the consumer's max_version is too + # old to allow the data exchange to happen. + + And this logic for the consumer in :func:`~array_api.from_dlpack`: + + .. code:: python + + try: + x.__dlpack__(max_version=(1, 0), ...) + # if it succeeds, store info from the capsule named "dltensor_versioned", + # and need to set the name to "used_dltensor_versioned" when we're done + except TypeError: + x.__dlpack__(...) + + This logic is also applicable to handling of the new ``dl_device`` and ``copy`` + keywords. + + DLPack 1.0 added a flag to indicate that the array is read-only + (``DLPACK_FLAG_BITMASK_READ_ONLY``). A consumer that does not support + read-only arrays should ignore this flag (this is preferred over + raising an exception; the user is then responsible for ensuring the + memory isn't modified). + + .. versionchanged:: 2022.12 + Added BufferError. + + .. versionchanged:: 2023.12 + Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + + .. versionchanged:: 2023.12 + Added recommendation for handling read-only arrays. + """ + + def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: + """ + Returns device type and device ID in DLPack format. Meant for use within :func:`~array_api.from_dlpack`. + + Parameters + ---------- + self: array + array instance. + + Returns + ------- + device: Tuple[Enum, int] + a tuple ``(device_type, device_id)`` in DLPack format. Valid device type enum members are: + + :: + + CPU = 1 + CUDA = 2 + CPU_PINNED = 3 + OPENCL = 4 + VULKAN = 7 + METAL = 8 + VPI = 9 + ROCM = 10 + CUDA_MANAGED = 13 + ONE_API = 14 + """ + + def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + r""" + Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + """ + + def __float__(self: array, /) -> float: + """ + Converts a zero-dimensional array to a Python ``float`` object. + + .. note:: + Casting integer values outside the representable bounds of Python's float type is not specified and is implementation-dependent. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: float + a Python ``float`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``float``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __floordiv__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i // other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. + """ + + def __ge__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + """ + + def __getitem__( + self: array, + key: Union[ + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, + ], + /, + ) -> array: + """ + Returns ``self[key]``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] + index key. + + Returns + ------- + out: array + an array containing the accessed value(s). The returned array must have the same data type as ``self``. + """ + + def __gt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + """ + + def __index__(self: array, /) -> int: + """ + Converts a zero-dimensional integer array to a Python ``int`` object. + + .. note:: + This method is called to implement `operator.index() `_. See also `PEP 357 `_. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have an integer data type. If ``self`` has a floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __int__(self: array, /) -> int: + """ + Converts a zero-dimensional array to a Python ``int`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + For floating-point operands, + + - If ``self`` is a finite number, the result is the integer part of ``self``. + - If ``self`` is ``-0``, the result is ``0``. + + **Raises** + + For floating-point operands, + + - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. + - If ``self`` is ``NaN``, raise ``ValueError``. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __invert__(self: array, /) -> array: + """ + Evaluates ``~self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as `self`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_invert`. + """ + + def __le__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + """ + + def __lshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i << other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. + """ + + def __lt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + """ + + def __matmul__(self: array, other: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + other: array + other array. Should have a numeric data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``self`` and ``other`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``self`` is a one-dimensional array having shape ``(K,)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + - The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. + + **Raises** + + - if either ``self`` or ``other`` is a zero-dimensional array. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __mod__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + """ + + def __mul__(self: array, other: Union[int, float, array], /) -> array: + r""" + Calculates the product for each element of an array instance with the respective element of the array ``other``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + """ + Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __neg__(self: array, /) -> array: + """ + Evaluates ``-self_i`` for each element of an array instance. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``self`` has a complex floating-point data type, both the real and imaginary components for each ``self_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __or__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i | other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + """ + + def __pos__(self: array, /) -> array: + """ + Evaluates ``+self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __pow__(self: array, other: Union[int, float, array], /) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. + + .. note:: + If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Parameters + ---------- + self: array + array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + other: Union[int, float, array] + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __rshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i >> other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. + """ + + def __setitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + value: Union[int, float, bool, array], + /, + ) -> None: + """ + Sets ``self[key]`` to ``value``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + index key. + value: Union[int, float, bool, array] + value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). + + + .. note:: + + Setting array values must not affect the data type of ``self``. + + When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + + When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + """ + + def __sub__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the difference for each element of an array instance with the respective element of the array ``other``. + + The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). + + Parameters + ---------- + self: array + array instance (minuend array). Should have a numeric data type. + other: Union[int, float, array] + subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __truediv__(self: array, other: Union[int, float, array], /) -> array: + r""" + Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __xor__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i ^ other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. + """ + + def to_device( + self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None + ) -> array: + """ + Copy the array from the device on which it currently resides to the specified ``device``. + + Parameters + ---------- + self: array + array instance. + device: device + a ``device`` object (see :ref:`device-support`). + stream: Optional[Union[int, Any]] + stream object to use during copy. In addition to the types supported in :meth:`array.__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. + + Returns + ------- + out: array + an array with the same data and data type as ``self`` and located on the specified ``device``. + + + Notes + ----- + + - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. + - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. + + .. versionchanged:: 2023.12 + Clarified behavior when a provided ``device`` object corresponds to the device on which an array instance resides. + """ + + +array = _array diff --git a/src/array_api_stubs/_2023_12/constants.py b/src/array_api_stubs/_2023_12/constants.py new file mode 100644 index 000000000..c5735d09f --- /dev/null +++ b/src/array_api_stubs/_2023_12/constants.py @@ -0,0 +1,30 @@ +__all__ = ["e", "inf", "nan", "newaxis", "pi"] + +e = 2.718281828459045 +""" +IEEE 754 floating-point representation of Euler's constant. + +``e = 2.71828182845904523536028747135266249775724709369995...`` +""" + +inf = float("inf") +""" +IEEE 754 floating-point representation of (positive) infinity. +""" + +nan = float("nan") +""" +IEEE 754 floating-point representation of Not a Number (``NaN``). +""" + +newaxis = None +""" +An alias for ``None`` which is useful for indexing arrays. +""" + +pi = 3.141592653589793 +""" +IEEE 754 floating-point representation of the mathematical constant ``π``. + +``pi = 3.1415926535897932384626433...`` +""" diff --git a/src/array_api_stubs/_2023_12/creation_functions.py b/src/array_api_stubs/_2023_12/creation_functions.py new file mode 100644 index 000000000..6de79268e --- /dev/null +++ b/src/array_api_stubs/_2023_12/creation_functions.py @@ -0,0 +1,647 @@ +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] + + +from ._types import ( + List, + NestedSequence, + Optional, + SupportsBufferProtocol, + Tuple, + Union, + array, + device, + dtype, +) + + +def arange( + start: Union[int, float], + /, + stop: Optional[Union[int, float]] = None, + step: Union[int, float] = 1, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. + + Parameters + ---------- + start: Union[int, float] + if ``stop`` is specified, the start of interval (inclusive); otherwise, the end of the interval (exclusive). If ``stop`` is not specified, the default starting value is ``0``. + stop: Optional[Union[int, float]] + the end of the interval. Default: ``None``. + step: Union[int, float] + the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + + .. note:: + This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. + """ + + +def asarray( + obj: Union[ + array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol + ], + /, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + r""" + Convert the input to an array. + + Parameters + ---------- + obj: Union[array, bool, int, float, complex, NestedSequence[bool | int | float | complex], SupportsBufferProtocol] + object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. + + .. admonition:: Tip + :class: important + + An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. + + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then, in order of precedence, + + - if all values are of type ``bool``, the output data type must be ``bool``. + - if all values are of type ``int`` or are a mixture of ``bool`` and ``int``, the output data type must be the default integer data type. + - if one or more values are ``complex`` numbers, the output data type must be the default complex floating-point data type. + - if one or more values are ``float``\s, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`array_api.astype`. + + .. note:: + If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def empty( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns an uninitialized array having a specified `shape`. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing uninitialized data. + """ + + +def empty_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns an uninitialized array with the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and containing uninitialized data. + """ + + +def eye( + n_rows: int, + n_cols: Optional[int] = None, + /, + *, + k: int = 0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + r""" + Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. + + .. note:: + An output array having a complex floating-point data type must have the value ``1 + 0j`` along the ``k``\th diagonal and ``0 + 0j`` elsewhere. + + Parameters + ---------- + n_rows: int + number of rows in the output array. + n_cols: Optional[int] + number of columns in the output array. If ``None``, the default number of columns in the output array is equal to ``n_rows``. Default: ``None``. + k: int + index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and ``0`` to the main diagonal. Default: ``0``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def from_dlpack( + x: object, + /, + *, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + """ + Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. + + Parameters + ---------- + x: object + input (array) object. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``x`` supports DLPack, the output array must be on the same device as ``x``. Default: ``None``. + + The v2023.12 standard only mandates that a compliant library should offer a way for ``from_dlpack`` to return an array + whose underlying memory is accessible to the Python interpreter, when the corresponding ``device`` is provided. If the + array library does not support such cases at all, the function must raise ``BufferError``. If a copy must be made to + enable this support but ``copy`` is set to ``False``, the function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy, and raise ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse the existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data in ``x``. + + .. admonition:: Note + :class: note + + The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array + may raise ``BufferError`` when the data cannot be exported as DLPack + (e.g., incompatible dtype, strides, or device). It may also raise other errors + when export fails for other reasons (e.g., not enough memory available + to materialize the data). ``from_dlpack`` must propagate such + exceptions. + AttributeError + If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present + on the input array. This may happen for libraries that are never able + to export their data with DLPack. + ValueError + If data exchange is possible via an explicit copy but ``copy`` is set to ``False``. + + Notes + ----- + See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in + order to handle DLPack versioning correctly. + + A way to move data from two array libraries to the same device (assumed supported by both libraries) in + a library-agnostic fashion is illustrated below: + + .. code:: python + + def func(x, y): + xp_x = x.__array_namespace__() + xp_y = y.__array_namespace__() + + # Other functions than `from_dlpack` only work if both arrays are from the same library. So if + # `y` is from a different one than `x`, let's convert `y` into an array of the same type as `x`: + if not xp_x == xp_y: + y = xp_x.from_dlpack(y, copy=True, device=x.device) + + # From now on use `xp_x.xxxxx` functions, as both arrays are from the library `xp_x` + ... + + + .. versionchanged:: 2023.12 + Required exceptions to address unsupported use cases. + + .. versionchanged:: 2023.12 + Added device and copy support. + """ + + +def full( + shape: Union[int, Tuple[int, ...]], + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ``fill_value``. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value`` according to the following rules: + + - If the fill value is an ``int``, the output array data type must be the default integer data type. + - If the fill value is a ``float``, the output array data type must be the default real-valued floating-point data type. + - If the fill value is a ``complex`` number, the output array data type must be the default complex floating-point data type. + - If the fill value is a ``bool``, the output array must have a boolean data type. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def full_like( + x: array, + /, + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + + .. note:: + If the ``fill_value`` has a data type which is not of the same data type kind (boolean, integer, or floating-point) as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def linspace( + start: Union[int, float, complex], + stop: Union[int, float, complex], + /, + num: int, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + endpoint: bool = True, +) -> array: + r""" + Returns evenly spaced numbers over a specified interval. + + Let :math:`N` be the number of generated values (which is either ``num`` or ``num+1`` depending on whether ``endpoint`` is ``True`` or ``False``, respectively). For real-valued output arrays, the spacing between values is given by + + .. math:: + \Delta_{\textrm{real}} = \frac{\textrm{stop} - \textrm{start}}{N - 1} + + For complex output arrays, let ``a = real(start)``, ``b = imag(start)``, ``c = real(stop)``, and ``d = imag(stop)``. The spacing between complex values is given by + + .. math:: + \Delta_{\textrm{complex}} = \frac{c-a}{N-1} + \frac{d-b}{N-1} j + + Parameters + ---------- + start: Union[int, float, complex] + the start of the interval. + stop: Union[int, float, complex] + the end of the interval. If ``endpoint`` is ``False``, the function must generate a sequence of ``num+1`` evenly spaced numbers starting with ``start`` and ending with ``stop`` and exclude the ``stop`` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval ``[start, stop)``. If ``endpoint`` is ``True``, the output array must consist of evenly spaced numbers over the closed interval ``[start, stop]``. Default: ``True``. + + .. note:: + The step size changes when `endpoint` is `False`. + + num: int + number of samples. Must be a nonnegative integer value. + dtype: Optional[dtype] + output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, + + - if either ``start`` or ``stop`` is a ``complex`` number, the output data type must be the default complex floating-point data type. + - if both ``start`` and ``stop`` are real-valued, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, conversion of ``start`` and ``stop`` should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + endpoint: bool + boolean indicating whether to include ``stop`` in the interval. Default: ``True``. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. + + Notes + ----- + + .. note:: + While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + + .. note:: + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: + """ + Returns coordinate matrices from coordinate vectors. + + Parameters + ---------- + arrays: array + an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. + indexing: str + Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. + + Returns + ------- + out: List[array] + list of N arrays, where ``N`` is the number of provided one-dimensional input arrays. Each returned array must have rank ``N``. For ``N`` one-dimensional arrays having lengths ``Ni = len(xi)``, + + - if matrix indexing ``ij``, then each returned array must have the shape ``(N1, N2, N3, ..., Nn)``. + - if Cartesian indexing ``xy``, then each returned array must have shape ``(N2, N1, N3, ..., Nn)``. + + Accordingly, for the two-dimensional case with input one-dimensional arrays of length ``M`` and ``N``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M)``. + + Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. + + Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ones. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tril(x: array, /, *, k: int = 0) -> array: + """ + Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The lower triangular part of the matrix is defined as the elements on and below the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal above which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def triu(x: array, /, *, k: int = 0) -> array: + """ + Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The upper triangular part of the matrix is defined as the elements on and above the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal below which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def zeros( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with zeros. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing zeros. + """ + + +def zeros_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with zeros. + """ diff --git a/src/array_api_stubs/_2023_12/data_type_functions.py b/src/array_api_stubs/_2023_12/data_type_functions.py new file mode 100644 index 000000000..e12d349c6 --- /dev/null +++ b/src/array_api_stubs/_2023_12/data_type_functions.py @@ -0,0 +1,228 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + +from ._types import ( + Union, + Tuple, + array, + dtype, + finfo_object, + iinfo_object, + device, + Optional, +) + + +def astype( + x: array, dtype: dtype, /, *, copy: bool = True, device: Optional[device] = None +) -> array: + """ + Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. + + .. note:: + Casting floating-point ``NaN`` and ``infinity`` values to integral data types is not specified and is implementation-dependent. + + .. note:: + Casting a complex floating-point array to a real-valued data type should not be permitted. + + Historically, when casting a complex floating-point array to a real-valued data type, libraries such as NumPy have discarded imaginary components such that, for a complex floating-point array ``x``, ``astype(x)`` equals ``astype(real(x))``). This behavior is considered problematic as the choice to discard the imaginary component is arbitrary and introduces more than one way to achieve the same outcome (i.e., for a complex floating-point array ``x``, ``astype(x)`` and ``astype(real(x))`` versus only ``astype(imag(x))``). Instead, in order to avoid ambiguity and to promote clarity, this specification requires that array API consumers explicitly express which component should be cast to a specified real-valued data type. + + .. note:: + When casting a boolean input array to a real-valued data type, a value of ``True`` must cast to a real-valued number equal to ``1``, and a value of ``False`` must cast to a real-valued number equal to ``0``. + + When casting a boolean input array to a complex floating-point data type, a value of ``True`` must cast to a complex number equal to ``1 + 0j``, and a value of ``False`` must cast to a complex number equal to ``0 + 0j``. + + .. note:: + When casting a real-valued input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. + + When casting a complex floating-point array to ``bool``, a value of ``0 + 0j`` must cast to ``False``, and all other values must cast to ``True``. + + Parameters + ---------- + x: array + array to cast. + dtype: dtype + desired data type. + copy: bool + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + device: Optional[device] + device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Added device keyword argument support. + """ + + +def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: + """ + Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. + + Parameters + ---------- + from_: Union[dtype, array] + input data type or array from which to cast. + to: dtype + desired data type. + + Returns + ------- + out: bool + ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. + """ + + +def finfo(type: Union[dtype, array], /) -> finfo_object: + """ + Machine limits for floating-point data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of floating-point data-type about which to get information. If complex, the information is about its component data type. + + .. note:: + Complex floating-point data types are specified to always use the same precision for both its real and imaginary components, so the information should be true for either component. + + Returns + ------- + out: finfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the real-valued floating-point data type. + + - **eps**: *float* + + difference between 1.0 and the next smallest representable real-valued floating-point number larger than 1.0 according to the IEEE-754 standard. + + - **max**: *float* + + largest representable real-valued number. + + - **min**: *float* + + smallest representable real-valued number. + + - **smallest_normal**: *float* + + smallest positive real-valued floating-point number with full precision. + + - **dtype**: dtype + + real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def iinfo(type: Union[dtype, array], /) -> iinfo_object: + """ + Machine limits for integer data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of integer data-type about which to get information. + + Returns + ------- + out: iinfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the type. + + - **max**: *int* + + largest representable number. + + - **min**: *int* + + smallest representable number. + + - **dtype**: dtype + + integer data type. + + .. versionadded:: 2022.12 + """ + + +def isdtype( + dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]] +) -> bool: + """ + Returns a boolean indicating whether a provided dtype is of a specified data type "kind". + + Parameters + ---------- + dtype: dtype + the input dtype. + kind: Union[str, dtype, Tuple[Union[str, dtype], ...]] + data type kind. + + - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. + - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. + + .. note:: + A conforming implementation of the array API standard is **not** limited to only including the dtypes described in this specification in the required data type kinds. For example, implementations supporting ``float16`` and ``bfloat16`` can include ``float16`` and ``bfloat16`` in the ``real floating`` data type kind. Similarly, implementations supporting ``int128`` can include ``int128`` in the ``signed integer`` data type kind. + + In short, conforming implementations may extend data type kinds; however, data type kinds must remain consistent (e.g., only integer dtypes may belong to integer data type kinds and only floating-point dtypes may belong to floating-point data type kinds), and extensions must be clearly documented as such in library documentation. + + Returns + ------- + out: bool + boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: + """ + Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. + + .. note:: + If provided mixed dtypes (e.g., integer and floating-point), the returned dtype will be implementation-specific. + + Parameters + ---------- + arrays_and_dtypes: Union[array, dtype] + an arbitrary number of input arrays and/or dtypes. + + Returns + ------- + out: dtype + the dtype resulting from an operation involving the input arrays and dtypes. + """ diff --git a/src/array_api_stubs/_2023_12/data_types.py b/src/array_api_stubs/_2023_12/data_types.py new file mode 100644 index 000000000..d15f4a9f7 --- /dev/null +++ b/src/array_api_stubs/_2023_12/data_types.py @@ -0,0 +1,22 @@ +__all__ = ["__eq__"] + + +from ._types import dtype + + +def __eq__(self: dtype, other: dtype, /) -> bool: + """ + Computes the truth value of ``self == other`` in order to test for data type object equality. + + Parameters + ---------- + self: dtype + data type instance. May be any supported data type. + other: dtype + other data type instance. May be any supported data type. + + Returns + ------- + out: bool + a boolean indicating whether the data type objects are equal. + """ diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py new file mode 100644 index 000000000..4462329d6 --- /dev/null +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -0,0 +1,2774 @@ +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "clip", + "conj", + "copysign", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "hypot", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "maximum", + "minimum", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "real", + "remainder", + "round", + "sign", + "signbit", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] + + +from ._types import Optional, Union, array + + +def abs(x: array, /) -> array: + r""" + Calculates the absolute value for each element ``x_i`` of the input array ``x``. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + .. note:: + For complex floating-point operands, the complex absolute value is known as the norm, modulus, or magnitude and, for a complex number :math:`z = a + bj` is computed as + + .. math:: + \operatorname{abs}(z) = \sqrt{a^2 + b^2} + + .. note:: + For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. + + .. + TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``-0``, the result is ``+0``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``. + - If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``. + - If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``. + - If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acos}(z) = \frac{1}{2}\pi + j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{acos}(z) = \pi - \operatorname{acos}(-z) + + .. note:: + For complex floating-point operands, ``acos(conj(x))`` must equal ``conj(acos(x))``. + + .. note:: + The inverse cosine (or arc cosine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \pi]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``. + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acosh}(z) = \ln(z + \sqrt{z+1}\sqrt{z-1}) + + For any :math:`z`, + + .. math:: + \operatorname{acosh}(z) = \frac{\sqrt{z-1}}{\sqrt{1-z}}\operatorname{acos}(z) + + or simply + + .. math:: + \operatorname{acosh}(z) = j\ \operatorname{acos}(z) + + in the upper half of the complex plane. + + .. note:: + For complex floating-point operands, ``acosh(conj(x))`` must equal ``conj(acosh(x))``. + + .. note:: + The inverse hyperbolic cosine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segment :math:`(-\infty, 1)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic cosine in the interval :math:`[0, \infty)` along the real axis and in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + πj/2``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN ± πj/2`` (sign of imaginary component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def add(x1: array, x2: array, /) -> array: + """ + Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is ``-infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is a nonzero finite number, the result is ``x2_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. + - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. + + .. note:: + Floating-point addition is a commutative operation, but not always associative. + + For complex floating-point operands, addition is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+------------+------------+----------------+ + | | c | dj | c + dj | + +============+============+============+================+ + | **a** | a + c | a + dj | (a+c) + dj | + +------------+------------+------------+----------------+ + | **bj** | c + bj | (b+d)j | c + (b+d)j | + +------------+------------+------------+----------------+ + | **a + bj** | (a+c) + bj | a + (b+d)j | (a+c) + (b+d)j | + +------------+------------+------------+----------------+ + + For complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. For example, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a`` is ``-0`` and ``c`` is ``-0``, the real component of the result is ``-0``. + - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. + + Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def asin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc sine of a complex number :math:`z` is + + .. math:: + \operatorname{asin}(z) = -j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asin}(z) = \operatorname{acos}(-z) - \frac{\pi}{2} + + .. note:: + For complex floating-point operands, ``asin(conj(x))`` must equal ``conj(asin(x))``. + + .. note:: + The inverse sine (or arc sine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse sine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def asinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic sine of a complex number :math:`z` is + + .. math:: + \operatorname{asinh}(z) = \ln(z + \sqrt{1+z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asinh}(z) = \frac{\operatorname{asin}(zj)}{j} + + .. note:: + For complex floating-point operands, ``asinh(conj(x))`` must equal ``conj(asinh(x))`` and ``asinh(-z)`` must equal ``-asinh(z)``. + + .. note:: + The inverse hyperbolic sine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic sine in the range of a strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the inverse tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atan}(z) = -\frac{\ln(1 - zj) - \ln(1 + zj)}{2}j + + .. note:: + For complex floating-point operands, ``atan(conj(x))`` must equal ``conj(atan(x))``. + + .. note:: + The inverse tangent (or arc tangent) is a multi-valued function and requires a branch on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(+j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse tangent in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan2(x1: array, x2: array, /) -> array: + """ + Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. + + The mathematical signs of ``x1_i`` and ``x2_i`` determine the quadrant of each element-wise result. The quadrant (i.e., branch) is chosen such that each element-wise result is the signed angle in radians between the ray ending at the origin and passing through the point ``(1,0)`` and the ray ending at the origin and passing through the point ``(x2_i, x1_i)``. + + .. note:: + Note the role reversal: the "y-coordinate" is the first function parameter; the "x-coordinate" is the second function parameter. The parameter order is intentional and traditional for the two-argument inverse tangent function where the y-coordinate argument is first and the x-coordinate argument is second. + + By IEEE 754 convention, the inverse tangent of the quotient ``x1/x2`` is defined for ``x2_i`` equal to positive or negative zero and for either or both of ``x1_i`` and ``x2_i`` equal to positive or negative ``infinity``. + + Parameters + ---------- + x1: array + input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. + x2: array + input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/4``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. + """ + + +def atanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atanh}(z) = \frac{\ln(1+z)-\ln(z-1)}{2} + + For any :math:`z`, + + .. math:: + \operatorname{atanh}(z) = \frac{\operatorname{atan}(zj)}{j} + + .. note:: + For complex floating-point operands, ``atanh(conj(x))`` must equal ``conj(atanh(x))`` and ``atanh(-x)`` must equal ``-atanh(x)``. + + .. note:: + The inverse hyperbolic tangent is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, 1]` and :math:`[1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic tangent in the range of a half-strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``+1``, the result is ``+infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``1`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def bitwise_and(x1: array, x2: array, /) -> array: + """ + Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_left_shift(x1: array, x2: array, /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. + + Parameters + ---------- + x1: array + first input array. Should have an integer data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_invert(x: array, /) -> array: + """ + Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + """ + + +def bitwise_or(x1: array, x2: array, /) -> array: + """ + Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_right_shift(x1: array, x2: array, /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. + + Parameters + ---------- + x1: array + first input array. Should have an integer data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_xor(x1: array, x2: array, /) -> array: + """ + Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def ceil(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def clip( + x: array, + /, + min: Optional[Union[int, float, array]] = None, + max: Optional[Union[int, float, array]] = None, +) -> array: + r""" + Clamps each element ``x_i`` of the input array ``x`` to the range ``[min, max]``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + min: Optional[Union[int, float, array]] + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + max: Optional[Union[int, float, array]] + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + + Returns + ------- + out: array + an array containing element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. + - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + + .. versionadded:: 2023.12 + """ + + +def conj(x: array, /) -> array: + """ + Returns the complex conjugate for each element ``x_i`` of the input array ``x``. + + For complex numbers of the form + + .. math:: + a + bj + + the complex conjugate is defined as + + .. math:: + a - bj + + Hence, the returned complex conjugates must be computed by negating the imaginary component of each element ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def copysign(x1: array, x2: array, /) -> array: + r""" + Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. + + Parameters + ---------- + x1: array + input array containing magnitudes. Should have a real-valued floating-point data type. + x2: array + input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``-0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``+0``, the result is ``|x1_i|``. + - If ``x2_i`` is greater than ``0``, the result is ``|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. + + If ``x1_i`` is ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + + .. versionadded:: 2023.12 + """ + + +def cos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The cosine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of cosine is + + .. math:: + \begin{align} \operatorname{cos}(x) &= \sum_{n=0}^\infty \frac{(-1)^n}{(2n)!} x^{2n} \\ &= \frac{e^{jx} + e^{-jx}}{2} \\ &= \operatorname{cosh}(jx) \end{align} + + where :math:`\operatorname{cosh}` is the hyperbolic cosine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``NaN``. + - If ``x_i`` is ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic cosine for each element ``x_i`` in the input array ``x``. + + The mathematical definition of the hyperbolic cosine is + + .. math:: + \operatorname{cosh}(x) = \frac{e^x + e^{-x}}{2} + + .. note:: + The hyperbolic cosine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``cosh(x)`` must equal ``cosh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``cosh(conj(x))`` must equal ``conj(cosh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is either ``+0`` or ``-0``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def divide(x1: array, x2: array, /) -> array: + r""" + Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + Parameters + ---------- + x1: array + dividend input array. Should have a numeric data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, division is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a / c | -(a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b/c)j | b/d | special rules | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a/c) + (b/c)j | b/d - (a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division + + .. math:: + \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def equal(x1: array, x2: array, /) -> array: + r""" + Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. May have any data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``False``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` equals ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``False``. + - In the remaining cases, the result is the logical AND of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a == c AND b == d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def exp(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def expm1(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``0 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b) - 1.0``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def floor(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def floor_divide(x1: array, x2: array, /) -> array: + r""" + Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + x1: array + dividend input array. Should have a real-valued data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``\s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + + To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. + + Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. + + This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + """ + + +def greater(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def greater_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def hypot(x1: array, x2: array, /) -> array: + r""" + Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + The value computed by this function may be interpreted as the length of the hypotenuse of a right-angled triangle with sides of length ``x1_i`` and ``x2_i``, the distance of a point ``(x1_i, x2_i)`` from the origin ``(0, 0)``, or the magnitude of a complex number ``x1_i + x2_i * 1j``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``+infinity`` or ``-infinity`` and ``x2_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x2_i`` is ``+infinity`` or ``-infinity`` and ``x1_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x2_i)``. + - If ``x2_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x1_i)``. + - If ``x1_i`` is a finite number or ``NaN`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is a finite number or ``NaN`` and ``x1_i`` is ``NaN``, the result is ``NaN``. + - Underflow may only occur when both arguments are subnormal and the correct result is also subnormal. + + For real-valued floating-point operands, ``hypot(x1, x2)`` must equal ``hypot(x2, x1)``, ``hypot(x1, -x2)``, ``hypot(-x1, x2)``, and ``hypot(-x1, -x2)``. + + .. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, conforming implementations may vary in their support for subnormal numbers. + + .. versionadded:: 2023.12 + """ + + +def imag(x: array, /) -> array: + """ + Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def isfinite(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if finite. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``x_i`` is ``NaN``, the result is ``False``. + - If ``x_i`` is a finite number, the result is ``True``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``False``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. + - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isinf(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. + - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isnan(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array should have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` or ``b`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def less(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def less_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def log(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + The natural logarithm of a complex number :math:`z` with polar coordinates :math:`(r,\theta)` equals :math:`\ln r + (\theta + 2n\pi)j` with principal value :math:`\ln r + \theta j`. + + .. note:: + For complex floating-point operands, ``log(conj(x))`` must equal ``conj(log(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-0`` and ``b`` is ``+0``, the result is ``-infinity + πj``. + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log1p(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-1`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log2(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log2(conj(x))`` must equal ``conj(log2(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log10(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log10(conj(x))`` must equal ``conj(log10(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def logaddexp(x1: array, x2: array, /) -> array: + """ + Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + """ + + +def logical_and(x1: array, x2: array, /) -> array: + """ + Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of `bool`. + """ + + +def logical_not(x: array, /) -> array: + """ + Computes the logical NOT for each element ``x_i`` of the input array ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x: array + input array. Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def logical_or(x1: array, x2: array, /) -> array: + """ + Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def logical_xor(x1: array, x2: array, /) -> array: + """ + Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def maximum(x1: array, x2: array, /) -> array: + r""" + Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise maximum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + """ + + +def minimum(x1: array, x2: array, /) -> array: + r""" + Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise minimum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + """ + + +def multiply(x1: array, x2: array, /) -> array: + r""" + Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign, the result has a positive mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` and ``x2_i`` have different mathematical signs, the result has a negative mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - In the remaining cases, where neither ``infinity`` nor ``NaN`` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, multiplication is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a * c | (a*d)j | (a*c) + (a*d)j | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b*c)j | -(b*d) | -(b*d) + (b*c)j | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a*c) + (b*c)j | -(b*d) + (a*d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), multiplication of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number multiplication + + .. math:: + (a + bj) \cdot (c + dj) = (ac - bd) + (bc + ad)j + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def negative(x: array, /) -> array: + """ + Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``x`` has a complex floating-point data type, both the real and imaginary components for each ``x_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def not_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. May have any data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``True``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` does not equal ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is the logical OR of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a != c OR b != d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def positive(x: array, /) -> array: + """ + Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pow(x1: array, x2: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. + + .. note:: + If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x1: array + first input array whose elements correspond to the exponentiation base. Should have a numeric data type. + x2: array + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x2_i`` is ``-0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is not equal to ``0``, the result is ``NaN``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``+infinity``, the result is ``1``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``-infinity``, the result is ``1``. + - If ``x1_i`` is ``1`` and ``x2_i`` is not ``NaN``, the result is ``1``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is greater than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + + For complex floating-point operands, special cases should be handled as if the operation is implemented as ``exp(x2*log(x1))``. + + .. note:: + Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def real(x: array, /) -> array: + """ + Returns the real component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def remainder(x1: array, x2: array, /) -> array: + """ + Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This function is equivalent to the Python modulus operator ``x1_i % x2_i``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + x1: array + dividend input array. Should have a real-valued data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + In general, similar to Python's ``%`` operator, this function is **not** recommended for floating-point operands as semantics do not follow IEEE 754. That this function is specified to accept floating-point operands is primarily for reasons of backward compatibility. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x2_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - In the remaining cases, the result must match that of the Python ``%`` operator. + """ + + +def round(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. + + .. note:: + For complex floating-point operands, real and imaginary components must be independently rounded to the nearest integer-valued number. + + Rounded real and imaginary components must be equal to their equivalent rounded real-valued floating-point counterparts (i.e., for complex-valued ``x``, ``real(round(x))`` must equal ``round(real(x)))`` and ``imag(round(x))`` must equal ``round(imag(x))``). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + .. note:: + For complex floating-point operands, the following special cases apply to real and imaginary components independently (e.g., if ``real(x_i)`` is ``NaN``, the rounded real component is ``NaN``). + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sign(x: array, /) -> array: + r""" + Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. + + The sign function (also known as the **signum function**) of a number :math:`x_i` is defined as + + .. math:: + \operatorname{sign}(x_i) = \begin{cases} + 0 & \textrm{if } x_i = 0 \\ + \frac{x}{|x|} & \textrm{otherwise} + \end{cases} + + where :math:`|x_i|` is the absolute value of :math:`x_i`. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + For real-valued operands, + + - If ``x_i`` is less than ``0``, the result is ``-1``. + - If ``x_i`` is either ``-0`` or ``+0``, the result is ``0``. + - If ``x_i`` is greater than ``0``, the result is ``+1``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def signbit(x: array, /) -> array: + r""" + Determines whether the sign bit is set for each element ``x_i`` of the input array ``x``. + + The sign bit of a real-valued floating-point number ``x_i`` is set whenever ``x_i`` is either ``-0``, less than zero, or a signed ``NaN`` (i.e., a ``NaN`` value whose sign bit is ``1``). + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``+0``, the result is ``False``. + - If ``x_i`` is ``-0``, the result is ``True``. + - If ``x_i`` is ``+infinity``, the result is ``False``. + - If ``x_i`` is ``-infinity``, the result is ``True``. + - If ``x_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``False``. + - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + + .. versionadded:: 2023.12 + """ + + +def sin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The sine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of sine is + + .. math:: + \begin{align} \operatorname{sin}(x) &= \frac{e^{jx} - e^{-jx}}{2j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \cdot \frac{j}{j} \\ &= -j \cdot \operatorname{sinh}(jx) \end{align} + + where :math:`\operatorname{sinh}` is the hyperbolic sine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic sine for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic sine is + + .. math:: + \operatorname{sinh}(x) = \frac{e^x - e^{-x}}{2} + + .. note:: + The hyperbolic sine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``sinh(x)`` must equal ``-sinh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``sinh(conj(x))`` must equal ``conj(sinh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def square(x: array, /) -> array: + r""" + Squares each element ``x_i`` of the input array ``x``. + + The square of a number ``x_i`` is defined as + + .. math:: + x_i^2 = x_i \cdot x_i + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sqrt(x: array, /) -> array: + r""" + Calculates the principal square root for each element ``x_i`` of the input array ``x``. + + .. note:: + After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). + + .. note:: + For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. + + .. note:: + By convention, the branch cut of the square root is the negative real axis :math:`(-\infty, 0)`. + + The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def subtract(x1: array, x2: array, /) -> array: + """ + Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the tangent for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + Tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the real component and has first order poles along the real line at coordinates :math:`(\pi (\frac{1}{2} + n), 0)`. However, IEEE 754 binary floating-point representation cannot represent the value :math:`\pi / 2` exactly, and, thus, no argument value is possible for which a pole error occurs. + + .. note:: + For complex arguments, the mathematical definition of tangent is + + .. math:: + \begin{align} \operatorname{tan}(x) &= \frac{j(e^{-jx} - e^{jx})}{e^{-jx} + e^{jx}} \\ &= (-1) \frac{j(e^{jx} - e^{-jx})}{e^{jx} + e^{-jx}} \\ &= -j \cdot \operatorname{tanh}(jx) \end{align} + + where :math:`\operatorname{tanh}` is the hyperbolic tangent. + + Parameters + ---------- + x: array + input array whose elements are expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic tangent is + + .. math:: + \begin{align} \operatorname{tanh}(x) &= \frac{\operatorname{sinh}(x)}{\operatorname{cosh}(x)} \\ &= \frac{e^x - e^{-x}}{e^x + e^{-x}} \end{align} + + where :math:`\operatorname{sinh}(x)` is the hyperbolic sine and :math:`\operatorname{cosh}(x)` is the hyperbolic cosine. + + .. note:: + The hyperbolic tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the imaginary component and has first order poles along the imaginary line at coordinates :math:`(0, \pi (\frac{1}{2} + n))`. However, IEEE 754 binary floating-point representation cannot represent :math:`\pi / 2` exactly, and, thus, no argument value is possible such that a pole error occurs. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``tanh(-x)`` must equal ``-tanh(x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+1``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``tanh(conj(x))`` must equal ``conj(tanh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``+0 + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``1 + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. warning:: + For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. + + Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def trunc(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ diff --git a/src/array_api_stubs/_2023_12/fft.py b/src/array_api_stubs/_2023_12/fft.py new file mode 100644 index 000000000..4e8131c8b --- /dev/null +++ b/src/array_api_stubs/_2023_12/fft.py @@ -0,0 +1,683 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + +from ._types import Tuple, Union, Sequence, array, Optional, Literal, device + + +def fft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def fftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def rfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse of ``rfft`` for complex-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def rfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)``, the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse of ``rfftn`` for complex-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def hfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + """ + + +def ihfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: + """ + Computes the discrete Fourier transform sample frequencies. + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) # if n is odd + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + """ + + +def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: + """ + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, n/2] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) # if n is odd + + The Nyquist frequency component is considered to be positive. + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + """ + + +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: + """ + Shifts the zero-frequency component to the center of the spectrum. + + This function swaps half-spaces for all axes (dimensions) specified by ``axes``. + + .. note:: + ``out[0]`` is the Nyquist component only if the length of the input is even. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: + """ + Inverse of ``fftshift``. + + .. note:: + Although identical for even-length ``x``, ``fftshift`` and ``ifftshift`` differ by one sample for odd-length ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ diff --git a/src/array_api_stubs/_2023_12/indexing_functions.py b/src/array_api_stubs/_2023_12/indexing_functions.py new file mode 100644 index 000000000..35066a4a2 --- /dev/null +++ b/src/array_api_stubs/_2023_12/indexing_functions.py @@ -0,0 +1,40 @@ +__all__ = ["take"] + +from ._types import Union, Optional, array + + +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: + """ + Returns elements of an array along an axis. + + .. note:: + Conceptually, ``take(x, indices, axis=3)`` is equivalent to ``x[:,:,:,indices,...]``; however, explicit indexing via arrays of indices is not currently supported in this specification due to concerns regarding ``__setitem__`` and array mutation semantics. + + Parameters + ---------- + x: array + input array. + indices: array + array indices. The array must be one-dimensional and have an integer data type. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + axis: Optional[int] + axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. + + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + + Returns + ------- + out: array + an array having the same data type as ``x``. The output array must have the same rank (i.e., number of dimensions) as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` whose size must equal the number of elements in ``indices``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Out-of-bounds behavior is explicitly left unspecified. + """ diff --git a/src/array_api_stubs/_2023_12/info.py b/src/array_api_stubs/_2023_12/info.py new file mode 100644 index 000000000..b755ca2c0 --- /dev/null +++ b/src/array_api_stubs/_2023_12/info.py @@ -0,0 +1,197 @@ +__all__ = [ + "__array_namespace_info__", + "capabilities", + "default_device", + "default_dtypes", + "devices", + "dtypes", +] + +from ._types import ( + Optional, + Union, + Tuple, + List, + device, + dtype, + DefaultDataTypes, + DataTypes, + Capabilities, + Info, +) + + +def __array_namespace_info__() -> Info: + """ + Returns a namespace with Array API namespace inspection utilities. + + Returns + ------- + out: Info + An object containing Array API namespace inspection utilities. + + Notes + ----- + + The returned object may be either a namespace or a class, so long as an Array API user can access inspection utilities as follows: + + :: + + info = xp.__array_namespace_info__() + info.capabilities() + info.devices() + info.dtypes() + info.default_dtypes() + # ... + + .. versionadded: 2023.12 + """ + + +def capabilities() -> Capabilities: + """ + Returns a dictionary of array library capabilities. + + The dictionary must contain the following keys: + + - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + + Returns + ------- + out: Capabilities + a dictionary of array library capabilities. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def default_device() -> device: + """ + Returns the default device. + + Returns + ------- + out: device + an object corresponding to the default device. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def default_dtypes( + *, + device: Optional[device] = None, +) -> DefaultDataTypes: + """ + Returns a dictionary containing default data types. + + The dictionary must have the following keys: + + - `"real floating"`: default real floating-point data type. + - `"complex floating"`: default complex floating-point data type. + - `"integral"`: default integral data type. + - `"indexing"`: default array index data type. + + Dictionary values must be the corresponding data type object. + + Parameters + ---------- + device: Optional[device] + device for which to return default data types. If ``device`` is ``None``, the returned data types must be the default data types for the current device; otherwise, the returned data types must be default data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the default data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the default data types for the default device. + + Returns + ------- + out: DefaultDataTypes + a dictionary containing the default data type for respective data type kinds. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def dtypes( + *, + device: Optional[device] = None, + kind: Optional[Union[str, Tuple[str, ...]]] = None, +) -> DataTypes: + """ + Returns a dictionary of supported *Array API* data types. + + .. note:: + While specification-conforming array libraries may support additional data types which are not present in this specification, data types which are not present in this specification should not be included in the returned dictionary. + + .. note:: + Specification-conforming array libraries must only return supported data types having expected properties as described in :ref:`data-types`. For example, if a library decides to alias ``float32`` as ``float64``, that library must not include ``float64`` in the dictionary of supported data types. + + Parameters + ---------- + kind: Optional[Union[str, Tuple[str, ...]]] + data type kind. + + - If ``kind`` is ``None``, the function must return a dictionary containing all supported Array API data types. + + - If ``kind`` is a string, the function must return a dictionary containing the data types belonging to the specified data type kind. The following data type kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of data type kinds, and the function must return a dictionary containing the data types belonging to at least one of the specified data type kinds. + + Default: ``None``. + device: Optional[device] + device for which to return supported data types. If ``device`` is ``None``, the returned data types must be the supported data types for the current device; otherwise, the returned data types must be supported data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the supported data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the supported data types for the default device. + + Returns + ------- + out: DataTypes + a dictionary containing supported data types. + + .. note:: + Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def devices() -> List[device]: + """ + Returns a list of supported devices which are available at runtime. + + Returns + ------- + out: List[device] + a list of supported devices. + + Notes + ----- + + Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + + Notes + ----- + + .. versionadded: 2023.12 + """ diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py new file mode 100644 index 000000000..0950e6937 --- /dev/null +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -0,0 +1,850 @@ +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] + + +from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype +from .constants import inf + + +def cholesky(x: array, /, *, upper: bool = False) -> array: + r""" + Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + + The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = LL^{H} \qquad \text{L $\in\ \mathbb{K}^{n \times n}$} + + where :math:`L` is a lower triangular matrix and :math:`L^{H}` is the conjugate transpose when :math:`L` is complex-valued and the transpose when :math:`L` is real-valued. + + The upper Cholesky decomposition is defined similarly + + .. math:: + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + + where :math:`U` is an upper triangular matrix. + + When ``x`` is a stack of matrices, the function must compute the Cholesky decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square complex Hermitian or real symmetric positive-definite matrices. Should have a floating-point data type. + upper: bool + If ``True``, the result must be the upper-triangular Cholesky factor :math:`U`. If ``False``, the result must be the lower-triangular Cholesky factor :math:`L`. Default: ``False``. + + Returns + ------- + out: array + an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: + """ + Returns the cross product of 3-element vectors. + + If ``x1`` and/or ``x2`` are multi-dimensional arrays (i.e., the broadcasted result has a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. + + Parameters + ---------- + x1: array + first input array. Must have a numeric data type. The size of the axis over which the cross product is to be computed must be equal to 3. + x2: array + second input array. Must be broadcast compatible with ``x1`` along all axes other than the axis along which the cross-product is computed (see :ref:`broadcasting`). The size of the axis over which the cross product is to be computed must be equal to 3. Must have a numeric data type. + + .. note:: + The compute axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted broadcasting to only non-compute axes and required that ``axis`` be a negative integer. + """ + + +def det(x: array, /) -> array: + """ + Returns the determinant of a square matrix (or a stack of square matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def diagonal(x: array, /, *, offset: int = 0) -> array: + """ + Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: `0`. + + Returns + ------- + out: array + an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. + """ + + +def eigh(x: array, /) -> Tuple[array]: + r""" + Returns an eigenvalue decomposition of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalue decomposition** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = Q \Lambda Q^H + + with :math:`Q \in \mathbb{K}^{n \times n}` and :math:`\Lambda \in \mathbb{R}^n` and where :math:`Q^H` is the conjugate transpose when :math:`Q` is complex and the transpose when :math:`Q` is real-valued and :math:`\Lambda` is a diagonal matrix whose diagonal elements are the corresponding eigenvalues. When ``x`` is real-valued, :math:`Q` is orthogonal, and, when ``x`` is complex, :math:`Q` is unitary. + + .. note:: + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. warning:: + The eigenvectors of a symmetric matrix are not unique and are not continuous with respect to ``x``. Because eigenvectors are not unique, different hardware and software may compute different eigenvectors. + + Non-uniqueness stems from the fact that multiplying an eigenvector by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another set of valid eigenvectors. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eig`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array] + a namedtuple (``eigenvalues``, ``eigenvectors``) whose + + - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). + - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def eigvalsh(x: array, /) -> array: + r""" + Returns the eigenvalues of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalues** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` are defined as the roots (counted with multiplicity) of the polynomial :math:`p` of degree :math:`n` given by + + .. math:: + p(\lambda) = \operatorname{det}(x - \lambda I_n) + + where :math:`\lambda \in \mathbb{R}` and where :math:`I_n` is the *n*-dimensional identity matrix. + + .. note:; + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eigvals`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def inv(x: array, /) -> array: + r""" + Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **inverse matrix** :math:`x^{-1} \in\ \mathbb{K}^{n \times n}` of a square matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x^{-1}x = xx^{-1} = I_n + + where :math:`I_n` is the *n*-dimensional identity matrix. + + The inverse matrix exists if and only if ``x`` is invertible. When ``x`` is invertible, the inverse is unique. + + When ``x`` is a stack of matrices, the function must compute the inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matmul(x1: array, x2: array, /) -> array: + """Alias for :func:`~array_api.matmul`.""" + + +def matrix_norm( + x: array, + /, + *, + keepdims: bool = False, + ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro", +) -> array: + """ + Computes the matrix norm of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + keepdims: bool + If ``True``, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the last two axes (dimensions) must not be included in the result. Default: ``False``. + ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] + order of the norm. The following mathematical norms must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | 'fro' | Frobenius norm | + +------------------+---------------------------------+ + | 'nuc' | nuclear norm | + +------------------+---------------------------------+ + | 1 | max(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | 2 | largest singular value | + +------------------+---------------------------------+ + | inf | max(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | -1 | min(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | -2 | smallest singular value | + +------------------+---------------------------------+ + | -inf | min(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + If ``ord=1``, the norm corresponds to the induced matrix norm where ``p=1`` (i.e., the maximum absolute value column sum). + + If ``ord=2``, the norm corresponds to the induced matrix norm where ``p=inf`` (i.e., the maximum absolute value row sum). + + If ``ord=inf``, the norm corresponds to the induced matrix norm where ``p=2`` (i.e., the largest singular value). + + Default: ``'fro'``. + + Returns + ------- + out: array + an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_power(x: array, n: int, /) -> array: + """ + Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + n: int + integer exponent. + + Returns + ------- + out: array + if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + """ + Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). + + When ``x`` is a stack of matrices, the function must compute the number of non-zero singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_transpose(x: array, /) -> array: + """Alias for :func:`~array_api.matrix_transpose`.""" + + +def outer(x1: array, x2: array, /) -> array: + """ + Returns the outer product of two vectors ``x1`` and ``x2``. + + Parameters + ---------- + x1: array + first one-dimensional input array of size ``N``. Must have a numeric data type. + x2: array + second one-dimensional input array of size ``M``. Must have a numeric data type. + + Returns + ------- + out: array + a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + r""" + Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. + + The pseudo-inverse of a matrix :math:`A`, denoted :math:`A^{+}`, is defined as the matrix that "solves" the least-squares problem :math:`Ax = b` (i.e., if :math:`\overline{x}` is a solution, then :math:`A^{+}` is the matrix such that :math:`\overline{x} = A^{+}b`). + + While the pseudo-inverse can be defined algebraically, one can understand the pseudo-inverse via singular value decomposition (SVD). Namely, if + + .. math:: + A = U \Sigma V^H + + is a singular decomposition of :math:`A`, then + + .. math:: + A^{+} = U \Sigma^{+} V^H + + where :math:`U` and :math:`V^H` are orthogonal matrices, :math:`\Sigma` is a diagonal matrix consisting of :math:`A`'s singular values, and :math:`\Sigma^{+}` is then a diagonal matrix consisting of the reciprocals of :math:`A`'s singular values, leaving zeros in place. During numerical computation, only elements larger than a small tolerance are considered nonzero, and all others replaced by zeros. + + When ``x`` is a stack of matrices, the function must compute the pseudo-inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def qr( + x: array, /, *, mode: Literal["reduced", "complete"] = "reduced" +) -> Tuple[array, array]: + r""" + Returns the QR decomposition of a full column rank matrix (or a stack of matrices). + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **complete QR decomposition** of a matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times m}` is orthogonal when ``x`` is real-valued and unitary when ``x`` is complex-valued and where :math:`R \in\ \mathbb{K}^{m \times n}` is an upper triangular matrix with real diagonal (even when ``x`` is complex-valued). + + When :math:`m \gt n` (tall matrix), as :math:`R` is upper triangular, the last :math:`m - n` rows are zero. In this case, the last :math:`m - n` columns of :math:`Q` can be dropped to form the **reduced QR decomposition**. + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. + + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). + + When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. + + .. warning:: + The elements in the diagonal of :math:`R` are not necessarily positive. Accordingly, the returned QR decomposition is only unique up to the sign of the diagonal of :math:`R`, and different libraries or inputs on different devices may produce different valid decompositions. + + .. warning:: + The QR decomposition is only well-defined if the first ``k = min(m,n)`` columns of every matrix in ``x`` are linearly independent. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a floating-point data type. + mode: Literal['reduced', 'complete'] + decomposition mode. Should be one of the following modes: + + - ``'reduced'``: compute only the leading ``K`` columns of ``q``, such that ``q`` and ``r`` have dimensions ``(..., M, K)`` and ``(..., K, N)``, respectively, and where ``K = min(M, N)``. + - ``'complete'``: compute ``q`` and ``r`` with dimensions ``(..., M, M)`` and ``(..., M, N)``, respectively. + + Default: ``'reduced'``. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(Q, R)`` whose + + - first element must have the field name ``Q`` and must be an array whose shape depends on the value of ``mode`` and contain matrices with orthonormal columns. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, M)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input array ``x``. + - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. + + Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def slogdet(x: array, /) -> Tuple[array, array]: + r""" + Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. + + .. note:: + The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling ``det`` may overflow or underflow. + + The sign of the determinant is given by + + .. math:: + \operatorname{sign}(\det x) = \begin{cases} + 0 & \textrm{if } \det x = 0 \\ + \frac{\det x}{|\det x|} & \textrm{otherwise} + \end{cases} + + where :math:`|\det x|` is the absolute value of the determinant of ``x``. + + When ``x`` is a stack of matrices, the function must compute the sign and natural logarithm of the absolute value of the determinant for each matrix in the stack. + + **Special Cases** + + For real-valued floating-point operands, + + - If the determinant is zero, the ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``. + + For complex floating-point operands, + + - If the determinant is ``0 + 0j``, the ``sign`` should be ``0 + 0j`` and ``logabsdet`` should be ``-infinity + 0j``. + + .. note:: + Depending on the underlying algorithm, when the determinant is zero, the returned result may differ from ``-infinity`` (or ``-infinity + 0j``). In all cases, the determinant should be equal to ``sign * exp(logabsdet)`` (although, again, the result may be subject to numerical precision errors). + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array, array] + a namedtuple (``sign``, ``logabsdet``) whose + + - first element must have the field name ``sign`` and must be an array containing a number representing the sign of the determinant for each square matrix. Must have the same data type as ``x``. + - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). + + Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def solve(x1: array, x2: array, /) -> array: + r""" + Returns the solution of a square system of linear equations with a unique solution. + + Let ``x1`` equal :math:`A` and ``x2`` equal :math:`B`. If the promoted data type of ``x1`` and ``x2`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if the promoted data type of ``x1`` and ``x2`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + This function computes the solution :math:`X \in\ \mathbb{K}^{m \times k}` of the **linear system** associated to :math:`A \in\ \mathbb{K}^{m \times m}` and :math:`B \in\ \mathbb{K}^{m \times k}` and is defined as + + .. math:: + AX = B + + This system of linear equations has a unique solution if and only if :math:`A` is invertible. + + .. note:: + Whether an array library explicitly checks whether ``x1`` is invertible is implementation-defined. + + When ``x1`` and/or ``x2`` is a stack of matrices, the function must compute a solution for each matrix in the stack. + + Parameters + ---------- + x1: array + coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. + x2: array + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: + r""" + Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The full **singular value decomposition** of an :math:`m \times n` matrix :math:`x \in\ \mathbb{K}^{m \times n}` is a factorization of the form + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times m}`, :math:`\Sigma \in\ \mathbb{K}^{m \times\ n}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}` with :math:`k = \operatorname{min}(m, n)`, :math:`V^H \in\ \mathbb{K}^{n \times n}`, and where :math:`V^H` is the conjugate transpose when :math:`V` is complex and the transpose when :math:`V` is real-valued. When ``x`` is real-valued, :math:`U`, :math:`V` (and thus :math:`V^H`) are orthogonal, and, when ``x`` is complex, :math:`U`, :math:`V` (and thus :math:`V^H`) are unitary. + + When :math:`m \gt n` (tall matrix), we can drop the last :math:`m - n` columns of :math:`U` to form the reduced SVD + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times k}`, :math:`\Sigma \in\ \mathbb{K}^{k \times\ k}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}`, and :math:`V^H \in\ \mathbb{K}^{k \times n}`. In this case, :math:`U` and :math:`V` have orthonormal columns. + + Similarly, when :math:`n \gt m` (wide matrix), we can drop the last :math:`n - m` columns of :math:`V` to also form a reduced SVD. + + This function returns the decomposition :math:`U`, :math:`S`, and :math:`V^H`, where :math:`S = \operatorname{diag}(\Sigma)`. + + When ``x`` is a stack of matrices, the function must compute the singular value decomposition for each matrix in the stack. + + .. warning:: + The returned arrays :math:`U` and :math:`V` are neither unique nor continuous with respect to ``x``. Because :math:`U` and :math:`V` are not unique, different hardware and software may compute different singular vectors. + + Non-uniqueness stems from the fact that multiplying any pair of singular vectors :math:`u_k`, :math:`v_k` by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another two valid singular vectors of the matrix. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + full_matrices: bool + If ``True``, compute full-sized ``U`` and ``Vh``, such that ``U`` has shape ``(..., M, M)`` and ``Vh`` has shape ``(..., N, N)``. If ``False``, compute on the leading ``K`` singular vectors, such that ``U`` has shape ``(..., M, K)`` and ``Vh`` has shape ``(..., K, N)`` and where ``K = min(M, N)``. Default: ``True``. + + Returns + ------- + out: Tuple[array, array, array] + a namedtuple ``(U, S, Vh)`` whose + + - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). + - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def svdvals(x: array, /) -> array: + """ + Returns the singular values of a matrix (or a stack of matrices) ``x``. + + When ``x`` is a stack of matrices, the function must compute the singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + + Returns + ------- + out: array + an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """Alias for :func:`~array_api.tensordot`.""" + + +def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> array: + """ + Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a numeric data type. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: ``0``. + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + Returns + ------- + out: array + an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if ``x`` has rank ``k`` and shape ``(I, J, K, ..., L, M, N)``, then an output array has rank ``k-2`` and shape ``(I, J, K, ..., L)`` where + + :: + + out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) + + The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: + """Alias for :func:`~array_api.vecdot`.""" + + +def vector_norm( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, + ord: Union[int, float, Literal[inf, -inf]] = 2, +) -> array: + r""" + Computes the vector norm of a vector (or batch of vectors) ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + If an integer, ``axis`` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, ``axis`` specifies the axes (dimensions) along which to compute batched vector norms. If ``None``, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: ``None``. + keepdims: bool + If ``True``, the axes (dimensions) specified by ``axis`` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the axes (dimensions) specified by ``axis`` must not be included in the result. Default: ``False``. + ord: Union[int, float, Literal[inf, -inf]] + order of the norm. The following mathematical norms must be supported: + + +------------------+----------------------------+ + | ord | description | + +==================+============================+ + | 1 | L1-norm (Manhattan) | + +------------------+----------------------------+ + | 2 | L2-norm (Euclidean) | + +------------------+----------------------------+ + | inf | infinity norm | + +------------------+----------------------------+ + | (int,float >= 1) | p-norm | + +------------------+----------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+--------------------------------+ + | ord | description | + +==================+================================+ + | 0 | sum(a != 0) | + +------------------+--------------------------------+ + | -1 | 1./sum(1./abs(a)) | + +------------------+--------------------------------+ + | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | + +------------------+--------------------------------+ + | -inf | min(abs(a)) | + +------------------+--------------------------------+ + | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | + +------------------+--------------------------------+ + + Default: ``2``. + + Returns + ------- + out: array + an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ diff --git a/src/array_api_stubs/_2023_12/linear_algebra_functions.py b/src/array_api_stubs/_2023_12/linear_algebra_functions.py new file mode 100644 index 000000000..da4c97743 --- /dev/null +++ b/src/array_api_stubs/_2023_12/linear_algebra_functions.py @@ -0,0 +1,166 @@ +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] + + +from ._types import Tuple, Union, Sequence, array + + +def matmul(x1: array, x2: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + x2: array + second input array. Should have a numeric data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``x1`` and ``x2`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``x1`` is a one-dimensional array having shape ``(K,)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``x1`` or ``x2`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(x1)[:-2]`` against ``shape(x2)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + + The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + **Raises** + + - if either ``x1`` or ``x2`` is a zero-dimensional array. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + + """ + + +def matrix_transpose(x: array, /) -> array: + """ + Transposes a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + + Returns + ------- + out: array + an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """ + Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. + + .. note:: + The ``tensordot`` function corresponds to the generalized matrix product. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Should have a numeric data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + + .. note:: + Contracted axes (dimensions) must not be broadcasted. + + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] + number of axes (dimensions) to contract or explicit sequences of axis (dimension) indices for ``x1`` and ``x2``, respectively. + + If ``axes`` is an ``int`` equal to ``N``, then contraction must be performed over the last ``N`` axes of ``x1`` and the first ``N`` axes of ``x2`` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. + + - If ``N`` equals ``0``, the result is the tensor (outer) product. + - If ``N`` equals ``1``, the result is the tensor dot product. + - If ``N`` equals ``2``, the result is the tensor double contraction (default). + + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each index referred to in a sequence must be unique. If ``x1`` has rank (i.e, number of dimensions) ``N``, a valid ``x1`` axis must reside on the half-open interval ``[-N, N)``. If ``x2`` has rank ``M``, a valid ``x2`` axis must reside on the half-open interval ``[-M, M)``. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the generalized matrix product. + + Returns + ------- + out: array + an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Allow negative axes. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: + r""" + Computes the (vector) dot product of two arrays. + + Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as + + .. math:: + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i + + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. + + Parameters + ---------- + x1: array + first input array. Should have a floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). The size of the axis over which to compute the dot product must be the same size as the respective axis in ``x1``. Should have a floating-point data type. + + .. note:: + The contracted axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the dot product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted ``axis`` to only negative integers. + """ diff --git a/src/array_api_stubs/_2023_12/manipulation_functions.py b/src/array_api_stubs/_2023_12/manipulation_functions.py new file mode 100644 index 000000000..87f9511b0 --- /dev/null +++ b/src/array_api_stubs/_2023_12/manipulation_functions.py @@ -0,0 +1,368 @@ +__all__ = [ + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "moveaxis", + "permute_dims", + "repeat", + "reshape", + "roll", + "squeeze", + "stack", + "tile", + "unstack", +] + + +from ._types import List, Optional, Tuple, Union, array + + +def broadcast_arrays(*arrays: array) -> List[array]: + """ + Broadcasts one or more arrays against one another. + + Parameters + ---------- + arrays: array + an arbitrary number of to-be broadcasted arrays. + + Returns + ------- + out: List[array] + a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. + """ + + +def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: + """ + Broadcasts an array to a specified shape. + + Parameters + ---------- + x: array + array to broadcast. + shape: Tuple[int, ...] + array shape. Must be compatible with ``x`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + + Returns + ------- + out: array + an array having a specified shape. Must have the same data type as ``x``. + """ + + +def concat( + arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0 +) -> array: + """ + Joins a sequence of arrays along an existing axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. The arrays must have the same shape, except in the dimension specified by ``axis``. + axis: Optional[int] + axis along which the arrays will be joined. If ``axis`` is ``None``, arrays must be flattened before concatenation. If ``axis`` is negative, the function must determine the axis along which to join by counting from the last dimension. Default: ``0``. + + Returns + ------- + out: array + an output array containing the concatenated values. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def expand_dims(x: array, /, *, axis: int = 0) -> array: + """ + Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. + + Parameters + ---------- + x: array + input array. + axis: int + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). + + Returns + ------- + out: array + an expanded output array having the same data type as ``x``. + + Raises + ------ + IndexError + If provided an invalid ``axis`` position, an ``IndexError`` should be raised. + """ + + +def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + """ + Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which to flip. If ``axis`` is ``None``, the function must flip all input array axes. If ``axis`` is negative, the function must count from the last dimension. If provided more than one axis, the function must flip only the specified axes. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. + """ + + +def moveaxis( + x: array, + source: Union[int, Tuple[int, ...]], + destination: Union[int, Tuple[int, ...]], + /, +) -> array: + """ + Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. + + Parameters + ---------- + x: array + input array. + source: Union[int, Tuple[int, ...]] + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + destination: Union[int, Tuple[int, ...]] + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + + Returns + ------- + out: array + an array containing reordered axes. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: + """ + Permutes the axes (dimensions) of an array ``x``. + + Parameters + ---------- + x: array + input array. + axes: Tuple[int, ...] + tuple containing a permutation of ``(0, 1, ..., N-1)`` where ``N`` is the number of axes (dimensions) of ``x``. + + Returns + ------- + out: array + an array containing the axes permutation. The returned array must have the same data type as ``x``. + """ + + +def repeat( + x: array, + repeats: Union[int, array], + /, + *, + axis: Optional[int] = None, +) -> array: + """ + Repeats each element of an array a specified number of times on a per-element basis. + + .. admonition:: Data-dependent output shape + :class: important + + When ``repeats`` is an array, the shape of the output array for this function depends on the data values in the ``repeats`` array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing the values in ``repeats``. Accordingly, such libraries may choose to omit support for ``repeats`` arrays; however, conforming implementations must support providing a literal ``int``. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array containing elements to repeat. + repeats: Union[int, array] + the number of repetitions for each element. + + If ``axis`` is ``None``, let ``N = prod(x.shape)`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(N,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(N,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape `(N,)`. + + If ``axis`` is not ``None``, let ``M = x.shape[axis]`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(M,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(M,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape ``(M,)``. + + If ``repeats`` is an array, the array must have an integer data type. + + .. note:: + For specification-conforming array libraries supporting hardware acceleration, providing an array for ``repeats`` may cause device synchronization due to an unknown output shape. For those array libraries where synchronization concerns are applicable, conforming array libraries are advised to include a warning in their documentation regarding potential performance degradation when ``repeats`` is an array. + + axis: Optional[int] + the axis (dimension) along which to repeat elements. If ``axis`` is `None`, the function must flatten the input array ``x`` and then repeat elements of the flattened input array and return the result as a one-dimensional output array. A flattened input array must be flattened in row-major, C-style order. Default: ``None``. + + Returns + ------- + out: array + an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def reshape( + x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None +) -> array: + """ + Reshapes an array without changing its data. + + Parameters + ---------- + x: array + input array to reshape. + shape: Tuple[int, ...] + a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. + copy: Optional[bool] + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If ``copy=False`` and a copy would be necessary, a ``ValueError`` + should be raised. + """ + + +def roll( + x: array, + /, + shift: Union[int, Tuple[int, ...]], + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, +) -> array: + """ + Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. + + Parameters + ---------- + x: array + input array. + shift: Union[int, Tuple[int, ...]] + number of places by which the elements are shifted. If ``shift`` is a tuple, then ``axis`` must be a tuple of the same size, and each of the given axes must be shifted by the corresponding element in ``shift``. If ``shift`` is an ``int`` and ``axis`` a tuple, then the same ``shift`` must be used for all specified axes. If a shift is positive, then array elements must be shifted positively (toward larger indices) along the dimension of ``axis``. If a shift is negative, then array elements must be shifted negatively (toward smaller indices) along the dimension of ``axis``. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which elements to shift. If ``axis`` is ``None``, the array must be flattened, shifted, and then restored to its original shape. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. + """ + + +def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: + """ + Removes singleton dimensions (axes) from ``x``. + + Parameters + ---------- + x: array + input array. + axis: Union[int, Tuple[int, ...]] + axis (or axes) to squeeze. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If a specified axis has a size greater than one (i.e., it is not a + singleton dimension), a ``ValueError`` should be raised. + """ + + +def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: + """ + Joins a sequence of arrays along a new axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. Each array must have the same shape. + axis: int + axis along which the arrays will be joined. Providing an ``axis`` specifies the index of the new axis in the dimensions of the result. For example, if ``axis`` is ``0``, the new axis will be the first dimension and the output array will have shape ``(N, A, B, C)``; if ``axis`` is ``1``, the new axis will be the second dimension and the output array will have shape ``(A, N, B, C)``; and, if ``axis`` is ``-1``, the new axis will be the last dimension and the output array will have shape ``(A, B, C, N)``. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: array + an output array having rank ``N+1``, where ``N`` is the rank (number of dimensions) of ``x``. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def tile(x: array, repetitions: Tuple[int, ...], /): + """ + Constructs an array by tiling an input array. + + Parameters + ---------- + x: array + input array. + repetitions: Tuple[int, ...] + number of repetitions along each axis (dimension). + + Let ``N = len(x.shape)`` and ``M = len(repetitions)``. + + If ``N > M``, the function must prepend ones until all axes (dimensions) are specified (e.g., if ``x`` has shape ``(8,6,4,2)`` and ``repetitions`` is the tuple ``(3,3)``, then ``repetitions`` must be treated as ``(1,1,3,3)``). + + If ``N < M``, the function must prepend singleton axes (dimensions) to ``x`` until ``x`` has as many axes (dimensions) as ``repetitions`` specifies (e.g., if ``x`` has shape ``(4,2)`` and ``repetitions`` is the tuple ``(3,3,3,3)``, then ``x`` must be treated as if it has shape ``(1,1,4,2)``). + + Returns + ------- + out: array + a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: + """ + Splits an array in a sequence of arrays along the given axis. + + Parameters + ---------- + x: array + input array. + axis: int + axis along which the array will be split. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: Tuple[array, ...] + tuple of slices along the given dimension. All the arrays have the same shape. + + Notes + ----- + + .. versionadded:: 2023.12 + """ diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py new file mode 100644 index 000000000..029459b9a --- /dev/null +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -0,0 +1,159 @@ +__all__ = ["argmax", "argmin", "nonzero", "searchsorted", "where"] + + +from ._types import Optional, Tuple, Literal, array + + +def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the maximum values along a specified axis. + + When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the maximum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. + """ + + +def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the minimum values along a specified axis. + + When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the minimum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. + """ + + +def nonzero(x: array, /) -> Tuple[array, ...]: + """ + Returns the indices of the array elements which are non-zero. + + .. note:: + If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + + .. note:: + If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. admonition:: Data-dependent output shape + :class: admonition important + + The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array. Must have a positive rank. If ``x`` is zero-dimensional, the function must raise an exception. + + Returns + ------- + out: Typle[array, ...] + a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def searchsorted( + x1: array, + x2: array, + /, + *, + side: Literal["left", "right"] = "left", + sorter: Optional[array] = None, +) -> array: + """ + Finds the indices into ``x1`` such that, if the corresponding elements in ``x2`` were inserted before the indices, the order of ``x1``, when sorted in ascending order, would be preserved. + + Parameters + ---------- + x1: array + input array. Must be a one-dimensional array. Should have a real-valued data type. If ``sorter`` is ``None``, must be sorted in ascending order; otherwise, ``sorter`` must be an array of indices that sort ``x1`` in ascending order. + x2: array + array containing search values. Should have a real-valued data type. + side: Literal['left', 'right'] + argument controlling which index is returned if a value lands exactly on an edge. + + Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + + If ``side == 'left'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``0``. + + Otherwise, if ``side == 'right'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + + Default: ``'left'``. + sorter: Optional[array] + array of indices that sort ``x1`` in ascending order. The array must have the same shape as ``x1`` and have an integer data type. Default: ``None``. + + Returns + ------- + out: array + an array of indices with the same shape as ``x2``. The returned array must have the default array index data type. + + Notes + ----- + + For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. + + While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + + .. versionadded:: 2023.12 + """ + + +def where(condition: array, x1: array, x2: array, /) -> array: + """ + Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. + + Parameters + ---------- + condition: array + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + x1: array + first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). + x2: array + second input array. Must be compatible with ``condition`` and ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. + """ diff --git a/src/array_api_stubs/_2023_12/set_functions.py b/src/array_api_stubs/_2023_12/set_functions.py new file mode 100644 index 000000000..5b7e9a56c --- /dev/null +++ b/src/array_api_stubs/_2023_12/set_functions.py @@ -0,0 +1,183 @@ +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] + + +from ._types import Tuple, array + + +def unique_all(x: array, /) -> Tuple[array, array, array, array]: + """ + Returns the unique elements of an input array ``x``, the first occurring indices for each unique element in ``x``, the indices from the set of unique elements that reconstruct ``x``, and the corresponding counts for each unique element in ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array, array, array] + a namedtuple ``(values, indices, inverse_indices, counts)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of a flattened ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. + - third element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and must have the default array index data type. + - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_counts(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple `(values, counts)` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_inverse(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(values, inverse_indices)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior. + """ + + +def unique_values(x: array, /) -> array: + """ + Returns the unique elements of an input array ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: array + a one-dimensional array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required that the output array must be one-dimensional. + """ diff --git a/src/array_api_stubs/_2023_12/sorting_functions.py b/src/array_api_stubs/_2023_12/sorting_functions.py new file mode 100644 index 000000000..2dc4ac410 --- /dev/null +++ b/src/array_api_stubs/_2023_12/sorting_functions.py @@ -0,0 +1,58 @@ +__all__ = ["argsort", "sort"] + + +from ._types import array + + +def argsort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns the indices that sort an array ``x`` along a specified axis. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x : array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the returned indices sort ``x`` in descending order (by value). If ``False``, the returned indices sort ``x`` in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned indices must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned indices may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. + """ + + +def sort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns a sorted copy of an input array ``x``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the array must be sorted in descending order (by value). If ``False``, the array must be sorted in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned array must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned array may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + a sorted array. The returned array must have the same data type and shape as ``x``. + """ diff --git a/src/array_api_stubs/_2023_12/statistical_functions.py b/src/array_api_stubs/_2023_12/statistical_functions.py new file mode 100644 index 000000000..9d3563e26 --- /dev/null +++ b/src/array_api_stubs/_2023_12/statistical_functions.py @@ -0,0 +1,374 @@ +__all__ = ["cumulative_sum", "max", "mean", "min", "prod", "std", "sum", "var"] + + +from ._types import Optional, Tuple, Union, array, dtype + + +def cumulative_sum( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative sum of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum by counting from the last dimension. + + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative sum. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative sum must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionadded:: 2023.12 + """ + + +def max( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the maximum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def mean( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the arithmetic mean of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the arithmetic mean. + + - If ``N`` is ``0``, the arithmetic mean is ``NaN``. + - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). + """ + + +def min( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the minimum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def prod( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the product of input array ``x`` elements. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the product. + + - If ``N`` is ``0``, the product is `1` (i.e., the empty product). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def std( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the standard deviation of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which standard deviations must be computed. By default, the standard deviation must be computed over the entire array. If a tuple of integers, standard deviations must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the standard deviation according to ``N-c`` where ``N`` corresponds to the total number of elements over which the standard deviation is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the standard deviation of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the corrected sample standard deviation, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the standard deviation. + + - If ``N - correction`` is less than or equal to ``0``, the standard deviation is ``NaN``. + - If ``x_i`` is ``NaN``, the standard deviation is ``NaN`` (i.e., ``NaN`` values propagate). + """ + + +def sum( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the sum of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def var( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the variance of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which variances must be computed. By default, the variance must be computed over the entire array. If a tuple of integers, variances must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the variance according to ``N-c`` where ``N`` corresponds to the total number of elements over which the variance is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the variance of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the unbiased sample variance, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the same data type as ``x``. + + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the variance. + + - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. + - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). + """ diff --git a/src/array_api_stubs/_2023_12/utility_functions.py b/src/array_api_stubs/_2023_12/utility_functions.py new file mode 100644 index 000000000..81d8dca41 --- /dev/null +++ b/src/array_api_stubs/_2023_12/utility_functions.py @@ -0,0 +1,86 @@ +__all__ = ["all", "any"] + + +from ._types import Optional, Tuple, Union, array + + +def all( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether all input array elements evaluate to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``True``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical AND reduction. By default, a logical AND reduction must be performed over the entire array. If a tuple of integers, logical AND reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def any( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether any input array element evaluates to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``False``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical OR reduction. By default, a logical OR reduction must be performed over the entire array. If a tuple of integers, logical OR reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index 4ac3783ef..ca9122e7f 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1 +1 @@ -from . import _2021_12, _2022_12, _draft +from . import _2021_12, _2022_12, _2023_12, _draft From ef81ddf066a3505c72baf7812364d18b9a4c728f Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:08:12 -0800 Subject: [PATCH 138/196] Empty commit for draft at 2023.12 From 2f95e0bb8132419fb500f4221d7027c9f66f74bd Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:11:52 -0800 Subject: [PATCH 139/196] build: update list of ignored files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d4f538406..cc40a3b43 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ tmp/ *.egg-info/ *.egg dist/ +.DS_STORE From f63e9fddec99d37827e7339ea02e01203e774f2d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:12:31 -0800 Subject: [PATCH 140/196] chore: remove files --- .DS_Store | Bin 6148 -> 0 bytes src/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 src/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index cb2845bfd45fe0b2d4e5d60af22acccb797086ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~F$w}f3`G;&V!>uh%V|7-Hy9Q@ffo=|Y(z!TdXDZ-CJ3(9BJu;tpJXO1`-+{7 zh-iP?&P6&AY2l_avoJ74-pEzXvXjkybvYhR$31FRAH`W)!#f%5$2NroNPq-LfCNb3 zhX~lc4QnS=8A*TyNZ?7pz7Gj*nnO!f|8yYu2mozRcEj3d323qcG>4X|sK7L)2aQ(s zF~sWL4oz_`hnA|fT{MOdjVG&3F)*#|q6rC1vkLuHq@&4g1L!&>UK-q5|WOfMZ}Ffv*yH E03NCmz5oCK diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index dd19daea5d1a7b84e37b40dd1eb49bfc451dd50b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOG-mQ5UkcL0xrzbzd)!;&mE;Ee}t(zyiRW?uaiBQ}gHU6T7I45$QbR6ZhEQ9WTW5%(>U(?D*S^_)rPCZTp zSWi@x0#abCz-4Y1-v96DC+7b#NjoVZ1^$%+He0P%OTJR|*2&9xuWj@Py4QTu-M9`4 nL$qUJv}10(9p6Mz)-_-Ac`qCigU)==iTX3(y2zx!Un}qfHa!=x From fa04c35c87708fa565a4a8f6bb8360ae836ac5d7 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 29 Feb 2024 06:07:32 +0100 Subject: [PATCH 141/196] Bump Sphinx and sphinx-material versions to latest releases (#757) --- doc-requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc-requirements.txt b/doc-requirements.txt index 08ced9aa2..5c0effdb8 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -1,5 +1,5 @@ -sphinx==6.2.1 -sphinx-material==0.0.30 +sphinx==7.2.6 +sphinx-material==0.0.36 myst-parser sphinx_markdown_tables sphinx_copybutton From c305b82a05fe85e47ea26b7ef61fb299b23f7ed6 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 5 Mar 2024 16:53:57 +0100 Subject: [PATCH 142/196] Fix version switcher by using sphinxcontrib-jquery (#758) Note that this doesn't work on local doc builds, it'll now give: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///path/to/array-api/_site/versions.json. (Reason: CORS request not http) --- doc-requirements.txt | 1 + src/_array_api_conf.py | 1 + 2 files changed, 2 insertions(+) diff --git a/doc-requirements.txt b/doc-requirements.txt index 5c0effdb8..3e31808f2 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -5,3 +5,4 @@ sphinx_markdown_tables sphinx_copybutton sphinx_favicon sphinx-math-dollar +sphinxcontrib-jquery diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index ec5d56d58..08929cc43 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -36,6 +36,7 @@ "sphinx_copybutton", "sphinx_favicon", "sphinx_markdown_tables", + "sphinxcontrib.jquery", ] autosummary_generate = True From 630149c51d8ec6dff62678eaec454c519a1d87dd Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 21 Mar 2024 02:21:31 -0700 Subject: [PATCH 143/196] docs: fix equation rendering in `linalg.cholesky` (#762) Closes: https://github.com/data-apis/array-api/issues/761 --- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_2023_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index a2207bb4c..7996d7472 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -6,7 +6,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: r""" Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. - If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py index 0950e6937..49cce7160 100644 --- a/src/array_api_stubs/_2023_12/linalg.py +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -33,7 +33,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: r""" Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. - If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 0950e6937..49cce7160 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -33,7 +33,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: r""" Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. - If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as From 91ff864decaef09a7fcca28a4b65de3c5f765d5f Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 4 Apr 2024 03:57:11 -0600 Subject: [PATCH 144/196] docs: fix typo in the changelog PR-URL: https://github.com/data-apis/array-api/pull/767 Reviewed-by: Athan Reines --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eace3f0a1..5d69bbc23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,7 +89,7 @@ The following is a list of breaking changes relative to the previous version of - `prod`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) - `sum`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) -- `vecdot`: only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) +- `vecdot`: only require a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) #### Extensions @@ -104,7 +104,7 @@ The following is a list of breaking changes in specification extensions relative - `fft.irfftn`: require the output array have a real-valued floating-point data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) - `fft.fftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) - `fft.rfftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) -- `linalg.cross`: broadcast only along non-compute axes and only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) +- `linalg.cross`: broadcast only along non-compute axes and only require a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) - `linalg.trace`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) * * * From 65d3102c5210310c74c73147e751c4c567e56bb1 Mon Sep 17 00:00:00 2001 From: Meekail Zain <34613774+Micky774@users.noreply.github.com> Date: Tue, 9 Apr 2024 21:55:39 -0400 Subject: [PATCH 145/196] Corrected typo in `__bool__` with backport (#785) --- src/array_api_stubs/_2022_12/array_object.py | 2 +- src/array_api_stubs/_2023_12/array_object.py | 2 +- src/array_api_stubs/_draft/array_object.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index b8f703996..f00df850b 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -237,7 +237,7 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. - For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. .. versionchanged:: 2022.12 Added boolean and complex data type support. diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index 6dd70c278..d71a26293 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -239,7 +239,7 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. - For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. **Lazy implementations** diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 6dd70c278..d71a26293 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -239,7 +239,7 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. - For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. **Lazy implementations** From 63633e7f0484c7afafa66b051a7d2bc75a1b0bab Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 25 Apr 2024 15:42:45 -0600 Subject: [PATCH 146/196] Add missing return type hint to tile() (#798) * Add missing return type hint to tile() * Add tile type signature fix to the draft version --- src/array_api_stubs/_2023_12/manipulation_functions.py | 2 +- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2023_12/manipulation_functions.py b/src/array_api_stubs/_2023_12/manipulation_functions.py index 87f9511b0..7d5111135 100644 --- a/src/array_api_stubs/_2023_12/manipulation_functions.py +++ b/src/array_api_stubs/_2023_12/manipulation_functions.py @@ -316,7 +316,7 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ -def tile(x: array, repetitions: Tuple[int, ...], /): +def tile(x: array, repetitions: Tuple[int, ...], /) -> array: """ Constructs an array by tiling an input array. diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 87f9511b0..7d5111135 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -316,7 +316,7 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ -def tile(x: array, repetitions: Tuple[int, ...], /): +def tile(x: array, repetitions: Tuple[int, ...], /) -> array: """ Constructs an array by tiling an input array. From 69e2733e003803eb992dc7524c3805fd06d5a0c1 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 30 Apr 2024 16:12:28 -0600 Subject: [PATCH 147/196] build: fix requirements to work with conda pip treats dashes and underscores the same but conda does not. The package names here are actually dashes (pip just replaces an underscore with a dash) so this is more correct anyway. PR-URL: https://github.com/data-apis/array-api/pull/800 Reviewed-by: Athan Reines --- doc-requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc-requirements.txt b/doc-requirements.txt index 3e31808f2..15ef0b245 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -1,8 +1,8 @@ sphinx==7.2.6 sphinx-material==0.0.36 myst-parser -sphinx_markdown_tables -sphinx_copybutton -sphinx_favicon +sphinx-markdown-tables +sphinx-copybutton +sphinx-favicon sphinx-math-dollar sphinxcontrib-jquery From 6a5767aebf512385a783b7631039398738253332 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 1 May 2024 21:01:57 -0700 Subject: [PATCH 148/196] feat: add `max rank` to inspection API capabilities PR-URL: https://github.com/data-apis/array-api/pull/763 Closes: https://github.com/data-apis/array-api/issues/694 Reviewed-by: Ralf Gommers Reviewed-by: Leo Fang --- src/array_api_stubs/_draft/_types.py | 7 ++++++- src/array_api_stubs/_draft/info.py | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 7c3d903d7..f2fa356f2 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -140,5 +140,10 @@ def dtypes( total=False, ) Capabilities = TypedDict( - "Capabilities", {"boolean indexing": bool, "data-dependent shapes": bool} + "Capabilities", + { + "boolean indexing": bool, + "data-dependent shapes": bool, + "max rank": Optional[int], + }, ) diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index b755ca2c0..e9eb66cf1 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -56,6 +56,7 @@ def capabilities() -> Capabilities: - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"max rank"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. Returns ------- From cee41670d93a73c0132dd3e2a943107bea28ecff Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 1 May 2024 21:50:36 -0700 Subject: [PATCH 149/196] feat: add `nextafter` to specification PR-URL: https://github.com/data-apis/array-api/pull/792 Closes: https://github.com/data-apis/array-api/issues/664 Reviewed-by: Ralf Gommers --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 4919cff98..a853ca18c 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -66,6 +66,7 @@ Objects in API minimum multiply negative + nextafter not_equal positive pow diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 4462329d6..ec0b0567c 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -48,6 +48,7 @@ "minimum", "multiply", "negative", + "nextafter", "not_equal", "positive", "pow", @@ -2069,6 +2070,35 @@ def negative(x: array, /) -> array: """ +def nextafter(x1: array, x2: array, /) -> array: + """ + Returns the next representable floating-point value for each element ``x1_i`` of the input array ``x1`` in the direction of the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have the same data type as ``x1``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x1``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``-0``. + """ + + def not_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. From 25e717735b72c6b55080f48af634015d94833838 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 22 May 2024 05:07:29 -0600 Subject: [PATCH 150/196] Fixes to the array-api stubs (#806) * Replace info with __array_namespace_info__ in the stubs 'info' is not an actual top-level name in the namespace. * Use consistent wording for complex dtypes in the fft stubs * Fix some copysign special-cases for better machine readability and consistency --- src/array_api_stubs/_2022_12/fft.py | 14 +++++------ src/array_api_stubs/_2023_12/__init__.py | 2 +- .../_2023_12/elementwise_functions.py | 14 +++++------ src/array_api_stubs/_2023_12/fft.py | 24 +++++++++---------- src/array_api_stubs/_draft/__init__.py | 2 +- .../_draft/elementwise_functions.py | 14 +++++------ src/array_api_stubs/_draft/fft.py | 24 +++++++++---------- 7 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index bdd7a9c83..f6fb3627a 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -35,7 +35,7 @@ def fft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -84,7 +84,7 @@ def ifft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -133,7 +133,7 @@ def fftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -188,7 +188,7 @@ def ifftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -292,7 +292,7 @@ def irfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -398,7 +398,7 @@ def irfftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. @@ -452,7 +452,7 @@ def hfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. diff --git a/src/array_api_stubs/_2023_12/__init__.py b/src/array_api_stubs/_2023_12/__init__.py index 8415f2765..537ea8f85 100644 --- a/src/array_api_stubs/_2023_12/__init__.py +++ b/src/array_api_stubs/_2023_12/__init__.py @@ -16,7 +16,7 @@ from .utility_functions import * from . import linalg from . import fft -from . import info +from .info import __array_namespace_info__ __array_api_version__: str = "YYYY.MM" diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 4462329d6..2d4847195 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -874,14 +874,12 @@ def copysign(x1: array, x2: array, /) -> array: - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. - If ``x1_i`` is ``NaN``, - - - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_2023_12/fft.py b/src/array_api_stubs/_2023_12/fft.py index 4e8131c8b..7a4538ccb 100644 --- a/src/array_api_stubs/_2023_12/fft.py +++ b/src/array_api_stubs/_2023_12/fft.py @@ -35,7 +35,7 @@ def fft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -66,7 +66,7 @@ def fft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -87,7 +87,7 @@ def ifft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -118,7 +118,7 @@ def ifft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -139,7 +139,7 @@ def fftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -176,7 +176,7 @@ def fftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -197,7 +197,7 @@ def ifftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -234,7 +234,7 @@ def ifftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -304,7 +304,7 @@ def irfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -413,7 +413,7 @@ def irfftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. @@ -470,7 +470,7 @@ def hfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -501,7 +501,7 @@ def hfft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + Required the input array to have a complex floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. """ diff --git a/src/array_api_stubs/_draft/__init__.py b/src/array_api_stubs/_draft/__init__.py index 8415f2765..537ea8f85 100644 --- a/src/array_api_stubs/_draft/__init__.py +++ b/src/array_api_stubs/_draft/__init__.py @@ -16,7 +16,7 @@ from .utility_functions import * from . import linalg from . import fft -from . import info +from .info import __array_namespace_info__ __array_api_version__: str = "YYYY.MM" diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index ec0b0567c..bd0fd8083 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -875,14 +875,12 @@ def copysign(x1: array, x2: array, /) -> array: - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. - If ``x1_i`` is ``NaN``, - - - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 4e8131c8b..7a4538ccb 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -35,7 +35,7 @@ def fft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -66,7 +66,7 @@ def fft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -87,7 +87,7 @@ def ifft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -118,7 +118,7 @@ def ifft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -139,7 +139,7 @@ def fftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -176,7 +176,7 @@ def fftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -197,7 +197,7 @@ def ifftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -234,7 +234,7 @@ def ifftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -304,7 +304,7 @@ def irfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -413,7 +413,7 @@ def irfftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. @@ -470,7 +470,7 @@ def hfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -501,7 +501,7 @@ def hfft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + Required the input array to have a complex floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. """ From b569b039612eed2993471c129d2ab95b3d7ea95e Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 25 Jul 2024 09:41:58 -0700 Subject: [PATCH 151/196] feat: add `reciprocal` to the specification PR-URL: https://github.com/data-apis/array-api/pull/802 Closes: https://github.com/data-apis/array-api/issues/790 --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index a853ca18c..9758c68db 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -71,6 +71,7 @@ Objects in API positive pow real + reciprocal remainder round sign diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index bd0fd8083..c9d5e2953 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -53,6 +53,7 @@ "positive", "pow", "real", + "reciprocal", "remainder", "round", "sign", @@ -2252,6 +2253,29 @@ def real(x: array, /) -> array: """ +def reciprocal(x: array, /) -> array: + """ + Returns the reciprocal for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``1.0 / x`` (see :func:`~array_api.divide`). + """ + + def remainder(x1: array, x2: array, /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. From b93391545a8d3e4099a10bac5215bf04680c8d9a Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 25 Jul 2024 10:55:58 -0600 Subject: [PATCH 152/196] docs: clarify broadcasting semantics and output shape in `linalg.solve` (#810) PR-URL: https://github.com/data-apis/array-api/pull/810 --- src/array_api_stubs/_2022_12/linalg.py | 4 ++-- src/array_api_stubs/_2023_12/linalg.py | 4 ++-- src/array_api_stubs/_2023_12/manipulation_functions.py | 2 +- src/array_api_stubs/_draft/linalg.py | 4 ++-- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index 7996d7472..b13a5bf01 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -594,12 +594,12 @@ def solve(x1: array, x2: array, /) -> array: x1: array coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. Notes ----- diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py index 49cce7160..a1c9fe028 100644 --- a/src/array_api_stubs/_2023_12/linalg.py +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -623,12 +623,12 @@ def solve(x1: array, x2: array, /) -> array: x1: array coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. Notes ----- diff --git a/src/array_api_stubs/_2023_12/manipulation_functions.py b/src/array_api_stubs/_2023_12/manipulation_functions.py index 7d5111135..131b81eb3 100644 --- a/src/array_api_stubs/_2023_12/manipulation_functions.py +++ b/src/array_api_stubs/_2023_12/manipulation_functions.py @@ -347,7 +347,7 @@ def tile(x: array, repetitions: Tuple[int, ...], /) -> array: def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: """ - Splits an array in a sequence of arrays along the given axis. + Splits an array into a sequence of arrays along the given axis. Parameters ---------- diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 49cce7160..a1c9fe028 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -623,12 +623,12 @@ def solve(x1: array, x2: array, /) -> array: x1: array coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. Notes ----- diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 7d5111135..131b81eb3 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -347,7 +347,7 @@ def tile(x: array, repetitions: Tuple[int, ...], /) -> array: def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: """ - Splits an array in a sequence of arrays along the given axis. + Splits an array into a sequence of arrays along the given axis. Parameters ---------- From 6bfea7ab9b54b5862aa8a3ec6d8b1f4496b2e79b Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 25 Jul 2024 11:00:22 -0600 Subject: [PATCH 153/196] feat!: rename "max rank" to "max dimensions" in `capabilities()` PR-URL: https://github.com/data-apis/array-api/pull/809 Ref: https://github.com/data-apis/array-api/pull/763#issuecomment-2138355341 --- src/array_api_stubs/_draft/info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index e9eb66cf1..1815a71e9 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -56,7 +56,7 @@ def capabilities() -> Capabilities: - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. - - `"max rank"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. + - `"max dimensions"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. Returns ------- From b2e232b7b687ff201bab1565254c81ec2f428110 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 15 Aug 2024 16:16:30 -0600 Subject: [PATCH 154/196] docs: cross-link to the inspection page in `__array_namespace_info__` PR-URL: https://github.com/data-apis/array-api/pull/836 Reviewed-by: Athan Reines --- spec/2023.12/API_specification/inspection.rst | 2 ++ spec/draft/API_specification/inspection.rst | 2 ++ src/array_api_stubs/_2023_12/info.py | 2 ++ src/array_api_stubs/_draft/info.py | 2 ++ 4 files changed, 8 insertions(+) diff --git a/spec/2023.12/API_specification/inspection.rst b/spec/2023.12/API_specification/inspection.rst index 04691e712..89d9c602a 100644 --- a/spec/2023.12/API_specification/inspection.rst +++ b/spec/2023.12/API_specification/inspection.rst @@ -1,3 +1,5 @@ +.. _inspection: + Inspection ========== diff --git a/spec/draft/API_specification/inspection.rst b/spec/draft/API_specification/inspection.rst index 04691e712..89d9c602a 100644 --- a/spec/draft/API_specification/inspection.rst +++ b/spec/draft/API_specification/inspection.rst @@ -1,3 +1,5 @@ +.. _inspection: + Inspection ========== diff --git a/src/array_api_stubs/_2023_12/info.py b/src/array_api_stubs/_2023_12/info.py index b755ca2c0..507c853c9 100644 --- a/src/array_api_stubs/_2023_12/info.py +++ b/src/array_api_stubs/_2023_12/info.py @@ -25,6 +25,8 @@ def __array_namespace_info__() -> Info: """ Returns a namespace with Array API namespace inspection utilities. + See :ref:`inspection` for a list of inspection APIs. + Returns ------- out: Info diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index 1815a71e9..6177fb12f 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -25,6 +25,8 @@ def __array_namespace_info__() -> Info: """ Returns a namespace with Array API namespace inspection utilities. + See :ref:`inspection` for a list of inspection APIs. + Returns ------- out: Info From 0cd4bdf6a8f1b3ca62c0d0c480b60a16467bd999 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Mon, 26 Aug 2024 19:53:23 -0700 Subject: [PATCH 155/196] docs: fix reference to eigh/eigvalsh PR-URL: https://github.com/data-apis/array-api/pull/838 Reviewed-by: Athan Reines --- spec/2021.12/extensions/linear_algebra_functions.rst | 4 ++-- spec/2022.12/extensions/linear_algebra_functions.rst | 4 ++-- spec/2023.12/extensions/linear_algebra_functions.rst | 4 ++-- spec/draft/extensions/linear_algebra_functions.rst | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/2021.12/extensions/linear_algebra_functions.rst b/spec/2021.12/extensions/linear_algebra_functions.rst index dbe643bed..de24d5a0b 100644 --- a/spec/2021.12/extensions/linear_algebra_functions.rst +++ b/spec/2021.12/extensions/linear_algebra_functions.rst @@ -48,8 +48,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. diff --git a/spec/2022.12/extensions/linear_algebra_functions.rst b/spec/2022.12/extensions/linear_algebra_functions.rst index 6759b2260..938221c79 100644 --- a/spec/2022.12/extensions/linear_algebra_functions.rst +++ b/spec/2022.12/extensions/linear_algebra_functions.rst @@ -51,8 +51,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. diff --git a/spec/2023.12/extensions/linear_algebra_functions.rst b/spec/2023.12/extensions/linear_algebra_functions.rst index 6759b2260..938221c79 100644 --- a/spec/2023.12/extensions/linear_algebra_functions.rst +++ b/spec/2023.12/extensions/linear_algebra_functions.rst @@ -51,8 +51,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. diff --git a/spec/draft/extensions/linear_algebra_functions.rst b/spec/draft/extensions/linear_algebra_functions.rst index 6759b2260..938221c79 100644 --- a/spec/draft/extensions/linear_algebra_functions.rst +++ b/spec/draft/extensions/linear_algebra_functions.rst @@ -51,8 +51,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. From 45b705de8e20a30487f1d369112a26428b5ab418 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Sep 2024 23:01:08 -0700 Subject: [PATCH 156/196] feat: add `diff` to specification PR-URL: https://github.com/data-apis/array-api/pull/791 Closes: https://github.com/data-apis/array-api/issues/784 --- .../API_specification/utility_functions.rst | 1 + .../_draft/utility_functions.py | 44 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/utility_functions.rst b/spec/draft/API_specification/utility_functions.rst index 5105fa3df..a09c99f79 100644 --- a/spec/draft/API_specification/utility_functions.rst +++ b/spec/draft/API_specification/utility_functions.rst @@ -20,3 +20,4 @@ Objects in API all any + diff diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index 81d8dca41..cdbe4a0f8 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -1,4 +1,4 @@ -__all__ = ["all", "any"] +__all__ = ["all", "any", "diff"] from ._types import Optional, Tuple, Union, array @@ -84,3 +84,45 @@ def any( .. versionchanged:: 2022.12 Added complex data type support. """ + + +def diff( + x: array, + /, + *, + axis: int = -1, + n: int = 1, + prepend: Optional[array] = None, + append: Optional[array] = None, +) -> array: + """ + Calculates the n-th discrete forward difference along a specified axis. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: int + axis along which to compute differences. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute differences by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``-1``. + n: int + number of times to recursively compute differences. Default: ``1``. + prepend: Optional[array] + values to prepend to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + append: Optional[array] + values to append to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + + Returns + ------- + out: array + an array containing the n-th differences. Should have the same data type as ``x``. Must have the same shape as ``x``, except for the axis specified by ``axis`` which must have a size determined as follows: + + - Let ``M`` be the number of elements along an axis specified by ``axis``. + - Let ``N1`` be the number of prepended values along an axis specified by ``axis``. + - Let ``N2`` be the number of appended values along an axis specified by ``axis``. + - The final size of the axis specified by ``axis`` must be ``M + N1 + N2 - n``. + + Notes + ----- + + - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). + """ From 8b0e405cdbe5d56a9705bc6a1d6b534554e29d64 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 19 Sep 2024 00:06:55 -0600 Subject: [PATCH 157/196] docs: specify the behavior of `clip()` when one of the operands is NaN PR-URL: https://github.com/data-apis/array-api/pull/813 Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2023_12/elementwise_functions.py | 6 ++++++ src/array_api_stubs/_draft/elementwise_functions.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 2d4847195..4739ab674 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -807,6 +807,12 @@ def clip( - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + **Special cases** + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``min_i`` is ``NaN``, the result is ``NaN``. + - If ``max_i`` is ``NaN``, the result is ``NaN``. + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index c9d5e2953..78a76b37d 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -809,6 +809,12 @@ def clip( - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + **Special cases** + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``min_i`` is ``NaN``, the result is ``NaN``. + - If ``max_i`` is ``NaN``, the result is ``NaN``. + .. versionadded:: 2023.12 """ From b877795060f9b5ba519507ccf453af516ec11f9f Mon Sep 17 00:00:00 2001 From: "hpkfft.com" Date: Wed, 18 Sep 2024 23:26:22 -0700 Subject: [PATCH 158/196] docs: clarify `roundTiesToEven` behavior for non-ties PR-URL: https://github.com/data-apis/array-api/pull/825 Reviewed-by: Athan Reines --- spec/draft/design_topics/accuracy.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/draft/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst index 8c97db698..61a2c49aa 100644 --- a/spec/draft/design_topics/accuracy.rst +++ b/spec/draft/design_topics/accuracy.rst @@ -23,7 +23,7 @@ including the corresponding element-wise array APIs defined in this standard - multiply - divide -for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., ties rounded toward the nearest value with an even least significant bit). +for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). Mathematical Functions ---------------------- From 390e9ccd27a0ee635c253a2b7acb2e338caf2c95 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Sep 2024 23:36:12 -0700 Subject: [PATCH 159/196] feat: add `take_long_axis` to specifiation PR-URL: https://github.com/data-apis/array-api/pull/816 Closes: https://github.com/data-apis/array-api/issues/808 --- .../API_specification/indexing_functions.rst | 1 + .../_draft/indexing_functions.py | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/indexing_functions.rst b/spec/draft/API_specification/indexing_functions.rst index aef298566..c13e55ecf 100644 --- a/spec/draft/API_specification/indexing_functions.rst +++ b/spec/draft/API_specification/indexing_functions.rst @@ -21,3 +21,4 @@ Objects in API :template: method.rst take + take_along_axis diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 35066a4a2..a9b38b482 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -1,4 +1,4 @@ -__all__ = ["take"] +__all__ = ["take", "take_along_axis"] from ._types import Union, Optional, array @@ -38,3 +38,27 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. versionchanged:: 2023.12 Out-of-bounds behavior is explicitly left unspecified. """ + + +def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: + """ + Returns elements from an array at the one-dimensional indices specified by ``indices`` along a provided ``axis``. + + Parameters + ---------- + x: array + input array. Must be compatible with ``indices``, except for the axis (dimension) specified by ``axis`` (see :ref:`broadcasting`). + indices: array + array indices. Must have the same rank (i.e., number of dimensions) as ``x``. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + axis: int + axis along which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. Default: ``-1``. + + Returns + ------- + out: array + an array having the same data type as ``x``. Must have the same rank (i.e., number of dimensions) as ``x`` and must have a shape determined according to :ref:`broadcasting`, except for the axis (dimension) specified by ``axis`` whose size must equal the size of the corresponding axis (dimension) in ``indices``. + """ From 1765933ad23c4dc3be3ff0b29d89e47f38739432 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Wed, 30 Oct 2024 20:30:12 -0700 Subject: [PATCH 160/196] docs: add missing subscripts in `sign` definition PR-URL: https://github.com/data-apis/array-api/pull/844 Reviewed-by: Athan Reines Reviewed-by: Oleksandr Pavlyk --- src/array_api_stubs/_2022_12/elementwise_functions.py | 2 +- src/array_api_stubs/_2023_12/elementwise_functions.py | 2 +- src/array_api_stubs/_draft/elementwise_functions.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index 9139612e8..fe0f5f2b1 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -2065,7 +2065,7 @@ def sign(x: array, /) -> array: .. math:: \operatorname{sign}(x_i) = \begin{cases} 0 & \textrm{if } x_i = 0 \\ - \frac{x}{|x|} & \textrm{otherwise} + \frac{x_i}{|x_i|} & \textrm{otherwise} \end{cases} where :math:`|x_i|` is the absolute value of :math:`x_i`. diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 4739ab674..251a770d6 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -2335,7 +2335,7 @@ def sign(x: array, /) -> array: .. math:: \operatorname{sign}(x_i) = \begin{cases} 0 & \textrm{if } x_i = 0 \\ - \frac{x}{|x|} & \textrm{otherwise} + \frac{x_i}{|x_i|} & \textrm{otherwise} \end{cases} where :math:`|x_i|` is the absolute value of :math:`x_i`. diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 78a76b37d..3f4c08898 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -2389,7 +2389,7 @@ def sign(x: array, /) -> array: .. math:: \operatorname{sign}(x_i) = \begin{cases} 0 & \textrm{if } x_i = 0 \\ - \frac{x}{|x|} & \textrm{otherwise} + \frac{x_i}{|x_i|} & \textrm{otherwise} \end{cases} where :math:`|x_i|` is the absolute value of :math:`x_i`. From c28d3c576a90281a3f713a1e53e0565f430e1647 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 30 Oct 2024 22:18:04 -0600 Subject: [PATCH 161/196] docs: add note that iteration is defined for 1-D arrays PR-URL: https://github.com/data-apis/array-api/pull/821 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_2021_12/array_object.py | 4 ++++ src/array_api_stubs/_2022_12/array_object.py | 4 ++++ src/array_api_stubs/_2023_12/array_object.py | 4 ++++ src/array_api_stubs/_draft/array_object.py | 8 ++++++++ 4 files changed, 20 insertions(+) diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index 528e0a286..07bd2c3e3 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -465,6 +465,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -914,6 +916,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index f00df850b..83abc9310 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -489,6 +489,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -937,6 +939,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index d71a26293..5c0b10dd9 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -616,6 +616,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -1085,6 +1087,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index d71a26293..dcd1c53fa 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -616,6 +616,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -627,6 +629,10 @@ def __getitem__( ------- out: array an array containing the accessed value(s). The returned array must have the same data type as ``self``. + + .. note:: + When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + """ def __gt__(self: array, other: Union[int, float, array], /) -> array: @@ -1085,6 +1091,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array From 6d205d72dde3db8fc8668ad6aef5d003cc8ef80f Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 30 Oct 2024 22:55:16 -0600 Subject: [PATCH 162/196] docs: add note that cross-kind comparisons are undefined PR-URL: https://github.com/data-apis/array-api/pull/822 Closes: https://github.com/data-apis/array-api/issues/819 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/array_object.py | 18 ++++++++++++++++++ .../_draft/elementwise_functions.py | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index dcd1c53fa..3c6fa8763 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -513,6 +513,9 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __float__(self: array, /) -> float: @@ -599,6 +602,9 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __getitem__( @@ -657,6 +663,9 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __index__(self: array, /) -> int: @@ -778,6 +787,9 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -823,6 +835,9 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __matmul__(self: array, other: array, /) -> array: @@ -949,6 +964,9 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + .. versionchanged:: 2022.12 Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 3f4c08898..156715200 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -1125,6 +1125,9 @@ def equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + .. versionchanged:: 2022.12 Added complex data type support. """ @@ -1354,6 +1357,10 @@ def greater(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + """ @@ -1375,6 +1382,9 @@ def greater_equal(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ @@ -1570,6 +1580,9 @@ def less(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ @@ -1591,6 +1604,9 @@ def less_equal(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ @@ -2141,6 +2157,9 @@ def not_equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + .. versionchanged:: 2022.12 Added complex data type support. """ From a7bcfe6932f71f508460257214058b8a3aef81f7 Mon Sep 17 00:00:00 2001 From: minerharry <35383543+minerharry@users.noreply.github.com> Date: Mon, 2 Dec 2024 04:56:03 -0500 Subject: [PATCH 163/196] Update copies_views_and_mutation.rst (#865) word order typo --- spec/draft/design_topics/copies_views_and_mutation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/draft/design_topics/copies_views_and_mutation.rst b/spec/draft/design_topics/copies_views_and_mutation.rst index 52be1c805..1ca5a039c 100644 --- a/spec/draft/design_topics/copies_views_and_mutation.rst +++ b/spec/draft/design_topics/copies_views_and_mutation.rst @@ -6,7 +6,7 @@ Copy-view behaviour and mutability .. admonition:: Mutating views :class: important - Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may be either a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. + Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may either be a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically have the concept of a "view", meaning an array containing data in memory that From 05ec5e72b0fe7b63f9822ede7b20a5108b7b20d3 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Wed, 11 Dec 2024 11:29:12 -0800 Subject: [PATCH 164/196] docs: clarify that implementations may add additional arguments (#870) --- spec/draft/purpose_and_scope.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/draft/purpose_and_scope.md b/spec/draft/purpose_and_scope.md index f375c9512..b2019b7dd 100644 --- a/spec/draft/purpose_and_scope.md +++ b/spec/draft/purpose_and_scope.md @@ -410,8 +410,8 @@ all the functions, arguments, data types, syntax, and semantics described in this specification. A conforming implementation of the array API standard may provide additional -values, objects, properties, data types, and functions beyond those described -in this specification. +features (e.g., values, objects, properties, data types, functions, and function +arguments) beyond those described in this specification. Libraries which aim to provide a conforming implementation but haven't yet completed such an implementation may, and are encouraged to, provide details on From 5cdcf75b66647a45374656605b66c9e922cfe01c Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 01:13:14 -0800 Subject: [PATCH 165/196] docs: add note regarding unspecified behavior for 0d arrays in `cumulative_sum` PR-URL: https://github.com/data-apis/array-api/pull/851 Closes: https://github.com/data-apis/array-api/issues/797 --- src/array_api_stubs/_draft/statistical_functions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 9d3563e26..4cb6de0a8 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -18,7 +18,7 @@ def cumulative_sum( Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have one or more dimensions (axes). Should have a numeric data type. axis: Optional[int] axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum by counting from the last dimension. @@ -48,6 +48,8 @@ def cumulative_sum( Notes ----- + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + **Special Cases** For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. From 5ffffeed9afc5643215bc051662c3647de4e8a3e Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 02:02:44 -0800 Subject: [PATCH 166/196] feat: add `count_nonzero` to specification PR-URL: https://github.com/data-apis/array-api/pull/803 Closes: https://github.com/data-apis/array-api/issues/794 --- .../API_specification/searching_functions.rst | 1 + .../_draft/searching_functions.py | 47 +++++++++++++++---- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/spec/draft/API_specification/searching_functions.rst b/spec/draft/API_specification/searching_functions.rst index c952f1aad..1a584f158 100644 --- a/spec/draft/API_specification/searching_functions.rst +++ b/spec/draft/API_specification/searching_functions.rst @@ -22,6 +22,7 @@ Objects in API argmax argmin + count_nonzero nonzero searchsorted where diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 029459b9a..4eee3173b 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -1,7 +1,7 @@ -__all__ = ["argmax", "argmin", "nonzero", "searchsorted", "where"] +__all__ = ["argmax", "argmin", "count_nonzero", "nonzero", "searchsorted", "where"] -from ._types import Optional, Tuple, Literal, array +from ._types import Optional, Tuple, Literal, Union, array def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: @@ -54,15 +54,41 @@ def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - """ -def nonzero(x: array, /) -> Tuple[array, ...]: +def count_nonzero( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ - Returns the indices of the array elements which are non-zero. + Counts the number of array elements which are non-zero. - .. note:: - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to count non-zero values. By default, the number of non-zero values must be computed over the entire array. If a tuple of integers, the number of non-zero values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. - .. note:: - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + Returns + ------- + out: array + if the number of non-zeros values was computed over the entire array, a zero-dimensional array containing the total number of non-zero values; otherwise, a non-zero-dimensional array containing the counts along the specified axes. The returned array must have the default array index data type. + + Notes + ----- + + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + """ + + +def nonzero(x: array, /) -> Tuple[array, ...]: + """ + Returns the indices of the array elements which are non-zero. .. admonition:: Data-dependent output shape :class: admonition important @@ -76,12 +102,15 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. Notes ----- + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + .. versionchanged:: 2022.12 Added complex data type support. """ From c492972ffe6db9911ffaeb222962b7ca5f916919 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 02:14:05 -0800 Subject: [PATCH 167/196] feat: add `cumulative_prod` specification PR-URL: https://github.com/data-apis/array-api/pull/793 Closes: https://github.com/data-apis/array-api/issues/598 --- .../statistical_functions.rst | 1 + .../_draft/statistical_functions.py | 64 ++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/statistical_functions.rst b/spec/draft/API_specification/statistical_functions.rst index 20e02b3f9..eb5e1a5d6 100644 --- a/spec/draft/API_specification/statistical_functions.rst +++ b/spec/draft/API_specification/statistical_functions.rst @@ -18,6 +18,7 @@ Objects in API :toctree: generated :template: method.rst + cumulative_prod cumulative_sum max mean diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 4cb6de0a8..347a97fff 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -1,9 +1,71 @@ -__all__ = ["cumulative_sum", "max", "mean", "min", "prod", "std", "sum", "var"] +__all__ = [ + "cumulative_sum", + "cumulative_prod", + "max", + "mean", + "min", + "prod", + "std", + "sum", + "var", +] from ._types import Optional, Tuple, Union, array, dtype +def cumulative_prod( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative product of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative product must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative product by counting from the last dimension. + + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the multiplicative identity (i.e., one). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative product. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative product must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + """ + + def cumulative_sum( x: array, /, From f7d16ff6516be1704f5ec00bdcdd808a90babdd7 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Thu, 12 Dec 2024 11:21:55 +0000 Subject: [PATCH 168/196] fix: clarify that `condition` should have a boolean dtype in `where` PR-URL: https://github.com/data-apis/array-api/pull/868 Ref: https://github.com/data-apis/array-api/pull/116 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2021_12/searching_functions.py | 2 +- src/array_api_stubs/_2022_12/searching_functions.py | 2 +- src/array_api_stubs/_2023_12/searching_functions.py | 2 +- src/array_api_stubs/_draft/searching_functions.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2021_12/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py index 14ebdd889..ca7d22420 100644 --- a/src/array_api_stubs/_2021_12/searching_functions.py +++ b/src/array_api_stubs/_2021_12/searching_functions.py @@ -69,7 +69,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py index 9dcc0f95c..2d2560502 100644 --- a/src/array_api_stubs/_2022_12/searching_functions.py +++ b/src/array_api_stubs/_2022_12/searching_functions.py @@ -91,7 +91,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py index 029459b9a..9d64fe6da 100644 --- a/src/array_api_stubs/_2023_12/searching_functions.py +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -146,7 +146,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 4eee3173b..9e0053825 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -175,7 +175,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array From 640e6cdcd977fb40f62eff7bd527c535cd3f7fce Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 06:10:14 -0800 Subject: [PATCH 169/196] feat: add complex dtype support for `mean` (#850) --- .../_draft/statistical_functions.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 347a97fff..92ffe60c5 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -177,7 +177,7 @@ def mean( Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. keepdims: bool @@ -189,17 +189,26 @@ def mean( if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. .. note:: - While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. Notes ----- **Special Cases** - Let ``N`` equal the number of elements over which to compute the arithmetic mean. + Let ``N`` equal the number of elements over which to compute the arithmetic mean. For real-valued operands, - If ``N`` is ``0``, the arithmetic mean is ``NaN``. - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). + + For complex floating-point operands, real-valued floating-point special cases should independently apply to the real and imaginary component operations involving real numbers. For example, let ``a = real(x_i)`` and ``b = imag(x_i)``, and + + - If ``N`` is ``0``, the arithmetic mean is ``NaN + NaN j``. + - If ``a`` is ``NaN``, the real component of the result is ``NaN``. + - Similarly, if ``b`` is ``NaN``, the imaginary component of the result is ``NaN``. + + .. note:: + Array libraries, such as NumPy, PyTorch, and JAX, currently deviate from this specification in their handling of components which are ``NaN`` when computing the arithmetic mean. In general, consumers of array libraries implementing this specification should use :func:`~array_api.isnan` to test whether the result of computing the arithmetic mean over an array have a complex floating-point data type is ``NaN``, rather than relying on ``NaN`` propagation of individual components. """ From 7757e67a93eecb5c0a085e65d04d9b127a37f6af Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jan 2025 10:29:49 -0800 Subject: [PATCH 170/196] feat: add support for scalars in `result_type` PR-URL: https://github.com/data-apis/array-api/pull/873 Closes: https://github.com/data-apis/array-api/issues/805 Reviewed-by: lucas.colley8@gmail.com --- .../_draft/data_type_functions.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index e12d349c6..f953f0596 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -209,20 +209,25 @@ def isdtype( """ -def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: +def result_type( + *arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] +) -> dtype: """ - Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. - - .. note:: - If provided mixed dtypes (e.g., integer and floating-point), the returned dtype will be implementation-specific. + Returns the dtype that results from applying type promotion rules (see :ref:`type-promotion`) to the arguments. Parameters ---------- - arrays_and_dtypes: Union[array, dtype] - an arbitrary number of input arrays and/or dtypes. + arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] + an arbitrary number of input arrays, scalars, and/or dtypes. Returns ------- out: dtype - the dtype resulting from an operation involving the input arrays and dtypes. + the dtype resulting from an operation involving the input arrays, scalars, and/or dtypes. + + Notes + ----- + + - At least one argument must be an array or a dtype. + - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and is implementation-dependent. """ From 456d186a5669e986e6dcd29fb5b495a235b86fd9 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Thu, 9 Jan 2025 07:50:47 +0000 Subject: [PATCH 171/196] docs: clarify behavior when providing a zero-dimensional array to `take` PR-URL: https://github.com/data-apis/array-api/pull/876 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/indexing_functions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index a9b38b482..536317dbb 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -13,7 +13,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: Parameters ---------- x: array - input array. + input array. Should have one or more dimensions (axes). indices: array array indices. The array must be one-dimensional and have an integer data type. @@ -33,6 +33,8 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: Notes ----- + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + .. versionadded:: 2022.12 .. versionchanged:: 2023.12 From fd6f507ee2037a66a1a194ccb50fb4f2b1411ee4 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 9 Jan 2025 00:32:35 -0800 Subject: [PATCH 172/196] fix: address default value regression for `axis` kwarg in `vecdot` PR-URL: https://github.com/data-apis/array-api/pull/880 Closes: https://github.com/data-apis/array-api/issues/804 Ref: https://github.com/data-apis/array-api/issues/355 Ref: https://github.com/data-apis/array-api/pull/358 Ref: https://github.com/data-apis/array-api/commit/cbbab62922ab7ddd4f31302c21f22d2db62d6f16 --- src/array_api_stubs/_2021_12/linalg.py | 2 +- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_2023_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 4e4ba52b2..06aa0accd 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -474,7 +474,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Alias for :func:`~array_api.vecdot`. """ diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index b13a5bf01..beec652bc 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -755,7 +755,7 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """Alias for :func:`~array_api.vecdot`.""" diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py index a1c9fe028..a43dc8dcf 100644 --- a/src/array_api_stubs/_2023_12/linalg.py +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -781,7 +781,7 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """Alias for :func:`~array_api.vecdot`.""" diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index a1c9fe028..a43dc8dcf 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -781,7 +781,7 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """Alias for :func:`~array_api.vecdot`.""" From d12a5e31564ba3dd16d0a328feb67964c07da1e7 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 9 Jan 2025 11:41:28 +0100 Subject: [PATCH 173/196] feat: add scalar support to `where` PR-URL: https://github.com/data-apis/array-api/pull/860 Ref: https://github.com/data-apis/array-api/issues/807 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Evgeni Burovski Reviewed-by: Lucas Colley --- .../API_specification/type_promotion.rst | 3 +++ .../_draft/searching_functions.py | 20 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/spec/draft/API_specification/type_promotion.rst b/spec/draft/API_specification/type_promotion.rst index 339b90e45..4b3791aca 100644 --- a/spec/draft/API_specification/type_promotion.rst +++ b/spec/draft/API_specification/type_promotion.rst @@ -120,6 +120,9 @@ Notes .. note:: Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. + +.. _mixing-scalars-and-arrays: + Mixing arrays with Python scalars ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 9e0053825..04d4fd818 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -168,7 +168,12 @@ def searchsorted( """ -def where(condition: array, x1: array, x2: array, /) -> array: +def where( + condition: array, + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: """ Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. @@ -176,13 +181,22 @@ def where(condition: array, x1: array, x2: array, /) -> array: ---------- condition: array when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). - x1: array + x1: Union[array, int, float, complex, bool] first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). - x2: array + x2: Union[array, int, float, complex, bool] second input array. Must be compatible with ``condition`` and ``x1`` (see :ref:`broadcasting`). Returns ------- out: array an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. + + Notes + ----- + + - At least one of ``x1`` and ``x2`` must be an array. + - If either ``x1`` or ``x2`` is a scalar value, the returned array must have a data type determined according to :ref:`mixing-scalars-and-arrays`. + + .. versionchanged:: 2024.12 + Added support for scalar arguments. """ From 532db5baeb7d47f28e6b0e3f0ede2e180bc0688f Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 9 Jan 2025 03:24:40 -0800 Subject: [PATCH 174/196] feat: add scalar support to element-wise functions PR-URL: https://github.com/data-apis/array-api/pull/862 Ref: https://github.com/data-apis/array-api/issues/807 Reviewed-by: Evgeni Burovski --- src/array_api_stubs/_draft/array_object.py | 179 ++++----- .../_draft/elementwise_functions.py | 361 +++++++++++------- 2 files changed, 300 insertions(+), 240 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 3c6fa8763..6d55b1eee 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -148,7 +148,7 @@ def __abs__(self: array, /) -> array: Added complex data type support. """ - def __add__(self: array, other: Union[int, float, array], /) -> array: + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the sum for each element of an array instance with the respective element of the array ``other``. @@ -167,8 +167,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. .. versionchanged:: 2022.12 Added complex data type support. @@ -190,9 +189,10 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ def __array_namespace__( @@ -494,7 +494,7 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: ONE_API = 14 """ - def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -502,7 +502,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -510,12 +510,11 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __float__(self: array, /) -> float: @@ -584,9 +583,6 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -599,12 +595,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __getitem__( @@ -645,9 +641,6 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -660,12 +653,12 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __index__(self: array, /) -> int: @@ -769,9 +762,6 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -784,12 +774,12 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -808,18 +798,16 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: out: array an array containing the element-wise results. The returned array must have the same data type as ``self``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -832,12 +820,12 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __matmul__(self: array, other: array, /) -> array: @@ -892,9 +880,6 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: """ Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - Parameters ---------- self: array @@ -907,12 +892,14 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. """ - def __mul__(self: array, other: Union[int, float, array], /) -> array: + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. @@ -923,7 +910,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -934,14 +921,13 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. .. versionchanged:: 2022.12 Added complex data type support. """ - def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -949,7 +935,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -957,15 +943,11 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). - Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. .. versionchanged:: 2022.12 Added complex data type support. @@ -1017,9 +999,10 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -1046,20 +1029,15 @@ def __pos__(self: array, /) -> array: Added complex data type support. """ - def __pow__(self: array, other: Union[int, float, array], /) -> array: + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. - .. note:: - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - Parameters ---------- self: array array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1070,8 +1048,9 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. .. versionchanged:: 2022.12 Added complex data type support. @@ -1093,9 +1072,10 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: out: array an array containing the element-wise results. The returned array must have the same data type as ``self``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ def __setitem__( @@ -1103,7 +1083,7 @@ def __setitem__( key: Union[ int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array ], - value: Union[int, float, bool, array], + value: Union[int, float, complex, bool, array], /, ) -> None: """ @@ -1117,30 +1097,26 @@ def __setitem__( array instance. key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] index key. - value: Union[int, float, bool, array] + value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). + Notes + ----- - .. note:: - - Setting array values must not affect the data type of ``self``. - - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). - - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + - Setting array values must not affect the data type of ``self``. + - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``complex``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. """ - def __sub__(self: array, other: Union[int, float, array], /) -> array: + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the difference for each element of an array instance with the respective element of the array ``other``. - The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). - Parameters ---------- self: array array instance (minuend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1151,27 +1127,22 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + - The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). .. versionchanged:: 2022.12 Added complex data type support. """ - def __truediv__(self: array, other: Union[int, float, array], /) -> array: + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - - Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. - Parameters ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1182,8 +1153,11 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + - If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. .. versionchanged:: 2022.12 Added complex data type support. @@ -1205,9 +1179,10 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ def to_device( diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 156715200..fa9390a01 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -272,15 +272,17 @@ def acosh(x: array, /) -> array: """ -def add(x1: array, x2: array, /) -> array: +def add( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: """ Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -291,6 +293,8 @@ def add(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, @@ -514,7 +518,7 @@ def atan(x: array, /) -> array: """ -def atan2(x1: array, x2: array, /) -> array: +def atan2(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. @@ -527,9 +531,9 @@ def atan2(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int, float] input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -540,6 +544,8 @@ def atan2(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For floating-point operands, @@ -639,39 +645,49 @@ def atanh(x: array, /) -> array: """ -def bitwise_and(x1: array, x2: array, /) -> array: +def bitwise_and(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: """ Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, bool] first input array. Should have an integer or boolean data type. - x2: array + x2: Union[array, int, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def bitwise_left_shift(x1: array, x2: array, /) -> array: +def bitwise_left_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. Parameters ---------- - x1: array + x1: Union[array, int] first input array. Should have an integer data type. - x2: array + x2: Union[array, int] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ @@ -691,25 +707,30 @@ def bitwise_invert(x: array, /) -> array: """ -def bitwise_or(x1: array, x2: array, /) -> array: +def bitwise_or(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: """ Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, bool] first input array. Should have an integer or boolean data type. - x2: array + x2: Union[array, int, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def bitwise_right_shift(x1: array, x2: array, /) -> array: +def bitwise_right_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. @@ -718,33 +739,43 @@ def bitwise_right_shift(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int] first input array. Should have an integer data type. - x2: array + x2: Union[array, int] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def bitwise_xor(x1: array, x2: array, /) -> array: +def bitwise_xor(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: """ Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, bool] first input array. Should have an integer or boolean data type. - x2: array + x2: Union[array, int, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ @@ -793,9 +824,9 @@ def clip( x: array input array. Should have a real-valued data type. min: Optional[Union[int, float, array]] - lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. max: Optional[Union[int, float, array]] - upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. Returns ------- @@ -852,15 +883,15 @@ def conj(x: array, /) -> array: """ -def copysign(x1: array, x2: array, /) -> array: +def copysign(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. Parameters ---------- - x1: array + x1: Union[array, int, float] input array containing magnitudes. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -871,6 +902,8 @@ def copysign(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, @@ -1003,20 +1036,17 @@ def cosh(x: array, /) -> array: """ -def divide(x1: array, x2: array, /) -> array: +def divide( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: r""" Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - - Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. - Parameters ---------- - x1: array + x1: Union[array, int, float, complex] dividend input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1027,6 +1057,12 @@ def divide(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + + - If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + **Special cases** For real-valued floating-point operands, @@ -1086,15 +1122,19 @@ def divide(x1: array, x2: array, /) -> array: """ -def equal(x1: array, x2: array, /) -> array: +def equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: r""" Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float, complex, bool] first input array. May have any data type. - x2: array + x2: Union[array, int, float, complex, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. Returns @@ -1105,6 +1145,8 @@ def equal(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special Cases** For real-valued floating-point operands, @@ -1279,18 +1321,17 @@ def floor(x: array, /) -> array: """ -def floor_divide(x1: array, x2: array, /) -> array: +def floor_divide( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. - .. note:: - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - Parameters ---------- - x1: array + x1: Union[array, int, float] dividend input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1301,6 +1342,9 @@ def floor_divide(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + **Special cases** .. note:: @@ -1339,18 +1383,15 @@ def floor_divide(x1: array, x2: array, /) -> array: """ -def greater(x1: array, x2: array, /) -> array: +def greater(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1358,24 +1399,27 @@ def greater(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ -def greater_equal(x1: array, x2: array, /) -> array: +def greater_equal( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: """ Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1383,12 +1427,16 @@ def greater_equal(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ -def hypot(x1: array, x2: array, /) -> array: +def hypot(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1397,9 +1445,9 @@ def hypot(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -1410,7 +1458,8 @@ def hypot(x1: array, x2: array, /) -> array: Notes ----- - The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + - At least one of ``x1`` or ``x2`` must be an array. + - The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. **Special Cases** @@ -1562,18 +1611,15 @@ def isnan(x: array, /) -> array: """ -def less(x1: array, x2: array, /) -> array: +def less(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1581,23 +1627,24 @@ def less(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ -def less_equal(x1: array, x2: array, /) -> array: +def less_equal(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1605,8 +1652,12 @@ def less_equal(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ @@ -1818,15 +1869,15 @@ def log10(x: array, /) -> array: """ -def logaddexp(x1: array, x2: array, /) -> array: +def logaddexp(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -1837,6 +1888,8 @@ def logaddexp(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For floating-point operands, @@ -1847,7 +1900,7 @@ def logaddexp(x1: array, x2: array, /) -> array: """ -def logical_and(x1: array, x2: array, /) -> array: +def logical_and(x1: Union[array, bool], x2: Union[array, bool], /) -> array: """ Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1856,15 +1909,20 @@ def logical_and(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, bool] first input array. Should have a boolean data type. - x2: array + x2: Union[array, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type of `bool`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ @@ -1887,7 +1945,7 @@ def logical_not(x: array, /) -> array: """ -def logical_or(x1: array, x2: array, /) -> array: +def logical_or(x1: Union[array, bool], x2: Union[array, bool], /) -> array: """ Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1896,19 +1954,24 @@ def logical_or(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, bool] first input array. Should have a boolean data type. - x2: array + x2: Union[array, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def logical_xor(x1: array, x2: array, /) -> array: +def logical_xor(x1: Union[array, bool], x2: Union[array, bool], /) -> array: """ Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1917,27 +1980,32 @@ def logical_xor(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, bool] first input array. Should have a boolean data type. - x2: array + x2: Union[array, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def maximum(x1: array, x2: array, /) -> array: +def maximum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1948,9 +2016,9 @@ def maximum(x1: array, x2: array, /) -> array: Notes ----- - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. - - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). **Special Cases** @@ -1962,15 +2030,15 @@ def maximum(x1: array, x2: array, /) -> array: """ -def minimum(x1: array, x2: array, /) -> array: +def minimum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1981,9 +2049,9 @@ def minimum(x1: array, x2: array, /) -> array: Notes ----- - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. - - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). **Special Cases** @@ -1995,7 +2063,9 @@ def minimum(x1: array, x2: array, /) -> array: """ -def multiply(x1: array, x2: array, /) -> array: +def multiply( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: r""" Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -2004,9 +2074,9 @@ def multiply(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -2017,6 +2087,8 @@ def multiply(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, @@ -2091,15 +2163,15 @@ def negative(x: array, /) -> array: """ -def nextafter(x1: array, x2: array, /) -> array: +def nextafter(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Returns the next representable floating-point value for each element ``x1_i`` of the input array ``x1`` in the direction of the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have the same data type as ``x1``. Returns @@ -2110,6 +2182,8 @@ def nextafter(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, @@ -2120,15 +2194,19 @@ def nextafter(x1: array, x2: array, /) -> array: """ -def not_equal(x1: array, x2: array, /) -> array: +def not_equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float, complex, bool] first input array. May have any data type. - x2: array + x2: Union[array, int, float, complex, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Returns @@ -2139,6 +2217,8 @@ def not_equal(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special Cases** For real-valued floating-point operands, @@ -2187,27 +2267,17 @@ def positive(x: array, /) -> array: """ -def pow(x1: array, x2: array, /) -> array: +def pow( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. - .. note:: - If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). - - .. note:: - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. - - The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). - - *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). - Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array whose elements correspond to the exponentiation base. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -2218,6 +2288,18 @@ def pow(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + + - If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + **Special cases** For real-valued floating-point operands, @@ -2301,21 +2383,18 @@ def reciprocal(x: array, /) -> array: """ -def remainder(x1: array, x2: array, /) -> array: +def remainder(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. .. note:: This function is equivalent to the Python modulus operator ``x1_i % x2_i``. - .. note:: - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - Parameters ---------- - x1: array + x1: Union[array, int, float] dividend input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -2326,6 +2405,9 @@ def remainder(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + **Special cases** .. note:: @@ -2681,17 +2763,17 @@ def sqrt(x: array, /) -> array: """ -def subtract(x1: array, x2: array, /) -> array: +def subtract( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: """ Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). - Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -2702,6 +2784,9 @@ def subtract(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + - The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + .. versionchanged:: 2022.12 Added complex data type support. """ From 52bbfebe4f5f4795063bdbcc4abd48a413bb9a3f Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Jan 2025 01:26:23 -0800 Subject: [PATCH 175/196] docs: clarify type promotion behavior in `diff` PR-URL: https://github.com/data-apis/array-api/pull/881 Closes: https://github.com/data-apis/array-api/issues/852 Reviewed-by: Ralf Gommers --- src/array_api_stubs/_draft/utility_functions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index cdbe4a0f8..7a234efbb 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -125,4 +125,5 @@ def diff( ----- - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). + - If a conforming implementation chooses to support ``prepend`` and ``append`` arrays which have a different data type than ``x``, behavior is unspecified and thus implementation-defined. Implementations may choose to type promote (:ref:`type-promotion`), cast ``prepend`` and/or ``append`` to the same data type as ``x``, or raise an exception. """ From 73e722861650872733e7d89e5d297c24989920f1 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:12:34 -0800 Subject: [PATCH 176/196] feat: add `dtype` kwarg support to `fftfreq` and `rfftfreq` PR-URL: https://github.com/data-apis/array-api/pull/885 Closes: https://github.com/data-apis/array-api/issues/717 Reviewed-by: Evgeni Burovski --- src/array_api_stubs/_draft/fft.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 7a4538ccb..3d1f4d9c7 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -15,7 +15,7 @@ "ifftshift", ] -from ._types import Tuple, Union, Sequence, array, Optional, Literal, device +from ._types import Tuple, Union, Sequence, array, Optional, Literal, dtype, device def fft( @@ -551,7 +551,14 @@ def ihfft( """ -def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: +def fftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Computes the discrete Fourier transform sample frequencies. @@ -568,13 +575,15 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar window length. d: float sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. Returns ------- out: array - an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + an array of shape ``(n,)`` containing the sample frequencies. Notes ----- @@ -586,7 +595,14 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar """ -def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: +def rfftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). @@ -605,13 +621,15 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a window length. d: float sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. Returns ------- out: array - an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + an array of shape ``(n//2+1,)`` containing the sample frequencies. Notes ----- From b0aacd9e51085b31a5a2f48778e5a3ae5eef7069 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:19:29 -0800 Subject: [PATCH 177/196] fix: resolve conflicting exception guidance in `__dlpack__` PR-URL: https://github.com/data-apis/array-api/pull/887 Closes: https://github.com/data-apis/array-api/issues/831 --- src/array_api_stubs/_2023_12/array_object.py | 2 +- src/array_api_stubs/_draft/array_object.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index 5c0b10dd9..f5cc9bcee 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -364,7 +364,7 @@ def __dlpack__( ``__dlpack__`` to return a capsule referencing an array whose underlying memory is accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). If a copy must be made to enable this support but ``copy`` is set to ``False``, the - function must raise ``ValueError``. + function must raise ``BufferError``. Other device kinds will be considered for standardization in a future version of this API standard. diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 6d55b1eee..ee4c2a0e3 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -364,7 +364,7 @@ def __dlpack__( ``__dlpack__`` to return a capsule referencing an array whose underlying memory is accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). If a copy must be made to enable this support but ``copy`` is set to ``False``, the - function must raise ``ValueError``. + function must raise ``BufferError``. Other device kinds will be considered for standardization in a future version of this API standard. From 7adeae8b6c4e7820e69b7325032a6d3d9a1af3b3 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:31:51 -0800 Subject: [PATCH 178/196] feat!: apply type promotion rules according to the device context PR-URL: https://github.com/data-apis/array-api/pull/889 Closes: https://github.com/data-apis/array-api/issues/672 BREAKING CHANGE: `can_cast` and `result_type` must account for device context Previously, the specification only required that conforming libraries consider the type promotion graph as defined in the specification. However, that resulted in situations where `can_cast` and `result_type` diverged from actual behavior due to device limitations. This commit requires conforming implementations to consider the device context when applying type promotion rules. --- src/array_api_stubs/_draft/data_type_functions.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index f953f0596..db793c16e 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -65,7 +65,7 @@ def astype( def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: """ - Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. + Determines if one data type can be cast to another data type according to type promotion rules (see :ref:`type-promotion`). Parameters ---------- @@ -77,7 +77,13 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: Returns ------- out: bool - ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. + ``True`` if the cast can occur according to type promotion rules (see :ref:`type-promotion`); otherwise, ``False``. + + Notes + ----- + + - When ``from_`` is a data type, the function must determine whether the data type can be cast to another data type according to the complete type promotion rules (see :ref:`type-promotion`) described in this specification, irrespective of whether a conforming array library supports devices which do not have full data type support. + - When ``from_`` is an array, the function must determine whether the data type of the array can be cast to the desired data type according to the type promotion graph of the array device. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the output of ``can_cast(array, dtype)`` may differ from ``can_cast(array.dtype, dtype)``. """ @@ -229,5 +235,7 @@ def result_type( ----- - At least one argument must be an array or a dtype. - - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and is implementation-dependent. + - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and thus implementation-dependent. + - If at least one argument is an array, the function must determine the resulting dtype according to the type promotion graph of the array device which is shared among all array arguments. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the returned dtype may differ from that determined from the complete type promotion graph defined in this specification (see :ref:`type-promotion`). + - If two or more arguments are arrays belonging to different devices, behavior is unspecified and thus implementation-dependent. Conforming implementations may choose to ignore device attributes, raise an exception, or some other behavior. """ From 4f26831f8bf38f042692f75973abef31088cbe04 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:35:07 -0800 Subject: [PATCH 179/196] fix: clarify broadcast behavior in `broadcast_to` PR-URL: https://github.com/data-apis/array-api/pull/888 Closes: https://github.com/data-apis/array-api/issues/823 --- src/array_api_stubs/_draft/manipulation_functions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 131b81eb3..c09f2643b 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -42,14 +42,14 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: Parameters ---------- x: array - array to broadcast. + array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. shape: Tuple[int, ...] - array shape. Must be compatible with ``x`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + array shape. Returns ------- out: array - an array having a specified shape. Must have the same data type as ``x``. + an array having the specified shape. Must have the same data type as ``x``. """ From 071780c7480fe05588afc768df3c3d15c5fc550e Mon Sep 17 00:00:00 2001 From: Evgeni Burovski Date: Thu, 6 Feb 2025 04:00:35 +0100 Subject: [PATCH 180/196] feat: add support for real-valued arrays in `real` and `conj` PR-URL: https://github.com/data-apis/array-api/pull/884 Closes: https://github.com/data-apis/array-api/issues/824 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_draft/elementwise_functions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index fa9390a01..119881adc 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -869,7 +869,7 @@ def conj(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex floating-point data type. + input array. Must have a numeric data type. Returns ------- @@ -879,6 +879,8 @@ def conj(x: array, /) -> array: Notes ----- + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + .. versionadded:: 2022.12 """ @@ -2346,7 +2348,7 @@ def real(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex floating-point data type. + input array. Must have a numeric data type. Returns ------- @@ -2356,6 +2358,8 @@ def real(x: array, /) -> array: Notes ----- + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + .. versionadded:: 2022.12 """ From df8081cafb31a7e09665180e3454df4b61356b87 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 21:44:50 -0800 Subject: [PATCH 181/196] docs: clarify support for negative indices in `take` and `take_along_axis` PR-URL: https://github.com/data-apis/array-api/pull/894 Reviewed-by: Matt Haberland --- .../_draft/indexing_functions.py | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 536317dbb..8be7cc00e 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -7,21 +7,14 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: """ Returns elements of an array along an axis. - .. note:: - Conceptually, ``take(x, indices, axis=3)`` is equivalent to ``x[:,:,:,indices,...]``; however, explicit indexing via arrays of indices is not currently supported in this specification due to concerns regarding ``__setitem__`` and array mutation semantics. - Parameters ---------- x: array input array. Should have one or more dimensions (axes). indices: array - array indices. The array must be one-dimensional and have an integer data type. - - .. note:: - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - + array indices. The array must be one-dimensional and have an integer data type. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). axis: Optional[int] - axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. + axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension (where ``-1`` refers to the last dimension). If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. @@ -33,6 +26,8 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: Notes ----- + - Conceptually, ``take(x, indices, axis=3)`` is equivalent to ``x[:,:,:,indices,...]``; however, explicit indexing via arrays of indices is not currently supported in this specification due to concerns regarding ``__setitem__`` and array mutation semantics. + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. .. versionadded:: 2022.12 @@ -51,16 +46,17 @@ def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: x: array input array. Must be compatible with ``indices``, except for the axis (dimension) specified by ``axis`` (see :ref:`broadcasting`). indices: array - array indices. Must have the same rank (i.e., number of dimensions) as ``x``. - - .. note:: - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - + array indices. Must have the same rank (i.e., number of dimensions) as ``x``. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). axis: int - axis along which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. Default: ``-1``. + axis along which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. Returns ------- out: array an array having the same data type as ``x``. Must have the same rank (i.e., number of dimensions) as ``x`` and must have a shape determined according to :ref:`broadcasting`, except for the axis (dimension) specified by ``axis`` whose size must equal the size of the corresponding axis (dimension) in ``indices``. + + Notes + ----- + + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. """ From 4dccde523af32b3346f90e5dd2b2f90d26319a34 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 21:48:24 -0800 Subject: [PATCH 182/196] docs: clarify that `sqrt` must be correctly rounded in accordance with IEEE 754 PR-URL: https://github.com/data-apis/array-api/pull/882 Closes: https://github.com/data-apis/array-api/issues/826 Closes: https://github.com/data-apis/array-api/issues/830 Reviewed-by: Leo Fang --- spec/draft/design_topics/accuracy.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/spec/draft/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst index 61a2c49aa..9d82dbb1f 100644 --- a/spec/draft/design_topics/accuracy.rst +++ b/spec/draft/design_topics/accuracy.rst @@ -23,11 +23,20 @@ including the corresponding element-wise array APIs defined in this standard - multiply - divide -for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). + +IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, conforming implementations may vary in their support for subnormal numbers. Mathematical Functions ---------------------- +The results of the following functions + +- reciprocal +- sqrt + +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. + This specification does **not** precisely define the behavior of the following functions - acos @@ -41,10 +50,12 @@ This specification does **not** precisely define the behavior of the following f - cosh - exp - expm1 +- hypot - log - log1p - log2 - log10 +- logaddexp - pow - sin - sinh @@ -75,3 +86,8 @@ Linear Algebra -------------- This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +Operations Involving Complex Numbers +------------------------------------ + +This specification does not specify accuracy requirements for arithmetic or functional operations involving complex-valued floating-point operands; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. From c7476ba49e7a5ace85e6bb36962a0ee63c7c1963 Mon Sep 17 00:00:00 2001 From: Evgeni Burovski Date: Thu, 6 Feb 2025 09:27:15 +0100 Subject: [PATCH 183/196] feat: define complex scalar fp array PR-URL: https://github.com/data-apis/array-api/pull/871 Closes: https://github.com/data-apis/array-api/issues/841 Ref: https://github.com/data-apis/array-api/issues/478 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Lucas Colley --- .../API_specification/type_promotion.rst | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/spec/draft/API_specification/type_promotion.rst b/spec/draft/API_specification/type_promotion.rst index 4b3791aca..7a82c763b 100644 --- a/spec/draft/API_specification/type_promotion.rst +++ b/spec/draft/API_specification/type_promotion.rst @@ -110,7 +110,6 @@ where - **c16**: double-precision complex floating-point number (i.e., ``complex128``) composed of two double-precision (64-bit) floating-point numbers - Notes ~~~~~ @@ -140,12 +139,25 @@ where ```` is a built-in operator (including in-place operators, but excludi Provided the above requirements are met, the expected behavior is equivalent to: -1. Convert the scalar to zero-dimensional array with the same data type as that of the array used in the expression. +1. Convert the scalar to a zero-dimensional array with the same data type as that of the array used in the expression. 2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). -.. note:: - Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. +Additionally, using Python ``complex`` scalars together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with a promoted array data type: + +- a Python ``complex`` for real-valued floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to a zero-dimensional array with a complex floating-point array data type having the same precision as that of the array operand used in the expression (e.g., if an array has a ``float32`` data type, the scalar must be converted to a zero-dimensional array having a ``complex64`` data type; if an array has a ``float64`` data type, the scalar must be converted to a zero-dimensional array have a ``complex128`` data type). +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +Behavior is not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. - Similarly, behavior is not specified when mixing a Python ``complex`` and an array with a real-valued data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. +Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. - Behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. +Behavior is not specified when mixing a Python ``complex`` and an array with an integer data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. From f73baff3a59ce9ab84ff3fea0cf30a8af69a3d0d Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 6 Feb 2025 02:29:00 -0700 Subject: [PATCH 184/196] docs: clarify that `clip` behavior is undefined when `min` or `max` is outside the bounds of `x` PR-URL: https://github.com/data-apis/array-api/pull/814 Ref: https://github.com/numpy/numpy/issues/24976 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_2023_12/elementwise_functions.py | 1 + src/array_api_stubs/_draft/elementwise_functions.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 251a770d6..f44838f63 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -805,6 +805,7 @@ def clip( - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. **Special cases** diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 119881adc..40775d6a3 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -838,6 +838,7 @@ def clip( - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. **Special cases** From 407a8aebced500b1fc0e38132a645e0142d51bb1 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 16 Feb 2025 22:53:07 -0800 Subject: [PATCH 185/196] fix: resolve typo in `broadcast_to` to require an exception PR-URL: https://github.com/data-apis/array-api/pull/897 Ref: https://github.com/data-apis/array-api/pull/888/files#r1944366064 --- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index c09f2643b..7e94cbc27 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -42,7 +42,7 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: Parameters ---------- x: array - array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function must raise an exception. shape: Tuple[int, ...] array shape. From cfa91d3ef9e6faf711f653abb09b8a73de64ceb6 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Feb 2025 01:57:40 -0800 Subject: [PATCH 186/196] docs: clarify the expected results for in-place operations for immutable array libraries PR-URL: https://github.com/data-apis/array-api/pull/895 Closes: https://github.com/data-apis/array-api/issues/828 Reviewed-by: Sebastian Berg --- .../API_specification/array_object.rst | 2 +- spec/draft/API_specification/array_object.rst | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/spec/2023.12/API_specification/array_object.rst b/spec/2023.12/API_specification/array_object.rst index f8a586ade..6a41d4016 100644 --- a/spec/2023.12/API_specification/array_object.rst +++ b/spec/2023.12/API_specification/array_object.rst @@ -87,7 +87,7 @@ A conforming implementation of the array API standard must provide and support a - `operator.matmul(x1, x2) `_ - `operator.__matmul__(x1, x2) `_ -The matmul ``@`` operator should be defined for arrays having real-valued data types. +The matmul ``@`` operator should be defined for arrays having numeric data types. Bitwise Operators ~~~~~~~~~~~~~~~~~ diff --git a/spec/draft/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst index f8a586ade..e3c7e8ae6 100644 --- a/spec/draft/API_specification/array_object.rst +++ b/spec/draft/API_specification/array_object.rst @@ -87,7 +87,7 @@ A conforming implementation of the array API standard must provide and support a - `operator.matmul(x1, x2) `_ - `operator.__matmul__(x1, x2) `_ -The matmul ``@`` operator should be defined for arrays having real-valued data types. +The matmul ``@`` operator should be defined for arrays having numeric data types. Bitwise Operators ~~~~~~~~~~~~~~~~~ @@ -169,14 +169,28 @@ For backward compatibility, conforming implementations may support complex numbe In-place Operators ~~~~~~~~~~~~~~~~~~ -A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. +.. note:: + In-place operations must be supported as discussed in :ref:`copyview-mutability`. + +A conforming implementation of the array API standard must provide and support an array object supporting the following "in-place" Python operators. + +.. note:: + This specification refers to the following operators as "in-place" as that is what these operators are called in `Python `. However, conforming array libraries which do not support array mutation may choose to not explicitly implement in-place Python operators. When a library does not implement a method corresponding to an in-place Python operator, Python falls back to the equivalent method for the corresponding binary arithmetic operation. An in-place operation must not change the data type or shape of the in-place array as a result of :ref:`type-promotion` or :ref:`broadcasting`. -An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1 = x1 + x2``. +Let ``x1 += x2`` be a representative in-place operation. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands ``x1`` and ``x2``, the resulting data type is equal to the data type of the array on the left-hand side of the operation (i.e., ``x1``), then an in-place operation must have the same behavior (including special cases) as the respective binary (i.e., two operand, non-assignment) operation. In this case, for the in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1[...] = x1 + x2``. + +If, however, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of the array on the left-hand side of the operation, then a conforming implementation may return results which differ from the respective binary operation due to casting behavior and selection of the operation's intermediate precision. The choice of casting behavior and intermediate precision is unspecified and thus implementation-defined. .. note:: - In-place operators must be supported as discussed in :ref:`copyview-mutability`. + Let ``x1`` be the operand on the left-hand side and ``x2`` be the operand on the right-hand side of an in-place operation. Consumers of the array API standard are advised of the following considerations when using in-place operations: + + 1. In-place operations do not guarantee in-place mutation. A conforming library may or may not support in-place mutation. + 2. If, after applying broadcasting (see :ref:`broadcasting`) to in-place operands, the resulting shape is not equal to the shape of ``x1``, in-place operators may raise an exception. + 3. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of ``x1``, the resulting data type may not equal the data type of ``x1`` and the operation's intermediate precision may be that of ``x1``, even if the promoted data type between ``x1`` and ``x2`` would have higher precision. + + In general, for in-place operations, consumers of the array API standard are advised to ensure operands have the same data type and broadcast to the shape of the operand on the left-hand side of the operation in order to maximize portability. Arithmetic Operators """""""""""""""""""" From 0a425d19717802d3762b6beb472cdd3d8fb5e432 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Feb 2025 02:03:43 -0800 Subject: [PATCH 187/196] docs: clarify `clip` behavior when arguments have different data types PR-URL: https://github.com/data-apis/array-api/pull/896 Closes: https://github.com/data-apis/array-api/pull/811 Ref: https://github.com/data-apis/array-api/pull/814#issuecomment-2428088370 Ref: https://github.com/data-apis/array-api/issues/807 Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2023_12/elementwise_functions.py | 4 ++-- src/array_api_stubs/_draft/elementwise_functions.py | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index f44838f63..2972fa623 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -791,9 +791,9 @@ def clip( x: array input array. Should have a real-valued data type. min: Optional[Union[int, float, array]] - lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` and ``max`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. max: Optional[Union[int, float, array]] - upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` and ``min`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. Returns ------- diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 40775d6a3..a35c04db5 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -824,22 +824,24 @@ def clip( x: array input array. Should have a real-valued data type. min: Optional[Union[int, float, array]] - lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` and ``max`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. max: Optional[Union[int, float, array]] - upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` and ``min`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. Returns ------- out: array - an array containing element-wise results. The returned array must have the same data type as ``x``. + an array containing element-wise results. The returned array should have the same data type as ``x``. Notes ----- + - This function is conceptually equivalent to ``maximum(minimum(x, max), min)`` when ``x``, ``min``, and ``max`` have the same data type. - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - For scalar ``min`` and/or ``max``, the scalar values should follow type promotion rules for operations involving arrays and scalar operands (see :ref:`type-promotion`). Hence, if ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. - - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + - If either ``min`` or ``max`` is an array having a different data type than ``x``, behavior is unspecified and thus implementation-dependent. **Special cases** From 287b83454a2908b4359dd0ac472cd561a21ee4f6 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Feb 2025 02:23:13 -0800 Subject: [PATCH 188/196] fix: address incorrect boundary conditions in `searchsorted` PR-URL: https://github.com/data-apis/array-api/pull/898 Closes: https://github.com/data-apis/array-api/issues/861 Reviewed-by: Matt Haberland Co-authored-by: Matt Haberland --- .../_2023_12/searching_functions.py | 15 ++++++--------- src/array_api_stubs/_draft/searching_functions.py | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py index 9d64fe6da..c854a1d98 100644 --- a/src/array_api_stubs/_2023_12/searching_functions.py +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -107,17 +107,14 @@ def searchsorted( side: Literal['left', 'right'] argument controlling which index is returned if a value lands exactly on an edge. - Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + Let ``v`` be an element of ``x2`` given by ``v = x2[j]``, where ``j`` refers to a valid index (see :ref:`indexing`). - If ``side == 'left'``, then + - If ``v`` is less than all elements in ``x1``, then ``out[j]`` must be ``0``. + - If ``v`` is greater than all elements in ``x1``, then ``out[j]`` must be ``M``, where ``M`` is the number of elements in ``x1``. + - Otherwise, each returned index ``i = out[j]`` must satisfy an index condition: - - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``0``. - - Otherwise, if ``side == 'right'``, then - - - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + - If ``side == 'left'``, then ``x1[i-1] < v <= x1[i]``. + - If ``side == 'right'``, then ``x1[i-1] <= v < x1[i]``. Default: ``'left'``. sorter: Optional[array] diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 04d4fd818..d8676b68b 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -136,17 +136,14 @@ def searchsorted( side: Literal['left', 'right'] argument controlling which index is returned if a value lands exactly on an edge. - Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + Let ``v`` be an element of ``x2`` given by ``v = x2[j]``, where ``j`` refers to a valid index (see :ref:`indexing`). - If ``side == 'left'``, then + - If ``v`` is less than all elements in ``x1``, then ``out[j]`` must be ``0``. + - If ``v`` is greater than all elements in ``x1``, then ``out[j]`` must be ``M``, where ``M`` is the number of elements in ``x1``. + - Otherwise, each returned index ``i = out[j]`` must satisfy an index condition: - - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``0``. - - Otherwise, if ``side == 'right'``, then - - - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + - If ``side == 'left'``, then ``x1[i-1] < v <= x1[i]``. + - If ``side == 'right'``, then ``x1[i-1] <= v < x1[i]``. Default: ``'left'``. sorter: Optional[array] From 04987212d5a5a17c36b81b6f9978e453a6651063 Mon Sep 17 00:00:00 2001 From: Athan Date: Fri, 21 Feb 2025 18:15:49 -0800 Subject: [PATCH 189/196] feat: add support for integer array indexing PR-URL: https://github.com/data-apis/array-api/pull/900 Closes: https://github.com/data-apis/array-api/issues/669 Co-authored-by: Evgeni Burovski Reviewed-by: Evgeni Burovski Reviewed-by: Stephan Hoyer Reviewed-by: Sebastian Berg Reviewed-by: Aaron Meurer --- spec/draft/API_specification/indexing.rst | 45 ++++++++++++++++++++++ src/array_api_stubs/_draft/array_object.py | 24 +++++++----- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/spec/draft/API_specification/indexing.rst b/spec/draft/API_specification/indexing.rst index eb61c26d5..058003c51 100644 --- a/spec/draft/API_specification/indexing.rst +++ b/spec/draft/API_specification/indexing.rst @@ -7,6 +7,9 @@ Indexing A conforming implementation of the array API standard must adhere to the following conventions. + +.. _indexing-single-axis: + Single-axis Indexing -------------------- @@ -121,6 +124,9 @@ The behavior outside of these bounds is unspecified. .. note:: *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 (consistent with Python* ``list`` *slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +.. _indexing-multi-axis: + Multi-axis Indexing ------------------- @@ -173,6 +179,45 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult *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.* +Integer Array Indexing +---------------------- + +.. note:: + Integer array indexing, as described in this specification, is a reduced subset of "vectorized indexing" semantics, as implemented in libraries such as NumPy. In vectorized indexing, integers and integer arrays are broadcasted to integer arrays having a common shape before being "zipped" together to form a list of index coordinates. This form of indexing diverges from the multi-axis indexing semantics described above (see :ref:`indexing-multi-axis`) where each element of an indexing tuple comprised of integers and slices independently indexes a particular axis. This latter form of indexing is commonly referred to as "orthogonal indexing" and is the default form of indexing outside of Python in languages such as Julia and MATLAB. + +An array must support indexing by an indexing tuple which contains only integers and integer arrays according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S1``. Let ``T`` be a tuple ``(t1, t2, ..., tN)`` having length ``N``. Let ``tk`` be an individual element of ``T``. + +.. note:: + This specification does not currently address indexing tuples which combine slices and integer arrays. Behavior for such indexing tuples is left unspecified and thus implementation-defined. This may be revisited in a future revision of this standard. + +.. note:: + This specification does not currently address indexing tuples which include array-like elements, such as Python lists, tuples, and other sequences. Behavior when indexing an array using array-like elements is left unspecified and thus implementation-defined. + +- If ``tk`` is an integer array, ``tk`` should have the default array index data type (see :ref:`data-type-defaults`). + +.. note:: + Conforming implementations of this standard may support integer arrays having other integer data types; however, consumers of this standard should be aware that integer arrays having uncommon array index data types such as ``int8`` and ``uint8`` may not be widely supported as index arrays across conforming array libraries. To dynamically resolve the default array index data type, including for that of the current device context, use the inspection API ``default_dtypes()``. + +- Providing a zero-dimensional integer array ``tk`` containing an integer index must be equivalent to providing an integer index having the value ``int(tk)``. Conversely, each integer index ``tk`` must be equivalent to a zero-dimensional integer array containing the same value and be treated as such, including shape inference and broadcasting. Accordingly, if ``T`` consists of only integers and zero-dimensional integer arrays, the result must be equivalent to indexing multiple axes using integer indices. For example, if ``A`` is a two-dimensional array, ``T`` is the tuple ``(i, J)``, ``i`` is a valid integer index, and ``J`` is a zero-dimensional array containing a valid integer index ``j``, the result of ``A[T]`` must be equivalent to ``A[(i,j)]`` (see :ref:`indexing-multi-axis`). + +- If ``tk`` is an integer array, each element in ``tk`` must independently satisfy the rules stated above for indexing a single-axis with an integer index (see :ref:`indexing-single-axis`). + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- If ``tk`` is an integer array containing duplicate valid integer indices, the result must include the corresponding elements of ``A`` with the same duplication. + + .. + TODO: once setitem semantics are determined, insert the following note: Given the assignment operation ``x[T] = y[...]``, if ``T`` contains an integer array having duplicate indices, the order in which elements in ``y`` are assigned to the corresponding element(s) in ``x`` is unspecified and thus implementation-defined. + +- If ``T`` contains at least one non-zero-dimensional integer array, all elements of ``T`` must be broadcast against each other to determine a common shape ``S2 = (s1, s2, ..., sN)`` according to standard broadcasting rules (see :ref:`broadcasting`). If one or more elements in ``T`` are not broadcast-compatible with the others, an exception must be raised. + +- After broadcasting elements of ``T`` to a common shape ``S2``, the resulting tuple ``U = (u1, u2, ..., uN)`` must only contain integer arrays having shape ``S2`` (i.e., ``u1 = broadcast_to(t1, S2)``, ``u2 = broadcast_to(t2, S2)``, et cetera). + +- Each element in ``U`` must specify a multi-dimensional index ``v_i = (u1[i], u2[i], ..., uN[i])``, where ``i`` ranges over ``S2``. The result of ``A[U]`` must be constructed by gathering elements from ``A`` at each coordinate tuple ``v_i``. For example, let ``A`` have shape ``(4,4)`` and ``U`` contain integer arrays equivalent to ``([0,1], [2,3])``, with ``u1 = [0,1]`` and ``u2 = [2,3]``. The resulting coordinate tuples must be ``(0,2)`` and ``(1,3)``, respectively, and the resulting array must have shape ``(2,)`` and contain elements ``A[(0,2)]`` and ``A[(1,3)]``. + +- The result of ``A[U]`` must be an array having the broadcasted shape ``S2``. + Boolean Array Indexing ---------------------- diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index ee4c2a0e3..55ef60f07 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -610,7 +610,7 @@ def __getitem__( slice, ellipsis, None, - Tuple[Union[int, slice, ellipsis, None], ...], + Tuple[Union[int, slice, ellipsis, array, None], ...], array, ], /, @@ -618,13 +618,11 @@ def __getitem__( """ Returns ``self[key]``. - See :ref:`indexing` for details on supported indexing semantics. - Parameters ---------- self: array array instance. - key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, array, None], ...], array] index key. Returns @@ -632,8 +630,11 @@ def __getitem__( out: array an array containing the accessed value(s). The returned array must have the same data type as ``self``. - .. note:: - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + Notes + ----- + + - See :ref:`indexing` for details on supported indexing semantics. + - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. """ @@ -1081,7 +1082,7 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: def __setitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array ], value: Union[int, float, complex, bool, array], /, @@ -1089,13 +1090,11 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. - See :ref:`indexing` for details on supported indexing semantics. - Parameters ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array] index key. value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). @@ -1103,6 +1102,11 @@ def __setitem__( Notes ----- + - See :ref:`indexing` for details on supported indexing semantics. + + .. note:: + Indexing semantics when ``key`` is an integer array or a tuple of integers and integer arrays is currently unspecified and thus implementation-defined. This will be revisited in a future revision of this standard. + - Setting array values must not affect the data type of ``self``. - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``complex``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. From 8b0852b4329360a0d8c3398e5ce9932f8fb30dff Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 01:38:24 -0800 Subject: [PATCH 190/196] fix: address typo in return type for `nonzero` PR-URL: https://github.com/data-apis/array-api/pull/904 --- src/array_api_stubs/_2021_12/searching_functions.py | 2 +- src/array_api_stubs/_2022_12/searching_functions.py | 2 +- src/array_api_stubs/_2023_12/searching_functions.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2021_12/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py index ca7d22420..eb615ffed 100644 --- a/src/array_api_stubs/_2021_12/searching_functions.py +++ b/src/array_api_stubs/_2021_12/searching_functions.py @@ -57,7 +57,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. """ diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py index 2d2560502..303ceb8e1 100644 --- a/src/array_api_stubs/_2022_12/searching_functions.py +++ b/src/array_api_stubs/_2022_12/searching_functions.py @@ -73,7 +73,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. Notes diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py index c854a1d98..4888f329e 100644 --- a/src/array_api_stubs/_2023_12/searching_functions.py +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -76,7 +76,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. Notes From 6b8172ea0d154d07f65fd83f97dad9685405c5b6 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 01:49:37 -0800 Subject: [PATCH 191/196] fix: address missing `complex` type in applicable function signatures PR-URL: https://github.com/data-apis/array-api/pull/905 Ref: https://github.com/data-apis/array-api/pull/862 --- src/array_api_stubs/_2022_12/array_object.py | 38 ++++++++++---------- src/array_api_stubs/_2023_12/array_object.py | 35 +++++++++--------- src/array_api_stubs/_draft/array_object.py | 3 ++ 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index 83abc9310..c5bfdf7a3 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -146,7 +146,7 @@ def __abs__(self: array, /) -> array: Added complex data type support. """ - def __add__(self: array, other: Union[int, float, array], /) -> array: + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the sum for each element of an array instance with the respective element of the array ``other``. @@ -154,7 +154,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (augend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -374,7 +374,7 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: ROCM = 10 """ - def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -382,7 +382,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -393,6 +393,9 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __float__(self: array, /) -> float: @@ -746,7 +749,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ - def __mul__(self: array, other: Union[int, float, array], /) -> array: + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. @@ -757,7 +760,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -775,7 +778,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -783,7 +786,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -852,9 +855,6 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. - - .. versionchanged:: 2022.12 - Added complex data type support. """ def __pos__(self: array, /) -> array: @@ -876,7 +876,7 @@ def __pos__(self: array, /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. """ - def __pow__(self: array, other: Union[int, float, array], /) -> array: + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. @@ -889,7 +889,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -933,7 +933,7 @@ def __setitem__( key: Union[ int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array ], - value: Union[int, float, bool, array], + value: Union[int, float, complex, bool, array], /, ) -> None: """ @@ -947,7 +947,7 @@ def __setitem__( array instance. key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] index key. - value: Union[int, float, bool, array] + value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). @@ -960,7 +960,7 @@ def __setitem__( When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. """ - def __sub__(self: array, other: Union[int, float, array], /) -> array: + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the difference for each element of an array instance with the respective element of the array ``other``. @@ -970,7 +970,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (minuend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -988,7 +988,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __truediv__(self: array, other: Union[int, float, array], /) -> array: + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -1001,7 +1001,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index f5cc9bcee..cac44d165 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -148,7 +148,7 @@ def __abs__(self: array, /) -> array: Added complex data type support. """ - def __add__(self: array, other: Union[int, float, array], /) -> array: + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the sum for each element of an array instance with the respective element of the array ``other``. @@ -156,7 +156,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (augend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -494,7 +494,7 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: ONE_API = 14 """ - def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -502,7 +502,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -513,6 +513,9 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __float__(self: array, /) -> float: @@ -893,7 +896,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ - def __mul__(self: array, other: Union[int, float, array], /) -> array: + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. @@ -904,7 +907,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -922,7 +925,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -930,7 +933,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -1024,7 +1027,7 @@ def __pos__(self: array, /) -> array: Added complex data type support. """ - def __pow__(self: array, other: Union[int, float, array], /) -> array: + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. @@ -1037,7 +1040,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1081,7 +1084,7 @@ def __setitem__( key: Union[ int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array ], - value: Union[int, float, bool, array], + value: Union[int, float, complex, bool, array], /, ) -> None: """ @@ -1095,7 +1098,7 @@ def __setitem__( array instance. key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] index key. - value: Union[int, float, bool, array] + value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). @@ -1108,7 +1111,7 @@ def __setitem__( When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. """ - def __sub__(self: array, other: Union[int, float, array], /) -> array: + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the difference for each element of an array instance with the respective element of the array ``other``. @@ -1118,7 +1121,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (minuend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1136,7 +1139,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __truediv__(self: array, other: Union[int, float, array], /) -> array: + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -1149,7 +1152,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 55ef60f07..ba5f99851 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -515,6 +515,9 @@ def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> ar - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __float__(self: array, /) -> float: From c91c82cec0f496372864b55bfe9fed57e73cbfb6 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 03:13:48 -0800 Subject: [PATCH 192/196] docs: add design topic on `copy` keyword argument behavior PR-URL: https://github.com/data-apis/array-api/pull/906 Closes: https://github.com/data-apis/array-api/pull/886 Closes: https://github.com/data-apis/array-api/issues/866 Closes: https://github.com/data-apis/array-api/issues/495 Reviewed-by: Evgeni Burovski --- .../copies_views_and_mutation.rst | 109 +++++++++++------- src/array_api_stubs/_draft/array_object.py | 2 +- .../_draft/creation_functions.py | 2 +- .../_draft/data_type_functions.py | 2 +- .../_draft/manipulation_functions.py | 2 +- 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/spec/draft/design_topics/copies_views_and_mutation.rst b/spec/draft/design_topics/copies_views_and_mutation.rst index 1ca5a039c..f302d8c8e 100644 --- a/spec/draft/design_topics/copies_views_and_mutation.rst +++ b/spec/draft/design_topics/copies_views_and_mutation.rst @@ -1,6 +1,6 @@ .. _copyview-mutability: -Copy-view behaviour and mutability +Copy-view behavior and mutability ================================== .. admonition:: Mutating views @@ -10,11 +10,11 @@ Copy-view behaviour and mutability Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically have the concept of a "view", meaning an array containing data in memory that -belongs to another array (i.e. a different "view" on the original data). -Views are useful for performance reasons - not copying data to a new location -saves memory and is faster than copying - but can also affect the semantics +belongs to another array (i.e., a different "view" on the original data). +Views are useful for performance reasons—not copying data to a new location +saves memory and is faster than copying—but can also affect the semantics of code. This happens when views are combined with *mutating* operations. -This simple example illustrates that: +The following example is illustrative: .. code-block:: python @@ -22,56 +22,81 @@ This simple example illustrates that: y = x[:] # `y` *may* be a view on the data of `x` y -= 1 # if `y` is a view, this modifies `x` -Code as simple as the above example will not be portable between array -libraries - for NumPy/PyTorch/CuPy/MXNet ``x`` will contain the value ``0``, -while for TensorFlow/JAX/Dask it will contain the value ``1``. The combination -of views and mutability is fundamentally problematic here if the goal is to -be able to write code with unambiguous semantics. +Code similar to the above example will not be portable between array +libraries. For example, for NumPy, PyTorch, and CuPy, ``x`` will contain the value ``0``, +while, for TensorFlow, JAX, and Dask, ``x`` will contain the value ``1``. In +this case, the combination of views and mutability is fundamentally problematic +if the goal is to be able to write code with unambiguous semantics. Views are necessary for getting good performance out of the current strided -array libraries. It is not always clear however when a library will return a -view, and when it will return a copy. This API standard does not attempt to -specify this - libraries can do either. +array libraries. It is not always clear, however, when a library will return a +view and when it will return a copy. This standard does not attempt to +specify this—libraries may do either. -There are several types of operations that do in-place mutation of data -contained in arrays. These include: +There are several types of operations that may perform in-place mutation of +array data. These include: -1. Inplace operators (e.g. ``*=``) +1. In-place operators (e.g. ``*=``) 2. Item assignment (e.g. ``x[0] = 1``) 3. Slice assignment (e.g., ``x[:2, :] = 3``) 4. The `out=` keyword present in some strided array libraries (e.g. ``sin(x, out=y)``) -Libraries like TensorFlow and JAX tend to support inplace operators, provide +Libraries such as TensorFlow and JAX tend to support in-place operators by providing alternative syntax for item and slice assignment (e.g. an ``update_index`` -function or ``x.at[idx].set(y)``), and have no need for ``out=``. +function or ``x.at[idx].set(y)``) and have no need for ``out=``. -A potential solution could be to make views read-only, or use copy-on-write -semantics. Both are hard to implement and would present significant issues -for backwards compatibility for current strided array libraries. Read-only -views would also not be a full solution, given that mutating the original -(base) array will also result in ambiguous semantics. Hence this API standard -does not attempt to go down this route. +A potential solution could be to make views read-only or implement copy-on-write +semantics. Both are hard to implement and would present significant backward +compatibility issues for current strided array libraries. Read-only +views would also not be a full solution due to the fact that mutating the original +(base) array will also result in ambiguous semantics. Accordingly, this standard +does not attempt to pursue this solution. -Both inplace operators and item/slice assignment can be mapped onto +Both in-place operators and item/slice assignment can be mapped onto equivalent functional expressions (e.g. ``x[idx] = val`` maps to -``x.at[idx].set(val)``), and given that both inplace operators and item/slice +``x.at[idx].set(val)``), and, given that both in-place operators and item/slice assignment are very widely used in both library and end user code, this standard chooses to include them. -The situation with ``out=`` is slightly different - it's less heavily used, and -easier to avoid. It's also not an optimal API, because it mixes an +The situation with ``out=`` is slightly different—it's less heavily used, and +easier to avoid. It's also not an optimal API because it mixes an "efficiency of implementation" consideration ("you're allowed to do this -inplace") with the semantics of a function ("the output _must_ be placed into -this array). There are libraries that do some form of tracing or abstract -interpretation over a language that does not support mutation (to make -analysis easier); in those cases implementing ``out=`` with correct handling of -views may even be impossible to do. There's alternatives, for example the -donated arguments in JAX or working buffers in LAPACK, that allow the user to -express "you _may_ overwrite this data, do whatever is fastest". Given that -those alternatives aren't widely used in array libraries today, this API -standard chooses to (a) leave out ``out=``, and (b) not specify another method -of reusing arrays that are no longer needed as buffers. - -This leaves the problem of the initial example - with this API standard it -remains possible to write code that will not work the same for all array -libraries. This is something that the user must be careful about. +in-place") with the semantics of a function ("the output _must_ be placed into +this array"). There are libraries that do some form of tracing or abstract +interpretation over a vocabulary that does not support mutation (to make +analysis easier). In those cases implementing ``out=`` with correct handling of +views may even be impossible to do. + +There are alternatives. For example, the concept of donated arguments in JAX or +working buffers in LAPACK which allow the user to express "you _may_ overwrite +this data; do whatever is fastest". Given that those alternatives aren't widely +used in array libraries today, this standard chooses to (a) leave out ``out=``, +and (b) not specify another method of reusing arrays that are no longer needed +as buffers. + +This leaves the problem of the initial example—despite the best efforts of this +standard, it remains possible to write code that will not work the same for all +array libraries. This is something that the users are advised to best keep in +mind and to reason carefully about the potential ambiguity of implemented code. + + +.. _copy-keyword-argument: + +Copy keyword argument behavior +------------------------------ + +Several APIs in this standard support a ``copy`` keyword argument (e.g., +``asarray``, ``astype``, ``reshape``, and ``__dlpack__``). Typically, when a +user sets ``copy=True``, the user does so in order to ensure that they are free +to mutate the returned array without side-effects—namely, without mutating other +views on the original (base) array. Accordingly, when ``copy=True``, unless an +array library can guarantee that an array can be mutated without side-effects, +conforming libraries are recommended to always perform a physical copy of the +underlying array data. + +.. note:: + Typically, in order to provide such a guarantee, libraries must perform + whole-program analysis. + +Conversely, consumers of this standard should expect that, if they set +``copy=True``, they are free to use in-place operations on a returned array. diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index ba5f99851..ca1422bf9 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -370,7 +370,7 @@ def __dlpack__( API standard. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the - function must always copy (performed by the producer). If ``False``, the + function must always copy (performed by the producer; see also :ref:`copy-keyword-argument`). If ``False``, the function must never copy, and raise a ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 6de79268e..c09800783 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -111,7 +111,7 @@ def asarray( device: Optional[device] device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] - boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + boolean indicating whether or not to copy the input. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. Returns ------- diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index db793c16e..d7ae3caee 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -43,7 +43,7 @@ def astype( dtype: dtype desired data type. copy: bool - specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned (see :ref:`copy-keyword-argument`). If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. device: Optional[device] device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 7e94cbc27..1fc178e20 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -230,7 +230,7 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. Returns ------- From 4e402cc917cbe8d096dcb5817e836ce3be7a1e3b Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 03:24:01 -0800 Subject: [PATCH 193/196] docs: add changelog for v2024.12 specification revision PR-URL: https://github.com/data-apis/array-api/pull/903 Reviewed-by: Evgeni Burovski --- CHANGELOG.md | 166 ++++++++++++++++++ src/array_api_stubs/_draft/array_object.py | 25 ++- .../_draft/data_type_functions.py | 9 + .../_draft/elementwise_functions.py | 117 ++++++++++++ src/array_api_stubs/_draft/fft.py | 6 + .../_draft/indexing_functions.py | 8 + src/array_api_stubs/_draft/info.py | 3 + src/array_api_stubs/_draft/linalg.py | 3 + .../_draft/manipulation_functions.py | 3 + .../_draft/searching_functions.py | 10 +- .../_draft/statistical_functions.py | 8 + .../_draft/utility_functions.py | 2 + 12 files changed, 358 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d69bbc23..0919472d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,172 @@ This changelog is organized by specification version and notes all changes with respect to the previous version. Within the section for a specific version (e.g., v2022.12), separate sections are used for (a) changes to existing APIs and requirements, (b) new APIs and new requirements, and (c) errata. +## v2024.12 + +### Updates + +> Updates to existing APIs and requirements. + +#### Normative + +- Clarify that conforming implementations may support additional arguments beyond those described in the Array API specification ([gh-870](https://github.com/data-apis/array-api/pull/870)) +- Clarify accuracy requirements for operations involving complex numbers ([gh-882](https://github.com/data-apis/array-api/pull/882)) +- Clarify expected results for in-place operations in conforming array libraries which do not support array mutation ([gh-895](https://github.com/data-apis/array-api/pull/895)) + +#### APIs + +- `__dlpack__`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `__eq__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__ge__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__getitem__`: clarify that iteration is defined for one-dimensional arrays ([gh-821](https://github.com/data-apis/array-api/pull/821)) +- `__gt__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__le__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__lt__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__ne__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `asarray`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `astype`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `clip`: specify behavior when one of the operands is `NaN` ([gh-813](https://github.com/data-apis/array-api/pull/813); backported to v2023.12 revision of the Array API specification) +- `clip`: clarify behavior when arguments have different data types ([gh-896](https://github.com/data-apis/array-api/pull/896)) +- `conj`: add support for real-valued arrays ([gh-884](https://github.com/data-apis/array-api/pull/884)) +- `cumulative_sum`: clarify that behavior when providing a zero-dimensional array is unspecified ([gh-851](https://github.com/data-apis/array-api/pull/851)) +- `equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `greater`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `greater_equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `less`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `less_equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `mean`: add support for complex floating-point data types ([gh-850](https://github.com/data-apis/array-api/pull/850)) +- `not_equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `real`: add support for real-valued arrays ([gh-884](https://github.com/data-apis/array-api/pull/884)) +- `reshape`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `sqrt`: clarify that results must be correctly rounded according to IEEE 754 ([gh-882](https://github.com/data-apis/array-api/pull/882)) +- `take`: clarify that behavior when provided a zero-dimensional input array is unspecified ([gh-876](https://github.com/data-apis/array-api/pull/876)) +- `take`: clarify support for negative indices ([gh-894](https://github.com/data-apis/array-api/pull/894)) + +##### Scalar Argument Support + +The following APIs were updated to support both scalar and array arguments for one or more arguments: + +- `add` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `atan2` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_and` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_left_shift` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_or` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_right_shift` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_xor` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `copysign` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `divide` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `floor_divide` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `greater` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `greater_equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `hypot` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `less` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `less_equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logaddexp` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logical_and` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logical_or` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logical_xor` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `maximum` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `minimum` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `multiply` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `nextafter` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `not_equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `pow` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `remainder` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `result_type` ([gh-873](https://github.com/data-apis/array-api/pull/873)) +- `subtract` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `where` ([gh-860](https://github.com/data-apis/array-api/pull/860)) + +#### Extensions + +> Updates to APIs and requirements included as part of specification extensions. + +- `fft.fftfreq`: add `dtype` keyword argument ([gh-885](https://github.com/data-apis/array-api/pull/885)) +- `fft.rfftfreq`: add `dtype` keyword argument ([gh-885](https://github.com/data-apis/array-api/pull/885)) + +* * * + +### Additions + +> New APIs and requirements added to the specification. + +#### Normative + +- Add support for integer array indexing ([gh-900](https://github.com/data-apis/array-api/pull/900)) + +#### APIs + +The following APIs were added to the specification: + +- `count_nonzero`: count the number of array elements which are non-zero ([gh-803](https://github.com/data-apis/array-api/pull/803)) +- `cumulative_prod`: calculate the cumulative product ([gh-793](https://github.com/data-apis/array-api/pull/793)) +- `diff`: calculate the n-th discrete forward difference along a specified axis ([gh-791](https://github.com/data-apis/array-api/pull/791), [gh-881](https://github.com/data-apis/array-api/pull/881)) +- `nextafter`: return the next representable floating-point value for each element in an array ([gh-792](https://github.com/data-apis/array-api/pull/792)) +- `reciprocal`: return the reciprocal for each element in an array ([gh-802](https://github.com/data-apis/array-api/pull/802)) +- `take_along_axis`: return elements from an array at locations specified by one-dimensional indices along an axis ([gh-816](https://github.com/data-apis/array-api/pull/816)) + +#### Inspection APIs + +The following inspection APIs were added to the specification: + +- `max dimensions`: return the maximum number of supported dimensions ([gh-763](https://github.com/data-apis/array-api/pull/763) and [gh-809](https://github.com/data-apis/array-api/pull/809)) + +* * * + +### Breaking Changes + +The following is a list of breaking changes relative to the previous version of the specification: + +#### Normative + +- An operation involving a Python `complex` scalar and a real-valued floating-point arrays must be equivalent to an operation involving a zero-dimensional array having a complex floating-point data type and a real-valued floating-point array ([gh-871](https://github.com/data-apis/array-api/pull/871)) + +#### APIs + +- `can_cast`: application of type promotion rules must account for device context ([gh-889](https://github.com/data-apis/array-api/pull/889)) +- `result_type`: application of type promotion rules must account for device context ([gh-889](https://github.com/data-apis/array-api/pull/889)) + +* * * + +### Errata + +The following is a list of fixes and points of clarification with regard to the previous version of the specification: + +- `__add__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__bool__`: fix typo in special case notes ([gh-785](https://github.com/data-apis/array-api/pull/785)) +- `__dlpack__`: resolve conflicting exception guidance ([gh-887](https://github.com/data-apis/array-api/pull/887)) +- `__eq__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__getitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) +- `__mul__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__ne__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__pow__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__setitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) +- `__setitem__`: fix typing for `value` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__sub__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__truediv__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `broadcast_to`: clarify broadcast behavior ([gh-888](https://github.com/data-apis/array-api/pull/888)) +- `broadcast_to`: clarify required exception behavior ([gh-897](https://github.com/data-apis/array-api/pull/897)) +- `clip`: clarify that the operation is only defined when elements in `min` and `max` are inside the bounds of the input array data type ([gh-814](https://github.com/data-apis/array-api/pull/814)) +- `clip`: fix typo in parameter description ([gh-896](https://github.com/data-apis/array-api/pull/896)) +- `copysign`: fix formatting of special cases ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.fft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.ifft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.fftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.ifftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.irfft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.irfftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.hfft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `linalg.solve`: clarify broadcasting semantics and output shape ([gh-810](https://github.com/data-apis/array-api/pull/810)) +- `nonzero`: fix return type ([gh-803](https://github.com/data-apis/array-api/pull/803) and [gh-https://github.com/data-apis/array-api/pull/904](https://github.com/data-apis/array-api/pull/904)) +- `searchsorted`: fix incorrect boundary conditions ([gh-898](https://github.com/data-apis/array-api/pull/898)) +- `sign`: fix equation in function description ([gh-844](https://github.com/data-apis/array-api/pull/844)) +- `tile`: fix missing return type ([gh-798](https://github.com/data-apis/array-api/pull/798)) +- `unstack`: fix typo in function description ([gh-810](https://github.com/data-apis/array-api/pull/810)) +- `vecdot`: fix regression in default value for `axis` keyword argument ([gh-880](https://github.com/data-apis/array-api/pull/880)) +- `where`: clarify that the `condition` argument should have a boolean data type ([gh-868](https://github.com/data-apis/array-api/pull/868)) + +* * * + ## v2023.12 ### Updates diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index ca1422bf9..08d5c0b6e 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -460,10 +460,13 @@ def __dlpack__( Added BufferError. .. versionchanged:: 2023.12 - Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + Added the ``max_version``, ``dl_device``, and ``copy`` keyword arguments. .. versionchanged:: 2023.12 Added recommendation for handling read-only arrays. + + .. versionchanged:: 2024.12 + Resolved conflicting exception guidance. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -518,6 +521,9 @@ def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> ar .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __float__(self: array, /) -> float: @@ -604,6 +610,9 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __getitem__( @@ -639,6 +648,8 @@ def __getitem__( - See :ref:`indexing` for details on supported indexing semantics. - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + .. versionchanged:: 2024.12 + Clarified that iteration is defined for one-dimensional arrays. """ def __gt__(self: array, other: Union[int, float, array], /) -> array: @@ -663,6 +674,9 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __index__(self: array, /) -> int: @@ -784,6 +798,9 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -830,6 +847,9 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __matmul__(self: array, other: array, /) -> array: @@ -955,6 +975,9 @@ def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> ar .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __neg__(self: array, /) -> array: diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index d7ae3caee..7a6c59d94 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -84,6 +84,9 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: - When ``from_`` is a data type, the function must determine whether the data type can be cast to another data type according to the complete type promotion rules (see :ref:`type-promotion`) described in this specification, irrespective of whether a conforming array library supports devices which do not have full data type support. - When ``from_`` is an array, the function must determine whether the data type of the array can be cast to the desired data type according to the type promotion graph of the array device. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the output of ``can_cast(array, dtype)`` may differ from ``can_cast(array.dtype, dtype)``. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. """ @@ -238,4 +241,10 @@ def result_type( - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and thus implementation-dependent. - If at least one argument is an array, the function must determine the resulting dtype according to the type promotion graph of the array device which is shared among all array arguments. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the returned dtype may differ from that determined from the complete type promotion graph defined in this specification (see :ref:`type-promotion`). - If two or more arguments are arrays belonging to different devices, behavior is unspecified and thus implementation-dependent. Conforming implementations may choose to ignore device attributes, raise an exception, or some other behavior. + + .. versionchanged:: 2024.12 + Added scalar argument support. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index a35c04db5..2f0cfc8c3 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -341,6 +341,9 @@ def add( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -573,6 +576,9 @@ def atan2(x1: Union[array, int, float], x2: Union[array, int, float], /) -> arra - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -665,6 +671,9 @@ def bitwise_and(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -688,6 +697,9 @@ def bitwise_left_shift(x1: Union[array, int], x2: Union[array, int], /) -> array ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -727,6 +739,9 @@ def bitwise_or(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> a ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -753,6 +768,9 @@ def bitwise_right_shift(x1: Union[array, int], x2: Union[array, int], /) -> arra ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -776,6 +794,9 @@ def bitwise_xor(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -850,6 +871,15 @@ def clip( - If ``max_i`` is ``NaN``, the result is ``NaN``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added special case behavior when one of the operands is ``NaN``. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when ``x``, ``min``, and ``max`` resolve to arrays having the same data type. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when elements of ``min`` and ``max`` are inside the bounds of the input array data type. """ @@ -885,6 +915,9 @@ def conj(x: array, /) -> array: - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. """ @@ -928,6 +961,9 @@ def copysign(x1: Union[array, int, float], x2: Union[array, int, float], /) -> a - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1124,6 +1160,9 @@ def divide( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1177,6 +1216,12 @@ def equal( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1385,6 +1430,9 @@ def floor_divide( - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1411,6 +1459,11 @@ def greater(x1: Union[array, int, float], x2: Union[array, int, float], /) -> ar - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1438,6 +1491,12 @@ def greater_equal( - At least one of ``x1`` or ``x2`` must be an array. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1486,6 +1545,9 @@ def hypot(x1: Union[array, int, float], x2: Union[array, int, float], /) -> arra Accordingly, conforming implementations may vary in their support for subnormal numbers. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1638,6 +1700,12 @@ def less(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array - At least one of ``x1`` or ``x2`` must be an array. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1663,6 +1731,12 @@ def less_equal(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - At least one of ``x1`` or ``x2`` must be an array. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1902,6 +1976,9 @@ def logaddexp(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1928,6 +2005,9 @@ def logical_and(x1: Union[array, bool], x2: Union[array, bool], /) -> array: ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1973,6 +2053,9 @@ def logical_or(x1: Union[array, bool], x2: Union[array, bool], /) -> array: ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1999,6 +2082,9 @@ def logical_xor(x1: Union[array, bool], x2: Union[array, bool], /) -> array: ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2032,6 +2118,9 @@ def maximum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> ar - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2065,6 +2154,9 @@ def minimum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> ar - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2137,6 +2229,9 @@ def multiply( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2196,6 +2291,8 @@ def nextafter(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``-0``. + + .. versionadded:: 2024.12 """ @@ -2247,6 +2344,12 @@ def not_equal( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2341,6 +2444,9 @@ def pow( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2364,6 +2470,9 @@ def real(x: array, /) -> array: - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. """ @@ -2387,6 +2496,8 @@ def reciprocal(x: array, /) -> array: **Special cases** For floating-point operands, special cases must be handled as if the operation is implemented as ``1.0 / x`` (see :func:`~array_api.divide`). + + .. versionadded:: 2024.12 """ @@ -2442,6 +2553,9 @@ def remainder(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) - In the remaining cases, the result must match that of the Python ``%`` operator. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2796,6 +2910,9 @@ def subtract( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 3d1f4d9c7..0924b2f9c 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -592,6 +592,9 @@ def fftfreq( .. versionchanged:: 2023.12 Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. """ @@ -638,6 +641,9 @@ def rfftfreq( .. versionchanged:: 2023.12 Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. """ diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 8be7cc00e..8e4fae25f 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -34,6 +34,12 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. versionchanged:: 2023.12 Out-of-bounds behavior is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Behavior when provided a zero-dimensional input array is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Clarified support for negative indices. """ @@ -59,4 +65,6 @@ def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: ----- - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + .. versionadded:: 2024.12 """ diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index 6177fb12f..fc8b302a8 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -69,6 +69,9 @@ def capabilities() -> Capabilities: ----- .. versionadded: 2023.12 + + .. versionchanged:: 2024.12 + Added support for querying the maximum number of supported dimensions. """ diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index a43dc8dcf..4086c333e 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -635,6 +635,9 @@ def solve(x1: array, x2: array, /) -> array: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Clarified broadcasting semantics and the shape of the output array. """ diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 1fc178e20..dd8d4cd69 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -50,6 +50,9 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: ------- out: array an array having the specified shape. Must have the same data type as ``x``. + + .. versionchanged:: 2024.12 + Clarified broadcast behavior. """ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index d8676b68b..2478cda11 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -83,6 +83,8 @@ def count_nonzero( - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. versionadded:: 2024.12 """ @@ -162,6 +164,9 @@ def searchsorted( While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Fixed incorrect boundary conditions. """ @@ -195,5 +200,8 @@ def where( - If either ``x1`` or ``x2`` is a scalar value, the returned array must have a data type determined according to :ref:`mixing-scalars-and-arrays`. .. versionchanged:: 2024.12 - Added support for scalar arguments. + Added scalar argument support. + + .. versionchanged:: 2024.12 + Clarified that the ``condition`` argument should have a boolean data type. """ diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 92ffe60c5..d318f6d2a 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -63,6 +63,8 @@ def cumulative_prod( **Special Cases** For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionadded:: 2024.12 """ @@ -117,6 +119,9 @@ def cumulative_sum( For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Behavior when providing a zero-dimensional array is explicitly left unspecified. """ @@ -209,6 +214,9 @@ def mean( .. note:: Array libraries, such as NumPy, PyTorch, and JAX, currently deviate from this specification in their handling of components which are ``NaN`` when computing the arithmetic mean. In general, consumers of array libraries implementing this specification should use :func:`~array_api.isnan` to test whether the result of computing the arithmetic mean over an array have a complex floating-point data type is ``NaN``, rather than relying on ``NaN`` propagation of individual components. + + .. versionchanged:: 2024.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index 7a234efbb..539833356 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -126,4 +126,6 @@ def diff( - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). - If a conforming implementation chooses to support ``prepend`` and ``append`` arrays which have a different data type than ``x``, behavior is unspecified and thus implementation-defined. Implementations may choose to type promote (:ref:`type-promotion`), cast ``prepend`` and/or ``append`` to the same data type as ``x``, or raise an exception. + + .. versionadded:: 2024.12 """ From aa9e0e9be2f1827c027bae1e3fad64d5a6b2a238 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 26 Feb 2025 16:45:22 -0800 Subject: [PATCH 194/196] build: create new release --- LICENSE | 2 +- Makefile | 3 +- .../API_specification/array_object.rst | 322 ++ .../API_specification/broadcasting.rst | 128 + spec/2024.12/API_specification/constants.rst | 26 + .../API_specification/creation_functions.rst | 36 + .../API_specification/data_type_functions.rst | 26 + spec/2024.12/API_specification/data_types.rst | 143 + .../elementwise_functions.rst | 86 + .../function_and_method_signatures.rst | 63 + spec/2024.12/API_specification/index.rst | 41 + spec/2024.12/API_specification/indexing.rst | 253 ++ .../API_specification/indexing_functions.rst | 24 + spec/2024.12/API_specification/inspection.rst | 42 + .../linear_algebra_functions.rst | 23 + .../manipulation_functions.rst | 34 + .../API_specification/searching_functions.rst | 28 + .../API_specification/set_functions.rst | 24 + .../API_specification/sorting_functions.rst | 31 + .../statistical_functions.rst | 29 + .../API_specification/type_promotion.rst | 163 + .../API_specification/utility_functions.rst | 23 + spec/2024.12/API_specification/version.rst | 22 + spec/2024.12/assumptions.md | 77 + spec/2024.12/benchmark_suite.md | 3 + spec/2024.12/changelog.rst | 5 + spec/2024.12/conf.py | 13 + spec/2024.12/design_topics/C_API.rst | 94 + spec/2024.12/design_topics/accuracy.rst | 93 + .../2024.12/design_topics/complex_numbers.rst | 61 + .../copies_views_and_mutation.rst | 102 + .../data_dependent_output_shapes.rst | 15 + .../design_topics/data_interchange.rst | 105 + spec/2024.12/design_topics/device_support.rst | 112 + spec/2024.12/design_topics/exceptions.rst | 28 + spec/2024.12/design_topics/index.rst | 18 + spec/2024.12/design_topics/lazy_eager.rst | 43 + spec/2024.12/design_topics/parallelism.rst | 24 + spec/2024.12/design_topics/static_typing.rst | 50 + .../fourier_transform_functions.rst | 45 + spec/2024.12/extensions/index.rst | 34 + .../extensions/linear_algebra_functions.rst | 116 + spec/2024.12/future_API_evolution.md | 60 + spec/2024.12/index.rst | 37 + spec/2024.12/license.rst | 9 + spec/2024.12/purpose_and_scope.md | 470 +++ spec/2024.12/usage_data.md | 86 + spec/2024.12/use_cases.md | 235 ++ spec/2024.12/verification_test_suite.md | 62 + spec/_ghpages/versions.json | 1 + src/_array_api_conf.py | 2 +- src/array_api_stubs/_2024_12/__init__.py | 25 + src/array_api_stubs/_2024_12/_types.py | 149 + src/array_api_stubs/_2024_12/array_object.py | 1250 +++++++ src/array_api_stubs/_2024_12/constants.py | 30 + .../_2024_12/creation_functions.py | 647 ++++ .../_2024_12/data_type_functions.py | 250 ++ src/array_api_stubs/_2024_12/data_types.py | 22 + .../_2024_12/elementwise_functions.py | 3060 +++++++++++++++++ src/array_api_stubs/_2024_12/fft.py | 707 ++++ .../_2024_12/indexing_functions.py | 70 + src/array_api_stubs/_2024_12/info.py | 203 ++ src/array_api_stubs/_2024_12/linalg.py | 853 +++++ .../_2024_12/linear_algebra_functions.py | 166 + .../_2024_12/manipulation_functions.py | 371 ++ .../_2024_12/searching_functions.py | 207 ++ src/array_api_stubs/_2024_12/set_functions.py | 183 + .../_2024_12/sorting_functions.py | 58 + .../_2024_12/statistical_functions.py | 455 +++ .../_2024_12/utility_functions.py | 131 + src/array_api_stubs/__init__.py | 2 +- 71 files changed, 12407 insertions(+), 4 deletions(-) create mode 100644 spec/2024.12/API_specification/array_object.rst create mode 100644 spec/2024.12/API_specification/broadcasting.rst create mode 100644 spec/2024.12/API_specification/constants.rst create mode 100644 spec/2024.12/API_specification/creation_functions.rst create mode 100644 spec/2024.12/API_specification/data_type_functions.rst create mode 100644 spec/2024.12/API_specification/data_types.rst create mode 100644 spec/2024.12/API_specification/elementwise_functions.rst create mode 100644 spec/2024.12/API_specification/function_and_method_signatures.rst create mode 100644 spec/2024.12/API_specification/index.rst create mode 100644 spec/2024.12/API_specification/indexing.rst create mode 100644 spec/2024.12/API_specification/indexing_functions.rst create mode 100644 spec/2024.12/API_specification/inspection.rst create mode 100644 spec/2024.12/API_specification/linear_algebra_functions.rst create mode 100644 spec/2024.12/API_specification/manipulation_functions.rst create mode 100644 spec/2024.12/API_specification/searching_functions.rst create mode 100644 spec/2024.12/API_specification/set_functions.rst create mode 100644 spec/2024.12/API_specification/sorting_functions.rst create mode 100644 spec/2024.12/API_specification/statistical_functions.rst create mode 100644 spec/2024.12/API_specification/type_promotion.rst create mode 100644 spec/2024.12/API_specification/utility_functions.rst create mode 100644 spec/2024.12/API_specification/version.rst create mode 100644 spec/2024.12/assumptions.md create mode 100644 spec/2024.12/benchmark_suite.md create mode 100644 spec/2024.12/changelog.rst create mode 100644 spec/2024.12/conf.py create mode 100644 spec/2024.12/design_topics/C_API.rst create mode 100644 spec/2024.12/design_topics/accuracy.rst create mode 100644 spec/2024.12/design_topics/complex_numbers.rst create mode 100644 spec/2024.12/design_topics/copies_views_and_mutation.rst create mode 100644 spec/2024.12/design_topics/data_dependent_output_shapes.rst create mode 100644 spec/2024.12/design_topics/data_interchange.rst create mode 100644 spec/2024.12/design_topics/device_support.rst create mode 100644 spec/2024.12/design_topics/exceptions.rst create mode 100644 spec/2024.12/design_topics/index.rst create mode 100644 spec/2024.12/design_topics/lazy_eager.rst create mode 100644 spec/2024.12/design_topics/parallelism.rst create mode 100644 spec/2024.12/design_topics/static_typing.rst create mode 100644 spec/2024.12/extensions/fourier_transform_functions.rst create mode 100644 spec/2024.12/extensions/index.rst create mode 100644 spec/2024.12/extensions/linear_algebra_functions.rst create mode 100644 spec/2024.12/future_API_evolution.md create mode 100644 spec/2024.12/index.rst create mode 100644 spec/2024.12/license.rst create mode 100644 spec/2024.12/purpose_and_scope.md create mode 100644 spec/2024.12/usage_data.md create mode 100644 spec/2024.12/use_cases.md create mode 100644 spec/2024.12/verification_test_suite.md create mode 100644 src/array_api_stubs/_2024_12/__init__.py create mode 100644 src/array_api_stubs/_2024_12/_types.py create mode 100644 src/array_api_stubs/_2024_12/array_object.py create mode 100644 src/array_api_stubs/_2024_12/constants.py create mode 100644 src/array_api_stubs/_2024_12/creation_functions.py create mode 100644 src/array_api_stubs/_2024_12/data_type_functions.py create mode 100644 src/array_api_stubs/_2024_12/data_types.py create mode 100644 src/array_api_stubs/_2024_12/elementwise_functions.py create mode 100644 src/array_api_stubs/_2024_12/fft.py create mode 100644 src/array_api_stubs/_2024_12/indexing_functions.py create mode 100644 src/array_api_stubs/_2024_12/info.py create mode 100644 src/array_api_stubs/_2024_12/linalg.py create mode 100644 src/array_api_stubs/_2024_12/linear_algebra_functions.py create mode 100644 src/array_api_stubs/_2024_12/manipulation_functions.py create mode 100644 src/array_api_stubs/_2024_12/searching_functions.py create mode 100644 src/array_api_stubs/_2024_12/set_functions.py create mode 100644 src/array_api_stubs/_2024_12/sorting_functions.py create mode 100644 src/array_api_stubs/_2024_12/statistical_functions.py create mode 100644 src/array_api_stubs/_2024_12/utility_functions.py diff --git a/LICENSE b/LICENSE index fb491e886..8d3ac90e9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2024 Consortium for Python Data API Standards contributors +Copyright (c) 2020-2025 Consortium for Python Data API Standards contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 51e1fbf76..aa2212611 100644 --- a/Makefile +++ b/Makefile @@ -24,5 +24,6 @@ spec: sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) sphinx-build "$(SOURCEDIR)/2023.12" "$(BUILDDIR)/2023.12" $(SPHINXOPTS) - cp -r "$(BUILDDIR)/2023.12" "$(BUILDDIR)/latest" + sphinx-build "$(SOURCEDIR)/2024.12" "$(BUILDDIR)/2024.12" $(SPHINXOPTS) + cp -r "$(BUILDDIR)/2024.12" "$(BUILDDIR)/latest" sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/spec/2024.12/API_specification/array_object.rst b/spec/2024.12/API_specification/array_object.rst new file mode 100644 index 000000000..e3c7e8ae6 --- /dev/null +++ b/spec/2024.12/API_specification/array_object.rst @@ -0,0 +1,322 @@ +.. _array-object: + +Array object +============ + + Array API specification for array object attributes and methods. + +A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods. + +Furthermore, a conforming implementation of the array API standard must support, at minimum, array objects of rank (i.e., number of dimensions) ``0``, ``1``, ``2``, ``3``, and ``4`` and must explicitly document their maximum supported rank ``N``. + +.. note:: + Conforming implementations must support zero-dimensional arrays. + + Apart from array object attributes, such as ``ndim``, ``device``, and ``dtype``, all operations in this standard return arrays (or tuples of arrays), including those operations, such as ``mean``, ``var``, and ``std``, from which some common array libraries (e.g., NumPy) return scalar values. + + *Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value.* + +------------------------------------------------- + +.. _operators: + +Operators +--------- + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. + +Arithmetic Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. + +- ``+x``: :meth:`.array.__pos__` + + - `operator.pos(x) `_ + - `operator.__pos__(x) `_ + +- `-x`: :meth:`.array.__neg__` + + - `operator.neg(x) `_ + - `operator.__neg__(x) `_ + +- `x1 + x2`: :meth:`.array.__add__` + + - `operator.add(x1, x2) `_ + - `operator.__add__(x1, x2) `_ + +- `x1 - x2`: :meth:`.array.__sub__` + + - `operator.sub(x1, x2) `_ + - `operator.__sub__(x1, x2) `_ + +- `x1 * x2`: :meth:`.array.__mul__` + + - `operator.mul(x1, x2) `_ + - `operator.__mul__(x1, x2) `_ + +- `x1 / x2`: :meth:`.array.__truediv__` + + - `operator.truediv(x1,x2) `_ + - `operator.__truediv__(x1, x2) `_ + +- `x1 // x2`: :meth:`.array.__floordiv__` + + - `operator.floordiv(x1, x2) `_ + - `operator.__floordiv__(x1, x2) `_ + +- `x1 % x2`: :meth:`.array.__mod__` + + - `operator.mod(x1, x2) `_ + - `operator.__mod__(x1, x2) `_ + +- `x1 ** x2`: :meth:`.array.__pow__` + + - `operator.pow(x1, x2) `_ + - `operator.__pow__(x1, x2) `_ + +Arithmetic operators should be defined for arrays having real-valued data types. + +Array Operators +~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. + +- `x1 @ x2`: :meth:`.array.__matmul__` + + - `operator.matmul(x1, x2) `_ + - `operator.__matmul__(x1, x2) `_ + +The matmul ``@`` operator should be defined for arrays having numeric data types. + +Bitwise Operators +~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. + +- `~x`: :meth:`.array.__invert__` + + - `operator.inv(x) `_ + - `operator.invert(x) `_ + - `operator.__inv__(x) `_ + - `operator.__invert__(x) `_ + +- `x1 & x2`: :meth:`.array.__and__` + + - `operator.and(x1, x2) `_ + - `operator.__and__(x1, x2) `_ + +- `x1 | x2`: :meth:`.array.__or__` + + - `operator.or(x1, x2) `_ + - `operator.__or__(x1, x2) `_ + +- `x1 ^ x2`: :meth:`.array.__xor__` + + - `operator.xor(x1, x2) `_ + - `operator.__xor__(x1, x2) `_ + +- `x1 << x2`: :meth:`.array.__lshift__` + + - `operator.lshift(x1, x2) `_ + - `operator.__lshift__(x1, x2) `_ + +- `x1 >> x2`: :meth:`.array.__rshift__` + + - `operator.rshift(x1, x2) `_ + - `operator.__rshift__(x1, x2) `_ + +Bitwise operators should be defined for arrays having integer and boolean data types. + +Comparison Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. + +- `x1 < x2`: :meth:`.array.__lt__` + + - `operator.lt(x1, x2) `_ + - `operator.__lt__(x1, x2) `_ + +- `x1 <= x2`: :meth:`.array.__le__` + + - `operator.le(x1, x2) `_ + - `operator.__le__(x1, x2) `_ + +- `x1 > x2`: :meth:`.array.__gt__` + + - `operator.gt(x1, x2) `_ + - `operator.__gt__(x1, x2) `_ + +- `x1 >= x2`: :meth:`.array.__ge__` + + - `operator.ge(x1, x2) `_ + - `operator.__ge__(x1, x2) `_ + +- `x1 == x2`: :meth:`.array.__eq__` + + - `operator.eq(x1, x2) `_ + - `operator.__eq__(x1, x2) `_ + +- `x1 != x2`: :meth:`.array.__ne__` + + - `operator.ne(x1, x2) `_ + - `operator.__ne__(x1, x2) `_ + +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + +In-place Operators +~~~~~~~~~~~~~~~~~~ + +.. note:: + In-place operations must be supported as discussed in :ref:`copyview-mutability`. + +A conforming implementation of the array API standard must provide and support an array object supporting the following "in-place" Python operators. + +.. note:: + This specification refers to the following operators as "in-place" as that is what these operators are called in `Python `. However, conforming array libraries which do not support array mutation may choose to not explicitly implement in-place Python operators. When a library does not implement a method corresponding to an in-place Python operator, Python falls back to the equivalent method for the corresponding binary arithmetic operation. + +An in-place operation must not change the data type or shape of the in-place array as a result of :ref:`type-promotion` or :ref:`broadcasting`. + +Let ``x1 += x2`` be a representative in-place operation. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands ``x1`` and ``x2``, the resulting data type is equal to the data type of the array on the left-hand side of the operation (i.e., ``x1``), then an in-place operation must have the same behavior (including special cases) as the respective binary (i.e., two operand, non-assignment) operation. In this case, for the in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1[...] = x1 + x2``. + +If, however, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of the array on the left-hand side of the operation, then a conforming implementation may return results which differ from the respective binary operation due to casting behavior and selection of the operation's intermediate precision. The choice of casting behavior and intermediate precision is unspecified and thus implementation-defined. + +.. note:: + Let ``x1`` be the operand on the left-hand side and ``x2`` be the operand on the right-hand side of an in-place operation. Consumers of the array API standard are advised of the following considerations when using in-place operations: + + 1. In-place operations do not guarantee in-place mutation. A conforming library may or may not support in-place mutation. + 2. If, after applying broadcasting (see :ref:`broadcasting`) to in-place operands, the resulting shape is not equal to the shape of ``x1``, in-place operators may raise an exception. + 3. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of ``x1``, the resulting data type may not equal the data type of ``x1`` and the operation's intermediate precision may be that of ``x1``, even if the promoted data type between ``x1`` and ``x2`` would have higher precision. + + In general, for in-place operations, consumers of the array API standard are advised to ensure operands have the same data type and broadcast to the shape of the operand on the left-hand side of the operation in order to maximize portability. + +Arithmetic Operators +"""""""""""""""""""" + +- ``+=``. May be implemented via ``__iadd__``. +- ``-=``. May be implemented via ``__isub__``. +- ``*=``. May be implemented via ``__imul__``. +- ``/=``. May be implemented via ``__itruediv__``. +- ``//=``. May be implemented via ``__ifloordiv__``. +- ``**=``. May be implemented via ``__ipow__``. +- ``%=``. May be implemented via ``__imod__``. + +Array Operators +""""""""""""""" + +- ``@=``. May be implemented via ``__imatmul__``. + +Bitwise Operators +""""""""""""""""" + +- ``&=``. May be implemented via ``__iand__``. +- ``|=``. May be implemented via ``__ior__``. +- ``^=``. May be implemented via ``__ixor__``. +- ``<<=``. May be implemented via ``__ilshift__``. +- ``>>=``. May be implemented via ``__irshift__``. + +Reflected Operators +~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. + +The results of applying reflected operators must match their non-reflected equivalents. + +.. note:: + All operators for which ``array scalar`` is implemented must have an equivalent reflected operator implementation. + +Arithmetic Operators +"""""""""""""""""""" + +- ``__radd__`` +- ``__rsub__`` +- ``__rmul__`` +- ``__rtruediv__`` +- ``__rfloordiv__`` +- ``__rpow__`` +- ``__rmod__`` + +Array Operators +""""""""""""""" + +- ``__rmatmul__`` + +Bitwise Operators +""""""""""""""""" + +- ``__rand__`` +- ``__ror__`` +- ``__rxor__`` +- ``__rlshift__`` +- ``__rrshift__`` + +------------------------------------------------- + +.. currentmodule:: array_api + +Attributes +---------- +.. + NOTE: please keep the attributes in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.dtype + array.device + array.mT + array.ndim + array.shape + array.size + array.T + +------------------------------------------------- + +Methods +------- +.. + NOTE: please keep the methods in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.__abs__ + array.__add__ + array.__and__ + array.__array_namespace__ + array.__bool__ + array.__complex__ + array.__dlpack__ + array.__dlpack_device__ + array.__eq__ + array.__float__ + array.__floordiv__ + array.__ge__ + array.__getitem__ + array.__gt__ + array.__index__ + array.__int__ + array.__invert__ + array.__le__ + array.__lshift__ + array.__lt__ + array.__matmul__ + array.__mod__ + array.__mul__ + array.__ne__ + array.__neg__ + array.__or__ + array.__pos__ + array.__pow__ + array.__rshift__ + array.__setitem__ + array.__sub__ + array.__truediv__ + array.__xor__ + array.to_device diff --git a/spec/2024.12/API_specification/broadcasting.rst b/spec/2024.12/API_specification/broadcasting.rst new file mode 100644 index 000000000..abb3ed222 --- /dev/null +++ b/spec/2024.12/API_specification/broadcasting.rst @@ -0,0 +1,128 @@ +.. _broadcasting: + +Broadcasting +============ + + Array API specification for broadcasting semantics. + +Overview +-------- + +**Broadcasting** refers to the automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +Broadcasting facilitates user ergonomics by encouraging users to avoid unnecessary copying of array data and can **potentially** enable more memory-efficient element-wise operations through vectorization, reduced memory consumption, and cache locality. + +Algorithm +--------- + +Given an element-wise operation involving two compatible arrays, an array having a singleton dimension (i.e., a dimension whose size is one) is broadcast (i.e., virtually repeated) across an array having a corresponding non-singleton dimension. + +If two arrays are of unequal rank, the array having a lower rank is promoted to a higher rank by (virtually) prepending singleton dimensions until the number of dimensions matches that of the array having a higher rank. + +The results of the element-wise operation must be stored in an array having a shape determined by the following algorithm. + +#. Let ``A`` and ``B`` both be arrays. + +#. Let ``shape1`` be a tuple describing the shape of array ``A``. + +#. Let ``shape2`` be a tuple describing the shape of array ``B``. + +#. Let ``N1`` be the number of dimensions of array ``A`` (i.e., the result of ``len(shape1)``). + +#. Let ``N2`` be the number of dimensions of array ``B`` (i.e., the result of ``len(shape2)``). + +#. Let ``N`` be the maximum value of ``N1`` and ``N2`` (i.e., the result of ``max(N1, N2)``). + +#. Let ``shape`` be a temporary list of length ``N`` for storing the shape of the result array. + +#. Let ``i`` be ``N-1``. + +#. Repeat, while ``i >= 0`` + + #. Let ``n1`` be ``N1 - N + i``. + + #. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. + + #. Let ``n2`` be ``N2 - N + i``. + + #. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. + + #. If ``d1 == 1``, then set the ``i``\th element of ``shape`` to ``d2``. + + #. Else, if ``d2 == 1``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, if ``d1 == d2``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, throw an exception. + + #. Set ``i`` to ``i-1``. + +#. Let ``tuple(shape)`` be the shape of the result array. + +Examples +~~~~~~~~ + +The following examples demonstrate the application of the broadcasting algorithm for two compatible arrays. + +:: + + A (4d array): 8 x 1 x 6 x 1 + B (3d array): 7 x 1 x 5 + --------------------------------- + Result (4d array): 8 x 7 x 6 x 5 + A (2d array): 5 x 4 + B (1d array): 1 + ------------------------- + Result (2d array): 5 x 4 + A (2d array): 5 x 4 + B (1d array): 4 + ------------------------- + Result (2d array): 5 x 4 + A (3d array): 15 x 3 x 5 + B (3d array): 15 x 1 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 1 + ------------------------------ + Result (3d array): 15 x 3 x 5 + + +The following examples demonstrate array shapes which do **not** broadcast. + +:: + + A (1d array): 3 + B (1d array): 4 # dimension does not match + + A (2d array): 2 x 1 + B (3d array): 8 x 4 x 3 # second dimension does not match + + A (3d array): 15 x 3 x 5 + B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended + +In-place Semantics +------------------ + +As implied by the broadcasting algorithm, in-place element-wise operations (including ``__setitem__``) must not change the shape of the in-place array as a result of broadcasting. Such operations should only be supported in the case where the right-hand operand can broadcast to the shape of the left-hand operand, after any indexing operations are performed. + +For example: + +:: + + x = empty((2, 3, 4)) + a = empty((1, 3, 4)) + + # This is OK. The shape of a, (1, 3, 4), can broadcast to the shape of x[...], (2, 3, 4) + x[...] = a + + # This is not allowed. The shape of a, (1, 3, 4), can NOT broadcast to the shape of x[1, ...], (3, 4) + x[1, ...] = a diff --git a/spec/2024.12/API_specification/constants.rst b/spec/2024.12/API_specification/constants.rst new file mode 100644 index 000000000..71cb8688d --- /dev/null +++ b/spec/2024.12/API_specification/constants.rst @@ -0,0 +1,26 @@ +Constants +========= + + Array API specification for constants. + +A conforming implementation of the array API standard must provide and support the following constants adhering to the following conventions. + +- Each constant must have a Python floating-point data type (i.e., ``float``) and be provided as a Python scalar value. + +Objects in API +-------------- + +.. currentmodule:: array_api.constants + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + + e + inf + nan + newaxis + pi diff --git a/spec/2024.12/API_specification/creation_functions.rst b/spec/2024.12/API_specification/creation_functions.rst new file mode 100644 index 000000000..ff5c06368 --- /dev/null +++ b/spec/2024.12/API_specification/creation_functions.rst @@ -0,0 +1,36 @@ +Creation Functions +================== + + Array API specification for creating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + arange + asarray + empty + empty_like + eye + from_dlpack + full + full_like + linspace + meshgrid + ones + ones_like + tril + triu + zeros + zeros_like diff --git a/spec/2024.12/API_specification/data_type_functions.rst b/spec/2024.12/API_specification/data_type_functions.rst new file mode 100644 index 000000000..d42968c7b --- /dev/null +++ b/spec/2024.12/API_specification/data_type_functions.rst @@ -0,0 +1,26 @@ +Data Type Functions +=================== + + Array API specification for data type functions. + +A conforming implementation of the array API standard must provide and support the following data type functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + astype + can_cast + finfo + iinfo + isdtype + result_type diff --git a/spec/2024.12/API_specification/data_types.rst b/spec/2024.12/API_specification/data_types.rst new file mode 100644 index 000000000..5987dd322 --- /dev/null +++ b/spec/2024.12/API_specification/data_types.rst @@ -0,0 +1,143 @@ +.. _data-types: + +Data Types +========== + + Array API specification for supported data types. + +A conforming implementation of the array API standard must provide and support +the following data types ("dtypes") in its array object, and as data type +objects in its main namespace under the specified names: + ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| dtype object | description | ++==============+============================================================================================================================================================================================+ +| bool | Boolean (``True`` or ``False``). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int8 | An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int16 | A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int32 | A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int64 | A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint8 | An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint16 | A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint32 | A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint64 | A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float32 | IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float64 | IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex64 | Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex128 | Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Data type objects must have the following methods (no attributes are required): + +.. + NOTE: please keep the functions in alphabetical order + +.. currentmodule:: array_api.data_types + +.. autosummary:: + :toctree: generated + :template: method.rst + + __eq__ + + +.. note:: + A conforming implementation of the array API standard may provide and + support additional data types beyond those described in this specification. + It may also support additional methods and attributes on dtype objects. + +.. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. + + +Use of data type objects +------------------------ + +Data type objects are used as ``dtype`` specifiers in functions and methods +(e.g., ``zeros((2, 3), dtype=float32)``), accessible as ``.dtype`` attribute on +arrays, and used in various casting and introspection functions (e.g., +``isdtype(x.dtype, 'integral')``). + +``dtype`` keywords in functions specify the data type of arrays returned from +functions or methods. ``dtype`` keywords are not required to affect the data +type used for intermediate calculations or results (e.g., implementors are free +to use a higher-precision data type when accumulating values for reductions, as +long as the returned array has the specified data type). + +.. note:: + Implementations may provide other ways to specify data types (e.g., ``zeros((2, 3), dtype='f4')``) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. + +See :ref:`type-promotion` for specification guidance describing the rules governing the interaction of two or more data types or data type objects. + + +.. _data-type-defaults: + +Default Data Types +------------------ + +A conforming implementation of the array API standard must define the following default data types. + +- a default real-valued floating-point data type (either ``float32`` or ``float64``). +- a default complex floating-point data type (either ``complex64`` or ``complex128``). +- a default integer data type (either ``int32`` or ``int64``). +- a default array index data type (either ``int32`` or ``int64``). + +The default real-valued floating-point and complex floating-point data types must be the same across platforms. + +The default complex floating-point point data type should match the default real-valued floating-point data type. For example, if the default real-valued floating-point data type is ``float32``, the default complex floating-point data type must be ``complex64``. If the default real-valued floating-point data type is ``float64``, the default complex floating-point data type must be ``complex128``. + +The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. + +The default array index data type may be ``int32`` on 32-bit platforms, but the default should be ``int64`` otherwise. + +Note that it is possible that a library supports multiple devices, with not all +those device types supporting the same data types. In this case, the default +integer or floating-point data types may vary with device. If that is the case, +the library should clearly warn about this in its documentation. + +.. note:: + The default data types should be clearly defined in a conforming library's documentation. + + +.. _data-type-categories: + +Data Type Categories +-------------------- + +For the purpose of organizing functions within this specification, the following data type categories are defined. + ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| data type category | dtypes | ++============================+========================================================================================================================================================+ +| Numeric | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Floating-point | ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued floating-point | ``float32`` and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Complex floating-point | ``complex64`` and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Boolean | ``bool``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +.. note:: + Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. diff --git a/spec/2024.12/API_specification/elementwise_functions.rst b/spec/2024.12/API_specification/elementwise_functions.rst new file mode 100644 index 000000000..9758c68db --- /dev/null +++ b/spec/2024.12/API_specification/elementwise_functions.rst @@ -0,0 +1,86 @@ +.. _element-wise-functions: + +Element-wise Functions +====================== + + Array API specification for element-wise functions. + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + abs + acos + acosh + add + asin + asinh + atan + atan2 + atanh + bitwise_and + bitwise_left_shift + bitwise_invert + bitwise_or + bitwise_right_shift + bitwise_xor + ceil + clip + conj + copysign + cos + cosh + divide + equal + exp + expm1 + floor + floor_divide + greater + greater_equal + hypot + imag + isfinite + isinf + isnan + less + less_equal + log + log1p + log2 + log10 + logaddexp + logical_and + logical_not + logical_or + logical_xor + maximum + minimum + multiply + negative + nextafter + not_equal + positive + pow + real + reciprocal + remainder + round + sign + signbit + sin + sinh + square + sqrt + subtract + tan + tanh + trunc diff --git a/spec/2024.12/API_specification/function_and_method_signatures.rst b/spec/2024.12/API_specification/function_and_method_signatures.rst new file mode 100644 index 000000000..0eca2ac69 --- /dev/null +++ b/spec/2024.12/API_specification/function_and_method_signatures.rst @@ -0,0 +1,63 @@ +.. _function-and-method-signatures: + +Function and method signatures +============================== + +Function signatures in this standard adhere to the following: + +1. Positional parameters should be `positional-only `_ parameters. + Positional-only parameters have no externally-usable name. When a function + accepting positional-only parameters is called, positional arguments are + mapped to these parameters based solely on their order. + + *Rationale: existing libraries have incompatible conventions, and using names + of positional parameters is not normal/recommended practice.* + + .. note:: + + Positional-only parameters are only available in Python >= 3.8. Libraries + still supporting 3.7 or 3.6 may consider making the API standard-compliant + namespace >= 3.8. Alternatively, they can add guidance to their users in the + documentation to use the functions as if they were positional-only. + +2. Optional parameters should be `keyword-only `_ arguments. + + *Rationale: this leads to more readable code, and it makes it easier to + evolve an API over time by adding keywords without having to worry about + keyword order.* + +3. For functions that have a single positional array parameter, that parameter + is called ``x``. For functions that have multiple array parameters, those + parameters are called ``xi`` with ``i = 1, 2, ...`` (i.e., ``x1``, ``x2``). + +4. Signatures include type annotations. The type annotations are also added to + individual parameter and return value descriptions. For code which aims to + adhere to the standard, adding type annotations is strongly recommended. + +A function signature and description will look like: + +:: + + funcname(x1, x2, /, *, key1=-1, key2=None) -> out: + Parameters + + x1 : array + description + x2 : array + description + key1 : int + description + key2 : Optional[str] + description + + Returns + + out : array + description + + +Method signatures will follow the same conventions modulo the addition of ``self``. + +Note that there are a few exceptions to rules (1) and (2), in cases where +it enhances readability or use of the non-default form of the parameter in +question is commonly used in code written for existing array libraries. diff --git a/spec/2024.12/API_specification/index.rst b/spec/2024.12/API_specification/index.rst new file mode 100644 index 000000000..ffc3d3775 --- /dev/null +++ b/spec/2024.12/API_specification/index.rst @@ -0,0 +1,41 @@ +.. _api-specification: + +API specification +================= + +A conforming implementation of the array API standard must provide and support the APIs and behavior detailed in this specification while adhering to the following conventions. + +- When a function signature includes a `/`, positional parameters must be `positional-only `_ parameters. See :ref:`function-and-method-signatures`. +- When a function signature includes a `*`, optional parameters must be `keyword-only `_ arguments. See :ref:`function-and-method-signatures`. +- Broadcasting semantics must follow the semantics defined in :ref:`broadcasting`. +- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. +- Functions may only be required for a subset of input data types. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in :ref:`accuracy`. + + +.. toctree:: + :caption: API specification + :maxdepth: 3 + + array_object + broadcasting + constants + creation_functions + data_type_functions + data_types + elementwise_functions + function_and_method_signatures + indexing + indexing_functions + inspection + linear_algebra_functions + manipulation_functions + searching_functions + set_functions + sorting_functions + statistical_functions + type_promotion + utility_functions + version diff --git a/spec/2024.12/API_specification/indexing.rst b/spec/2024.12/API_specification/indexing.rst new file mode 100644 index 000000000..058003c51 --- /dev/null +++ b/spec/2024.12/API_specification/indexing.rst @@ -0,0 +1,253 @@ +.. _indexing: + +Indexing +======== + + Array API specification for indexing arrays. + +A conforming implementation of the array API standard must adhere to the following conventions. + + +.. _indexing-single-axis: + +Single-axis Indexing +-------------------- + +To index a single array axis, an array must support standard Python indexing rules. Let ``n`` be the axis (dimension) size. + +- An integer index must be an object satisfying `operator.index `_ (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 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:: + 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]``. + + .. note:: + 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``. + +- Colons ``:`` must be used for `slices `_: ``start:stop:step``, where ``start`` is inclusive and ``stop`` is exclusive. + + .. note:: + The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. + +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``). 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. + +:: + + A[:] + A[i:] + A[:j] + A[i:k] + A[::] + A[i::] + A[:j:] + A[::k] + A[i:j:] + A[i::k] + A[:j:k] + A[i::k] + A[i:j:k] + +.. note:: + Slice syntax can be equivalently achieved using the Python built-in `slice() `_ API. From the perspective of ``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 + +:: + + i, i+k, i+2k, i+3k, ..., i+(m-1)k + +where + +:: + + m = q + r + +and ``q`` and ``r`` (``r != 0``) are the quotient and remainder obtained by dividing ``j-i`` by ``k`` + +:: + + j - i = qk + r + +such that + +:: + + j > i + (m-1)k + +.. note:: + 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:: + 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``. +- 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``. + +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``. + +- 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:: + This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where ``0:100`` and ``0:10`` are equivalent on a list of length ``10``. + +The following ranges for the start and stop values of a slice must be supported. Let ``n`` be the axis (dimension) size being sliced. For a slice ``i:j:k``, the behavior specified above should be implemented for the following: + +- ``i`` or ``j`` omitted (``None``). +- ``-n <= i <= n``. +- For ``k > 0`` or ``k`` omitted (``None``), ``-n <= j <= n``. +- For ``k < 0``, ``-n - 1 <= j <= max(0, n - 1)``. + +The behavior outside of these bounds is unspecified. + +.. note:: + *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 (consistent with Python* ``list`` *slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + + +.. _indexing-multi-axis: + +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``. + +- 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, ``A[(exp1, exp2, ..., expN)]`` is equivalent to ``A[exp1, exp2, ..., expN]``; the latter is syntactic sugar for the former. + + Accordingly, if ``A`` has rank ``1``, then ``A[(2:10,)]`` must be equivalent to ``A[2:10]``. If ``A`` has rank ``2``, then ``A[(2:10, :)]`` must be equivalent to ``A[2:10, :]``. And so on and so forth. + +- 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+i+1``, 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 must 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``. + + .. note:: + When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. + +- Providing a slice must retain array dimensions (i.e., the array rank must remain the same; ``rank(A) == rank(A[:])``). + +- 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 ``IndexError`` exception must be raised if more than one ellipsis is provided. + +- Providing an empty tuple or an ellipsis to an array of rank ``0`` must result in an array of the same rank (i.e., if ``A`` has rank ``0``, ``A == A[()]`` and ``A == A[...]``). + + .. note:: + This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. + +- Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. + + .. note:: + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. + + .. note:: + The constant ``newaxis`` is an alias of ``None`` and can thus be used in a similar manner as ``None``. + +- Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. + + .. note:: + Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. + + To perform flat indexing, use ``reshape(x, (-1,))[integer]``. + +- An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions (excluding ``None``) is greater than ``N``. + + .. 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.* + +Integer Array Indexing +---------------------- + +.. note:: + Integer array indexing, as described in this specification, is a reduced subset of "vectorized indexing" semantics, as implemented in libraries such as NumPy. In vectorized indexing, integers and integer arrays are broadcasted to integer arrays having a common shape before being "zipped" together to form a list of index coordinates. This form of indexing diverges from the multi-axis indexing semantics described above (see :ref:`indexing-multi-axis`) where each element of an indexing tuple comprised of integers and slices independently indexes a particular axis. This latter form of indexing is commonly referred to as "orthogonal indexing" and is the default form of indexing outside of Python in languages such as Julia and MATLAB. + +An array must support indexing by an indexing tuple which contains only integers and integer arrays according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S1``. Let ``T`` be a tuple ``(t1, t2, ..., tN)`` having length ``N``. Let ``tk`` be an individual element of ``T``. + +.. note:: + This specification does not currently address indexing tuples which combine slices and integer arrays. Behavior for such indexing tuples is left unspecified and thus implementation-defined. This may be revisited in a future revision of this standard. + +.. note:: + This specification does not currently address indexing tuples which include array-like elements, such as Python lists, tuples, and other sequences. Behavior when indexing an array using array-like elements is left unspecified and thus implementation-defined. + +- If ``tk`` is an integer array, ``tk`` should have the default array index data type (see :ref:`data-type-defaults`). + +.. note:: + Conforming implementations of this standard may support integer arrays having other integer data types; however, consumers of this standard should be aware that integer arrays having uncommon array index data types such as ``int8`` and ``uint8`` may not be widely supported as index arrays across conforming array libraries. To dynamically resolve the default array index data type, including for that of the current device context, use the inspection API ``default_dtypes()``. + +- Providing a zero-dimensional integer array ``tk`` containing an integer index must be equivalent to providing an integer index having the value ``int(tk)``. Conversely, each integer index ``tk`` must be equivalent to a zero-dimensional integer array containing the same value and be treated as such, including shape inference and broadcasting. Accordingly, if ``T`` consists of only integers and zero-dimensional integer arrays, the result must be equivalent to indexing multiple axes using integer indices. For example, if ``A`` is a two-dimensional array, ``T`` is the tuple ``(i, J)``, ``i`` is a valid integer index, and ``J`` is a zero-dimensional array containing a valid integer index ``j``, the result of ``A[T]`` must be equivalent to ``A[(i,j)]`` (see :ref:`indexing-multi-axis`). + +- If ``tk`` is an integer array, each element in ``tk`` must independently satisfy the rules stated above for indexing a single-axis with an integer index (see :ref:`indexing-single-axis`). + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- If ``tk`` is an integer array containing duplicate valid integer indices, the result must include the corresponding elements of ``A`` with the same duplication. + + .. + TODO: once setitem semantics are determined, insert the following note: Given the assignment operation ``x[T] = y[...]``, if ``T`` contains an integer array having duplicate indices, the order in which elements in ``y`` are assigned to the corresponding element(s) in ``x`` is unspecified and thus implementation-defined. + +- If ``T`` contains at least one non-zero-dimensional integer array, all elements of ``T`` must be broadcast against each other to determine a common shape ``S2 = (s1, s2, ..., sN)`` according to standard broadcasting rules (see :ref:`broadcasting`). If one or more elements in ``T`` are not broadcast-compatible with the others, an exception must be raised. + +- After broadcasting elements of ``T`` to a common shape ``S2``, the resulting tuple ``U = (u1, u2, ..., uN)`` must only contain integer arrays having shape ``S2`` (i.e., ``u1 = broadcast_to(t1, S2)``, ``u2 = broadcast_to(t2, S2)``, et cetera). + +- Each element in ``U`` must specify a multi-dimensional index ``v_i = (u1[i], u2[i], ..., uN[i])``, where ``i`` ranges over ``S2``. The result of ``A[U]`` must be constructed by gathering elements from ``A`` at each coordinate tuple ``v_i``. For example, let ``A`` have shape ``(4,4)`` and ``U`` contain integer arrays equivalent to ``([0,1], [2,3])``, with ``u1 = [0,1]`` and ``u2 = [2,3]``. The resulting coordinate tuples must be ``(0,2)`` and ``(1,3)``, respectively, and the resulting array must have shape ``(2,)`` and contain elements ``A[(0,2)]`` and ``A[(1,3)]``. + +- The result of ``A[U]`` must be an array having the broadcasted shape ``S2``. + +Boolean Array Indexing +---------------------- + +.. admonition:: Data-dependent output shape + :class: admonition important + + For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See :ref:`data-dependent-output-shapes` section for more details. + +An array must support indexing where the **sole index** is an ``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)``. + + .. note:: + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~array_api.expand_dims`. + +- 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:: + 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``) 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``. + +Return Values +------------- + +The result of an indexing operation (e.g., multi-axis indexing, boolean array indexing, etc) must be an array of the same data type as the indexed array. + +.. note:: + The specified return value behavior includes indexing operations which return a single value (e.g., accessing a single element within a one-dimensional array). diff --git a/spec/2024.12/API_specification/indexing_functions.rst b/spec/2024.12/API_specification/indexing_functions.rst new file mode 100644 index 000000000..c13e55ecf --- /dev/null +++ b/spec/2024.12/API_specification/indexing_functions.rst @@ -0,0 +1,24 @@ +.. _indexing-functions: + +Indexing Functions +=================== + + Array API specification for functions for indexing arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + take + take_along_axis diff --git a/spec/2024.12/API_specification/inspection.rst b/spec/2024.12/API_specification/inspection.rst new file mode 100644 index 000000000..89d9c602a --- /dev/null +++ b/spec/2024.12/API_specification/inspection.rst @@ -0,0 +1,42 @@ +.. _inspection: + +Inspection +========== + + Array API specification for namespace inspection utilities. + +A conforming implementation of the array API standard must provide and support the following functions and associated inspection APIs. + + +Objects in API +-------------- + +.. currentmodule:: array_api.info + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + __array_namespace_info__ + + +Inspection APIs +--------------- + +In the namespace (or class) returned by ``__array_namespace_info__``, a conforming implementation of the array API standard must provide and support the following functions (or methods) for programmatically querying data type and device support, capabilities, and other specification-defined implementation-specific behavior, as documented in the functions described below. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + capabilities + default_device + default_dtypes + devices + dtypes diff --git a/spec/2024.12/API_specification/linear_algebra_functions.rst b/spec/2024.12/API_specification/linear_algebra_functions.rst new file mode 100644 index 000000000..04d36f50a --- /dev/null +++ b/spec/2024.12/API_specification/linear_algebra_functions.rst @@ -0,0 +1,23 @@ +Linear Algebra Functions +======================== + + Array API specification for linear algebra functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + matmul + matrix_transpose + tensordot + vecdot diff --git a/spec/2024.12/API_specification/manipulation_functions.rst b/spec/2024.12/API_specification/manipulation_functions.rst new file mode 100644 index 000000000..395c1c3e2 --- /dev/null +++ b/spec/2024.12/API_specification/manipulation_functions.rst @@ -0,0 +1,34 @@ +Manipulation Functions +====================== + + Array API specification for manipulating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + broadcast_arrays + broadcast_to + concat + expand_dims + flip + moveaxis + permute_dims + repeat + reshape + roll + squeeze + stack + tile + unstack diff --git a/spec/2024.12/API_specification/searching_functions.rst b/spec/2024.12/API_specification/searching_functions.rst new file mode 100644 index 000000000..1a584f158 --- /dev/null +++ b/spec/2024.12/API_specification/searching_functions.rst @@ -0,0 +1,28 @@ +.. _searching-functions: + +Searching Functions +=================== + + Array API specification for functions for searching arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argmax + argmin + count_nonzero + nonzero + searchsorted + where diff --git a/spec/2024.12/API_specification/set_functions.rst b/spec/2024.12/API_specification/set_functions.rst new file mode 100644 index 000000000..addf31e1f --- /dev/null +++ b/spec/2024.12/API_specification/set_functions.rst @@ -0,0 +1,24 @@ +Set Functions +============= + + Array API specification for creating and operating on sets. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + unique_all + unique_counts + unique_inverse + unique_values diff --git a/spec/2024.12/API_specification/sorting_functions.rst b/spec/2024.12/API_specification/sorting_functions.rst new file mode 100644 index 000000000..ad3af8857 --- /dev/null +++ b/spec/2024.12/API_specification/sorting_functions.rst @@ -0,0 +1,31 @@ +Sorting Functions +================= + + Array API specification for sorting functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. note:: + + For floating-point input arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. + + Implementations may choose to sort signed zeros (``-0 < +0``) or may choose to rely solely on value equality (``==``). + + Implementations may choose to sort NaNs (e.g., to the end or to the beginning of a returned array) or leave them in-place. Should an implementation sort NaNs, the sorting convention should be clearly documented in the conforming implementation's documentation. + + While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argsort + sort diff --git a/spec/2024.12/API_specification/statistical_functions.rst b/spec/2024.12/API_specification/statistical_functions.rst new file mode 100644 index 000000000..eb5e1a5d6 --- /dev/null +++ b/spec/2024.12/API_specification/statistical_functions.rst @@ -0,0 +1,29 @@ +Statistical Functions +===================== + + Array API specification for statistical functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cumulative_prod + cumulative_sum + max + mean + min + prod + std + sum + var diff --git a/spec/2024.12/API_specification/type_promotion.rst b/spec/2024.12/API_specification/type_promotion.rst new file mode 100644 index 000000000..7a82c763b --- /dev/null +++ b/spec/2024.12/API_specification/type_promotion.rst @@ -0,0 +1,163 @@ +.. _type-promotion: + +Type Promotion Rules +==================== + + Array API specification for type promotion rules. + +Type promotion rules can be understood at a high level from the following diagram: + +.. image:: ../../_static/images/dtype_promotion_lattice.png + :target: Type promotion diagram + +*Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* + +Rules +----- + +A conforming implementation of the array API standard must implement the following type promotion rules governing the common result type for two **array** operands during an arithmetic operation. + +A conforming implementation of the array API standard may support additional type promotion rules beyond those described in this specification. + +.. note:: + Type codes are used here to keep tables readable; they are not part of the standard. In code, use the data type objects specified in :ref:`data-types` (e.g., ``int16`` rather than ``'i2'``). + +.. + Note: please keep table columns aligned + +The following type promotion tables specify the casting behavior for operations involving two array operands. When more than two array operands participate, application of the promotion tables is associative (i.e., the result does not depend on operand order). + +Signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | i1 | i2 | i4 | i8 | ++========+====+====+====+====+ +| **i1** | i1 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i2** | i2 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i4** | i4 | i4 | i4 | i8 | ++--------+----+----+----+----+ +| **i8** | i8 | i8 | i8 | i8 | ++--------+----+----+----+----+ + +where + +- **i1**: 8-bit signed integer (i.e., ``int8``) +- **i2**: 16-bit signed integer (i.e., ``int16``) +- **i4**: 32-bit signed integer (i.e., ``int32``) +- **i8**: 64-bit signed integer (i.e., ``int64``) + +Unsigned integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | u1 | u2 | u4 | u8 | ++========+====+====+====+====+ +| **u1** | u1 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u2** | u2 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u4** | u4 | u4 | u4 | u8 | ++--------+----+----+----+----+ +| **u8** | u8 | u8 | u8 | u8 | ++--------+----+----+----+----+ + +where + +- **u1**: 8-bit unsigned integer (i.e., ``uint8``) +- **u2**: 16-bit unsigned integer (i.e., ``uint16``) +- **u4**: 32-bit unsigned integer (i.e., ``uint32``) +- **u8**: 64-bit unsigned integer (i.e., ``uint64``) + +Mixed unsigned and signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+ +| | u1 | u2 | u4 | ++========+====+====+====+ +| **i1** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i2** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i4** | i4 | i4 | i8 | ++--------+----+----+----+ +| **i8** | i8 | i8 | i8 | ++--------+----+----+----+ + +Floating-point type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++---------+-----+-----+-----+-----+ +| | f4 | f8 | c8 | c16 | ++=========+=====+=====+=====+=====+ +| **f4** | f4 | f8 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **f8** | f8 | f8 | c16 | c16 | ++---------+-----+-----+-----+-----+ +| **c8** | c8 | c16 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **c16** | c16 | c16 | c16 | c16 | ++---------+-----+-----+-----+-----+ + +where + +- **f4**: single-precision (32-bit) floating-point number (i.e., ``float32``) +- **f8**: double-precision (64-bit) floating-point number (i.e., ``float64``) +- **c8**: single-precision complex floating-point number (i.e., ``complex64``) + composed of two single-precision (32-bit) floating-point numbers +- **c16**: double-precision complex floating-point number (i.e., ``complex128``) + composed of two double-precision (64-bit) floating-point numbers + +Notes +~~~~~ + +- Type promotion rules must apply when determining the common result type for two **array** operands during an arithmetic operation, regardless of array dimension. Accordingly, zero-dimensional arrays must be subject to the same type promotion rules as dimensional arrays. +- Type promotion of non-numerical data types to numerical data types is unspecified (e.g., ``bool`` to ``intxx`` or ``floatxx``). + +.. note:: + Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. + + +.. _mixing-scalars-and-arrays: + +Mixing arrays with Python scalars +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using Python scalars (i.e., instances of ``bool``, ``int``, ``float``, ``complex``) together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with the array data type: + +- a Python ``bool`` for a ``bool`` array data type. +- a Python ``int`` within the bounds of the given data type for integer array :ref:`data-types`. +- a Python ``int`` or ``float`` for real-valued floating-point array data types. +- a Python ``int``, ``float``, or ``complex`` for complex floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to a zero-dimensional array with the same data type as that of the array used in the expression. +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +Additionally, using Python ``complex`` scalars together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with a promoted array data type: + +- a Python ``complex`` for real-valued floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to a zero-dimensional array with a complex floating-point array data type having the same precision as that of the array operand used in the expression (e.g., if an array has a ``float32`` data type, the scalar must be converted to a zero-dimensional array having a ``complex64`` data type; if an array has a ``float64`` data type, the scalar must be converted to a zero-dimensional array have a ``complex128`` data type). +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +Behavior is not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. + +Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. + +Behavior is not specified when mixing a Python ``complex`` and an array with an integer data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. diff --git a/spec/2024.12/API_specification/utility_functions.rst b/spec/2024.12/API_specification/utility_functions.rst new file mode 100644 index 000000000..a09c99f79 --- /dev/null +++ b/spec/2024.12/API_specification/utility_functions.rst @@ -0,0 +1,23 @@ +Utility Functions +================= + + Array API specification for utility functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + all + any + diff diff --git a/spec/2024.12/API_specification/version.rst b/spec/2024.12/API_specification/version.rst new file mode 100644 index 000000000..346395d9a --- /dev/null +++ b/spec/2024.12/API_specification/version.rst @@ -0,0 +1,22 @@ +Version +======= + + Array API specification for versioning. + +A conforming implementation of the array API standard must provide a `__array_api_version__` attribute - see :ref:`api-versioning` for details. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + :nosignatures: + + __array_api_version__ diff --git a/spec/2024.12/assumptions.md b/spec/2024.12/assumptions.md new file mode 100644 index 000000000..b11482c5a --- /dev/null +++ b/spec/2024.12/assumptions.md @@ -0,0 +1,77 @@ +(Assumptions)= + +# Assumptions + +## Hardware and software environments + +No assumptions on a specific hardware environment are made. It must be possible +to create an array library adhering to this standard that runs (efficiently) on +a variety of different hardware: CPUs with different architectures, GPUs, +distributed systems and TPUs and other emerging accelerators. + +The same applies to software environments: it must be possible to create an +array library adhering to this standard that runs efficiently independent of +what compilers, build-time or run-time execution environment, or distribution +and install method is employed. Parallel execution, JIT compilation, and +delayed (lazy) evaluation must all be possible. + +The variety of hardware and software environments puts _constraints_ on choices +made in the API standard. For example, JIT compilers may require output dtypes +of functions to be predictable from input dtypes only rather than input values. + + +(assumptions-dependencies)= + +## Dependencies + +The only dependency that's assumed in this standard is that on Python itself. +Python >= 3.8 is assumed, motivated by the use of positional-only parameters +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). + +Importantly, array libraries are not assumed to be aware of each other, or of +a common array-specific layer. The [use cases](use_cases.md) do not require +such a dependency, and building and evolving an array library is easier without +such a coupling. Facilitation support of multiple array types in downstream +libraries is an important use case however, the assumed dependency structure +for that is: + +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) + +Array libraries may know how to interoperate with each other, for example by +constructing their own array type from that of another library or by shared +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). +This can be done without a dependency though - only adherence to a protocol is +enough. + +Array-consuming libraries will have to depend on one or more array libraries. +That could be a "soft dependency" though, meaning retrieving an array library +namespace from array instances that are passed in, but not explicitly doing +`import arraylib_name`. + + +## Backwards compatibility + +The assumption made during creation of this standard is that libraries are +constrained by backwards compatibility guarantees to their users, and are +likely unwilling to make significant backwards-incompatible changes for the +purpose of conforming to this standard. Therefore it is assumed that the +standard will be made available in a new namespace within each library, or the +library will provide a way to retrieve a module or module-like object that +adheres to this standard. See {ref}`how-to-adopt-this-api` for more details. + + +## Production code & interactive use + +It is assumed that the primary use case is writing production code, for example +in array-consuming libraries. As a consequence, making it easy to ensure that +code is written as intended and has unambiguous semantics is preferred - and +clear exceptions must be raised otherwise. + +It is also assumed that this does not significantly detract from the +interactive user experience. However, in case existing libraries differ in +behavior, the more strict version of that behavior is typically preferred. A +good example is array inputs to functions - while NumPy accepts lists, tuples, +generators, and anything else that could be turned into an array, most other +libraries only accept their own array types. This standard follows the latter choice. +It is likely always possible to put a thin "interactive use convenience layer" +on top of a more strict behavior. diff --git a/spec/2024.12/benchmark_suite.md b/spec/2024.12/benchmark_suite.md new file mode 100644 index 000000000..41066c6a4 --- /dev/null +++ b/spec/2024.12/benchmark_suite.md @@ -0,0 +1,3 @@ +# Benchmark suite + +Adding a benchmark suite is planned in the future. diff --git a/spec/2024.12/changelog.rst b/spec/2024.12/changelog.rst new file mode 100644 index 000000000..701a3dbcd --- /dev/null +++ b/spec/2024.12/changelog.rst @@ -0,0 +1,5 @@ +Changelog per API standard version +================================== + +.. include:: ../../CHANGELOG.md + :parser: myst_parser.sphinx_ diff --git a/spec/2024.12/conf.py b/spec/2024.12/conf.py new file mode 100644 index 000000000..dfe216bb5 --- /dev/null +++ b/spec/2024.12/conf.py @@ -0,0 +1,13 @@ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) + +from array_api_stubs import _2024_12 as stubs_mod +from _array_api_conf import * + +release = "2024.12" + +nav_title = html_theme_options.get("nav_title") + " {}".format(release) +html_theme_options.update({"nav_title": nav_title}) +sys.modules["array_api"] = stubs_mod diff --git a/spec/2024.12/design_topics/C_API.rst b/spec/2024.12/design_topics/C_API.rst new file mode 100644 index 000000000..6a44596b0 --- /dev/null +++ b/spec/2024.12/design_topics/C_API.rst @@ -0,0 +1,94 @@ +.. _C-API: + +C API +===== + +Use of a C API is out of scope for this array API, as mentioned in :ref:`Scope`. +There are a lot of libraries that do use such an API - in particular via Cython code +or via direct usage of the NumPy C API. When the maintainers of such libraries +want to use this array API standard to support multiple types of arrays, they +need a way to deal with that issue. This section aims to provide some guidance. + +The assumption in the rest of this section is that performance matters for the library, +and hence the goal is to make other array types work without converting to a +``numpy.ndarray`` or another particular array type. If that's not the case (e.g. for a +visualization package), then other array types can simply be handled by converting +to the supported array type. + +.. note:: + Often a zero-copy conversion to ``numpy.ndarray`` is possible, at least for CPU arrays. + If that's the case, this may be a good way to support other array types. + The main difficulty in that case will be getting the return array type right - however, + this standard does provide a Python-level API for array construction that should allow + doing this. A relevant question is if it's possible to know with + certainty that a conversion will be zero-copy. This may indeed be + possible, see :ref:`data-interchange`. + + +Example situations for C/Cython usage +------------------------------------- + +Situation 1: a Python package that is mostly pure Python, with a limited number of Cython extensions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include Statsmodels, scikit-bio and QuTiP + +Main strategy: documentation. The functionality using Cython code will not support other array types (or only with conversion to/from ``numpy.ndarray``), which can be documented per function. + + +Situation 2: a Python package that contains a lot of Cython code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include scikit-learn and scikit-image + +Main strategy: add support for other array types *per submodule*. This keeps it manageable to explain to the user which functionality does and doesn't have support. + +Longer term: specific support for particular array types (e.g. ``cupy.ndarray`` can be supported with Python-only code via ``cupy.ElementwiseKernel``). + + +Situation 3: a Python package that uses the NumPy or Python C API directly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include SciPy and Astropy + +Strategy: similar to *situation 2*, but the number of submodules that can support all array types may be limited. + + +Device support +-------------- + +Supporting non-CPU array types in code using the C API or Cython seems problematic, +this almost inevitably will require custom device-specific code (e.g., CUDA, ROCm) or +something like JIT compilation with Numba. + + +Other longer-term approaches +---------------------------- + +Further Python API standardization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There may be cases where it makes sense to standardize additional sets of +functions, because they're important enough that array libraries tend to +reimplement them. An example of this may be *special functions*, as provided +by ``scipy.special``. Bessel and gamma functions for example are commonly +reimplemented by array libraries. This may avoid having to drop into a +particular implementation that does use a C API (e.g., one can then rely on +``arraylib.special.gamma`` rather than having to use ``scipy.special.gamma``). + +HPy +~~~ + +`HPy `_ is a new project that will provide a higher-level +C API and ABI than CPython offers. A Cython backend targeting HPy will be provided as well. + +- Better PyPy support +- Universal ABI - single binary for all supported Python versions +- Cython backend generating HPy rather than CPython code + +HPy isn't quite ready for mainstream usage today, but once it is it may +help make supporting multiple array libraries or adding non-CPU device +support to Cython more feasible. diff --git a/spec/2024.12/design_topics/accuracy.rst b/spec/2024.12/design_topics/accuracy.rst new file mode 100644 index 000000000..9d82dbb1f --- /dev/null +++ b/spec/2024.12/design_topics/accuracy.rst @@ -0,0 +1,93 @@ +.. _accuracy: + +Accuracy +======== + + Array API specification for minimum accuracy requirements. + +Arithmetic Operations +--------------------- + +The results of element-wise arithmetic operations + +- ``+`` +- ``-`` +- ``*`` +- ``/`` +- ``%`` + +including the corresponding element-wise array APIs defined in this standard + +- add +- subtract +- multiply +- divide + +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). + +IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, conforming implementations may vary in their support for subnormal numbers. + +Mathematical Functions +---------------------- + +The results of the following functions + +- reciprocal +- sqrt + +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. + +This specification does **not** precisely define the behavior of the following functions + +- acos +- acosh +- asin +- asinh +- atan +- atan2 +- atanh +- cos +- cosh +- exp +- expm1 +- hypot +- log +- log1p +- log2 +- log10 +- logaddexp +- pow +- sin +- sinh +- tan +- tanh + +except to require specific results for certain argument values that represent boundary cases of interest. + +.. note:: + To help readers identify functions lacking precisely defined accuracy behavior, this specification uses the phrase "implementation-dependent approximation" in function descriptions. + +For other argument values, these functions should compute approximations to the results of respective mathematical functions; however, this specification recognizes that array libraries may be constrained by underlying hardware and/or seek to optimize performance over absolute accuracy and, thus, allows some latitude in the choice of approximation algorithms. + +Although the specification leaves the choice of algorithms to the implementation, this specification recommends (but does not specify) that implementations use the approximation algorithms for IEEE 754-2019 arithmetic contained in `FDLIBM `_, the freely distributable mathematical library from Sun Microsystems, or some other comparable IEEE 754-2019 compliant mathematical library. + +.. note:: + With exception of a few mathematical functions, returning results which are indistinguishable from correctly rounded infinitely precise results is difficult, if not impossible, to achieve due to the algorithms involved, the limits of finite-precision, and error propagation. However, this specification recognizes that numerical accuracy alignment among array libraries is desirable in order to ensure portability and reproducibility. Accordingly, for each mathematical function, the specification test suite includes test values which span a function's domain and reports the average and maximum deviation from either a designated standard implementation (e.g., an arbitrary precision arithmetic implementation) or an average computed across a subset of known array library implementations. Such reporting aids users who need to know how accuracy varies among libraries and developers who need to check the validity of their implementations. + +Statistical Functions +--------------------- + +This specification does not specify accuracy requirements for statistical functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +.. note:: + In order for an array library to pass the specification test suite, an array library's statistical function implementations must satisfy certain bare-minimum accuracy requirements (e.g., accurate summation of a small set of positive integers). Unfortunately, imposing more rigorous accuracy requirements is not possible without severely curtailing possible implementation algorithms and unduly increasing implementation complexity. + +Linear Algebra +-------------- + +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +Operations Involving Complex Numbers +------------------------------------ + +This specification does not specify accuracy requirements for arithmetic or functional operations involving complex-valued floating-point operands; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2024.12/design_topics/complex_numbers.rst b/spec/2024.12/design_topics/complex_numbers.rst new file mode 100644 index 000000000..0eca79e91 --- /dev/null +++ b/spec/2024.12/design_topics/complex_numbers.rst @@ -0,0 +1,61 @@ +.. _complex-numbers: + +Complex Numbers +=============== + +The Complex Plane +----------------- + +Mathematically, equality comparison between complex numbers depends on the choice of topology. For example, the complex plane has a continuum of infinities; however, when the complex plane is projected onto the surface of a sphere (a stereographic projection commonly referred to as the *Riemann sphere*), infinities coalesce into a single *point at infinity*, thus modeling the extended complex plane. For the former, the value :math:`\infty + 3j` is distinct from (i.e., does not equal) :math:`\infty + 4j`, while, for the latter, :math:`\infty + 3j` does equal :math:`\infty + 4j`. + +Modeling complex numbers as a Riemann sphere conveys certain mathematical niceties (e.g., well-behaved division by zero and preservation of the identity :math:`\frac{1}{\frac{1}{z}} = z`); however, translating the model to IEEE 754 floating-point operations can lead to some unexpected results. For example, according to IEEE 754, :math:`+\infty` and :math:`-\infty` are distinct values; hence, for equality comparison, if :math:`x = +\infty` and :math:`y = -\infty`, then :math:`x \neq y`. In contrast, if we convert :math:`x` and :math:`y` to their complex number equivalents :math:`x = +\infty + 0j` and :math:`y = -\infty + 0j` and then interpret within the context of the extended complex plane, we arrive at the opposite result; namely, :math:`x = y`. + +In short, given the constraints of floating-point arithmetic and the subtleties of signed zeros, infinities, NaNs, and their interaction, crafting a specification which always yields intuitive results and satisfies all use cases involving complex numbers is not possible. Instead, this specification attempts to follow precedent (e.g., C99, Python, Julia, NumPy, and elsewhere), while also minimizing surprise. The result is an imperfect balance in which certain APIs may appear to embrace the one-infinity model found in C/C++ for algebraic operations involving complex numbers (e.g., considering :math:`\infty + \operatorname{NaN}\ j` to be infinite, irrespective of the imaginary component's value, including NaN), while other APIs may rely on the complex plane with its multiplicity of infinities (e.g., in transcendental functions). Accordingly, consumers of this specification should expect that certain results involving complex numbers for one operation may not be wholly consistent with results involving complex numbers for another operation. + + +.. _branch-cuts: + +Branch Cuts +----------- + +In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. + +For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. + +Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. + +In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. + +.. warning:: + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. + + +.. _complex-number-ordering: + +Complex Number Ordering +----------------------- + +Given a set :math:`\{a_1, \ldots, a_n\}`, an order relation must satisfy the following properties: + +1. **Reflexive**: for any :math:`a` in the set, :math:`a \leq a`. +2. **Transitive**: for any :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`b \leq c`, then :math:`a \leq c`. +3. **Antisymmetric**: for any :math:`a` and :math:`b` in the set, if :math:`a \leq b` and :math:`b \leq a`, then :math:`a = b`. +4. **Total Order**: in addition to the *partial order* established by 1-3, for any :math:`a` and :math:`b` in the set, either :math:`a \leq b` or :math:`b \leq a` (or both). +5. **Compatible with Addition**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b`, then :math:`a + c \leq b + c`. +6. **Compatible with Multiplication**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`0 \leq c`, then :math:`ac \leq bc`. + +Defining an order relation for complex numbers which satisfies all six properties defined above is not possible. Accordingly, this specification does not require that a conforming implementation of the array API standard adopt any specific complex number order relation. + +In order to satisfy backward compatibility guarantees, conforming implementations of the array API standard may choose to define an ordering for complex numbers (e.g., lexicographic); however, consumers of the array API standard should **not** assume that complex number ordering is consistent between implementations or even supported. + +If a conforming implementation chooses to define an ordering for complex numbers, the ordering must be clearly documented. + + +Valued-based Promotion +---------------------- + +According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. + +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/2024.12/design_topics/copies_views_and_mutation.rst b/spec/2024.12/design_topics/copies_views_and_mutation.rst new file mode 100644 index 000000000..f302d8c8e --- /dev/null +++ b/spec/2024.12/design_topics/copies_views_and_mutation.rst @@ -0,0 +1,102 @@ +.. _copyview-mutability: + +Copy-view behavior and mutability +================================== + +.. admonition:: Mutating views + :class: important + + Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may either be a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. + +Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically +have the concept of a "view", meaning an array containing data in memory that +belongs to another array (i.e., a different "view" on the original data). +Views are useful for performance reasons—not copying data to a new location +saves memory and is faster than copying—but can also affect the semantics +of code. This happens when views are combined with *mutating* operations. +The following example is illustrative: + +.. code-block:: python + + x = ones(1) + y = x[:] # `y` *may* be a view on the data of `x` + y -= 1 # if `y` is a view, this modifies `x` + +Code similar to the above example will not be portable between array +libraries. For example, for NumPy, PyTorch, and CuPy, ``x`` will contain the value ``0``, +while, for TensorFlow, JAX, and Dask, ``x`` will contain the value ``1``. In +this case, the combination of views and mutability is fundamentally problematic +if the goal is to be able to write code with unambiguous semantics. + +Views are necessary for getting good performance out of the current strided +array libraries. It is not always clear, however, when a library will return a +view and when it will return a copy. This standard does not attempt to +specify this—libraries may do either. + +There are several types of operations that may perform in-place mutation of +array data. These include: + +1. In-place operators (e.g. ``*=``) +2. Item assignment (e.g. ``x[0] = 1``) +3. Slice assignment (e.g., ``x[:2, :] = 3``) +4. The `out=` keyword present in some strided array libraries (e.g. ``sin(x, out=y)``) + +Libraries such as TensorFlow and JAX tend to support in-place operators by providing +alternative syntax for item and slice assignment (e.g. an ``update_index`` +function or ``x.at[idx].set(y)``) and have no need for ``out=``. + +A potential solution could be to make views read-only or implement copy-on-write +semantics. Both are hard to implement and would present significant backward +compatibility issues for current strided array libraries. Read-only +views would also not be a full solution due to the fact that mutating the original +(base) array will also result in ambiguous semantics. Accordingly, this standard +does not attempt to pursue this solution. + +Both in-place operators and item/slice assignment can be mapped onto +equivalent functional expressions (e.g. ``x[idx] = val`` maps to +``x.at[idx].set(val)``), and, given that both in-place operators and item/slice +assignment are very widely used in both library and end user code, this +standard chooses to include them. + +The situation with ``out=`` is slightly different—it's less heavily used, and +easier to avoid. It's also not an optimal API because it mixes an +"efficiency of implementation" consideration ("you're allowed to do this +in-place") with the semantics of a function ("the output _must_ be placed into +this array"). There are libraries that do some form of tracing or abstract +interpretation over a vocabulary that does not support mutation (to make +analysis easier). In those cases implementing ``out=`` with correct handling of +views may even be impossible to do. + +There are alternatives. For example, the concept of donated arguments in JAX or +working buffers in LAPACK which allow the user to express "you _may_ overwrite +this data; do whatever is fastest". Given that those alternatives aren't widely +used in array libraries today, this standard chooses to (a) leave out ``out=``, +and (b) not specify another method of reusing arrays that are no longer needed +as buffers. + +This leaves the problem of the initial example—despite the best efforts of this +standard, it remains possible to write code that will not work the same for all +array libraries. This is something that the users are advised to best keep in +mind and to reason carefully about the potential ambiguity of implemented code. + + +.. _copy-keyword-argument: + +Copy keyword argument behavior +------------------------------ + +Several APIs in this standard support a ``copy`` keyword argument (e.g., +``asarray``, ``astype``, ``reshape``, and ``__dlpack__``). Typically, when a +user sets ``copy=True``, the user does so in order to ensure that they are free +to mutate the returned array without side-effects—namely, without mutating other +views on the original (base) array. Accordingly, when ``copy=True``, unless an +array library can guarantee that an array can be mutated without side-effects, +conforming libraries are recommended to always perform a physical copy of the +underlying array data. + +.. note:: + Typically, in order to provide such a guarantee, libraries must perform + whole-program analysis. + +Conversely, consumers of this standard should expect that, if they set +``copy=True``, they are free to use in-place operations on a returned array. diff --git a/spec/2024.12/design_topics/data_dependent_output_shapes.rst b/spec/2024.12/design_topics/data_dependent_output_shapes.rst new file mode 100644 index 000000000..43daa9765 --- /dev/null +++ b/spec/2024.12/design_topics/data_dependent_output_shapes.rst @@ -0,0 +1,15 @@ +.. _data-dependent-output-shapes: + +Data-dependent output shapes +============================ + +Array libraries which build computation graphs commonly employ static analysis that relies upon known shapes. For example, JAX requires known array sizes when compiling code, in order to perform static memory allocation. Functions and operations which are value-dependent present difficulties for such libraries, as array sizes cannot be inferred ahead of time without also knowing the contents of the respective arrays. + +While value-dependent functions and operations are not impossible to implement for array libraries which build computation graphs, this specification does not want to impose an undue burden on such libraries and permits omission of value-dependent operations. All other array libraries are expected, however, to implement the value-dependent operations included in this specification in order to be array specification compliant. + +Value-dependent operations are demarcated in this specification using an admonition similar to the following: + +.. admonition:: Data-dependent output shape + :class: important + + The shape of the output array for this function/operation depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function/operation difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. diff --git a/spec/2024.12/design_topics/data_interchange.rst b/spec/2024.12/design_topics/data_interchange.rst new file mode 100644 index 000000000..3b3040672 --- /dev/null +++ b/spec/2024.12/design_topics/data_interchange.rst @@ -0,0 +1,105 @@ +.. _data-interchange: + +Data interchange mechanisms +=========================== + +This section discusses the mechanism to convert one type of array into another. +As discussed in the :ref:`assumptions-dependencies ` section, +*functions* provided by an array library are not expected to operate on +*array types* implemented by another library. Instead, the array can be +converted to a "native" array type. + +The interchange mechanism must offer the following: + +1. Data access via a protocol that describes the memory layout of the array + in an implementation-independent manner. + + *Rationale: any number of libraries must be able to exchange data, and no + particular package must be needed to do so.* + +2. Support for all dtypes in this API standard (see :ref:`data-types`). + +3. Device support. It must be possible to determine on what device the array + that is to be converted lives. + + *Rationale: there are CPU-only, GPU-only, and multi-device array types; + it's best to support these with a single protocol (with separate + per-device protocols it's hard to figure out unambiguous rules for which + protocol gets used, and the situation will get more complex over time + as TPU's and other accelerators become more widely available).* + +4. Zero-copy semantics where possible, making a copy only if needed (e.g. + when data is not contiguous in memory). + + *Rationale: performance.* + +5. A Python-side and a C-side interface, the latter with a stable C ABI. + + *Rationale: all prominent existing array libraries are implemented in + C/C++, and are released independently from each other. Hence a stable C + ABI is required for packages to work well together.* + +DLPack: An in-memory tensor structure +------------------------------------- + +The best candidate for this protocol is +`DLPack `_, and hence that is what this +standard has chosen as the primary/recommended protocol. Note that the +``asarray`` function also supports the Python buffer protocol (CPU-only) to +support libraries that already implement buffer protocol support. + +.. note:: + The main alternatives to DLPack are device-specific methods: + + - The `buffer protocol `_ on CPU + - ``__cuda_array_interface__`` for CUDA, specified in the Numba documentation + `here `_ + (Python-side only at the moment) + + An issue with device-specific protocols are: if two libraries both + support multiple device types, in which order should the protocols be + tried? A growth in the number of protocols to support each time a new + device gets supported by array libraries (e.g. TPUs, AMD GPUs, emerging + hardware accelerators) also seems undesirable. + + In addition to the above argument, it is also clear from adoption + patterns that DLPack has the widest support. The buffer protocol, despite + being a lot older and standardized as part of Python itself via PEP 3118, + hardly has any support from array libraries. CPU interoperability is + mostly dealt with via the NumPy-specific ``__array__`` (which, when called, + means the object it is attached to must return a ``numpy.ndarray`` + containing the data the object holds). + + See the `RFC to adopt DLPack `_ + for discussion that preceded the adoption of DLPack. + +DLPack's documentation can be found at: https://dmlc.github.io/dlpack/latest/. + +The `Python specification of DLPack `__ +page gives a high-level specification for data exchange in Python using DLPack. + +.. note:: + DLPack is a standalone protocol/project and can therefore be used outside of + this standard. Python libraries that want to implement only DLPack support + are recommended to do so using the same syntax and semantics as outlined + below. They are not required to return an array object from ``from_dlpack`` + which conforms to this standard. + +Non-supported use cases +----------------------- + +Use of DLPack requires that the data can be represented by a strided, in-memory +layout on a single device. This covers usage by a large range of, but not all, +known and possible array libraries. Use cases that are not supported by DLPack +include: + +- Distributed arrays, i.e., the data residing on multiple nodes or devices, +- Sparse arrays, i.e., sparse representations where a data value (typically + zero) is implicit. + +There may be other reasons why it is not possible or desirable for an +implementation to materialize the array as strided data in memory. In such +cases, the implementation may raise a `BufferError` in the `__dlpack__` or +`__dlpack_device__` method. In case an implementation is never able to export +its array data via DLPack, it may omit `__dlpack__` and `__dlpack_device__` +completely, and hence `from_dlpack` may raise an `AttributeError`. diff --git a/spec/2024.12/design_topics/device_support.rst b/spec/2024.12/design_topics/device_support.rst new file mode 100644 index 000000000..593b0b9fa --- /dev/null +++ b/spec/2024.12/design_topics/device_support.rst @@ -0,0 +1,112 @@ +.. _device-support: + +Device support +============== + +For libraries that support execution on more than a single hardware device - e.g. CPU and GPU, or multiple GPUs - it is important to be able to control on which device newly created arrays get placed and where execution happens. Attempting to be fully implicit doesn't always scale well to situations with multiple GPUs. + +Existing libraries employ one or more of these three methods to exert such control over data placement: + +1. A global default device, which may be fixed or user-switchable. +2. A context manager to control device assignment within its scope. +3. Local control for data allocation target device via explicit keywords, and a method to transfer arrays to another device. + +Libraries differ in how execution is controlled, via a context manager or with the convention that execution takes place on the same device where all argument arrays are allocated. And they may or may not allow mixing arrays on different devices via implicit data transfers. + +This standard chooses to add support for method 3 (local control), with the convention that execution takes place on the same device where all argument arrays are allocated. The rationale for choosing method 3 is because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see :ref:`device-out-of-scope` for details. + +Intended usage +-------------- + +The intended usage for the device support in the current version of the +standard is *device handling in library code*. The assumed pattern is that +users create arrays (for which they can use all the relevant device syntax +that the library they use provides), and that they then pass those arrays +into library code which may have to do the following: + +- Create new arrays on the same device as an array that's passed in. +- Determine whether two input arrays are present on the same device or not. +- Move an array from one device to another. +- Create output arrays on the same device as the input arrays. +- Pass on a specified device to other library code. + +.. note:: + Given that there is not much that's currently common in terms of + device-related syntax between different array libraries, the syntax included + in the standard is kept as minimal as possible while enabling the + above-listed use cases. + +Syntax for device assignment +---------------------------- + +The array API provides the following syntax for device assignment and +cross-device data transfer: + +1. A ``.device`` property on the array object, which returns a ``Device`` object + representing the device the data in the array is stored on, and supports + comparing devices for equality with ``==`` and ``!=`` within the same library + (e.g., by implementing ``__eq__``); comparing device objects from different + libraries is out of scope). +2. A ``device=None`` keyword for array creation functions, which takes an + instance of a ``Device`` object. +3. A ``.to_device`` method on the array object to copy an array to a different device. + +.. note:: + The current API standard does **not** include a universal ``Device`` object + recognized by all compliant libraries. Accordingly, the standard does not + provide a means of instantiating a ``Device`` object to point to a specific + physical or logical device. + + The choice to not include a standardized ``Device`` object may be revisited + in a future revision of this standard. + + For array libraries which concern themselves with multi-device support, + including CPU and GPU, they are free to expose a library-specific device + object (e.g., for creating an array on a particular device). While a + library-specific device object can be used as input to ``to_device``, beware + that this will mean non-portability as code will be specific to that + library. + +Semantics +--------- + +Handling devices is complex, and some frameworks have elaborate policies for +handling device placement. Therefore this section only gives recommendations, +rather than hard requirements: + +- Respect explicit device assignment (i.e. if the input to the ``device=`` keyword is not ``None``, guarantee that the array is created on the given device, and raise an exception otherwise). +- Preserve device assignment as much as possible (e.g. output arrays from a function are expected to be on the same device as input arrays to the function). +- Raise an exception if an operation involves arrays on different devices (i.e. avoid implicit data transfer between devices). +- Use a default for ``device=None`` which is consistent between functions within the same library. +- If a library has multiple ways of controlling device placement, the most explicit method should have the highest priority. For example: + + 1. If ``device=`` keyword is specified, that always takes precedence + + 2. If ``device=None``, then use the setting from a context manager, if set. + + 3. If no context manager was used, then use the global default device/strategy + +.. _device-out-of-scope: + +Out of scope for device support +------------------------------- + +Individual libraries may offers APIs for one or more of the following topics, +however those are out of scope for this standard: + +- Identifying a specific physical or logical device across libraries +- Setting a default device globally +- Stream/queue control +- Distributed allocation +- Memory pinning +- A context manager for device control + +.. note:: + A context manager for controlling the default device is present in most existing array + libraries (NumPy being the exception). There are concerns with using a + context manager however. A context manager can be tricky to use at a high + level, since it may affect library code below function calls (non-local + effects). See, e.g., `this PyTorch issue `_ + for a discussion on a good context manager API. + + Adding a context manager may be considered in a future version of this API standard. diff --git a/spec/2024.12/design_topics/exceptions.rst b/spec/2024.12/design_topics/exceptions.rst new file mode 100644 index 000000000..570fe56e3 --- /dev/null +++ b/spec/2024.12/design_topics/exceptions.rst @@ -0,0 +1,28 @@ +.. _exceptions: + +Exceptions +========== + +This standard specifies expected syntax and semantics for a set of APIs. When +inputs to an API do not match what is expected, libraries may emit warnings, +raise exceptions, or misbehave in unexpected ways. In general, it is not +possible to foresee or specify all the ways in which unexpected or invalid +inputs are provided. Therefore, this standard does not attempt to specify +exception or warning types to the extent needed in order to do exception +handling in a portable manner. In general, it is expected that array library +implementers follow `the guidance given by the documentation of the Python +language `__, and either use +builtin exception or warning types that are appropriate for the +situation or use custom exceptions or warnings that derive from those builtin +ones. + +In specific cases, it may be useful to provide guidance to array library +authors regarding what an appropriate exception is. That guidance will be +phrased as *should* rather than *must* (typically in a *Raises* section), +because (a) there may be reasons for an implementer to deviate, and (b) more +often than not, existing array library implementation already differ in their +choices, and it may not be worth them breaking backward compatibility in order +to comply with a "must" in this standard. + +In other cases, this standard will only specify that an exception should or +must be raised, but not mention what type of exception that is. diff --git a/spec/2024.12/design_topics/index.rst b/spec/2024.12/design_topics/index.rst new file mode 100644 index 000000000..548eda90c --- /dev/null +++ b/spec/2024.12/design_topics/index.rst @@ -0,0 +1,18 @@ +Design topics & constraints +=========================== + +.. toctree:: + :caption: Design topics & constraints + :maxdepth: 1 + + copies_views_and_mutation + data_dependent_output_shapes + lazy_eager + data_interchange + device_support + static_typing + accuracy + exceptions + complex_numbers + C_API + parallelism diff --git a/spec/2024.12/design_topics/lazy_eager.rst b/spec/2024.12/design_topics/lazy_eager.rst new file mode 100644 index 000000000..63297ac73 --- /dev/null +++ b/spec/2024.12/design_topics/lazy_eager.rst @@ -0,0 +1,43 @@ +.. _lazy-eager: + +Lazy vs. eager execution +======================== + +While the execution model for implementations is out of scope of this standard, +there are a few aspects of lazy (or graph-based) execution as contrasted to +eager execution that may have an impact on the prescribed semantics of +individual APIs, and will therefore show up in the API specification. + +One important difference is data-dependent or value-dependent behavior, as +described in :ref:`data-dependent-output-shapes`. Because such behavior is hard +to implement, implementers may choose to omit such APIs from their library. + +Another difference is when the Python language itself prescribes that a +specific type *must* be returned. For those cases, it is not possible to return +a lazy/delayed kind of object to avoid computing a value. This is the case for +five dunder methods: `__bool__`, `__int__`, `__float__`, `__complex__` and +`__index__`. Each implementation has only two choices when one of these methods +is called: + +1. Compute a value of the required type (a Python scalar of type `bool`, `int`, + `float` or `complex`), or +2. Raise an exception. + +When an implementation is 100% lazy, for example when it serializes a +computation graph, computing the value is not possible and hence such an +implementation has no choice but to raise an exception. For a "mostly lazy" +implementation, it may make sense to trigger execution instead - but it is not +required to, both choices are valid. + +A common code construct where this happens is conditional logic, e.g.:: + + vals = compute_something() + if all(vals): + # The if-statement will make Python call the __bool__ method + # on the result of `all(vals)`. + do_something_else() + +Note that the API does not contain control flow constructs, as of now, that +would allow avoiding the implicit `__bool__` call in the example above. The +only control flow-like function is `where`, but there's no function like `cond` +to replace an `if`-statement. diff --git a/spec/2024.12/design_topics/parallelism.rst b/spec/2024.12/design_topics/parallelism.rst new file mode 100644 index 000000000..f013a9cf9 --- /dev/null +++ b/spec/2024.12/design_topics/parallelism.rst @@ -0,0 +1,24 @@ +Parallelism +=========== + +Parallelism is mostly, but not completely, an execution or runtime concern +rather than an API concern. Execution semantics are out of scope for this API +standard, and hence won't be discussed further here. The API related part +involves how libraries allow users to exercise control over the parallelism +they offer, such as: + +- Via environment variables. This is the method of choice for BLAS libraries and libraries using OpenMP. +- Via a keyword to individual functions or methods. Examples include the ``n_jobs`` keyword used in scikit-learn and the ``workers`` keyword used in SciPy. +- Build-time settings to enable a parallel or distributed backend. +- Via letting the user set chunk sizes. Dask uses this approach. + +When combining multiple libraries, one has to deal with auto-parallelization +semantics and nested parallelism. Two things that could help improve the +coordination of parallelization behavior in a stack of Python libraries are: + +1. A common API pattern for enabling parallelism +2. A common library providing a parallelization layer + +Option (1) may possibly fit in a future version of this array API standard. +`array-api issue 4 `_ contains +more detailed discussion on the topic of parallelism. diff --git a/spec/2024.12/design_topics/static_typing.rst b/spec/2024.12/design_topics/static_typing.rst new file mode 100644 index 000000000..26a1fb901 --- /dev/null +++ b/spec/2024.12/design_topics/static_typing.rst @@ -0,0 +1,50 @@ +Static typing +============= + +Good support for static typing both in array libraries and array-consuming +code is desirable. Therefore the exact type or set of types for each +parameter, keyword and return value is specified for functions and methods - +see :ref:`function-and-method-signatures`. That section specifies arrays +simply as ``array``; what that means is dealt with in this section. + +Introducing type annotations in libraries became more relevant only when +Python 2.7 support was dropped at the start of 2020. As a consequence, using +type annotations with array libraries is largely still a work in progress. +This version of the API standard does not deal with trying to type *array +properties* like shape, dimensionality or dtype, because that's not a solved +problem in individual array libraries yet. + +An ``array`` type annotation can mean either the type of one specific array +object, or some superclass or typing Protocol - as long as it is consistent +with the array object specified in :ref:`array-object`. To illustrate by +example: + +.. code-block:: python + + # `Array` is a particular class in the library + def sin(x: Array, / ...) -> Array: + ... + +and + +.. code-block:: python + + # There's some base class `_BaseArray`, and there may be multiple + # array subclasses inside the library + A = TypeVar('A', bound=_BaseArray) + def sin(x: A, / ...) -> A: + ... + +should both be fine. There may be other variations possible. Also note that +this standard does not require that input and output array types are the same +(they're expected to be defined in the same library though). Given that +array libraries don't have to be aware of other types of arrays defined in +other libraries (see :ref:`assumptions-dependencies`), this should be enough +for a single array library. + +That said, an array-consuming library aiming to support multiple array types +may need more - for example a protocol to enable structural subtyping. This +API standard currently takes the position that it does not provide any +reference implementation or package that can or should be relied on at +runtime, hence no such protocol is defined here. This may be dealt with in a +future version of this standard. diff --git a/spec/2024.12/extensions/fourier_transform_functions.rst b/spec/2024.12/extensions/fourier_transform_functions.rst new file mode 100644 index 000000000..170ae390b --- /dev/null +++ b/spec/2024.12/extensions/fourier_transform_functions.rst @@ -0,0 +1,45 @@ +Fourier transform Functions +=========================== + + Array API specification for Fourier transform functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``fft``. + +If implemented, this ``fft`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'fft'): + >>> # Use `xp.fft` + + +Objects in API +-------------- + +A conforming implementation of this ``fft`` extension must provide and support the following functions. + +.. currentmodule:: array_api.fft + +.. + NOTE: please keep the functions and their inverse together + +.. autosummary:: + :toctree: generated + :template: method.rst + + fft + ifft + fftn + ifftn + rfft + irfft + rfftn + irfftn + hfft + ihfft + fftfreq + rfftfreq + fftshift + ifftshift diff --git a/spec/2024.12/extensions/index.rst b/spec/2024.12/extensions/index.rst new file mode 100644 index 000000000..3b9409954 --- /dev/null +++ b/spec/2024.12/extensions/index.rst @@ -0,0 +1,34 @@ +.. _extensions: + +Extensions +========== + +Extensions are coherent sets of functionality that are commonly implemented +across array libraries. Each array library supporting this standard may, but is +not required to, implement an extension. If an extension is supported, it +must be accessible inside the main array API supporting namespace as a separate +namespace. + +Extension module implementors must aim to provide all functions and other +public objects in an extension. The rationale for this is that downstream usage +can then check whether or not the extension is present (using ``hasattr(xp, +'extension_name')`` should be enough), and can then assume that functions are +implemented. This in turn makes it also easy for array-consuming libraries to +document which array libraries they support - e.g., "all libraries implementing +the array API standard and its linear algebra extension". + +The mechanism through which the extension namespace is made available is up to +the implementer, e.g. via a regular submodule that is imported under the +``linalg`` name, or via a module-level ``__getattr__``. + +The functions in an extension must adhere to the same conventions as those in +the array API standard. See :ref:`api-specification`. + +------------------------------------------------------------------------------ + +.. toctree:: + :caption: Extension modules: + :maxdepth: 1 + + fourier_transform_functions + linear_algebra_functions diff --git a/spec/2024.12/extensions/linear_algebra_functions.rst b/spec/2024.12/extensions/linear_algebra_functions.rst new file mode 100644 index 000000000..938221c79 --- /dev/null +++ b/spec/2024.12/extensions/linear_algebra_functions.rst @@ -0,0 +1,116 @@ +.. _linear-algebra-extension: + +Linear Algebra Extension +======================== + + Array API specification for linear algebra functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``linalg``. + +If implemented, this ``linalg`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'linalg'): + >>> # Use `xp.linalg` + + +Design Principles +----------------- + +A principal goal of this specification is to standardize commonly implemented interfaces among array libraries. While this specification endeavors to avoid straying too far from common practice, this specification does, with due restraint, seek to address design decisions arising more from historical accident than first principles. This is especially true for linear algebra APIs, which have arisen and evolved organically over time and have often been tied to particular underlying implementations (e.g., to BLAS and LAPACK). + +Accordingly, the standardization process affords the opportunity to reduce interface complexity among linear algebra APIs by inferring and subsequently codifying common design themes, thus allowing more consistent APIs. What follows is the set of design principles governing the APIs which follow: + +1. **Batching**: if an operation is explicitly defined in terms of matrices (i.e., two-dimensional arrays), then the associated interface should support "batching" (i.e., the ability to perform the operation over a "stack" of matrices). Example operations include: + + - ``inv``: computing the multiplicative inverse of a square matrix. + - ``cholesky``: performing Cholesky decomposition. + - ``matmul``: performing matrix multiplication. + +2. **Data types**: if an operation requires decimal operations and :ref:`type-promotion` semantics are undefined (e.g., as is the case for mixed-kind promotions), then the associated interface should be specified as being restricted to floating-point data types. While the specification uses the term "SHOULD" rather than "MUST", a conforming implementation of the array API standard should only ignore the restriction provided overly compelling reasons for doing so. Example operations which should be limited to floating-point data types include: + + - ``inv``: computing the multiplicative inverse. + - ``slogdet``: computing the natural logarithm of the absolute value of the determinant. + - ``norm``: computing the matrix or vector norm. + + Certain operations are solely comprised of multiplications and additions. Accordingly, associated interfaces need not be restricted to floating-point data types. However, careful consideration should be given to overflow, and use of floating-point data types may be more prudent in practice. Example operations include: + + - ``matmul``: performing matrix multiplication. + - ``trace``: computing the sum along the diagonal. + - ``cross``: computing the vector cross product. + + Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: + + - ``matrix_transpose``: computing the transpose. + - ``diagonal``: returning the diagonal. + +3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. + + In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: + + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. + +4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. + + Historically, at a time when all array computing happened on CPUs, BLAS and LAPACK underpinned most numerical computing libraries and environments. Naturally, language and library abstractions catered to the parameterization of those libraries, often exposing low-level implementation details verbatim in their higher-level interfaces, even if such choices would be considered poor or ill-advised by today's standards (e.g., NumPy's use of `UPLO` in `eigh`). However, the present day is considerably different. While still important, BLAS and LAPACK no longer hold a monopoly over linear algebra operations, especially given the proliferation of devices and hardware on which such operations must be performed. Accordingly, interfaces must be conservative in the parameterization they support in order to best ensure universality. Such conservatism applies even to performance optimization parameters afforded by certain hardware. + +5. **Orthogonality**: an interface should have clearly defined and delineated functionality which, ideally, has no overlap with the functionality of other interfaces in the specification. Providing multiple interfaces which can all perform the same operation creates unnecessary confusion regarding interface applicability (i.e., which interface is best at which time) and decreases readability of both library and user code. Where overlap is possible, the specification must be parsimonious in the number of interfaces, ensuring that each interface provides a unique and compelling abstraction. Examples of related interfaces which provide distinct levels of abstraction (and generality) include: + + - ``vecdot``: computing the dot product of two vectors. + - ``matmul``: performing matrix multiplication (including between two vectors and thus the dot product). + - ``tensordot``: computing tensor contractions (generalized sum-products). + - ``einsum``: expressing operations in terms of Einstein summation convention, including dot products and tensor contractions. + + The above can be contrasted with, e.g., NumPy, which provides the following interfaces for computing the dot product or related operations: + + - ``dot``: dot product, matrix multiplication, and tensor contraction. + - ``inner``: dot product. + - ``vdot``: dot product with flattening and complex conjugation. + - ``multi_dot``: chained dot product. + - ``tensordot``: tensor contraction. + - ``matmul``: matrix multiplication (dot product for two vectors). + - ``einsum``: Einstein summation convention. + + where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. + +.. currentmodule:: array_api.linalg + +Objects in API +-------------- + +A conforming implementation of this ``linalg`` extension must provide and support the following functions. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cholesky + cross + det + diagonal + eigh + eigvalsh + inv + matmul + matrix_norm + matrix_power + matrix_rank + matrix_transpose + outer + pinv + qr + slogdet + solve + svd + svdvals + tensordot + trace + vecdot + vector_norm diff --git a/spec/2024.12/future_API_evolution.md b/spec/2024.12/future_API_evolution.md new file mode 100644 index 000000000..443f683d5 --- /dev/null +++ b/spec/2024.12/future_API_evolution.md @@ -0,0 +1,60 @@ +(future-API-evolution)= + +# Future API standard evolution + +## Scope extensions + +Proposals for scope extensions in a future version of the API standard will follow +the process documented at https://github.com/data-apis/governance/blob/master/process_document.md + +In summary, proposed new APIs go through several maturity stages, and will only be +accepted in a future version of this API standard once they have reached the "Final" +maturity stage, which means multiple array libraries have compliant implementations +and real-world experience from use of those implementations is available. + + +## Backwards compatibility + +Functions, objects, keywords and specified behavior are added to this API standard +only if those are already present in multiple existing array libraries, and if there is +data that those APIs are used. Therefore it is highly unlikely that future versions +of this standard will make backwards-incompatible changes. + +The aim is for future versions to be 100% backwards compatible with older versions. +Any exceptions must have strong rationales and be clearly documented in the updated +API specification. + + +(api-versioning)= + +## Versioning + +This API standard uses the following versioning scheme: + +- The version is date-based, in the form `yyyy.mm` (e.g., `2020.12`). +- The version shall not include a standard way to do `alpha`/`beta`/`rc` or + `.post`/`.dev` type versions. + _Rationale: that's for Python packages, not for a standard._ +- The version must be made available at runtime via an attribute + `__array_api_version__` by a compliant implementation, in `'yyyy.mm'` format + as a string, in the namespace that implements the API standard. + _Rationale: dunder version strings are the standard way of doing this._ + +No utilities for dealing with version comparisons need to be provided; given +the format simple string comparisons with Python operators (`=-`, `<`, `>=`, +etc.) will be enough. + +```{note} + +Rationale for the `yyyy.mm` versioning scheme choice: +the API will be provided as part of a library, which already has a versioning +scheme (typically PEP 440 compliant and in the form `major.minor.bugfix`), +and a way to access it via `module.__version__`. The API standard version is +completely independent from the package version. Given the standardization +process, it resembles a C/C++ versioning scheme (e.g. `C99`, `C++14`) more +than Python package versioning. +``` + +The frequency of releasing a new version of an API standard will likely be at +regular intervals and on the order of one year, however no assumption on +frequency of new versions appearing must be made. diff --git a/spec/2024.12/index.rst b/spec/2024.12/index.rst new file mode 100644 index 000000000..3e51cc68e --- /dev/null +++ b/spec/2024.12/index.rst @@ -0,0 +1,37 @@ +Python array API standard +========================= + +Contents +-------- + +.. toctree:: + :caption: Context + :maxdepth: 1 + + purpose_and_scope + use_cases + assumptions + +.. toctree:: + :caption: API + :maxdepth: 1 + + design_topics/index + future_API_evolution + API_specification/index + extensions/index + +.. toctree:: + :caption: Methodology and Usage + :maxdepth: 1 + + usage_data + verification_test_suite + benchmark_suite + +.. toctree:: + :caption: Other + :maxdepth: 1 + + changelog + license diff --git a/spec/2024.12/license.rst b/spec/2024.12/license.rst new file mode 100644 index 000000000..06ec75dfc --- /dev/null +++ b/spec/2024.12/license.rst @@ -0,0 +1,9 @@ +License +======= + +All content on this website and the corresponding +`GitHub repository `__ is licensed +under the following license: + + .. include:: ../../LICENSE + :parser: myst_parser.sphinx_ diff --git a/spec/2024.12/purpose_and_scope.md b/spec/2024.12/purpose_and_scope.md new file mode 100644 index 000000000..b2019b7dd --- /dev/null +++ b/spec/2024.12/purpose_and_scope.md @@ -0,0 +1,470 @@ +# Purpose and scope + +## Introduction + +Python users have a wealth of choice for libraries and frameworks for +numerical computing, data science, machine learning, and deep learning. New +frameworks pushing forward the state of the art in these fields are appearing +every year. One unintended consequence of all this activity and creativity +has been fragmentation in multidimensional array (a.k.a. tensor) libraries - +which are the fundamental data structure for these fields. Choices include +NumPy, Tensorflow, PyTorch, Dask, JAX, CuPy, MXNet, Xarray, and others. + +The APIs of each of these libraries are largely similar, but with enough +differences that it's quite difficult to write code that works with multiple +(or all) of these libraries. This array API standard aims to address that +issue, by specifying an API for the most common ways arrays are constructed +and used. + +Why not simply pick an existing API and bless that as the standard? In short, +because there are often good reasons for the current inconsistencies between +libraries. The most obvious candidate for that existing API is NumPy. However +NumPy was not designed with non-CPU devices, graph-based libraries, or JIT +compilers in mind. Other libraries often deviate from NumPy for good +(necessary) reasons. Choices made in this API standard are often the same +ones NumPy makes, or close to it, but are different where necessary to make +sure all existing array libraries can adopt this API. + + +### This API standard + +This document aims to standardize functionality that exists in most/all array +libraries and either is commonly used or is needed for +consistency/completeness. Usage is determined via analysis of downstream +libraries, see {ref}`usage-data`. An example of consistency is: there are +functional equivalents for all Python operators (including the rarely used +ones). + +Beyond usage and consistency, there's a set of use cases that inform the API +design to ensure it's fit for a wide range of users and situations - see +{ref}`use-cases`. + +A question that may arise when reading this document is: _"what about +functionality that's not present in this document?_ This: + +- means that there is no guarantee the functionality is present in libraries + adhering to the standard +- does _not_ mean that that functionality is unimportant +- may indicate that that functionality, if present in a particular array + library, is unlikely to be present in all other libraries + +### History + +The first library for numerical and scientific computing in Python was +Numeric, developed in the mid-1990s. In the early 2000s a second, similar +library, Numarray, was created. In 2005 NumPy was written, superceding both +Numeric and Numarray and resolving the fragmentation at that time. For +roughly a decade, NumPy was the only widely used array library. Over the past +~5 years, mainly due to the emergence of new hardware and the rise of deep +learning, many other libraries have appeared, leading to more severe +fragmentation. Concepts and APIs in newer libraries were often inspired by +(or copied from) those in older ones - and then changed or improved upon to +fit new needs and use cases. Individual library authors discussed ideas, +however there was never (before this array API standard) a serious attempt +to coordinate between all libraries to avoid fragmentation and arrive at a +common API standard. + +The idea for this array API standard grew gradually out of many conversations +between maintainers during 2019-2020. It quickly became clear that any +attempt to write a new "reference library" to fix the current fragmentation +was infeasible - unlike in 2005, there are now too many different use cases +and too many stakeholders, and the speed of innovation is too high. In May +2020 an initial group of maintainers was assembled in the [Consortium for +Python Data API Standards](https://data-apis.org/) to start drafting a +specification for an array API that could be adopted by each of the existing +array and tensor libraries. That resulted in this document, describing that +API. + + +(Scope)= + +## Scope (includes out-of-scope / non-goals) + +This section outlines what is in scope and out of scope for this API standard. + +### In scope + +The scope of the array API standard includes: + +- Functionality which needs to be included in an array library for it to adhere + to this standard. +- Names of functions, methods, classes and other objects. +- Function signatures, including type annotations. +- Semantics of functions and methods. I.e. expected outputs including precision + for and dtypes of numerical results. +- Semantics in the presence of `nan`'s, `inf`'s, empty arrays (i.e. arrays + including one or more dimensions of size `0`). +- Casting rules, broadcasting, indexing +- Data interchange. I.e. protocols to convert one type of array into another + type, potentially sharing memory. +- Device support. + +Furthermore, meta-topics included in this standard include: + +- Use cases for the API standard and assumptions made in it +- API standard adoption +- API standard versioning +- Future API standard evolution +- Array library and API standard versioning +- Verification of API standard conformance + +The concrete set of functionality that is in scope for this version of the +standard is shown in this diagram: + +![Scope of array API](../_static/images/scope_of_array_API.png) + + +**Goals** for the API standard include: + +- Make it possible for array-consuming libraries to start using multiple types + of arrays as inputs. +- Enable more sharing and reuse of code built on top of the core functionality + in the API standard. +- For authors of new array libraries, provide a concrete API that can be + adopted as is, rather than each author having to decide what to borrow from + where and where to deviate. +- Make the learning curve for users less steep when they switch from one array + library to another one. + + +### Out of scope + +1. Implementations of the standard are out of scope. + + _Rationale: the standard will consist of a document and an accompanying test + suite with which the conformance of an implementation can be verified. Actual + implementations will live in array libraries; no reference implementation is + planned._ + +2. Execution semantics are out of scope. This includes single-threaded vs. + parallel execution, task scheduling and synchronization, eager vs. delayed + evaluation, performance characteristics of a particular implementation of the + standard, and other such topics. + + _Rationale: execution is the domain of implementations. Attempting to specify + execution behavior in a standard is likely to require much more fine-grained + coordination between developers of implementations, and hence is likely to + become an obstacle to adoption._ + +3. Non-Python API standardization (e.g., Cython or NumPy C APIs) + + _Rationale: this is an important topic for some array-consuming libraries, + but there is no widely shared C/Cython API and hence it doesn't make sense at + this point in time to standardize anything. See + the [C API section](design_topics/C_API.rst) for more details._ + +4. Standardization of these dtypes is out of scope: bfloat16, extended + precision floating point, datetime, string, object and void dtypes. + + _Rationale: these dtypes aren't uniformly supported, and their inclusion at + this point in time could put a significant implementation burden on + libraries. It is expected that some of these dtypes - in particular + `bfloat16` - will be included in a future version of the standard._ + +5. The following topics are out of scope: I/O, polynomials, error handling, + testing routines, building and packaging related functionality, methods of + binding compiled code (e.g., `cffi`, `ctypes`), subclassing of an array + class, masked arrays, and missing data. + + _Rationale: these topics are not core functionality for an array library, + and/or are too tied to implementation details._ + +6. NumPy (generalized) universal functions, i.e. ufuncs and gufuncs. + + _Rationale: these are NumPy-specific concepts, and are mostly just a + particular way of building regular functions with a few extra + methods/properties._ + +7. Behaviour for unexpected/invalid input to functions and methods. + + _Rationale: there are a huge amount of ways in which users can provide + invalid or unspecified input to functionality in the standard. Exception + types or other resulting behaviour cannot be completely covered and would + be hard to make consistent between libraries._ + + +**Non-goals** for the API standard include: + +- Making array libraries identical so they can be merged. + + _Each library will keep having its own particular strength, whether it's + offering functionality beyond what's in the standard, performance advantages + for a given use case, specific hardware or software environment support, or + more._ + +- Implement a backend or runtime switching system to be able to switch from one + array library to another with a single setting or line of code. + + _This may be feasible, however it's assumed that when an array-consuming + library switches from one array type to another, some testing and possibly + code adjustment for performance or other reasons may be needed._ + +- Making it possible to mix multiple array libraries in function calls. + + _Most array libraries do not know about other libraries, and the functions + they implement may try to convert "foreign" input, or raise an exception. + This behaviour is hard to specify; ensuring only a single array type is + used is best left to the end user._ + + +### Implications of in/out of scope + +If something is out of scope and therefore will not be part of (the current +version of) the API standard, that means that there are no guarantees that that +functionality works the same way, or even exists at all, across the set of +array libraries that conform to the standard. It does _not_ imply that this +functionality is less important or should not be used. + + +## Stakeholders + +Arrays are fundamental to scientific computing, data science, and machine +learning and deep learning. Hence there are many stakeholders for an array API +standard. The _direct_ stakeholders of this standard are **authors/maintainers of +Python array libraries**. There are many more types of _indirect_ stakeholders +though, including: + +- maintainers of libraries and other programs which depend on array libraries + (called "array-consuming libraries" in the rest of this document) +- authors of non-Python array libraries +- developers of compilers and runtimes with array-specific functionality +- end users + +Libraries that are being actively considered - in terms of current behaviour and +API surface - during the creation of the first version of this standard +include: + +- [NumPy](https://numpy.org) +- [TensorFlow](https://www.tensorflow.org/) +- [PyTorch](https://pytorch.org/) +- [MXNet](https://numpy.mxnet.io/) +- [JAX](https://github.com/google/jax) +- [Dask](https://dask.org/) +- [CuPy](https://cupy.chainer.org/) + +Other Python array libraries that are currently under active development and +could adopt this API standard include: + +- [xarray](https://xarray.pydata.org/) +- [PyData/Sparse](https://sparse.pydata.org) +- [Weld](https://github.com/weld-project/weld) +- [Bohrium](https://bohrium.readthedocs.io/) +- [Arkouda](https://github.com/mhmerrill/arkouda) +- [Legate](https://research.nvidia.com/publication/2019-11_Legate-NumPy%3A-Accelerated) + +There are a huge amount of array-consuming libraries; some of the most +prominent ones that are being taken into account - in terms of current array +API usage or impact of design decisions on them - include (this list is likely +to grow it over time): + +- [Pandas](https://pandas.pydata.org/) +- [SciPy](https://github.com/scipy/scipy) +- [scikit-learn](https://scikit-learn.org/) +- [Matplotlib](https://matplotlib.org/) +- [scikit-image](https://scikit-image.org/) +- [NetworkX](https://networkx.github.io/) + +Array libraries in other languages, some of which may grow a Python API in the +future or have taken inspiration from NumPy or other array libraries, include: + +- [Xtensor](https://xtensor.readthedocs.io) (C++, cross-language) +- [XND](https://xnd.io/) (C, cross-language) +- [stdlib](https://stdlib.io/) (JavaScript) +- [rust-ndarray](https://github.com/rust-ndarray/ndarray) (Rust) +- [rray](https://github.com/r-lib/rray) (R) +- [ND4J](https://github.com/deeplearning4j/nd4j) (JVM) +- [NumSharp](https://github.com/SciSharp/NumSharp) (C#) + +Compilers, runtimes, and dispatching layers for which this API standard may be +relevant: + +- [Cython](https://cython.org/) +- [Numba](http://numba.pydata.org/) +- [Pythran](https://pythran.readthedocs.io/en/latest/) +- [Transonic](https://transonic.readthedocs.io) +- [ONNX](https://onnx.ai/) +- [Apache TVM](https://tvm.apache.org/) +- [MLIR](https://mlir.llvm.org/) +- [TACO](https://github.com/tensor-compiler/taco) +- [unumpy](https://github.com/Quansight-Labs/unumpy) +- [einops](https://github.com/arogozhnikov/einops) +- [Apache Arrow](https://arrow.apache.org/) + + + +## How to read this document + +For guidance on how to read and understand the type annotations included in this specification, consult the Python [documentation](https://docs.python.org/3/library/typing.html). + + +(how-to-adopt-this-api)= + +## How to adopt this API + +Most (all) existing array libraries will find something in this API standard +that is incompatible with a current implementation, and that they cannot +change due to backwards compatibility concerns. Therefore we expect that each +of those libraries will want to offer a standard-compliant API in a _new +namespace_. The question then becomes: how does a user access this namespace? + +The simplest method is: document the import to use to directly access the +namespace (e.g. `import package_name.array_api`). This has two issues though: + +1. Array-consuming libraries that want to support multiple array libraries + then have to explicitly import each library. +2. It is difficult to _version_ the array API standard implementation (see + {ref}`api-versioning`). + +To address both issues, a uniform way must be provided by a conforming +implementation to access the API namespace, namely a [method on the array +object](array.__array_namespace__): + +``` +xp = x.__array_namespace__() +``` + +The method must take one keyword, `api_version=None`, to make it possible to +request a specific API version: + +``` +xp = x.__array_namespace__(api_version='2020.10') +``` + +The `xp` namespace must contain all functionality specified in +{ref}`api-specification`. The namespace may contain other functionality; however, +including additional functionality is not recommended as doing so may hinder +portability and inter-operation of array libraries within user code. + +### Checking an array object for Compliance + +Array-consuming libraries are likely to want a mechanism for determining +whether a provided array is specification compliant. The recommended approach +to check for compliance is by checking whether an array object has an +`__array_namespace__` attribute, as this is the one distinguishing feature of +an array-compliant object. + +Checking for an `__array_namespace__` attribute can be implemented as a small +utility function similar to the following. + +```python +def is_array_api_obj(x): + return hasattr(x, '__array_namespace__') +``` + +```{note} +Providing a "reference library" on which people depend is out-of-scope for +the standard. Hence the standard cannot, e.g., provide an array ABC from +which libraries can inherit to enable an `isinstance` check. However, note +that the `numpy.array_api` implementation aims to provide a reference +implementation with only the behavior specified in this standard - it may +prove useful for verifying one is writing portable code. +``` + +### Discoverability of conforming implementations + +It may be useful to have a way to discover all packages in a Python +environment which provide a conforming array API implementation, and the +namespace that that implementation resides in. +To assist array-consuming libraries which need to create arrays originating +from multiple conforming array implementations, or developers who want to perform +for example cross-library testing, libraries may provide an +{pypa}`entry point ` in order to make an array API +namespace discoverable. + +:::{admonition} Optional feature +Given that entry points typically require build system & package installer +specific implementation, this standard chooses to recommend rather than +mandate providing an entry point. +::: + +The following code is an example for how one can discover installed +conforming libraries: + +```python +from importlib.metadata import entry_points + +try: + eps = entry_points()['array_api'] + ep = next(ep for ep in eps if ep.name == 'package_name') +except TypeError: + # The dict interface for entry_points() is deprecated in py3.10, + # supplanted by a new select interface. + ep = entry_points(group='array_api', name='package_name') + +xp = ep.load() +``` + +An entry point must have the following properties: + +- **group**: equal to `array_api`. +- **name**: equal to the package name. +- **object reference**: equal to the array API namespace import path. + + +* * * + +## Conformance + +A conforming implementation of the array API standard must provide and support +all the functions, arguments, data types, syntax, and semantics described in +this specification. + +A conforming implementation of the array API standard may provide additional +features (e.g., values, objects, properties, data types, functions, and function +arguments) beyond those described in this specification. + +Libraries which aim to provide a conforming implementation but haven't yet +completed such an implementation may, and are encouraged to, provide details on +the level of (non-)conformance. For details on how to do this, see +[Verification - measuring conformance](verification_test_suite.md). + + +* * * + +## Terms and Definitions + +For the purposes of this specification, the following terms and definitions apply. + + + +**array**: +a (usually fixed-size) multidimensional container of items of the same type and size. + +**axis**: +an array dimension. + +**branch cut**: +a curve in the complex plane across which a given complex function fails to be continuous. + +**broadcast**: +automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +**compatible**: +two arrays whose dimensions are compatible (i.e., where the size of each dimension in one array is either equal to one or to the size of the corresponding dimension in a second array). + +**element-wise**: +an operation performed element-by-element, in which individual array elements are considered in isolation and independently of other elements within the same array. + +**matrix**: +a two-dimensional array. + +**rank**: +number of array dimensions (not to be confused with the number of linearly independent columns of a matrix). + +**shape**: +a tuple of `N` non-negative integers that specify the sizes of each dimension and where `N` corresponds to the number of dimensions. + +**singleton dimension**: +a dimension whose size is one. + +**vector**: +a one-dimensional array. + +* * * + +## Normative References + +The following referenced documents are indispensable for the application of this specification. + +- __IEEE 754-2019: IEEE Standard for Floating-Point Arithmetic.__ Institute of Electrical and Electronic Engineers, New York (2019). +- Scott Bradner. 1997. "Key words for use in RFCs to Indicate Requirement Levels". RFC 2119. doi:[10.17487/rfc2119](https://tools.ietf.org/html/rfc2119). diff --git a/spec/2024.12/usage_data.md b/spec/2024.12/usage_data.md new file mode 100644 index 000000000..c2dcd5d65 --- /dev/null +++ b/spec/2024.12/usage_data.md @@ -0,0 +1,86 @@ +(usage-data)= + +# Usage Data + +> Summary of existing array API design and usage. + +## Introduction + +With rare exception, technical standardization ("standardization") occurs neither in a vacuum nor from first principles. Instead, standardization finds its origins in two or more, sometimes competing, implementations differing in design and behavior. These differences introduce friction as those (e.g., downstream end-users and library authors) who operate at higher levels of abstraction must either focus on an implementation subset (e.g., only NumPy-like array libraries) or accommodate variation through increased complexity (e.g., if NumPy array, call method `.foo()`; else if Dask array, call method `.bar()`). + +Standardization aspires to reduce this friction and is a process which codifies that which is common, while still encouraging experimentation and innovation. Through the process of standardization, implementations can align around a subset of established practices and channel development resources toward that which is new and novel. In short, standardization aims to thwart reinventing the proverbial wheel. + +A foundational step in standardization is articulating a subset of established practices and defining those practices in unambiguous terms. To this end, the standardization process must approach the problem from two directions: **design** and **usage**. The former direction seeks to understand + +- current implementation design (APIs, names, signatures, classes, and objects) +- current implementation semantics (calling conventions and behavior) + +while the latter direction seeks to quantify API + +- consumers (e.g., which downstream libraries utilize an API?) +- usage frequency (e.g., how often is an API consumed?) +- consumption patterns (e.g., which optional arguments are provided and in what context?) + +By analyzing both design and usage, the standardization process grounds specification decisions in empirical data and analysis. + +## Design + +To understand API design, standardization follows the following process. + +- Identify a representative sample of commonly used Python array libraries (e.g., NumPy, Dask Array, CuPy, MXNet, JAX, TensorFlow, and PyTorch). +- Acquire public APIs (e.g., by analyzing module exports and scraping public documentation). +- Unify and standardize public API data representation for subsequent analysis. +- Extract commonalities and differences by analyzing the intersection and complement of available APIs. +- Derive a common API subset suitable for standardization (based on prevalence and ease of implementation), where such a subset may include attribute names, method names, and positional and keyword arguments. +- Leverage usage data to validate API need and to inform naming conventions, supported data types, and/or optional arguments. +- Summarize findings and provide tooling for additional analysis and exploration. + +See the [`array-api-comparison`](https://github.com/data-apis/array-api-comparison) +repository for design data and summary analysis. + +## Usage + +To understand usage patterns, standardization follows the following process. + +- Identify a representative sample of commonly used Python libraries ("downstream libraries") which consume the subset of array libraries identified during design analysis (e.g., pandas, Matplotlib, SciPy, Xarray, scikit-learn, and scikit-image). +- Instrument downstream libraries in order to record Python array API calls. +- Collect traces while running downstream library test suites. +- Transform trace data into structured data (e.g., as JSON) for subsequent analysis. +- Generate empirical APIs based on provided arguments and associated types, noting which downstream library called which empirical API and at what frequency. +- Derive a single inferred API which unifies the individual empirical API calling semantics. +- Organize API results in human-readable form as type definition files. +- Compare the inferred API to the documented API. + +The following is an inferred API for `numpy.arange`. The docstring includes the number of lines of code that invoked this function for each downstream library when running downstream library test suites. + +```python +def arange( + _0: object, + /, + *_args: object, + dtype: Union[type, str, numpy.dtype, None] = ..., + step: Union[int, float] = ..., + stop: int = ..., +): + """ + usage.dask: 347 + usage.matplotlib: 359 + usage.pandas: 894 + usage.sample-usage: 4 + usage.scipy: 1173 + usage.skimage: 174 + usage.sklearn: 373 + usage.xarray: 666 + """ + ... +``` + +See the [`python-record-api`](https://github.com/data-apis/python-record-api) repository for source code, usage data, and analysis. To perform a similar analysis on additional downstream libraries, including those not publicly released, see the published PyPI [package](https://pypi.org/project/record_api/). + +## Use in Decision-Making + +Design and usage data support specification decision-making in the following ways. + +- Validate user stories to ensure that proposals satisfy existing needs. +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2024.12/use_cases.md b/spec/2024.12/use_cases.md new file mode 100644 index 000000000..e24aa50db --- /dev/null +++ b/spec/2024.12/use_cases.md @@ -0,0 +1,235 @@ +(use-cases)= + +# Use cases + +Use cases inform the requirements for, and design choices made in, this array +API standard. This section first discusses what types of use cases are +considered, and then works out a few concrete use cases in more detail. + +## Types of use cases + +- Packages that depend on a specific array library currently, and would like + to support multiple of them (e.g. for GPU or distributed array support, for + improved performance, or for reaching a wider user base). +- Writing new libraries/tools that wrap multiple array libraries. +- Projects that implement new types of arrays with, e.g., hardware-specific + optimizations or auto-parallelization behavior, and need an API to put on + top that is familiar to end users. +- End users that want to switch from one library to another without learning + about all the small differences between those libraries. + + +## Concrete use cases + +- {ref}`use-case-scipy` +- {ref}`use-case-einops` +- {ref}`use-case-xtensor` +- {ref}`use-case-numba` + + +(use-case-scipy)= + +### Use case 1: add hardware accelerator and distributed support to SciPy + +When surveying a representative set of advanced users and research software +engineers in 2019 (for [this NSF proposal](https://figshare.com/articles/Mid-Scale_Research_Infrastructure_-_The_Scientific_Python_Ecosystem/8009441)), +the single most common pain point brought up about SciPy was performance. + +SciPy heavily relies on NumPy (its only non-optional runtime dependency). +NumPy provides an array implementation that's in-memory, CPU-only and +single-threaded. Common performance-related wishes users have are: + +- parallel algorithms (can be multi-threaded or multiprocessing based) +- support for distributed arrays (with Dask in particular) +- support for GPUs and other hardware accelerators (shortened to just "GPU" + in the rest of this use case) + +Some parallelism can be supported in SciPy, it has a `workers` keyword +(similar to scikit-learn's `n_jobs` keyword) that allows specifying to use +parallelism in some algorithms. However SciPy itself will not directly start +depending on a GPU or distributed array implementation, or contain (e.g.) +CUDA code - that's not maintainable given the resources for development. +_However_, there is a way to provide distributed or GPU support. Part of the +solution is provided by NumPy's "array protocols" (see [gh-1](https://github.com/data-apis/array-api/issues/1)), that allow +dispatching to other array implementations. The main problem then becomes how +to know whether this will work with a particular distributed or GPU array +implementation - given that there are zero other array implementations that +are even close to providing full NumPy compatibility - without adding that +array implementation as a dependency. + +It's clear that SciPy functionality that relies on compiled extensions (C, +C++, Cython, Fortran) directly can't easily be run on another array library +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python +code can work though. There's two main possibilities: + +1. Testing with another package, manually or in CI, and simply provide a list + of functionality that is found to work. Then make ad-hoc fixes to expand + the set that works. +2. Start relying on a well-defined subset of the NumPy API (or a new + NumPy-like API), for which compatibility is guaranteed. + +Option (2) seems strongly preferable, and that "well-defined subset" is _what +an API standard should provide_. Testing will still be needed, to ensure there +are no critical corner cases or bugs between array implementations, however +that's then a very tractable task. + +As a concrete example, consider the spectral analysis functions in `scipy.signal`. +All of those functions (e.g., `periodogram`, `spectrogram`, `csd`, `welch`, `stft`, +`istft`) are pure Python - with the exception of `lombscargle` which is ~40 +lines of Cython - and uses NumPy function calls, array attributes and +indexing. The beginning of each function could be changed to retrieve the +module that implements the array API standard for the given input array type, +and then functions from that module could be used instead of NumPy functions. + +If the user has another array type, say a CuPy or PyTorch array `x` on their +GPU, doing: +``` +from scipy import signal + +signal.welch(x) +``` +will result in: +``` +# For CuPy +ValueError: object __array__ method not producing an array + +# For PyTorch +TypeError: can't convert cuda:0 device type tensor to numpy. +``` +and therefore the user will have to explicitly convert to and from a +`numpy.ndarray` (which is quite inefficient): +``` +# For CuPy +x_np = cupy.asnumpy(x) +freq, Pxx = (cupy.asarray(res) for res in signal.welch(x_np)) + +# For PyTorch +x_np = x.cpu().numpy() +# Note: ends up with tensors on CPU, may still have to move them back +freq, Pxx = (torch.tensor(res) for res in signal.welch(x_np)) +``` +This code will look a little different for each array library. The end goal +here is to be able to write this instead as: +``` +freq, Pxx = signal.welch(x) +``` +and have `freq`, `Pxx` be arrays of the same type and on the same device as `x`. + +```{note} + +This type of use case applies to many other libraries, from scikit-learn +and scikit-image to domain-specific libraries like AstroPy and +scikit-bio, to code written for a single purpose or user. +``` + +(use-case-einops)= + +### Use case 2: simplify einops by removing the backend system + +[einops](https://github.com/arogozhnikov/einops) is a library that provides flexible tensor operations and supports many array libraries (NumPy, TensorFlow, PyTorch, CuPy, MXNet, JAX). +Most of the code in `einops` is: + +- [einops.py](https://github.com/arogozhnikov/einops/blob/master/einops/einops.py) + contains the functions it offers as public API (`rearrange`, `reduce`, `repeat`). +- [_backends.py](https://github.com/arogozhnikov/einops/blob/master/einops/_backends.py) + contains the glue code needed to support that many array libraries. + +The amount of code in each of those two files is almost the same (~550 LoC each). +The typical pattern in `einops.py` is: +``` +def some_func(x): + ... + backend = get_backend(x) + shape = backend.shape(x) + result = backend.reduce(x) + ... +``` +With a standard array API, the `_backends.py` glue layer could almost completely disappear, +because the purpose it serves (providing a unified interface to array operations from each +of the supported backends) is already addressed by the array API standard. +Hence the complete `einops` code base could be close to 50% smaller, and easier to maintain or add to. + +```{note} + +Other libraries that have a similar backend system to support many array libraries +include [TensorLy](https://github.com/tensorly/tensorly), the (now discontinued) +multi-backend version of [Keras](https://github.com/keras-team/keras), +[Unumpy](https://github.com/Quansight-Labs/unumpy) and +[EagerPy](https://github.com/jonasrauber/eagerpy). Many end users and +organizations will also have such glue code - it tends to be needed whenever +one tries to support multiple array types in a single API. +``` + + +(use-case-xtensor)= + +### Use case 3: adding a Python API to xtensor + +[xtensor](https://github.com/xtensor-stack/xtensor) is a C++ array library +that is NumPy-inspired and provides lazy arrays. It has Python (and Julia and R) +bindings, however it does not have a Python array API. + +Xtensor aims to follow NumPy closely, however it only implements a subset of functionality +and documents some API differences in +[Notable differences with NumPy](https://xtensor.readthedocs.io/en/latest/numpy-differences.html). + +Note that other libraries document similar differences, see for example +[this page for JAX](https://jax.readthedocs.io/en/latest/jax.numpy.html) and +[this page for TensorFlow](https://www.tensorflow.org/guide/tf_numpy). + +Each time an array library author designs a new API, they have to choose (a) +what subset of NumPy makes sense to implement, and (b) where to deviate +because NumPy's API for a particular function is suboptimal or the semantics +don't fit their execution model. + +This array API standard aims to provide an API that can be readily adopted, +without having to make the above-mentioned choices. + +```{note} + +XND is another array library, written in C, that still needs a Python API. +Array implementations in other languages are often in a similar situation, +and could translate this array API standard 1:1 to their language. +``` + + +(use-case-numba)= + +### Use case 4: make JIT compilation of array computations easier and more robust + +[Numba](https://github.com/numba/numba) is a Just-In-Time (JIT) compiler for +numerical functions in Python; it is NumPy-aware. [PyPy](https://pypy.org) +is an implementation of Python with a JIT at its core; its NumPy support relies +on running NumPy itself through a compatibility layer (`cpyext`), while a +previous attempt to implement NumPy support directly was unsuccessful. + +Other array libraries may have an internal JIT (e.g., TensorFlow, PyTorch, +JAX, MXNet) or work with an external JIT like +[XLA](https://www.tensorflow.org/xla) or [VTA](https://tvm.apache.org/docs/vta/index.html). + +Numba currently has to jump through some hoops to accommodate NumPy's casting rules +and may not attain full compatibility with NumPy in some cases - see, e.g., +[this](https://github.com/numba/numba/issues/4749) or +[this](https://github.com/numba/numba/issues/5907) example issue regarding (array) scalar +return values. + +An [explicit suggestion from a Numba developer](https://twitter.com/esc___/status/1295389487485333505) +for this array API standard was: + +> for JIT compilers (e.g. Numba) it will be important, that the type of the + returned value(s) depends only on the *types* of the input but not on the + *values*. + +A concrete goal for this use case is to have better matching between +JIT-compiled and non-JIT execution. Here is an example from the Numba code +base, the need for which should be avoided in the future: + +``` +def check(x, y): + got = cfunc(x, y) + np.testing.assert_array_almost_equal(got, pyfunc(x, y)) + # Check the power operation conserved the input's dtype + # (this is different from Numpy, whose behaviour depends on + # the *values* of the arguments -- see PyArray_CanCastArrayTo). + self.assertEqual(got.dtype, x.dtype) +``` diff --git a/spec/2024.12/verification_test_suite.md b/spec/2024.12/verification_test_suite.md new file mode 100644 index 000000000..cbe770e48 --- /dev/null +++ b/spec/2024.12/verification_test_suite.md @@ -0,0 +1,62 @@ +# Verification - test suite + +## Measuring conformance + +In addition to the specification documents, a test suite is being developed to +aid library developers check conformance to the spec. **NOTE: The test suite +is still a work in progress.** It can be found at +. + +It is important to note that while the aim of the array API test suite is to +cover as much of the spec as possible, there are necessarily some aspects of +the spec that are not covered by the test suite, typically because they are +impossible to effectively test. Furthermore, if the test suite appears to +diverge in any way from what the spec documents say, this should be considered +a bug in the test suite. The specification is the ground source of truth. + +## Running the tests + +To run the tests, first clone the [test suite +repo](https://github.com/data-apis/array-api-tests), and install the testing +dependencies, + + pip install pytest hypothesis + +or + + conda install pytest hypothesis + +as well as the array libraries that you want to test. To run the tests, you +need to specify the array library that is to be tested. There are two ways to +do this. One way is to set the `ARRAY_API_TESTS_MODULE` environment variable. +For example + + ARRAY_API_TESTS_MODULE=numpy pytest + +Alternatively, edit the `array_api_tests/_array_module.py` file and change the +line + +```py +array_module = None +``` + +to + +```py +import numpy as array_module +``` + +(replacing `numpy` with the array module namespace to be tested). + +In either case, the tests should be run with the `pytest` command. + +Aside from the two testing dependencies (`pytest` and `hypothesis`), the test +suite has no dependencies. In particular, it does not depend on any specific +array libraries such as NumPy. All tests are run using only the array library +that is being tested, comparing results against the behavior as defined in the +spec. The test suite is designed to be standalone so that it can easily be vendored. + +See the +[README](https://github.com/data-apis/array-api-tests/blob/master/README.md) +in the test suite repo for more information about how to run and interpret the +test suite results. diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json index 04777bd78..65a52628a 100644 --- a/spec/_ghpages/versions.json +++ b/spec/_ghpages/versions.json @@ -2,6 +2,7 @@ "2021.12": "2021.12", "2022.12": "2022.12", "2023.12": "2023.12", + "2024.12": "2024.12", "latest": "latest", "draft": "draft" } diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 08929cc43..e8d4629f2 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- project = "Python array API standard" -copyright = "2020-2024, Consortium for Python Data API Standards" +copyright = "2020-2025, Consortium for Python Data API Standards" author = "Consortium for Python Data API Standards" # -- General configuration --------------------------------------------------- diff --git a/src/array_api_stubs/_2024_12/__init__.py b/src/array_api_stubs/_2024_12/__init__.py new file mode 100644 index 000000000..537ea8f85 --- /dev/null +++ b/src/array_api_stubs/_2024_12/__init__.py @@ -0,0 +1,25 @@ +"""Function stubs and API documentation for the array API standard.""" + +from .array_object import * +from .constants import * +from .creation_functions import * +from .data_type_functions import * +from . import data_types as dtype +from .elementwise_functions import * +from .indexing_functions import * +from .linear_algebra_functions import * +from .manipulation_functions import * +from .searching_functions import * +from .set_functions import * +from .sorting_functions import * +from .statistical_functions import * +from .utility_functions import * +from . import linalg +from . import fft +from .info import __array_namespace_info__ + + +__array_api_version__: str = "YYYY.MM" +""" +String representing the version of the array API specification which the conforming implementation adheres to. +""" diff --git a/src/array_api_stubs/_2024_12/_types.py b/src/array_api_stubs/_2024_12/_types.py new file mode 100644 index 000000000..f2fa356f2 --- /dev/null +++ b/src/array_api_stubs/_2024_12/_types.py @@ -0,0 +1,149 @@ +""" +Types for type annotations used in the array API standard. + +The type variables should be replaced with the actual types for a given +library, e.g., for NumPy TypeVar('array') would be replaced with ndarray. +""" +from __future__ import annotations + +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", + "DefaultDataTypes", + "DataTypes", + "Capabilities", + "Info", +] + +from dataclasses import dataclass +from typing import ( + Any, + List, + Literal, + Optional, + Sequence, + Tuple, + TypedDict, + TypeVar, + Union, + Protocol, +) +from enum import Enum + +array = TypeVar("array") +device = TypeVar("device") +dtype = TypeVar("dtype") +SupportsDLPack = TypeVar("SupportsDLPack") +SupportsBufferProtocol = TypeVar("SupportsBufferProtocol") +PyCapsule = TypeVar("PyCapsule") +# ellipsis cannot actually be imported from anywhere, so include a dummy here +# to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 +ellipsis = TypeVar("ellipsis") + + +@dataclass +class finfo_object: + """Dataclass returned by `finfo`.""" + + bits: int + eps: float + max: float + min: float + smallest_normal: float + dtype: dtype + + +@dataclass +class iinfo_object: + """Dataclass returned by `iinfo`.""" + + bits: int + max: int + min: int + dtype: dtype + + +_T_co = TypeVar("_T_co", covariant=True) + + +class NestedSequence(Protocol[_T_co]): + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: + ... + + def __len__(self, /) -> int: + ... + + +class Info(Protocol): + """Namespace returned by `__array_namespace_info__`.""" + + def capabilities(self) -> Capabilities: + ... + + def default_device(self) -> device: + ... + + def default_dtypes(self, *, device: Optional[device]) -> DefaultDataTypes: + ... + + def devices(self) -> List[device]: + ... + + def dtypes( + self, *, device: Optional[device], kind: Optional[Union[str, Tuple[str, ...]]] + ) -> DataTypes: + ... + + +DefaultDataTypes = TypedDict( + "DefaultDataTypes", + { + "real floating": dtype, + "complex floating": dtype, + "integral": dtype, + "indexing": dtype, + }, +) +DataTypes = TypedDict( + "DataTypes", + { + "bool": dtype, + "float32": dtype, + "float64": dtype, + "complex64": dtype, + "complex128": dtype, + "int8": dtype, + "int16": dtype, + "int32": dtype, + "int64": dtype, + "uint8": dtype, + "uint16": dtype, + "uint32": dtype, + "uint64": dtype, + }, + total=False, +) +Capabilities = TypedDict( + "Capabilities", + { + "boolean indexing": bool, + "data-dependent shapes": bool, + "max rank": Optional[int], + }, +) diff --git a/src/array_api_stubs/_2024_12/array_object.py b/src/array_api_stubs/_2024_12/array_object.py new file mode 100644 index 000000000..08d5c0b6e --- /dev/null +++ b/src/array_api_stubs/_2024_12/array_object.py @@ -0,0 +1,1250 @@ +from __future__ import annotations + +__all__ = ["array"] + +from ._types import ( + array, + dtype as Dtype, + device as Device, + Optional, + Tuple, + Union, + Any, + PyCapsule, + Enum, + ellipsis, +) + + +class _array: + def __init__(self: array) -> None: + """Initialize the attributes for the array object class.""" + + @property + def dtype(self: array) -> Dtype: + """ + Data type of the array elements. + + Returns + ------- + out: dtype + array data type. + """ + + @property + def device(self: array) -> Device: + """ + Hardware device the array data resides on. + + Returns + ------- + out: device + a ``device`` object (see :ref:`device-support`). + """ + + @property + def mT(self: array) -> array: + """ + Transpose of a matrix (or a stack of matrices). + + If an array instance has fewer than two dimensions, an error should be raised. + + Returns + ------- + out: array + array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape ``(..., M, N)``, the returned array must have shape ``(..., N, M)``). The returned array must have the same data type as the original array. + """ + + @property + def ndim(self: array) -> int: + """ + Number of array dimensions (axes). + + Returns + ------- + out: int + number of array dimensions (axes). + """ + + @property + def shape(self: array) -> Tuple[Optional[int], ...]: + """ + Array dimensions. + + Returns + ------- + out: Tuple[Optional[int], ...] + array dimensions. An array dimension must be ``None`` if and only if a dimension is unknown. + + + .. note:: + For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; ``A[:, B > 0]``) and thus cannot be statically resolved without knowing array contents. + + .. note:: + The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. + """ + + @property + def size(self: array) -> Optional[int]: + """ + Number of elements in an array. + + .. note:: + This must equal the product of the array's dimensions. + + Returns + ------- + out: Optional[int] + number of elements in an array. The returned value must be ``None`` if and only if one or more array dimensions are unknown. + + + .. note:: + For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. + """ + + @property + def T(self: array) -> array: + """ + Transpose of the array. + + The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. + + Returns + ------- + out: array + two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. + + + .. note:: + Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional ``permute_dims`` interface found in this specification. + """ + + def __abs__(self: array, /) -> array: + """ + Calculates the absolute value for each element of an array instance. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: + """ + Calculates the sum for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance (augend array). Should have a numeric data type. + other: Union[int, float, array] + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __and__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i & other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. + """ + + def __array_namespace__( + self: array, /, *, api_version: Optional[str] = None + ) -> Any: + """ + Returns an object that has all the array API functions on it. + + Parameters + ---------- + self: array + array instance. + api_version: Optional[str] + string representing the version of the array API specification to be returned, in ``'YYYY.MM'`` form, for example, ``'2020.10'``. If it is ``None``, it should return the namespace corresponding to latest version of the array API specification. If the given version is invalid or not implemented for the given module, an error should be raised. Default: ``None``. + + Returns + ------- + out: Any + an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. + """ + + def __bool__(self: array, /) -> bool: + """ + Converts a zero-dimensional array to a Python ``bool`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: bool + a Python ``bool`` object representing the single element of the array. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``True``. + - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``bool``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __complex__(self: array, /) -> complex: + """ + Converts a zero-dimensional array to a Python ``complex`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: complex + a Python ``complex`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1+0j``. + - If ``self`` is ``False``, the result is ``0+0j``. + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. + - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. + - If ``self`` is a finite number, the result is ``self + 0j``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __dlpack__( + self: array, + /, + *, + stream: Optional[Union[int, Any]] = None, + max_version: Optional[tuple[int, int]] = None, + dl_device: Optional[tuple[Enum, int]] = None, + copy: Optional[bool] = None, + ) -> PyCapsule: + """ + Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. + + Parameters + ---------- + self: array + array instance. + stream: Optional[Union[int, Any]] + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be an integer larger than or equal to ``-1`` (see below for allowed values on each platform). If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. + + For other device types which do have a stream, queue, or similar synchronization/ordering mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + + .. note:: + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + + Device-specific values of ``stream`` for CUDA: + + - ``None``: producer must assume the legacy default stream (default). + - ``1``: the legacy default stream. + - ``2``: the per-thread default stream. + - ``> 2``: stream number represented as a Python integer. + - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. + + Device-specific values of ``stream`` for ROCm: + + - ``None``: producer must assume the legacy default stream (default). + - ``0``: the default stream. + - ``> 2``: stream number represented as a Python integer. + - Using ``1`` and ``2`` is not supported. + + .. note:: + When ``dl_device`` is provided explicitly, ``stream`` must be a valid + construct for the specified device type. In particular, when ``kDLCPU`` + is in use, ``stream`` must be ``None`` and a synchronization must be + performed to ensure data safety. + + .. admonition:: Tip + :class: important + + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronizations than necessary. + max_version: Optional[tuple[int, int]] + the maximum DLPack version that the *consumer* (i.e., the caller of + ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. + This method may return a capsule of version ``max_version`` (recommended + if it does support that), or of a different version. + This means the consumer must verify the version even when + `max_version` is passed. + dl_device: Optional[tuple[enum.Enum, int]] + the DLPack device type. Default is ``None``, meaning the exported capsule + should be on the same device as ``self`` is. When specified, the format + must be a 2-tuple, following that of the return value of :meth:`array.__dlpack_device__`. + If the device type cannot be handled by the producer, this function must + raise ``BufferError``. + + The v2023.12 standard only mandates that a compliant library should offer a way for + ``__dlpack__`` to return a capsule referencing an array whose underlying memory is + accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). + If a copy must be made to enable this support but ``copy`` is set to ``False``, the + function must raise ``BufferError``. + + Other device kinds will be considered for standardization in a future version of this + API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the + function must always copy (performed by the producer; see also :ref:`copy-keyword-argument`). If ``False``, the + function must never copy, and raise a ``BufferError`` in case a copy is + deemed necessary (e.g. if a cross-device data movement is requested, and + it is not possible without a copy). If ``None``, the function must reuse + the existing memory buffer if possible and copy otherwise. Default: ``None``. + + When a copy happens, the ``DLPACK_FLAG_BITMASK_IS_COPIED`` flag must be set. + + .. note:: + If a copy happens, and if the consumer-provided ``stream`` and ``dl_device`` + can be understood by the producer, the copy must be performed over ``stream``. + + Returns + ------- + capsule: PyCapsule + a DLPack capsule for the array. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + Implementations should raise ``BufferError`` when the data cannot + be exported as DLPack (e.g., incompatible dtype or strides). Other + errors are raised when export fails for other reasons (e.g., incorrect + arguments passed or out of memory). + + Notes + ----- + The DLPack version scheme is SemVer, where the major DLPack versions + represent ABI breaks, and minor versions represent ABI-compatible additions + (e.g., new enum values for new data types or device types). + + The ``max_version`` keyword was introduced in v2023.12, and goes + together with the ``DLManagedTensorVersioned`` struct added in DLPack + 1.0. This keyword may not be used by consumers until a later time after + introduction, because producers may implement the support at a different + point in time. + + It is recommended for the producer to use this logic in the implementation + of ``__dlpack__``: + + .. code:: python + + if max_version is None: + # Keep and use the DLPack 0.X implementation + # Note: from March 2025 onwards (but ideally as late as + # possible), it's okay to raise BufferError here + else: + # We get to produce `DLManagedTensorVersioned` now. Note that + # our_own_dlpack_version is the max version that the *producer* + # supports and fills in the `DLManagedTensorVersioned::version` + # field + if max_version >= our_own_dlpack_version: + # Consumer understands us, just return a Capsule with our max version + elif max_version[0] == our_own_dlpack_version[0]: + # major versions match, we should still be fine here - + # return our own max version + else: + # if we're at a higher major version internally, did we + # keep an implementation of the older major version around? + # For example, if the producer is on DLPack 1.x and the consumer + # is 0.y, can the producer still export a capsule containing + # DLManagedTensor and not DLManagedTensorVersioned? + # If so, use that. Else, the producer should raise a BufferError + # here to tell users that the consumer's max_version is too + # old to allow the data exchange to happen. + + And this logic for the consumer in :func:`~array_api.from_dlpack`: + + .. code:: python + + try: + x.__dlpack__(max_version=(1, 0), ...) + # if it succeeds, store info from the capsule named "dltensor_versioned", + # and need to set the name to "used_dltensor_versioned" when we're done + except TypeError: + x.__dlpack__(...) + + This logic is also applicable to handling of the new ``dl_device`` and ``copy`` + keywords. + + DLPack 1.0 added a flag to indicate that the array is read-only + (``DLPACK_FLAG_BITMASK_READ_ONLY``). A consumer that does not support + read-only arrays should ignore this flag (this is preferred over + raising an exception; the user is then responsible for ensuring the + memory isn't modified). + + .. versionchanged:: 2022.12 + Added BufferError. + + .. versionchanged:: 2023.12 + Added the ``max_version``, ``dl_device``, and ``copy`` keyword arguments. + + .. versionchanged:: 2023.12 + Added recommendation for handling read-only arrays. + + .. versionchanged:: 2024.12 + Resolved conflicting exception guidance. + """ + + def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: + """ + Returns device type and device ID in DLPack format. Meant for use within :func:`~array_api.from_dlpack`. + + Parameters + ---------- + self: array + array instance. + + Returns + ------- + device: Tuple[Enum, int] + a tuple ``(device_type, device_id)`` in DLPack format. Valid device type enum members are: + + :: + + CPU = 1 + CUDA = 2 + CPU_PINNED = 3 + OPENCL = 4 + VULKAN = 7 + METAL = 8 + VPI = 9 + ROCM = 10 + CUDA_MANAGED = 13 + ONE_API = 14 + """ + + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: + r""" + Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, complex, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __float__(self: array, /) -> float: + """ + Converts a zero-dimensional array to a Python ``float`` object. + + .. note:: + Casting integer values outside the representable bounds of Python's float type is not specified and is implementation-dependent. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: float + a Python ``float`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``float``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __floordiv__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i // other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. + """ + + def __ge__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __getitem__( + self: array, + key: Union[ + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, array, None], ...], + array, + ], + /, + ) -> array: + """ + Returns ``self[key]``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, array, None], ...], array] + index key. + + Returns + ------- + out: array + an array containing the accessed value(s). The returned array must have the same data type as ``self``. + + Notes + ----- + + - See :ref:`indexing` for details on supported indexing semantics. + - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + + .. versionchanged:: 2024.12 + Clarified that iteration is defined for one-dimensional arrays. + """ + + def __gt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __index__(self: array, /) -> int: + """ + Converts a zero-dimensional integer array to a Python ``int`` object. + + .. note:: + This method is called to implement `operator.index() `_. See also `PEP 357 `_. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have an integer data type. If ``self`` has a floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __int__(self: array, /) -> int: + """ + Converts a zero-dimensional array to a Python ``int`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + For floating-point operands, + + - If ``self`` is a finite number, the result is the integer part of ``self``. + - If ``self`` is ``-0``, the result is ``0``. + + **Raises** + + For floating-point operands, + + - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. + - If ``self`` is ``NaN``, raise ``ValueError``. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __invert__(self: array, /) -> array: + """ + Evaluates ``~self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as `self`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_invert`. + """ + + def __le__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __lshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i << other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. + """ + + def __lt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __matmul__(self: array, other: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + other: array + other array. Should have a numeric data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``self`` and ``other`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``self`` is a one-dimensional array having shape ``(K,)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + - The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. + + **Raises** + + - if either ``self`` or ``other`` is a zero-dimensional array. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __mod__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + """ + + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: + r""" + Calculates the product for each element of an array instance with the respective element of the array ``other``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, complex, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: + """ + Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, complex, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __neg__(self: array, /) -> array: + """ + Evaluates ``-self_i`` for each element of an array instance. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``self`` has a complex floating-point data type, both the real and imaginary components for each ``self_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __or__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i | other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + """ + + def __pos__(self: array, /) -> array: + """ + Evaluates ``+self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. + + Parameters + ---------- + self: array + array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + other: Union[int, float, complex, array] + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __rshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i >> other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. + """ + + def __setitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array + ], + value: Union[int, float, complex, bool, array], + /, + ) -> None: + """ + Sets ``self[key]`` to ``value``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array] + index key. + value: Union[int, float, complex, bool, array] + value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). + + Notes + ----- + + - See :ref:`indexing` for details on supported indexing semantics. + + .. note:: + Indexing semantics when ``key`` is an integer array or a tuple of integers and integer arrays is currently unspecified and thus implementation-defined. This will be revisited in a future revision of this standard. + + - Setting array values must not affect the data type of ``self``. + - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``complex``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + """ + + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: + """ + Calculates the difference for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance (minuend array). Should have a numeric data type. + other: Union[int, float, complex, array] + subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + - The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: + r""" + Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, complex, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + - If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __xor__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i ^ other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. + """ + + def to_device( + self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None + ) -> array: + """ + Copy the array from the device on which it currently resides to the specified ``device``. + + Parameters + ---------- + self: array + array instance. + device: device + a ``device`` object (see :ref:`device-support`). + stream: Optional[Union[int, Any]] + stream object to use during copy. In addition to the types supported in :meth:`array.__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. + + Returns + ------- + out: array + an array with the same data and data type as ``self`` and located on the specified ``device``. + + + Notes + ----- + + - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. + - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. + + .. versionchanged:: 2023.12 + Clarified behavior when a provided ``device`` object corresponds to the device on which an array instance resides. + """ + + +array = _array diff --git a/src/array_api_stubs/_2024_12/constants.py b/src/array_api_stubs/_2024_12/constants.py new file mode 100644 index 000000000..c5735d09f --- /dev/null +++ b/src/array_api_stubs/_2024_12/constants.py @@ -0,0 +1,30 @@ +__all__ = ["e", "inf", "nan", "newaxis", "pi"] + +e = 2.718281828459045 +""" +IEEE 754 floating-point representation of Euler's constant. + +``e = 2.71828182845904523536028747135266249775724709369995...`` +""" + +inf = float("inf") +""" +IEEE 754 floating-point representation of (positive) infinity. +""" + +nan = float("nan") +""" +IEEE 754 floating-point representation of Not a Number (``NaN``). +""" + +newaxis = None +""" +An alias for ``None`` which is useful for indexing arrays. +""" + +pi = 3.141592653589793 +""" +IEEE 754 floating-point representation of the mathematical constant ``π``. + +``pi = 3.1415926535897932384626433...`` +""" diff --git a/src/array_api_stubs/_2024_12/creation_functions.py b/src/array_api_stubs/_2024_12/creation_functions.py new file mode 100644 index 000000000..c09800783 --- /dev/null +++ b/src/array_api_stubs/_2024_12/creation_functions.py @@ -0,0 +1,647 @@ +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] + + +from ._types import ( + List, + NestedSequence, + Optional, + SupportsBufferProtocol, + Tuple, + Union, + array, + device, + dtype, +) + + +def arange( + start: Union[int, float], + /, + stop: Optional[Union[int, float]] = None, + step: Union[int, float] = 1, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. + + Parameters + ---------- + start: Union[int, float] + if ``stop`` is specified, the start of interval (inclusive); otherwise, the end of the interval (exclusive). If ``stop`` is not specified, the default starting value is ``0``. + stop: Optional[Union[int, float]] + the end of the interval. Default: ``None``. + step: Union[int, float] + the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + + .. note:: + This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. + """ + + +def asarray( + obj: Union[ + array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol + ], + /, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + r""" + Convert the input to an array. + + Parameters + ---------- + obj: Union[array, bool, int, float, complex, NestedSequence[bool | int | float | complex], SupportsBufferProtocol] + object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. + + .. admonition:: Tip + :class: important + + An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. + + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then, in order of precedence, + + - if all values are of type ``bool``, the output data type must be ``bool``. + - if all values are of type ``int`` or are a mixture of ``bool`` and ``int``, the output data type must be the default integer data type. + - if one or more values are ``complex`` numbers, the output data type must be the default complex floating-point data type. + - if one or more values are ``float``\s, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`array_api.astype`. + + .. note:: + If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def empty( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns an uninitialized array having a specified `shape`. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing uninitialized data. + """ + + +def empty_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns an uninitialized array with the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and containing uninitialized data. + """ + + +def eye( + n_rows: int, + n_cols: Optional[int] = None, + /, + *, + k: int = 0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + r""" + Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. + + .. note:: + An output array having a complex floating-point data type must have the value ``1 + 0j`` along the ``k``\th diagonal and ``0 + 0j`` elsewhere. + + Parameters + ---------- + n_rows: int + number of rows in the output array. + n_cols: Optional[int] + number of columns in the output array. If ``None``, the default number of columns in the output array is equal to ``n_rows``. Default: ``None``. + k: int + index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and ``0`` to the main diagonal. Default: ``0``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def from_dlpack( + x: object, + /, + *, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + """ + Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. + + Parameters + ---------- + x: object + input (array) object. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``x`` supports DLPack, the output array must be on the same device as ``x``. Default: ``None``. + + The v2023.12 standard only mandates that a compliant library should offer a way for ``from_dlpack`` to return an array + whose underlying memory is accessible to the Python interpreter, when the corresponding ``device`` is provided. If the + array library does not support such cases at all, the function must raise ``BufferError``. If a copy must be made to + enable this support but ``copy`` is set to ``False``, the function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy, and raise ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse the existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data in ``x``. + + .. admonition:: Note + :class: note + + The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array + may raise ``BufferError`` when the data cannot be exported as DLPack + (e.g., incompatible dtype, strides, or device). It may also raise other errors + when export fails for other reasons (e.g., not enough memory available + to materialize the data). ``from_dlpack`` must propagate such + exceptions. + AttributeError + If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present + on the input array. This may happen for libraries that are never able + to export their data with DLPack. + ValueError + If data exchange is possible via an explicit copy but ``copy`` is set to ``False``. + + Notes + ----- + See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in + order to handle DLPack versioning correctly. + + A way to move data from two array libraries to the same device (assumed supported by both libraries) in + a library-agnostic fashion is illustrated below: + + .. code:: python + + def func(x, y): + xp_x = x.__array_namespace__() + xp_y = y.__array_namespace__() + + # Other functions than `from_dlpack` only work if both arrays are from the same library. So if + # `y` is from a different one than `x`, let's convert `y` into an array of the same type as `x`: + if not xp_x == xp_y: + y = xp_x.from_dlpack(y, copy=True, device=x.device) + + # From now on use `xp_x.xxxxx` functions, as both arrays are from the library `xp_x` + ... + + + .. versionchanged:: 2023.12 + Required exceptions to address unsupported use cases. + + .. versionchanged:: 2023.12 + Added device and copy support. + """ + + +def full( + shape: Union[int, Tuple[int, ...]], + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ``fill_value``. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value`` according to the following rules: + + - If the fill value is an ``int``, the output array data type must be the default integer data type. + - If the fill value is a ``float``, the output array data type must be the default real-valued floating-point data type. + - If the fill value is a ``complex`` number, the output array data type must be the default complex floating-point data type. + - If the fill value is a ``bool``, the output array must have a boolean data type. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def full_like( + x: array, + /, + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + + .. note:: + If the ``fill_value`` has a data type which is not of the same data type kind (boolean, integer, or floating-point) as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def linspace( + start: Union[int, float, complex], + stop: Union[int, float, complex], + /, + num: int, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + endpoint: bool = True, +) -> array: + r""" + Returns evenly spaced numbers over a specified interval. + + Let :math:`N` be the number of generated values (which is either ``num`` or ``num+1`` depending on whether ``endpoint`` is ``True`` or ``False``, respectively). For real-valued output arrays, the spacing between values is given by + + .. math:: + \Delta_{\textrm{real}} = \frac{\textrm{stop} - \textrm{start}}{N - 1} + + For complex output arrays, let ``a = real(start)``, ``b = imag(start)``, ``c = real(stop)``, and ``d = imag(stop)``. The spacing between complex values is given by + + .. math:: + \Delta_{\textrm{complex}} = \frac{c-a}{N-1} + \frac{d-b}{N-1} j + + Parameters + ---------- + start: Union[int, float, complex] + the start of the interval. + stop: Union[int, float, complex] + the end of the interval. If ``endpoint`` is ``False``, the function must generate a sequence of ``num+1`` evenly spaced numbers starting with ``start`` and ending with ``stop`` and exclude the ``stop`` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval ``[start, stop)``. If ``endpoint`` is ``True``, the output array must consist of evenly spaced numbers over the closed interval ``[start, stop]``. Default: ``True``. + + .. note:: + The step size changes when `endpoint` is `False`. + + num: int + number of samples. Must be a nonnegative integer value. + dtype: Optional[dtype] + output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, + + - if either ``start`` or ``stop`` is a ``complex`` number, the output data type must be the default complex floating-point data type. + - if both ``start`` and ``stop`` are real-valued, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, conversion of ``start`` and ``stop`` should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + endpoint: bool + boolean indicating whether to include ``stop`` in the interval. Default: ``True``. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. + + Notes + ----- + + .. note:: + While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + + .. note:: + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: + """ + Returns coordinate matrices from coordinate vectors. + + Parameters + ---------- + arrays: array + an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. + indexing: str + Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. + + Returns + ------- + out: List[array] + list of N arrays, where ``N`` is the number of provided one-dimensional input arrays. Each returned array must have rank ``N``. For ``N`` one-dimensional arrays having lengths ``Ni = len(xi)``, + + - if matrix indexing ``ij``, then each returned array must have the shape ``(N1, N2, N3, ..., Nn)``. + - if Cartesian indexing ``xy``, then each returned array must have shape ``(N2, N1, N3, ..., Nn)``. + + Accordingly, for the two-dimensional case with input one-dimensional arrays of length ``M`` and ``N``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M)``. + + Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. + + Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ones. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tril(x: array, /, *, k: int = 0) -> array: + """ + Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The lower triangular part of the matrix is defined as the elements on and below the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal above which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def triu(x: array, /, *, k: int = 0) -> array: + """ + Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The upper triangular part of the matrix is defined as the elements on and above the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal below which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def zeros( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with zeros. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing zeros. + """ + + +def zeros_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with zeros. + """ diff --git a/src/array_api_stubs/_2024_12/data_type_functions.py b/src/array_api_stubs/_2024_12/data_type_functions.py new file mode 100644 index 000000000..7a6c59d94 --- /dev/null +++ b/src/array_api_stubs/_2024_12/data_type_functions.py @@ -0,0 +1,250 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + +from ._types import ( + Union, + Tuple, + array, + dtype, + finfo_object, + iinfo_object, + device, + Optional, +) + + +def astype( + x: array, dtype: dtype, /, *, copy: bool = True, device: Optional[device] = None +) -> array: + """ + Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. + + .. note:: + Casting floating-point ``NaN`` and ``infinity`` values to integral data types is not specified and is implementation-dependent. + + .. note:: + Casting a complex floating-point array to a real-valued data type should not be permitted. + + Historically, when casting a complex floating-point array to a real-valued data type, libraries such as NumPy have discarded imaginary components such that, for a complex floating-point array ``x``, ``astype(x)`` equals ``astype(real(x))``). This behavior is considered problematic as the choice to discard the imaginary component is arbitrary and introduces more than one way to achieve the same outcome (i.e., for a complex floating-point array ``x``, ``astype(x)`` and ``astype(real(x))`` versus only ``astype(imag(x))``). Instead, in order to avoid ambiguity and to promote clarity, this specification requires that array API consumers explicitly express which component should be cast to a specified real-valued data type. + + .. note:: + When casting a boolean input array to a real-valued data type, a value of ``True`` must cast to a real-valued number equal to ``1``, and a value of ``False`` must cast to a real-valued number equal to ``0``. + + When casting a boolean input array to a complex floating-point data type, a value of ``True`` must cast to a complex number equal to ``1 + 0j``, and a value of ``False`` must cast to a complex number equal to ``0 + 0j``. + + .. note:: + When casting a real-valued input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. + + When casting a complex floating-point array to ``bool``, a value of ``0 + 0j`` must cast to ``False``, and all other values must cast to ``True``. + + Parameters + ---------- + x: array + array to cast. + dtype: dtype + desired data type. + copy: bool + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned (see :ref:`copy-keyword-argument`). If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + device: Optional[device] + device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Added device keyword argument support. + """ + + +def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: + """ + Determines if one data type can be cast to another data type according to type promotion rules (see :ref:`type-promotion`). + + Parameters + ---------- + from_: Union[dtype, array] + input data type or array from which to cast. + to: dtype + desired data type. + + Returns + ------- + out: bool + ``True`` if the cast can occur according to type promotion rules (see :ref:`type-promotion`); otherwise, ``False``. + + Notes + ----- + + - When ``from_`` is a data type, the function must determine whether the data type can be cast to another data type according to the complete type promotion rules (see :ref:`type-promotion`) described in this specification, irrespective of whether a conforming array library supports devices which do not have full data type support. + - When ``from_`` is an array, the function must determine whether the data type of the array can be cast to the desired data type according to the type promotion graph of the array device. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the output of ``can_cast(array, dtype)`` may differ from ``can_cast(array.dtype, dtype)``. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. + """ + + +def finfo(type: Union[dtype, array], /) -> finfo_object: + """ + Machine limits for floating-point data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of floating-point data-type about which to get information. If complex, the information is about its component data type. + + .. note:: + Complex floating-point data types are specified to always use the same precision for both its real and imaginary components, so the information should be true for either component. + + Returns + ------- + out: finfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the real-valued floating-point data type. + + - **eps**: *float* + + difference between 1.0 and the next smallest representable real-valued floating-point number larger than 1.0 according to the IEEE-754 standard. + + - **max**: *float* + + largest representable real-valued number. + + - **min**: *float* + + smallest representable real-valued number. + + - **smallest_normal**: *float* + + smallest positive real-valued floating-point number with full precision. + + - **dtype**: dtype + + real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def iinfo(type: Union[dtype, array], /) -> iinfo_object: + """ + Machine limits for integer data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of integer data-type about which to get information. + + Returns + ------- + out: iinfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the type. + + - **max**: *int* + + largest representable number. + + - **min**: *int* + + smallest representable number. + + - **dtype**: dtype + + integer data type. + + .. versionadded:: 2022.12 + """ + + +def isdtype( + dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]] +) -> bool: + """ + Returns a boolean indicating whether a provided dtype is of a specified data type "kind". + + Parameters + ---------- + dtype: dtype + the input dtype. + kind: Union[str, dtype, Tuple[Union[str, dtype], ...]] + data type kind. + + - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. + - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. + + .. note:: + A conforming implementation of the array API standard is **not** limited to only including the dtypes described in this specification in the required data type kinds. For example, implementations supporting ``float16`` and ``bfloat16`` can include ``float16`` and ``bfloat16`` in the ``real floating`` data type kind. Similarly, implementations supporting ``int128`` can include ``int128`` in the ``signed integer`` data type kind. + + In short, conforming implementations may extend data type kinds; however, data type kinds must remain consistent (e.g., only integer dtypes may belong to integer data type kinds and only floating-point dtypes may belong to floating-point data type kinds), and extensions must be clearly documented as such in library documentation. + + Returns + ------- + out: bool + boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def result_type( + *arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] +) -> dtype: + """ + Returns the dtype that results from applying type promotion rules (see :ref:`type-promotion`) to the arguments. + + Parameters + ---------- + arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] + an arbitrary number of input arrays, scalars, and/or dtypes. + + Returns + ------- + out: dtype + the dtype resulting from an operation involving the input arrays, scalars, and/or dtypes. + + Notes + ----- + + - At least one argument must be an array or a dtype. + - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and thus implementation-dependent. + - If at least one argument is an array, the function must determine the resulting dtype according to the type promotion graph of the array device which is shared among all array arguments. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the returned dtype may differ from that determined from the complete type promotion graph defined in this specification (see :ref:`type-promotion`). + - If two or more arguments are arrays belonging to different devices, behavior is unspecified and thus implementation-dependent. Conforming implementations may choose to ignore device attributes, raise an exception, or some other behavior. + + .. versionchanged:: 2024.12 + Added scalar argument support. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. + """ diff --git a/src/array_api_stubs/_2024_12/data_types.py b/src/array_api_stubs/_2024_12/data_types.py new file mode 100644 index 000000000..d15f4a9f7 --- /dev/null +++ b/src/array_api_stubs/_2024_12/data_types.py @@ -0,0 +1,22 @@ +__all__ = ["__eq__"] + + +from ._types import dtype + + +def __eq__(self: dtype, other: dtype, /) -> bool: + """ + Computes the truth value of ``self == other`` in order to test for data type object equality. + + Parameters + ---------- + self: dtype + data type instance. May be any supported data type. + other: dtype + other data type instance. May be any supported data type. + + Returns + ------- + out: bool + a boolean indicating whether the data type objects are equal. + """ diff --git a/src/array_api_stubs/_2024_12/elementwise_functions.py b/src/array_api_stubs/_2024_12/elementwise_functions.py new file mode 100644 index 000000000..2f0cfc8c3 --- /dev/null +++ b/src/array_api_stubs/_2024_12/elementwise_functions.py @@ -0,0 +1,3060 @@ +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "clip", + "conj", + "copysign", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "hypot", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "maximum", + "minimum", + "multiply", + "negative", + "nextafter", + "not_equal", + "positive", + "pow", + "real", + "reciprocal", + "remainder", + "round", + "sign", + "signbit", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] + + +from ._types import Optional, Union, array + + +def abs(x: array, /) -> array: + r""" + Calculates the absolute value for each element ``x_i`` of the input array ``x``. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + .. note:: + For complex floating-point operands, the complex absolute value is known as the norm, modulus, or magnitude and, for a complex number :math:`z = a + bj` is computed as + + .. math:: + \operatorname{abs}(z) = \sqrt{a^2 + b^2} + + .. note:: + For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. + + .. + TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``-0``, the result is ``+0``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``. + - If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``. + - If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``. + - If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acos}(z) = \frac{1}{2}\pi + j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{acos}(z) = \pi - \operatorname{acos}(-z) + + .. note:: + For complex floating-point operands, ``acos(conj(x))`` must equal ``conj(acos(x))``. + + .. note:: + The inverse cosine (or arc cosine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \pi]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``. + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acosh}(z) = \ln(z + \sqrt{z+1}\sqrt{z-1}) + + For any :math:`z`, + + .. math:: + \operatorname{acosh}(z) = \frac{\sqrt{z-1}}{\sqrt{1-z}}\operatorname{acos}(z) + + or simply + + .. math:: + \operatorname{acosh}(z) = j\ \operatorname{acos}(z) + + in the upper half of the complex plane. + + .. note:: + For complex floating-point operands, ``acosh(conj(x))`` must equal ``conj(acosh(x))``. + + .. note:: + The inverse hyperbolic cosine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segment :math:`(-\infty, 1)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic cosine in the interval :math:`[0, \infty)` along the real axis and in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + πj/2``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN ± πj/2`` (sign of imaginary component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def add( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + """ + Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is ``-infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is a nonzero finite number, the result is ``x2_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. + - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. + + .. note:: + Floating-point addition is a commutative operation, but not always associative. + + For complex floating-point operands, addition is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+------------+------------+----------------+ + | | c | dj | c + dj | + +============+============+============+================+ + | **a** | a + c | a + dj | (a+c) + dj | + +------------+------------+------------+----------------+ + | **bj** | c + bj | (b+d)j | c + (b+d)j | + +------------+------------+------------+----------------+ + | **a + bj** | (a+c) + bj | a + (b+d)j | (a+c) + (b+d)j | + +------------+------------+------------+----------------+ + + For complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. For example, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a`` is ``-0`` and ``c`` is ``-0``, the real component of the result is ``-0``. + - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. + + Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def asin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc sine of a complex number :math:`z` is + + .. math:: + \operatorname{asin}(z) = -j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asin}(z) = \operatorname{acos}(-z) - \frac{\pi}{2} + + .. note:: + For complex floating-point operands, ``asin(conj(x))`` must equal ``conj(asin(x))``. + + .. note:: + The inverse sine (or arc sine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse sine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def asinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic sine of a complex number :math:`z` is + + .. math:: + \operatorname{asinh}(z) = \ln(z + \sqrt{1+z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asinh}(z) = \frac{\operatorname{asin}(zj)}{j} + + .. note:: + For complex floating-point operands, ``asinh(conj(x))`` must equal ``conj(asinh(x))`` and ``asinh(-z)`` must equal ``-asinh(z)``. + + .. note:: + The inverse hyperbolic sine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic sine in the range of a strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the inverse tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atan}(z) = -\frac{\ln(1 - zj) - \ln(1 + zj)}{2}j + + .. note:: + For complex floating-point operands, ``atan(conj(x))`` must equal ``conj(atan(x))``. + + .. note:: + The inverse tangent (or arc tangent) is a multi-valued function and requires a branch on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(+j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse tangent in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan2(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. + + The mathematical signs of ``x1_i`` and ``x2_i`` determine the quadrant of each element-wise result. The quadrant (i.e., branch) is chosen such that each element-wise result is the signed angle in radians between the ray ending at the origin and passing through the point ``(1,0)`` and the ray ending at the origin and passing through the point ``(x2_i, x1_i)``. + + .. note:: + Note the role reversal: the "y-coordinate" is the first function parameter; the "x-coordinate" is the second function parameter. The parameter order is intentional and traditional for the two-argument inverse tangent function where the y-coordinate argument is first and the x-coordinate argument is second. + + By IEEE 754 convention, the inverse tangent of the quotient ``x1/x2`` is defined for ``x2_i`` equal to positive or negative zero and for either or both of ``x1_i`` and ``x2_i`` equal to positive or negative ``infinity``. + + Parameters + ---------- + x1: Union[array, int, float] + input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/4``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def atanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atanh}(z) = \frac{\ln(1+z)-\ln(z-1)}{2} + + For any :math:`z`, + + .. math:: + \operatorname{atanh}(z) = \frac{\operatorname{atan}(zj)}{j} + + .. note:: + For complex floating-point operands, ``atanh(conj(x))`` must equal ``conj(atanh(x))`` and ``atanh(-x)`` must equal ``-atanh(x)``. + + .. note:: + The inverse hyperbolic tangent is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, 1]` and :math:`[1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic tangent in the range of a half-strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``+1``, the result is ``+infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``1`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def bitwise_and(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: + """ + Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, bool] + first input array. Should have an integer or boolean data type. + x2: Union[array, int, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_left_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. + + Parameters + ---------- + x1: Union[array, int] + first input array. Should have an integer data type. + x2: Union[array, int] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_invert(x: array, /) -> array: + """ + Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + """ + + +def bitwise_or(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: + """ + Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, bool] + first input array. Should have an integer or boolean data type. + x2: Union[array, int, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_right_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. + + Parameters + ---------- + x1: Union[array, int] + first input array. Should have an integer data type. + x2: Union[array, int] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_xor(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: + """ + Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, bool] + first input array. Should have an integer or boolean data type. + x2: Union[array, int, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def ceil(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def clip( + x: array, + /, + min: Optional[Union[int, float, array]] = None, + max: Optional[Union[int, float, array]] = None, +) -> array: + r""" + Clamps each element ``x_i`` of the input array ``x`` to the range ``[min, max]``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + min: Optional[Union[int, float, array]] + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` and ``max`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. + max: Optional[Union[int, float, array]] + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` and ``min`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. + + Returns + ------- + out: array + an array containing element-wise results. The returned array should have the same data type as ``x``. + + Notes + ----- + + - This function is conceptually equivalent to ``maximum(minimum(x, max), min)`` when ``x``, ``min``, and ``max`` have the same data type. + - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. + - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - For scalar ``min`` and/or ``max``, the scalar values should follow type promotion rules for operations involving arrays and scalar operands (see :ref:`type-promotion`). Hence, if ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. + - If either ``min`` or ``max`` is an array having a different data type than ``x``, behavior is unspecified and thus implementation-dependent. + + **Special cases** + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``min_i`` is ``NaN``, the result is ``NaN``. + - If ``max_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added special case behavior when one of the operands is ``NaN``. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when ``x``, ``min``, and ``max`` resolve to arrays having the same data type. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when elements of ``min`` and ``max`` are inside the bounds of the input array data type. + """ + + +def conj(x: array, /) -> array: + """ + Returns the complex conjugate for each element ``x_i`` of the input array ``x``. + + For complex numbers of the form + + .. math:: + a + bj + + the complex conjugate is defined as + + .. math:: + a - bj + + Hence, the returned complex conjugates must be computed by negating the imaginary component of each element ``x_i``. + + Parameters + ---------- + x: array + input array. Must have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. + """ + + +def copysign(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. + + Parameters + ---------- + x1: Union[array, int, float] + input array containing magnitudes. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``-0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``+0``, the result is ``|x1_i|``. + - If ``x2_i`` is greater than ``0``, the result is ``|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. + + - If ``x1_i`` is ``NaN`` and ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def cos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The cosine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of cosine is + + .. math:: + \begin{align} \operatorname{cos}(x) &= \sum_{n=0}^\infty \frac{(-1)^n}{(2n)!} x^{2n} \\ &= \frac{e^{jx} + e^{-jx}}{2} \\ &= \operatorname{cosh}(jx) \end{align} + + where :math:`\operatorname{cosh}` is the hyperbolic cosine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``NaN``. + - If ``x_i`` is ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic cosine for each element ``x_i`` in the input array ``x``. + + The mathematical definition of the hyperbolic cosine is + + .. math:: + \operatorname{cosh}(x) = \frac{e^x + e^{-x}}{2} + + .. note:: + The hyperbolic cosine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``cosh(x)`` must equal ``cosh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``cosh(conj(x))`` must equal ``conj(cosh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is either ``+0`` or ``-0``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def divide( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + r""" + Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + dividend input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + - If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, division is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a / c | -(a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b/c)j | b/d | special rules | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a/c) + (b/c)j | b/d - (a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division + + .. math:: + \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: + r""" + Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex, bool] + first input array. May have any data type. + x2: Union[array, int, float, complex, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``False``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` equals ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``False``. + - In the remaining cases, the result is the logical AND of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a == c AND b == d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def exp(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def expm1(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``0 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b) - 1.0``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def floor(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def floor_divide( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: + r""" + Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. + + Parameters + ---------- + x1: Union[array, int, float] + dividend input array. Should have a real-valued data type. + x2: Union[array, int, float] + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + **Special cases** + + .. note:: + Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``\s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + + To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. + + Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. + + This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def greater(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def greater_equal( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: + """ + Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def hypot(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + The value computed by this function may be interpreted as the length of the hypotenuse of a right-angled triangle with sides of length ``x1_i`` and ``x2_i``, the distance of a point ``(x1_i, x2_i)`` from the origin ``(0, 0)``, or the magnitude of a complex number ``x1_i + x2_i * 1j``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``+infinity`` or ``-infinity`` and ``x2_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x2_i`` is ``+infinity`` or ``-infinity`` and ``x1_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x2_i)``. + - If ``x2_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x1_i)``. + - If ``x1_i`` is a finite number or ``NaN`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is a finite number or ``NaN`` and ``x1_i`` is ``NaN``, the result is ``NaN``. + - Underflow may only occur when both arguments are subnormal and the correct result is also subnormal. + + For real-valued floating-point operands, ``hypot(x1, x2)`` must equal ``hypot(x2, x1)``, ``hypot(x1, -x2)``, ``hypot(-x1, x2)``, and ``hypot(-x1, -x2)``. + + .. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, conforming implementations may vary in their support for subnormal numbers. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def imag(x: array, /) -> array: + """ + Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def isfinite(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if finite. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``x_i`` is ``NaN``, the result is ``False``. + - If ``x_i`` is a finite number, the result is ``True``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``False``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. + - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isinf(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. + - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isnan(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array should have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` or ``b`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def less(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def less_equal(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def log(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + The natural logarithm of a complex number :math:`z` with polar coordinates :math:`(r,\theta)` equals :math:`\ln r + (\theta + 2n\pi)j` with principal value :math:`\ln r + \theta j`. + + .. note:: + For complex floating-point operands, ``log(conj(x))`` must equal ``conj(log(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-0`` and ``b`` is ``+0``, the result is ``-infinity + πj``. + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log1p(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-1`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log2(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log2(conj(x))`` must equal ``conj(log2(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log10(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log10(conj(x))`` must equal ``conj(log10(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def logaddexp(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def logical_and(x1: Union[array, bool], x2: Union[array, bool], /) -> array: + """ + Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: Union[array, bool] + first input array. Should have a boolean data type. + x2: Union[array, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of `bool`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def logical_not(x: array, /) -> array: + """ + Computes the logical NOT for each element ``x_i`` of the input array ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x: array + input array. Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def logical_or(x1: Union[array, bool], x2: Union[array, bool], /) -> array: + """ + Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: Union[array, bool] + first input array. Should have a boolean data type. + x2: Union[array, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def logical_xor(x1: Union[array, bool], x2: Union[array, bool], /) -> array: + """ + Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: Union[array, bool] + first input array. Should have a boolean data type. + x2: Union[array, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def maximum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise maximum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def minimum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise minimum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def multiply( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + r""" + Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign, the result has a positive mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` and ``x2_i`` have different mathematical signs, the result has a negative mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - In the remaining cases, where neither ``infinity`` nor ``NaN`` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, multiplication is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a * c | (a*d)j | (a*c) + (a*d)j | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b*c)j | -(b*d) | -(b*d) + (b*c)j | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a*c) + (b*c)j | -(b*d) + (a*d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), multiplication of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number multiplication + + .. math:: + (a + bj) \cdot (c + dj) = (ac - bd) + (bc + ad)j + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def negative(x: array, /) -> array: + """ + Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``x`` has a complex floating-point data type, both the real and imaginary components for each ``x_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def nextafter(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Returns the next representable floating-point value for each element ``x1_i`` of the input array ``x1`` in the direction of the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have the same data type as ``x1``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x1``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``-0``. + + .. versionadded:: 2024.12 + """ + + +def not_equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: + """ + Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex, bool] + first input array. May have any data type. + x2: Union[array, int, float, complex, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``True``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` does not equal ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is the logical OR of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a != c OR b != d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def positive(x: array, /) -> array: + """ + Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pow( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array whose elements correspond to the exponentiation base. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + - If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + **Special cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x2_i`` is ``-0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is not equal to ``0``, the result is ``NaN``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``+infinity``, the result is ``1``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``-infinity``, the result is ``1``. + - If ``x1_i`` is ``1`` and ``x2_i`` is not ``NaN``, the result is ``1``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is greater than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + + For complex floating-point operands, special cases should be handled as if the operation is implemented as ``exp(x2*log(x1))``. + + .. note:: + Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def real(x: array, /) -> array: + """ + Returns the real component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Must have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. + """ + + +def reciprocal(x: array, /) -> array: + """ + Returns the reciprocal for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``1.0 / x`` (see :func:`~array_api.divide`). + + .. versionadded:: 2024.12 + """ + + +def remainder(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This function is equivalent to the Python modulus operator ``x1_i % x2_i``. + + Parameters + ---------- + x1: Union[array, int, float] + dividend input array. Should have a real-valued data type. + x2: Union[array, int, float] + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + **Special cases** + + .. note:: + In general, similar to Python's ``%`` operator, this function is **not** recommended for floating-point operands as semantics do not follow IEEE 754. That this function is specified to accept floating-point operands is primarily for reasons of backward compatibility. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x2_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - In the remaining cases, the result must match that of the Python ``%`` operator. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def round(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. + + .. note:: + For complex floating-point operands, real and imaginary components must be independently rounded to the nearest integer-valued number. + + Rounded real and imaginary components must be equal to their equivalent rounded real-valued floating-point counterparts (i.e., for complex-valued ``x``, ``real(round(x))`` must equal ``round(real(x)))`` and ``imag(round(x))`` must equal ``round(imag(x))``). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + .. note:: + For complex floating-point operands, the following special cases apply to real and imaginary components independently (e.g., if ``real(x_i)`` is ``NaN``, the rounded real component is ``NaN``). + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sign(x: array, /) -> array: + r""" + Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. + + The sign function (also known as the **signum function**) of a number :math:`x_i` is defined as + + .. math:: + \operatorname{sign}(x_i) = \begin{cases} + 0 & \textrm{if } x_i = 0 \\ + \frac{x_i}{|x_i|} & \textrm{otherwise} + \end{cases} + + where :math:`|x_i|` is the absolute value of :math:`x_i`. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + For real-valued operands, + + - If ``x_i`` is less than ``0``, the result is ``-1``. + - If ``x_i`` is either ``-0`` or ``+0``, the result is ``0``. + - If ``x_i`` is greater than ``0``, the result is ``+1``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def signbit(x: array, /) -> array: + r""" + Determines whether the sign bit is set for each element ``x_i`` of the input array ``x``. + + The sign bit of a real-valued floating-point number ``x_i`` is set whenever ``x_i`` is either ``-0``, less than zero, or a signed ``NaN`` (i.e., a ``NaN`` value whose sign bit is ``1``). + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``+0``, the result is ``False``. + - If ``x_i`` is ``-0``, the result is ``True``. + - If ``x_i`` is ``+infinity``, the result is ``False``. + - If ``x_i`` is ``-infinity``, the result is ``True``. + - If ``x_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``False``. + - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + + .. versionadded:: 2023.12 + """ + + +def sin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The sine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of sine is + + .. math:: + \begin{align} \operatorname{sin}(x) &= \frac{e^{jx} - e^{-jx}}{2j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \cdot \frac{j}{j} \\ &= -j \cdot \operatorname{sinh}(jx) \end{align} + + where :math:`\operatorname{sinh}` is the hyperbolic sine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic sine for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic sine is + + .. math:: + \operatorname{sinh}(x) = \frac{e^x - e^{-x}}{2} + + .. note:: + The hyperbolic sine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``sinh(x)`` must equal ``-sinh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``sinh(conj(x))`` must equal ``conj(sinh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def square(x: array, /) -> array: + r""" + Squares each element ``x_i`` of the input array ``x``. + + The square of a number ``x_i`` is defined as + + .. math:: + x_i^2 = x_i \cdot x_i + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sqrt(x: array, /) -> array: + r""" + Calculates the principal square root for each element ``x_i`` of the input array ``x``. + + .. note:: + After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). + + .. note:: + For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. + + .. note:: + By convention, the branch cut of the square root is the negative real axis :math:`(-\infty, 0)`. + + The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def subtract( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + """ + Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def tan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the tangent for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + Tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the real component and has first order poles along the real line at coordinates :math:`(\pi (\frac{1}{2} + n), 0)`. However, IEEE 754 binary floating-point representation cannot represent the value :math:`\pi / 2` exactly, and, thus, no argument value is possible for which a pole error occurs. + + .. note:: + For complex arguments, the mathematical definition of tangent is + + .. math:: + \begin{align} \operatorname{tan}(x) &= \frac{j(e^{-jx} - e^{jx})}{e^{-jx} + e^{jx}} \\ &= (-1) \frac{j(e^{jx} - e^{-jx})}{e^{jx} + e^{-jx}} \\ &= -j \cdot \operatorname{tanh}(jx) \end{align} + + where :math:`\operatorname{tanh}` is the hyperbolic tangent. + + Parameters + ---------- + x: array + input array whose elements are expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic tangent is + + .. math:: + \begin{align} \operatorname{tanh}(x) &= \frac{\operatorname{sinh}(x)}{\operatorname{cosh}(x)} \\ &= \frac{e^x - e^{-x}}{e^x + e^{-x}} \end{align} + + where :math:`\operatorname{sinh}(x)` is the hyperbolic sine and :math:`\operatorname{cosh}(x)` is the hyperbolic cosine. + + .. note:: + The hyperbolic tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the imaginary component and has first order poles along the imaginary line at coordinates :math:`(0, \pi (\frac{1}{2} + n))`. However, IEEE 754 binary floating-point representation cannot represent :math:`\pi / 2` exactly, and, thus, no argument value is possible such that a pole error occurs. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``tanh(-x)`` must equal ``-tanh(x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+1``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``tanh(conj(x))`` must equal ``conj(tanh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``+0 + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``1 + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. warning:: + For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. + + Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def trunc(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ diff --git a/src/array_api_stubs/_2024_12/fft.py b/src/array_api_stubs/_2024_12/fft.py new file mode 100644 index 000000000..0924b2f9c --- /dev/null +++ b/src/array_api_stubs/_2024_12/fft.py @@ -0,0 +1,707 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + +from ._types import Tuple, Union, Sequence, array, Optional, Literal, dtype, device + + +def fft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def fftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def rfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse of ``rfft`` for complex-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def rfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)``, the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse of ``rfftn`` for complex-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def hfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array to have a complex floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + """ + + +def ihfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def fftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Computes the discrete Fourier transform sample frequencies. + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) # if n is odd + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n,)`` containing the sample frequencies. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. + """ + + +def rfftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, n/2] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) # if n is odd + + The Nyquist frequency component is considered to be positive. + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n//2+1,)`` containing the sample frequencies. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. + """ + + +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: + """ + Shifts the zero-frequency component to the center of the spectrum. + + This function swaps half-spaces for all axes (dimensions) specified by ``axes``. + + .. note:: + ``out[0]`` is the Nyquist component only if the length of the input is even. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: + """ + Inverse of ``fftshift``. + + .. note:: + Although identical for even-length ``x``, ``fftshift`` and ``ifftshift`` differ by one sample for odd-length ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ diff --git a/src/array_api_stubs/_2024_12/indexing_functions.py b/src/array_api_stubs/_2024_12/indexing_functions.py new file mode 100644 index 000000000..8e4fae25f --- /dev/null +++ b/src/array_api_stubs/_2024_12/indexing_functions.py @@ -0,0 +1,70 @@ +__all__ = ["take", "take_along_axis"] + +from ._types import Union, Optional, array + + +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: + """ + Returns elements of an array along an axis. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). + indices: array + array indices. The array must be one-dimensional and have an integer data type. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). + axis: Optional[int] + axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension (where ``-1`` refers to the last dimension). + + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + + Returns + ------- + out: array + an array having the same data type as ``x``. The output array must have the same rank (i.e., number of dimensions) as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` whose size must equal the number of elements in ``indices``. + + Notes + ----- + + - Conceptually, ``take(x, indices, axis=3)`` is equivalent to ``x[:,:,:,indices,...]``; however, explicit indexing via arrays of indices is not currently supported in this specification due to concerns regarding ``__setitem__`` and array mutation semantics. + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Out-of-bounds behavior is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Behavior when provided a zero-dimensional input array is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Clarified support for negative indices. + """ + + +def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: + """ + Returns elements from an array at the one-dimensional indices specified by ``indices`` along a provided ``axis``. + + Parameters + ---------- + x: array + input array. Must be compatible with ``indices``, except for the axis (dimension) specified by ``axis`` (see :ref:`broadcasting`). + indices: array + array indices. Must have the same rank (i.e., number of dimensions) as ``x``. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). + axis: int + axis along which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + + Returns + ------- + out: array + an array having the same data type as ``x``. Must have the same rank (i.e., number of dimensions) as ``x`` and must have a shape determined according to :ref:`broadcasting`, except for the axis (dimension) specified by ``axis`` whose size must equal the size of the corresponding axis (dimension) in ``indices``. + + Notes + ----- + + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + .. versionadded:: 2024.12 + """ diff --git a/src/array_api_stubs/_2024_12/info.py b/src/array_api_stubs/_2024_12/info.py new file mode 100644 index 000000000..fc8b302a8 --- /dev/null +++ b/src/array_api_stubs/_2024_12/info.py @@ -0,0 +1,203 @@ +__all__ = [ + "__array_namespace_info__", + "capabilities", + "default_device", + "default_dtypes", + "devices", + "dtypes", +] + +from ._types import ( + Optional, + Union, + Tuple, + List, + device, + dtype, + DefaultDataTypes, + DataTypes, + Capabilities, + Info, +) + + +def __array_namespace_info__() -> Info: + """ + Returns a namespace with Array API namespace inspection utilities. + + See :ref:`inspection` for a list of inspection APIs. + + Returns + ------- + out: Info + An object containing Array API namespace inspection utilities. + + Notes + ----- + + The returned object may be either a namespace or a class, so long as an Array API user can access inspection utilities as follows: + + :: + + info = xp.__array_namespace_info__() + info.capabilities() + info.devices() + info.dtypes() + info.default_dtypes() + # ... + + .. versionadded: 2023.12 + """ + + +def capabilities() -> Capabilities: + """ + Returns a dictionary of array library capabilities. + + The dictionary must contain the following keys: + + - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"max dimensions"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. + + Returns + ------- + out: Capabilities + a dictionary of array library capabilities. + + Notes + ----- + + .. versionadded: 2023.12 + + .. versionchanged:: 2024.12 + Added support for querying the maximum number of supported dimensions. + """ + + +def default_device() -> device: + """ + Returns the default device. + + Returns + ------- + out: device + an object corresponding to the default device. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def default_dtypes( + *, + device: Optional[device] = None, +) -> DefaultDataTypes: + """ + Returns a dictionary containing default data types. + + The dictionary must have the following keys: + + - `"real floating"`: default real floating-point data type. + - `"complex floating"`: default complex floating-point data type. + - `"integral"`: default integral data type. + - `"indexing"`: default array index data type. + + Dictionary values must be the corresponding data type object. + + Parameters + ---------- + device: Optional[device] + device for which to return default data types. If ``device`` is ``None``, the returned data types must be the default data types for the current device; otherwise, the returned data types must be default data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the default data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the default data types for the default device. + + Returns + ------- + out: DefaultDataTypes + a dictionary containing the default data type for respective data type kinds. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def dtypes( + *, + device: Optional[device] = None, + kind: Optional[Union[str, Tuple[str, ...]]] = None, +) -> DataTypes: + """ + Returns a dictionary of supported *Array API* data types. + + .. note:: + While specification-conforming array libraries may support additional data types which are not present in this specification, data types which are not present in this specification should not be included in the returned dictionary. + + .. note:: + Specification-conforming array libraries must only return supported data types having expected properties as described in :ref:`data-types`. For example, if a library decides to alias ``float32`` as ``float64``, that library must not include ``float64`` in the dictionary of supported data types. + + Parameters + ---------- + kind: Optional[Union[str, Tuple[str, ...]]] + data type kind. + + - If ``kind`` is ``None``, the function must return a dictionary containing all supported Array API data types. + + - If ``kind`` is a string, the function must return a dictionary containing the data types belonging to the specified data type kind. The following data type kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of data type kinds, and the function must return a dictionary containing the data types belonging to at least one of the specified data type kinds. + + Default: ``None``. + device: Optional[device] + device for which to return supported data types. If ``device`` is ``None``, the returned data types must be the supported data types for the current device; otherwise, the returned data types must be supported data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the supported data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the supported data types for the default device. + + Returns + ------- + out: DataTypes + a dictionary containing supported data types. + + .. note:: + Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def devices() -> List[device]: + """ + Returns a list of supported devices which are available at runtime. + + Returns + ------- + out: List[device] + a list of supported devices. + + Notes + ----- + + Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + + Notes + ----- + + .. versionadded: 2023.12 + """ diff --git a/src/array_api_stubs/_2024_12/linalg.py b/src/array_api_stubs/_2024_12/linalg.py new file mode 100644 index 000000000..4086c333e --- /dev/null +++ b/src/array_api_stubs/_2024_12/linalg.py @@ -0,0 +1,853 @@ +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] + + +from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype +from .constants import inf + + +def cholesky(x: array, /, *, upper: bool = False) -> array: + r""" + Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = LL^{H} \qquad \text{L $\in\ \mathbb{K}^{n \times n}$} + + where :math:`L` is a lower triangular matrix and :math:`L^{H}` is the conjugate transpose when :math:`L` is complex-valued and the transpose when :math:`L` is real-valued. + + The upper Cholesky decomposition is defined similarly + + .. math:: + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + + where :math:`U` is an upper triangular matrix. + + When ``x`` is a stack of matrices, the function must compute the Cholesky decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square complex Hermitian or real symmetric positive-definite matrices. Should have a floating-point data type. + upper: bool + If ``True``, the result must be the upper-triangular Cholesky factor :math:`U`. If ``False``, the result must be the lower-triangular Cholesky factor :math:`L`. Default: ``False``. + + Returns + ------- + out: array + an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: + """ + Returns the cross product of 3-element vectors. + + If ``x1`` and/or ``x2`` are multi-dimensional arrays (i.e., the broadcasted result has a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. + + Parameters + ---------- + x1: array + first input array. Must have a numeric data type. The size of the axis over which the cross product is to be computed must be equal to 3. + x2: array + second input array. Must be broadcast compatible with ``x1`` along all axes other than the axis along which the cross-product is computed (see :ref:`broadcasting`). The size of the axis over which the cross product is to be computed must be equal to 3. Must have a numeric data type. + + .. note:: + The compute axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted broadcasting to only non-compute axes and required that ``axis`` be a negative integer. + """ + + +def det(x: array, /) -> array: + """ + Returns the determinant of a square matrix (or a stack of square matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def diagonal(x: array, /, *, offset: int = 0) -> array: + """ + Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: `0`. + + Returns + ------- + out: array + an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. + """ + + +def eigh(x: array, /) -> Tuple[array]: + r""" + Returns an eigenvalue decomposition of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalue decomposition** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = Q \Lambda Q^H + + with :math:`Q \in \mathbb{K}^{n \times n}` and :math:`\Lambda \in \mathbb{R}^n` and where :math:`Q^H` is the conjugate transpose when :math:`Q` is complex and the transpose when :math:`Q` is real-valued and :math:`\Lambda` is a diagonal matrix whose diagonal elements are the corresponding eigenvalues. When ``x`` is real-valued, :math:`Q` is orthogonal, and, when ``x`` is complex, :math:`Q` is unitary. + + .. note:: + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. warning:: + The eigenvectors of a symmetric matrix are not unique and are not continuous with respect to ``x``. Because eigenvectors are not unique, different hardware and software may compute different eigenvectors. + + Non-uniqueness stems from the fact that multiplying an eigenvector by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another set of valid eigenvectors. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eig`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array] + a namedtuple (``eigenvalues``, ``eigenvectors``) whose + + - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). + - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def eigvalsh(x: array, /) -> array: + r""" + Returns the eigenvalues of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalues** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` are defined as the roots (counted with multiplicity) of the polynomial :math:`p` of degree :math:`n` given by + + .. math:: + p(\lambda) = \operatorname{det}(x - \lambda I_n) + + where :math:`\lambda \in \mathbb{R}` and where :math:`I_n` is the *n*-dimensional identity matrix. + + .. note:; + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eigvals`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def inv(x: array, /) -> array: + r""" + Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **inverse matrix** :math:`x^{-1} \in\ \mathbb{K}^{n \times n}` of a square matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x^{-1}x = xx^{-1} = I_n + + where :math:`I_n` is the *n*-dimensional identity matrix. + + The inverse matrix exists if and only if ``x`` is invertible. When ``x`` is invertible, the inverse is unique. + + When ``x`` is a stack of matrices, the function must compute the inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matmul(x1: array, x2: array, /) -> array: + """Alias for :func:`~array_api.matmul`.""" + + +def matrix_norm( + x: array, + /, + *, + keepdims: bool = False, + ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro", +) -> array: + """ + Computes the matrix norm of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + keepdims: bool + If ``True``, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the last two axes (dimensions) must not be included in the result. Default: ``False``. + ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] + order of the norm. The following mathematical norms must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | 'fro' | Frobenius norm | + +------------------+---------------------------------+ + | 'nuc' | nuclear norm | + +------------------+---------------------------------+ + | 1 | max(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | 2 | largest singular value | + +------------------+---------------------------------+ + | inf | max(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | -1 | min(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | -2 | smallest singular value | + +------------------+---------------------------------+ + | -inf | min(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + If ``ord=1``, the norm corresponds to the induced matrix norm where ``p=1`` (i.e., the maximum absolute value column sum). + + If ``ord=2``, the norm corresponds to the induced matrix norm where ``p=inf`` (i.e., the maximum absolute value row sum). + + If ``ord=inf``, the norm corresponds to the induced matrix norm where ``p=2`` (i.e., the largest singular value). + + Default: ``'fro'``. + + Returns + ------- + out: array + an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_power(x: array, n: int, /) -> array: + """ + Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + n: int + integer exponent. + + Returns + ------- + out: array + if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + """ + Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). + + When ``x`` is a stack of matrices, the function must compute the number of non-zero singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_transpose(x: array, /) -> array: + """Alias for :func:`~array_api.matrix_transpose`.""" + + +def outer(x1: array, x2: array, /) -> array: + """ + Returns the outer product of two vectors ``x1`` and ``x2``. + + Parameters + ---------- + x1: array + first one-dimensional input array of size ``N``. Must have a numeric data type. + x2: array + second one-dimensional input array of size ``M``. Must have a numeric data type. + + Returns + ------- + out: array + a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + r""" + Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. + + The pseudo-inverse of a matrix :math:`A`, denoted :math:`A^{+}`, is defined as the matrix that "solves" the least-squares problem :math:`Ax = b` (i.e., if :math:`\overline{x}` is a solution, then :math:`A^{+}` is the matrix such that :math:`\overline{x} = A^{+}b`). + + While the pseudo-inverse can be defined algebraically, one can understand the pseudo-inverse via singular value decomposition (SVD). Namely, if + + .. math:: + A = U \Sigma V^H + + is a singular decomposition of :math:`A`, then + + .. math:: + A^{+} = U \Sigma^{+} V^H + + where :math:`U` and :math:`V^H` are orthogonal matrices, :math:`\Sigma` is a diagonal matrix consisting of :math:`A`'s singular values, and :math:`\Sigma^{+}` is then a diagonal matrix consisting of the reciprocals of :math:`A`'s singular values, leaving zeros in place. During numerical computation, only elements larger than a small tolerance are considered nonzero, and all others replaced by zeros. + + When ``x`` is a stack of matrices, the function must compute the pseudo-inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def qr( + x: array, /, *, mode: Literal["reduced", "complete"] = "reduced" +) -> Tuple[array, array]: + r""" + Returns the QR decomposition of a full column rank matrix (or a stack of matrices). + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **complete QR decomposition** of a matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times m}` is orthogonal when ``x`` is real-valued and unitary when ``x`` is complex-valued and where :math:`R \in\ \mathbb{K}^{m \times n}` is an upper triangular matrix with real diagonal (even when ``x`` is complex-valued). + + When :math:`m \gt n` (tall matrix), as :math:`R` is upper triangular, the last :math:`m - n` rows are zero. In this case, the last :math:`m - n` columns of :math:`Q` can be dropped to form the **reduced QR decomposition**. + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. + + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). + + When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. + + .. warning:: + The elements in the diagonal of :math:`R` are not necessarily positive. Accordingly, the returned QR decomposition is only unique up to the sign of the diagonal of :math:`R`, and different libraries or inputs on different devices may produce different valid decompositions. + + .. warning:: + The QR decomposition is only well-defined if the first ``k = min(m,n)`` columns of every matrix in ``x`` are linearly independent. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a floating-point data type. + mode: Literal['reduced', 'complete'] + decomposition mode. Should be one of the following modes: + + - ``'reduced'``: compute only the leading ``K`` columns of ``q``, such that ``q`` and ``r`` have dimensions ``(..., M, K)`` and ``(..., K, N)``, respectively, and where ``K = min(M, N)``. + - ``'complete'``: compute ``q`` and ``r`` with dimensions ``(..., M, M)`` and ``(..., M, N)``, respectively. + + Default: ``'reduced'``. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(Q, R)`` whose + + - first element must have the field name ``Q`` and must be an array whose shape depends on the value of ``mode`` and contain matrices with orthonormal columns. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, M)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input array ``x``. + - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. + + Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def slogdet(x: array, /) -> Tuple[array, array]: + r""" + Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. + + .. note:: + The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling ``det`` may overflow or underflow. + + The sign of the determinant is given by + + .. math:: + \operatorname{sign}(\det x) = \begin{cases} + 0 & \textrm{if } \det x = 0 \\ + \frac{\det x}{|\det x|} & \textrm{otherwise} + \end{cases} + + where :math:`|\det x|` is the absolute value of the determinant of ``x``. + + When ``x`` is a stack of matrices, the function must compute the sign and natural logarithm of the absolute value of the determinant for each matrix in the stack. + + **Special Cases** + + For real-valued floating-point operands, + + - If the determinant is zero, the ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``. + + For complex floating-point operands, + + - If the determinant is ``0 + 0j``, the ``sign`` should be ``0 + 0j`` and ``logabsdet`` should be ``-infinity + 0j``. + + .. note:: + Depending on the underlying algorithm, when the determinant is zero, the returned result may differ from ``-infinity`` (or ``-infinity + 0j``). In all cases, the determinant should be equal to ``sign * exp(logabsdet)`` (although, again, the result may be subject to numerical precision errors). + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array, array] + a namedtuple (``sign``, ``logabsdet``) whose + + - first element must have the field name ``sign`` and must be an array containing a number representing the sign of the determinant for each square matrix. Must have the same data type as ``x``. + - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). + + Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def solve(x1: array, x2: array, /) -> array: + r""" + Returns the solution of a square system of linear equations with a unique solution. + + Let ``x1`` equal :math:`A` and ``x2`` equal :math:`B`. If the promoted data type of ``x1`` and ``x2`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if the promoted data type of ``x1`` and ``x2`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + This function computes the solution :math:`X \in\ \mathbb{K}^{m \times k}` of the **linear system** associated to :math:`A \in\ \mathbb{K}^{m \times m}` and :math:`B \in\ \mathbb{K}^{m \times k}` and is defined as + + .. math:: + AX = B + + This system of linear equations has a unique solution if and only if :math:`A` is invertible. + + .. note:: + Whether an array library explicitly checks whether ``x1`` is invertible is implementation-defined. + + When ``x1`` and/or ``x2`` is a stack of matrices, the function must compute a solution for each matrix in the stack. + + Parameters + ---------- + x1: array + coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. + x2: array + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Clarified broadcasting semantics and the shape of the output array. + """ + + +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: + r""" + Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The full **singular value decomposition** of an :math:`m \times n` matrix :math:`x \in\ \mathbb{K}^{m \times n}` is a factorization of the form + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times m}`, :math:`\Sigma \in\ \mathbb{K}^{m \times\ n}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}` with :math:`k = \operatorname{min}(m, n)`, :math:`V^H \in\ \mathbb{K}^{n \times n}`, and where :math:`V^H` is the conjugate transpose when :math:`V` is complex and the transpose when :math:`V` is real-valued. When ``x`` is real-valued, :math:`U`, :math:`V` (and thus :math:`V^H`) are orthogonal, and, when ``x`` is complex, :math:`U`, :math:`V` (and thus :math:`V^H`) are unitary. + + When :math:`m \gt n` (tall matrix), we can drop the last :math:`m - n` columns of :math:`U` to form the reduced SVD + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times k}`, :math:`\Sigma \in\ \mathbb{K}^{k \times\ k}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}`, and :math:`V^H \in\ \mathbb{K}^{k \times n}`. In this case, :math:`U` and :math:`V` have orthonormal columns. + + Similarly, when :math:`n \gt m` (wide matrix), we can drop the last :math:`n - m` columns of :math:`V` to also form a reduced SVD. + + This function returns the decomposition :math:`U`, :math:`S`, and :math:`V^H`, where :math:`S = \operatorname{diag}(\Sigma)`. + + When ``x`` is a stack of matrices, the function must compute the singular value decomposition for each matrix in the stack. + + .. warning:: + The returned arrays :math:`U` and :math:`V` are neither unique nor continuous with respect to ``x``. Because :math:`U` and :math:`V` are not unique, different hardware and software may compute different singular vectors. + + Non-uniqueness stems from the fact that multiplying any pair of singular vectors :math:`u_k`, :math:`v_k` by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another two valid singular vectors of the matrix. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + full_matrices: bool + If ``True``, compute full-sized ``U`` and ``Vh``, such that ``U`` has shape ``(..., M, M)`` and ``Vh`` has shape ``(..., N, N)``. If ``False``, compute on the leading ``K`` singular vectors, such that ``U`` has shape ``(..., M, K)`` and ``Vh`` has shape ``(..., K, N)`` and where ``K = min(M, N)``. Default: ``True``. + + Returns + ------- + out: Tuple[array, array, array] + a namedtuple ``(U, S, Vh)`` whose + + - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). + - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def svdvals(x: array, /) -> array: + """ + Returns the singular values of a matrix (or a stack of matrices) ``x``. + + When ``x`` is a stack of matrices, the function must compute the singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + + Returns + ------- + out: array + an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """Alias for :func:`~array_api.tensordot`.""" + + +def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> array: + """ + Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a numeric data type. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: ``0``. + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + Returns + ------- + out: array + an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if ``x`` has rank ``k`` and shape ``(I, J, K, ..., L, M, N)``, then an output array has rank ``k-2`` and shape ``(I, J, K, ..., L)`` where + + :: + + out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) + + The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: + """Alias for :func:`~array_api.vecdot`.""" + + +def vector_norm( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, + ord: Union[int, float, Literal[inf, -inf]] = 2, +) -> array: + r""" + Computes the vector norm of a vector (or batch of vectors) ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + If an integer, ``axis`` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, ``axis`` specifies the axes (dimensions) along which to compute batched vector norms. If ``None``, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: ``None``. + keepdims: bool + If ``True``, the axes (dimensions) specified by ``axis`` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the axes (dimensions) specified by ``axis`` must not be included in the result. Default: ``False``. + ord: Union[int, float, Literal[inf, -inf]] + order of the norm. The following mathematical norms must be supported: + + +------------------+----------------------------+ + | ord | description | + +==================+============================+ + | 1 | L1-norm (Manhattan) | + +------------------+----------------------------+ + | 2 | L2-norm (Euclidean) | + +------------------+----------------------------+ + | inf | infinity norm | + +------------------+----------------------------+ + | (int,float >= 1) | p-norm | + +------------------+----------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+--------------------------------+ + | ord | description | + +==================+================================+ + | 0 | sum(a != 0) | + +------------------+--------------------------------+ + | -1 | 1./sum(1./abs(a)) | + +------------------+--------------------------------+ + | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | + +------------------+--------------------------------+ + | -inf | min(abs(a)) | + +------------------+--------------------------------+ + | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | + +------------------+--------------------------------+ + + Default: ``2``. + + Returns + ------- + out: array + an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ diff --git a/src/array_api_stubs/_2024_12/linear_algebra_functions.py b/src/array_api_stubs/_2024_12/linear_algebra_functions.py new file mode 100644 index 000000000..da4c97743 --- /dev/null +++ b/src/array_api_stubs/_2024_12/linear_algebra_functions.py @@ -0,0 +1,166 @@ +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] + + +from ._types import Tuple, Union, Sequence, array + + +def matmul(x1: array, x2: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + x2: array + second input array. Should have a numeric data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``x1`` and ``x2`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``x1`` is a one-dimensional array having shape ``(K,)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``x1`` or ``x2`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(x1)[:-2]`` against ``shape(x2)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + + The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + **Raises** + + - if either ``x1`` or ``x2`` is a zero-dimensional array. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + + """ + + +def matrix_transpose(x: array, /) -> array: + """ + Transposes a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + + Returns + ------- + out: array + an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """ + Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. + + .. note:: + The ``tensordot`` function corresponds to the generalized matrix product. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Should have a numeric data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + + .. note:: + Contracted axes (dimensions) must not be broadcasted. + + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] + number of axes (dimensions) to contract or explicit sequences of axis (dimension) indices for ``x1`` and ``x2``, respectively. + + If ``axes`` is an ``int`` equal to ``N``, then contraction must be performed over the last ``N`` axes of ``x1`` and the first ``N`` axes of ``x2`` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. + + - If ``N`` equals ``0``, the result is the tensor (outer) product. + - If ``N`` equals ``1``, the result is the tensor dot product. + - If ``N`` equals ``2``, the result is the tensor double contraction (default). + + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each index referred to in a sequence must be unique. If ``x1`` has rank (i.e, number of dimensions) ``N``, a valid ``x1`` axis must reside on the half-open interval ``[-N, N)``. If ``x2`` has rank ``M``, a valid ``x2`` axis must reside on the half-open interval ``[-M, M)``. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the generalized matrix product. + + Returns + ------- + out: array + an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Allow negative axes. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: + r""" + Computes the (vector) dot product of two arrays. + + Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as + + .. math:: + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i + + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. + + Parameters + ---------- + x1: array + first input array. Should have a floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). The size of the axis over which to compute the dot product must be the same size as the respective axis in ``x1``. Should have a floating-point data type. + + .. note:: + The contracted axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the dot product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted ``axis`` to only negative integers. + """ diff --git a/src/array_api_stubs/_2024_12/manipulation_functions.py b/src/array_api_stubs/_2024_12/manipulation_functions.py new file mode 100644 index 000000000..dd8d4cd69 --- /dev/null +++ b/src/array_api_stubs/_2024_12/manipulation_functions.py @@ -0,0 +1,371 @@ +__all__ = [ + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "moveaxis", + "permute_dims", + "repeat", + "reshape", + "roll", + "squeeze", + "stack", + "tile", + "unstack", +] + + +from ._types import List, Optional, Tuple, Union, array + + +def broadcast_arrays(*arrays: array) -> List[array]: + """ + Broadcasts one or more arrays against one another. + + Parameters + ---------- + arrays: array + an arbitrary number of to-be broadcasted arrays. + + Returns + ------- + out: List[array] + a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. + """ + + +def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: + """ + Broadcasts an array to a specified shape. + + Parameters + ---------- + x: array + array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function must raise an exception. + shape: Tuple[int, ...] + array shape. + + Returns + ------- + out: array + an array having the specified shape. Must have the same data type as ``x``. + + .. versionchanged:: 2024.12 + Clarified broadcast behavior. + """ + + +def concat( + arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0 +) -> array: + """ + Joins a sequence of arrays along an existing axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. The arrays must have the same shape, except in the dimension specified by ``axis``. + axis: Optional[int] + axis along which the arrays will be joined. If ``axis`` is ``None``, arrays must be flattened before concatenation. If ``axis`` is negative, the function must determine the axis along which to join by counting from the last dimension. Default: ``0``. + + Returns + ------- + out: array + an output array containing the concatenated values. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def expand_dims(x: array, /, *, axis: int = 0) -> array: + """ + Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. + + Parameters + ---------- + x: array + input array. + axis: int + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). + + Returns + ------- + out: array + an expanded output array having the same data type as ``x``. + + Raises + ------ + IndexError + If provided an invalid ``axis`` position, an ``IndexError`` should be raised. + """ + + +def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + """ + Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which to flip. If ``axis`` is ``None``, the function must flip all input array axes. If ``axis`` is negative, the function must count from the last dimension. If provided more than one axis, the function must flip only the specified axes. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. + """ + + +def moveaxis( + x: array, + source: Union[int, Tuple[int, ...]], + destination: Union[int, Tuple[int, ...]], + /, +) -> array: + """ + Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. + + Parameters + ---------- + x: array + input array. + source: Union[int, Tuple[int, ...]] + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + destination: Union[int, Tuple[int, ...]] + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + + Returns + ------- + out: array + an array containing reordered axes. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: + """ + Permutes the axes (dimensions) of an array ``x``. + + Parameters + ---------- + x: array + input array. + axes: Tuple[int, ...] + tuple containing a permutation of ``(0, 1, ..., N-1)`` where ``N`` is the number of axes (dimensions) of ``x``. + + Returns + ------- + out: array + an array containing the axes permutation. The returned array must have the same data type as ``x``. + """ + + +def repeat( + x: array, + repeats: Union[int, array], + /, + *, + axis: Optional[int] = None, +) -> array: + """ + Repeats each element of an array a specified number of times on a per-element basis. + + .. admonition:: Data-dependent output shape + :class: important + + When ``repeats`` is an array, the shape of the output array for this function depends on the data values in the ``repeats`` array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing the values in ``repeats``. Accordingly, such libraries may choose to omit support for ``repeats`` arrays; however, conforming implementations must support providing a literal ``int``. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array containing elements to repeat. + repeats: Union[int, array] + the number of repetitions for each element. + + If ``axis`` is ``None``, let ``N = prod(x.shape)`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(N,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(N,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape `(N,)`. + + If ``axis`` is not ``None``, let ``M = x.shape[axis]`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(M,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(M,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape ``(M,)``. + + If ``repeats`` is an array, the array must have an integer data type. + + .. note:: + For specification-conforming array libraries supporting hardware acceleration, providing an array for ``repeats`` may cause device synchronization due to an unknown output shape. For those array libraries where synchronization concerns are applicable, conforming array libraries are advised to include a warning in their documentation regarding potential performance degradation when ``repeats`` is an array. + + axis: Optional[int] + the axis (dimension) along which to repeat elements. If ``axis`` is `None`, the function must flatten the input array ``x`` and then repeat elements of the flattened input array and return the result as a one-dimensional output array. A flattened input array must be flattened in row-major, C-style order. Default: ``None``. + + Returns + ------- + out: array + an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def reshape( + x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None +) -> array: + """ + Reshapes an array without changing its data. + + Parameters + ---------- + x: array + input array to reshape. + shape: Tuple[int, ...] + a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. + copy: Optional[bool] + whether or not to copy the input array. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If ``copy=False`` and a copy would be necessary, a ``ValueError`` + should be raised. + """ + + +def roll( + x: array, + /, + shift: Union[int, Tuple[int, ...]], + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, +) -> array: + """ + Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. + + Parameters + ---------- + x: array + input array. + shift: Union[int, Tuple[int, ...]] + number of places by which the elements are shifted. If ``shift`` is a tuple, then ``axis`` must be a tuple of the same size, and each of the given axes must be shifted by the corresponding element in ``shift``. If ``shift`` is an ``int`` and ``axis`` a tuple, then the same ``shift`` must be used for all specified axes. If a shift is positive, then array elements must be shifted positively (toward larger indices) along the dimension of ``axis``. If a shift is negative, then array elements must be shifted negatively (toward smaller indices) along the dimension of ``axis``. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which elements to shift. If ``axis`` is ``None``, the array must be flattened, shifted, and then restored to its original shape. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. + """ + + +def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: + """ + Removes singleton dimensions (axes) from ``x``. + + Parameters + ---------- + x: array + input array. + axis: Union[int, Tuple[int, ...]] + axis (or axes) to squeeze. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If a specified axis has a size greater than one (i.e., it is not a + singleton dimension), a ``ValueError`` should be raised. + """ + + +def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: + """ + Joins a sequence of arrays along a new axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. Each array must have the same shape. + axis: int + axis along which the arrays will be joined. Providing an ``axis`` specifies the index of the new axis in the dimensions of the result. For example, if ``axis`` is ``0``, the new axis will be the first dimension and the output array will have shape ``(N, A, B, C)``; if ``axis`` is ``1``, the new axis will be the second dimension and the output array will have shape ``(A, N, B, C)``; and, if ``axis`` is ``-1``, the new axis will be the last dimension and the output array will have shape ``(A, B, C, N)``. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: array + an output array having rank ``N+1``, where ``N`` is the rank (number of dimensions) of ``x``. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def tile(x: array, repetitions: Tuple[int, ...], /) -> array: + """ + Constructs an array by tiling an input array. + + Parameters + ---------- + x: array + input array. + repetitions: Tuple[int, ...] + number of repetitions along each axis (dimension). + + Let ``N = len(x.shape)`` and ``M = len(repetitions)``. + + If ``N > M``, the function must prepend ones until all axes (dimensions) are specified (e.g., if ``x`` has shape ``(8,6,4,2)`` and ``repetitions`` is the tuple ``(3,3)``, then ``repetitions`` must be treated as ``(1,1,3,3)``). + + If ``N < M``, the function must prepend singleton axes (dimensions) to ``x`` until ``x`` has as many axes (dimensions) as ``repetitions`` specifies (e.g., if ``x`` has shape ``(4,2)`` and ``repetitions`` is the tuple ``(3,3,3,3)``, then ``x`` must be treated as if it has shape ``(1,1,4,2)``). + + Returns + ------- + out: array + a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: + """ + Splits an array into a sequence of arrays along the given axis. + + Parameters + ---------- + x: array + input array. + axis: int + axis along which the array will be split. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: Tuple[array, ...] + tuple of slices along the given dimension. All the arrays have the same shape. + + Notes + ----- + + .. versionadded:: 2023.12 + """ diff --git a/src/array_api_stubs/_2024_12/searching_functions.py b/src/array_api_stubs/_2024_12/searching_functions.py new file mode 100644 index 000000000..2478cda11 --- /dev/null +++ b/src/array_api_stubs/_2024_12/searching_functions.py @@ -0,0 +1,207 @@ +__all__ = ["argmax", "argmin", "count_nonzero", "nonzero", "searchsorted", "where"] + + +from ._types import Optional, Tuple, Literal, Union, array + + +def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the maximum values along a specified axis. + + When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the maximum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. + """ + + +def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the minimum values along a specified axis. + + When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the minimum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. + """ + + +def count_nonzero( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Counts the number of array elements which are non-zero. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to count non-zero values. By default, the number of non-zero values must be computed over the entire array. If a tuple of integers, the number of non-zero values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the number of non-zeros values was computed over the entire array, a zero-dimensional array containing the total number of non-zero values; otherwise, a non-zero-dimensional array containing the counts along the specified axes. The returned array must have the default array index data type. + + Notes + ----- + + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. versionadded:: 2024.12 + """ + + +def nonzero(x: array, /) -> Tuple[array, ...]: + """ + Returns the indices of the array elements which are non-zero. + + .. admonition:: Data-dependent output shape + :class: admonition important + + The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array. Must have a positive rank. If ``x`` is zero-dimensional, the function must raise an exception. + + Returns + ------- + out: Tuple[array, ...] + a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def searchsorted( + x1: array, + x2: array, + /, + *, + side: Literal["left", "right"] = "left", + sorter: Optional[array] = None, +) -> array: + """ + Finds the indices into ``x1`` such that, if the corresponding elements in ``x2`` were inserted before the indices, the order of ``x1``, when sorted in ascending order, would be preserved. + + Parameters + ---------- + x1: array + input array. Must be a one-dimensional array. Should have a real-valued data type. If ``sorter`` is ``None``, must be sorted in ascending order; otherwise, ``sorter`` must be an array of indices that sort ``x1`` in ascending order. + x2: array + array containing search values. Should have a real-valued data type. + side: Literal['left', 'right'] + argument controlling which index is returned if a value lands exactly on an edge. + + Let ``v`` be an element of ``x2`` given by ``v = x2[j]``, where ``j`` refers to a valid index (see :ref:`indexing`). + + - If ``v`` is less than all elements in ``x1``, then ``out[j]`` must be ``0``. + - If ``v`` is greater than all elements in ``x1``, then ``out[j]`` must be ``M``, where ``M`` is the number of elements in ``x1``. + - Otherwise, each returned index ``i = out[j]`` must satisfy an index condition: + + - If ``side == 'left'``, then ``x1[i-1] < v <= x1[i]``. + - If ``side == 'right'``, then ``x1[i-1] <= v < x1[i]``. + + Default: ``'left'``. + sorter: Optional[array] + array of indices that sort ``x1`` in ascending order. The array must have the same shape as ``x1`` and have an integer data type. Default: ``None``. + + Returns + ------- + out: array + an array of indices with the same shape as ``x2``. The returned array must have the default array index data type. + + Notes + ----- + + For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. + + While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Fixed incorrect boundary conditions. + """ + + +def where( + condition: array, + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: + """ + Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. + + Parameters + ---------- + condition: array + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + x1: Union[array, int, float, complex, bool] + first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). + x2: Union[array, int, float, complex, bool] + second input array. Must be compatible with ``condition`` and ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. + + Notes + ----- + + - At least one of ``x1`` and ``x2`` must be an array. + - If either ``x1`` or ``x2`` is a scalar value, the returned array must have a data type determined according to :ref:`mixing-scalars-and-arrays`. + + .. versionchanged:: 2024.12 + Added scalar argument support. + + .. versionchanged:: 2024.12 + Clarified that the ``condition`` argument should have a boolean data type. + """ diff --git a/src/array_api_stubs/_2024_12/set_functions.py b/src/array_api_stubs/_2024_12/set_functions.py new file mode 100644 index 000000000..5b7e9a56c --- /dev/null +++ b/src/array_api_stubs/_2024_12/set_functions.py @@ -0,0 +1,183 @@ +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] + + +from ._types import Tuple, array + + +def unique_all(x: array, /) -> Tuple[array, array, array, array]: + """ + Returns the unique elements of an input array ``x``, the first occurring indices for each unique element in ``x``, the indices from the set of unique elements that reconstruct ``x``, and the corresponding counts for each unique element in ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array, array, array] + a namedtuple ``(values, indices, inverse_indices, counts)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of a flattened ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. + - third element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and must have the default array index data type. + - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_counts(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple `(values, counts)` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_inverse(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(values, inverse_indices)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior. + """ + + +def unique_values(x: array, /) -> array: + """ + Returns the unique elements of an input array ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: array + a one-dimensional array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required that the output array must be one-dimensional. + """ diff --git a/src/array_api_stubs/_2024_12/sorting_functions.py b/src/array_api_stubs/_2024_12/sorting_functions.py new file mode 100644 index 000000000..2dc4ac410 --- /dev/null +++ b/src/array_api_stubs/_2024_12/sorting_functions.py @@ -0,0 +1,58 @@ +__all__ = ["argsort", "sort"] + + +from ._types import array + + +def argsort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns the indices that sort an array ``x`` along a specified axis. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x : array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the returned indices sort ``x`` in descending order (by value). If ``False``, the returned indices sort ``x`` in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned indices must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned indices may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. + """ + + +def sort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns a sorted copy of an input array ``x``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the array must be sorted in descending order (by value). If ``False``, the array must be sorted in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned array must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned array may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + a sorted array. The returned array must have the same data type and shape as ``x``. + """ diff --git a/src/array_api_stubs/_2024_12/statistical_functions.py b/src/array_api_stubs/_2024_12/statistical_functions.py new file mode 100644 index 000000000..d318f6d2a --- /dev/null +++ b/src/array_api_stubs/_2024_12/statistical_functions.py @@ -0,0 +1,455 @@ +__all__ = [ + "cumulative_sum", + "cumulative_prod", + "max", + "mean", + "min", + "prod", + "std", + "sum", + "var", +] + + +from ._types import Optional, Tuple, Union, array, dtype + + +def cumulative_prod( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative product of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative product must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative product by counting from the last dimension. + + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the multiplicative identity (i.e., one). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative product. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative product must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionadded:: 2024.12 + """ + + +def cumulative_sum( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative sum of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum by counting from the last dimension. + + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative sum. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative sum must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Behavior when providing a zero-dimensional array is explicitly left unspecified. + """ + + +def max( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the maximum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def mean( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the arithmetic mean of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the arithmetic mean. For real-valued operands, + + - If ``N`` is ``0``, the arithmetic mean is ``NaN``. + - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). + + For complex floating-point operands, real-valued floating-point special cases should independently apply to the real and imaginary component operations involving real numbers. For example, let ``a = real(x_i)`` and ``b = imag(x_i)``, and + + - If ``N`` is ``0``, the arithmetic mean is ``NaN + NaN j``. + - If ``a`` is ``NaN``, the real component of the result is ``NaN``. + - Similarly, if ``b`` is ``NaN``, the imaginary component of the result is ``NaN``. + + .. note:: + Array libraries, such as NumPy, PyTorch, and JAX, currently deviate from this specification in their handling of components which are ``NaN`` when computing the arithmetic mean. In general, consumers of array libraries implementing this specification should use :func:`~array_api.isnan` to test whether the result of computing the arithmetic mean over an array have a complex floating-point data type is ``NaN``, rather than relying on ``NaN`` propagation of individual components. + + .. versionchanged:: 2024.12 + Added complex data type support. + """ + + +def min( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the minimum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def prod( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the product of input array ``x`` elements. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the product. + + - If ``N`` is ``0``, the product is `1` (i.e., the empty product). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def std( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the standard deviation of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which standard deviations must be computed. By default, the standard deviation must be computed over the entire array. If a tuple of integers, standard deviations must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the standard deviation according to ``N-c`` where ``N`` corresponds to the total number of elements over which the standard deviation is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the standard deviation of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the corrected sample standard deviation, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the standard deviation. + + - If ``N - correction`` is less than or equal to ``0``, the standard deviation is ``NaN``. + - If ``x_i`` is ``NaN``, the standard deviation is ``NaN`` (i.e., ``NaN`` values propagate). + """ + + +def sum( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the sum of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def var( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the variance of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which variances must be computed. By default, the variance must be computed over the entire array. If a tuple of integers, variances must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the variance according to ``N-c`` where ``N`` corresponds to the total number of elements over which the variance is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the variance of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the unbiased sample variance, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the same data type as ``x``. + + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the variance. + + - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. + - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). + """ diff --git a/src/array_api_stubs/_2024_12/utility_functions.py b/src/array_api_stubs/_2024_12/utility_functions.py new file mode 100644 index 000000000..539833356 --- /dev/null +++ b/src/array_api_stubs/_2024_12/utility_functions.py @@ -0,0 +1,131 @@ +__all__ = ["all", "any", "diff"] + + +from ._types import Optional, Tuple, Union, array + + +def all( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether all input array elements evaluate to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``True``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical AND reduction. By default, a logical AND reduction must be performed over the entire array. If a tuple of integers, logical AND reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def any( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether any input array element evaluates to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``False``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical OR reduction. By default, a logical OR reduction must be performed over the entire array. If a tuple of integers, logical OR reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def diff( + x: array, + /, + *, + axis: int = -1, + n: int = 1, + prepend: Optional[array] = None, + append: Optional[array] = None, +) -> array: + """ + Calculates the n-th discrete forward difference along a specified axis. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: int + axis along which to compute differences. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute differences by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``-1``. + n: int + number of times to recursively compute differences. Default: ``1``. + prepend: Optional[array] + values to prepend to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + append: Optional[array] + values to append to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + + Returns + ------- + out: array + an array containing the n-th differences. Should have the same data type as ``x``. Must have the same shape as ``x``, except for the axis specified by ``axis`` which must have a size determined as follows: + + - Let ``M`` be the number of elements along an axis specified by ``axis``. + - Let ``N1`` be the number of prepended values along an axis specified by ``axis``. + - Let ``N2`` be the number of appended values along an axis specified by ``axis``. + - The final size of the axis specified by ``axis`` must be ``M + N1 + N2 - n``. + + Notes + ----- + + - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). + - If a conforming implementation chooses to support ``prepend`` and ``append`` arrays which have a different data type than ``x``, behavior is unspecified and thus implementation-defined. Implementations may choose to type promote (:ref:`type-promotion`), cast ``prepend`` and/or ``append`` to the same data type as ``x``, or raise an exception. + + .. versionadded:: 2024.12 + """ diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index ca9122e7f..beb6809b8 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1 +1 @@ -from . import _2021_12, _2022_12, _2023_12, _draft +from . import _2021_12, _2022_12, _2023_12, _2024_12, _draft From 772fb461da6ff904ecfcac4a24676e40efcbdb0c Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 17:17:40 -0800 Subject: [PATCH 195/196] docs: fix changelog links PR-URL: https://github.com/data-apis/array-api/pull/908 Reviewed-by: Athan Reines --- CHANGELOG.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0919472d9..ca883c3b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,18 +135,18 @@ The following is a list of breaking changes relative to the previous version of The following is a list of fixes and points of clarification with regard to the previous version of the specification: -- `__add__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__add__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `__bool__`: fix typo in special case notes ([gh-785](https://github.com/data-apis/array-api/pull/785)) - `__dlpack__`: resolve conflicting exception guidance ([gh-887](https://github.com/data-apis/array-api/pull/887)) -- `__eq__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__eq__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `__getitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) -- `__mul__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__ne__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__pow__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__mul__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__ne__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__pow__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `__setitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) -- `__setitem__`: fix typing for `value` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__sub__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__truediv__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__setitem__`: fix typing for `value` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__sub__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__truediv__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `broadcast_to`: clarify broadcast behavior ([gh-888](https://github.com/data-apis/array-api/pull/888)) - `broadcast_to`: clarify required exception behavior ([gh-897](https://github.com/data-apis/array-api/pull/897)) - `clip`: clarify that the operation is only defined when elements in `min` and `max` are inside the bounds of the input array data type ([gh-814](https://github.com/data-apis/array-api/pull/814)) @@ -160,7 +160,7 @@ The following is a list of fixes and points of clarification with regard to the - `fft.irfftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) - `fft.hfft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) - `linalg.solve`: clarify broadcasting semantics and output shape ([gh-810](https://github.com/data-apis/array-api/pull/810)) -- `nonzero`: fix return type ([gh-803](https://github.com/data-apis/array-api/pull/803) and [gh-https://github.com/data-apis/array-api/pull/904](https://github.com/data-apis/array-api/pull/904)) +- `nonzero`: fix return type ([gh-803](https://github.com/data-apis/array-api/pull/803) and [gh-904](https://github.com/data-apis/array-api/pull/904)) - `searchsorted`: fix incorrect boundary conditions ([gh-898](https://github.com/data-apis/array-api/pull/898)) - `sign`: fix equation in function description ([gh-844](https://github.com/data-apis/array-api/pull/844)) - `tile`: fix missing return type ([gh-798](https://github.com/data-apis/array-api/pull/798)) From 0941b216f6231195f1f6a332f957e45554f5da79 Mon Sep 17 00:00:00 2001 From: Guido Imperiale Date: Thu, 3 Apr 2025 08:10:54 +0100 Subject: [PATCH 196/196] docs: fix `indexing` kwarg typing in `meshgrid` PR-URL: https://github.com/data-apis/array-api/pull/915 Reviewed-by: Athan Reines Reviewed-by: Lucas Colley --- src/array_api_stubs/_2021_12/creation_functions.py | 5 +++-- src/array_api_stubs/_2022_12/creation_functions.py | 5 +++-- src/array_api_stubs/_2023_12/creation_functions.py | 5 +++-- src/array_api_stubs/_2024_12/creation_functions.py | 5 +++-- src/array_api_stubs/_draft/creation_functions.py | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index c7659d0df..6942459ee 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -1,5 +1,6 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -311,7 +312,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -319,7 +320,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py index 42d6f9420..88fd6159f 100644 --- a/src/array_api_stubs/_2022_12/creation_functions.py +++ b/src/array_api_stubs/_2022_12/creation_functions.py @@ -1,5 +1,6 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -372,7 +373,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -380,7 +381,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_2023_12/creation_functions.py b/src/array_api_stubs/_2023_12/creation_functions.py index 6de79268e..66c3e1d6b 100644 --- a/src/array_api_stubs/_2023_12/creation_functions.py +++ b/src/array_api_stubs/_2023_12/creation_functions.py @@ -20,6 +20,7 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -454,7 +455,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -462,7 +463,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_2024_12/creation_functions.py b/src/array_api_stubs/_2024_12/creation_functions.py index c09800783..bfe690cd6 100644 --- a/src/array_api_stubs/_2024_12/creation_functions.py +++ b/src/array_api_stubs/_2024_12/creation_functions.py @@ -20,6 +20,7 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -454,7 +455,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -462,7 +463,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index c09800783..bfe690cd6 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -20,6 +20,7 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -454,7 +455,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -462,7 +463,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns