From bcde70def53d2526925610b446dcb13f05ffbbb7 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 20 Nov 2024 14:02:53 -0500 Subject: [PATCH] [NDTensors] Excise libraries --- .../src/lib/AllocateData/.JuliaFormatter.toml | 2 - NDTensors/src/lib/AllocateData/README.md | 15 - .../src/lib/AllocateData/src/AllocateData.jl | 8 - .../AllocateDataLinearAlgebraExt.jl | 4 - .../AllocateDataLinearAlgebraExt/diagonal.jl | 16 - .../AllocateDataLinearAlgebraExt/hermitian.jl | 19 - .../src/lib/AllocateData/src/allocate.jl | 38 - NDTensors/src/lib/AllocateData/src/base.jl | 11 - .../src/lib/AllocateData/src/defaults.jl | 4 - .../src/lib/AllocateData/src/initializers.jl | 29 - NDTensors/src/lib/AllocateData/src/to_axis.jl | 16 - .../src/lib/AllocateData/test/Project.toml | 3 - .../src/lib/AllocateData/test/runtests.jl | 39 - .../lib/BaseExtensions/.JuliaFormatter.toml | 2 - .../lib/BaseExtensions/src/BaseExtensions.jl | 3 - .../src/lib/BaseExtensions/src/replace.jl | 32 - .../src/lib/BaseExtensions/test/Project.toml | 3 - .../src/lib/BaseExtensions/test/runtests.jl | 15 - .../BlockSparseArrays/.JuliaFormatter.toml | 2 - .../src/lib/BlockSparseArrays/Project.toml | 3 - NDTensors/src/lib/BlockSparseArrays/README.md | 192 --- .../BlockSparseArrays/examples/Project.toml | 4 - .../lib/BlockSparseArrays/examples/README.jl | 206 ---- .../src/BlockSparseArraysAdaptExt.jl | 5 - .../src/BlockSparseArraysGradedAxesExt.jl | 156 --- .../src/reducewhile.jl | 34 - .../test/Project.toml | 4 - .../test/runtests.jl | 322 ----- .../src/BlockSparseArraysTensorAlgebraExt.jl | 24 - .../test/Project.toml | 4 - .../test/runtests.jl | 17 - .../BlockArraysExtensions.jl | 591 ---------- .../BlockArraysSparseArraysBaseExt.jl | 11 - .../src/BlockSparseArrays.jl | 28 - .../abstractblocksparsearray.jl | 78 -- .../abstractblocksparsematrix.jl | 1 - .../abstractblocksparsevector.jl | 1 - .../abstractblocksparsearray/arraylayouts.jl | 53 - .../src/abstractblocksparsearray/broadcast.jl | 48 - .../src/abstractblocksparsearray/cat.jl | 7 - .../abstractblocksparsearray/linearalgebra.jl | 18 - .../src/abstractblocksparsearray/map.jl | 151 --- .../sparsearrayinterface.jl | 38 - .../src/abstractblocksparsearray/views.jl | 294 ----- .../wrappedabstractblocksparsearray.jl | 310 ----- .../lib/BlockSparseArrays/src/backup/qr.jl | 143 --- .../src/blocksparsearray/blocksparsearray.jl | 199 ---- .../src/blocksparsearray/defaults.jl | 42 - .../blocksparsearrayinterface/arraylayouts.jl | 48 - .../blocksparsearrayinterface.jl | 274 ----- .../blocksparsearrayinterface/blockzero.jl | 45 - .../blocksparsearrayinterface/broadcast.jl | 39 - .../src/blocksparsearrayinterface/cat.jl | 26 - .../linearalgebra.jl | 12 - .../src/blocksparsearrayinterface/map.jl | 19 - .../src/blocksparsearrayinterface/views.jl | 3 - .../lib/BlockSparseArrays/test/Project.toml | 6 - .../test/TestBlockSparseArraysUtils.jl | 15 - .../lib/BlockSparseArrays/test/runtests.jl | 5 - .../lib/BlockSparseArrays/test/test_basics.jl | 1033 ----------------- .../.JuliaFormatter.toml | 2 - .../src/BroadcastMapConversion.jl | 48 - .../BroadcastMapConversion/test/runtests.jl | 14 - .../lib/DiagonalArrays/.JuliaFormatter.toml | 2 - NDTensors/src/lib/DiagonalArrays/README.md | 84 -- .../lib/DiagonalArrays/examples/Project.toml | 4 - .../src/lib/DiagonalArrays/examples/README.jl | 79 -- .../lib/DiagonalArrays/src/DiagonalArrays.jl | 14 - .../abstractdiagonalarray.jl | 3 - .../src/abstractdiagonalarray/arraylayouts.jl | 7 - .../diagonalarraydiaginterface.jl | 23 - .../sparsearrayinterface.jl | 22 - .../src/diaginterface/defaults.jl | 3 - .../src/diaginterface/diagindex.jl | 14 - .../src/diaginterface/diagindices.jl | 14 - .../src/diaginterface/diaginterface.jl | 57 - .../src/diagonalarray/arraylayouts.jl | 11 - .../src/diagonalarray/diagonalarray.jl | 107 -- .../src/diagonalarray/diagonalmatrix.jl | 5 - .../src/diagonalarray/diagonalvector.jl | 5 - .../src/lib/DiagonalArrays/test/Project.toml | 2 - .../src/lib/DiagonalArrays/test/runtests.jl | 59 - .../src/lib/GradedAxes/.JuliaFormatter.toml | 2 - .../src/lib/GradedAxes/src/GradedAxes.jl | 9 - .../lib/GradedAxes/src/blockedunitrange.jl | 186 --- NDTensors/src/lib/GradedAxes/src/dual.jl | 15 - NDTensors/src/lib/GradedAxes/src/fusion.jl | 112 -- .../src/lib/GradedAxes/src/gradedunitrange.jl | 384 ------ .../lib/GradedAxes/src/gradedunitrangedual.jl | 134 --- .../GradedAxes/src/labelledunitrangedual.jl | 49 - NDTensors/src/lib/GradedAxes/src/onetoone.jl | 9 - .../src/lib/GradedAxes/test/Project.toml | 4 - NDTensors/src/lib/GradedAxes/test/runtests.jl | 8 - .../src/lib/GradedAxes/test/test_basics.jl | 256 ---- .../src/lib/GradedAxes/test/test_dual.jl | 280 ----- .../GradedAxes/test/test_tensor_product.jl | 88 -- .../lib/LabelledNumbers/.JuliaFormatter.toml | 2 - .../LabelledNumbers/src/LabelledNumbers.jl | 8 - .../src/LabelledNumbersBlockArraysExt.jl | 22 - .../LabelledNumbers/src/labelled_interface.jl | 62 - .../lib/LabelledNumbers/src/labelledarray.jl | 20 - .../LabelledNumbers/src/labelledinteger.jl | 123 -- .../lib/LabelledNumbers/src/labellednumber.jl | 41 - .../LabelledNumbers/src/labelledunitrange.jl | 63 - .../src/lib/LabelledNumbers/test/Project.toml | 4 - .../src/lib/LabelledNumbers/test/runtests.jl | 132 --- .../lib/NamedDimsArrays/.JuliaFormatter.toml | 2 - NDTensors/src/lib/NamedDimsArrays/README.md | 36 - .../examples/example_readme.jl | 29 - .../src/NamedDimsArraysAdaptExt.jl | 3 - .../src/adapt_structure.jl | 6 - .../NamedDimsArraysAdaptExt/test/Project.toml | 4 - .../NamedDimsArraysAdaptExt/test/runtests.jl | 13 - .../src/NamedDimsArraysSparseArraysBaseExt.jl | 3 - .../src/densearray.jl | 8 - .../test/Project.toml | 4 - .../test/runtests.jl | 12 - .../src/NamedDimsArraysTensorAlgebraExt.jl | 7 - .../src/contract.jl | 31 - .../src/eigen.jl | 47 - .../src/fusedims.jl | 52 - .../NamedDimsArraysTensorAlgebraExt/src/qr.jl | 18 - .../src/svd.jl | 53 - .../test/Project.toml | 3 - .../test/runtests.jl | 59 - .../lib/NamedDimsArrays/generate_readme.jl | 10 - .../NamedDimsArrays/src/NamedDimsArrays.jl | 27 - .../src/abstractnameddimsarray.jl | 176 --- .../src/abstractnameddimsmatrix.jl | 1 - .../src/abstractnameddimsvector.jl | 1 - .../NamedDimsArrays/src/abstractnamedint.jl | 41 - .../src/abstractnamedunitrange.jl | 35 - .../src/lib/NamedDimsArrays/src/broadcast.jl | 49 - .../NamedDimsArrays/src/broadcast_shape.jl | 24 - .../lib/NamedDimsArrays/src/constructors.jl | 48 - NDTensors/src/lib/NamedDimsArrays/src/map.jl | 14 - NDTensors/src/lib/NamedDimsArrays/src/name.jl | 2 - .../lib/NamedDimsArrays/src/nameddimsarray.jl | 114 -- .../src/lib/NamedDimsArrays/src/namedint.jl | 28 - .../lib/NamedDimsArrays/src/namedunitrange.jl | 12 - .../lib/NamedDimsArrays/src/permutedims.jl | 4 - .../lib/NamedDimsArrays/src/promote_shape.jl | 12 - .../src/lib/NamedDimsArrays/src/randname.jl | 5 - .../src/lib/NamedDimsArrays/src/similar.jl | 49 - .../src/lib/NamedDimsArrays/src/traits.jl | 1 - .../src/lib/NamedDimsArrays/test/Project.toml | 3 - .../src/lib/NamedDimsArrays/test/runtests.jl | 11 - .../test/test_NDTensorsNamedDimsArraysExt.jl | 33 - .../test/test_NamedDimsArraysAdaptExt.jl | 5 - ...test_NamedDimsArraysSparseArraysBaseExt.jl | 5 - .../test_NamedDimsArraysTensorAlgebraExt.jl | 5 - .../lib/NamedDimsArrays/test/test_basic.jl | 108 -- .../test/test_tensoralgebra.jl | 80 -- .../src/NestedPermutedDimsArrays.jl | 276 ----- .../test/Project.toml | 2 - .../NestedPermutedDimsArrays/test/runtests.jl | 23 - .../src/lib/SmallVectors/.JuliaFormatter.toml | 2 - NDTensors/src/lib/SmallVectors/README.md | 73 -- .../SmallVectors/src/BaseExt/insertstyle.jl | 9 - .../src/lib/SmallVectors/src/BaseExt/sort.jl | 23 - .../SmallVectors/src/BaseExt/sortedunique.jl | 241 ---- .../SmallVectors/src/BaseExt/thawfreeze.jl | 6 - .../src/lib/SmallVectors/src/SmallVectors.jl | 45 - .../SmallVectors/src/abstractarray/insert.jl | 2 - .../abstractsmallvector.jl | 34 - .../src/abstractsmallvector/deque.jl | 324 ------ .../src/msmallvector/msmallvector.jl | 80 -- .../src/msmallvector/thawfreeze.jl | 2 - .../src/smallvector/insertstyle.jl | 1 - .../src/smallvector/smallvector.jl | 82 -- .../src/smallvector/thawfreeze.jl | 2 - .../src/subsmallvector/subsmallvector.jl | 80 -- .../src/lib/SmallVectors/test/runtests.jl | 158 --- .../src/lib/SortedSets/.JuliaFormatter.toml | 2 - .../src/lib/SortedSets/src/BaseExt/sorted.jl | 54 - .../SortedSets/src/DictionariesExt/insert.jl | 35 - .../src/DictionariesExt/isinsertable.jl | 1 - .../SmallVectorsDictionariesExt/interface.jl | 3 - .../src/lib/SortedSets/src/SortedSets.jl | 21 - .../src/SortedSetsSmallVectorsExt/smallset.jl | 16 - .../src/lib/SortedSets/src/abstractset.jl | 88 -- .../lib/SortedSets/src/abstractwrappedset.jl | 117 -- NDTensors/src/lib/SortedSets/src/sortedset.jl | 301 ----- NDTensors/src/lib/SortedSets/test/runtests.jl | 42 - .../lib/SparseArraysBase/.JuliaFormatter.toml | 2 - NDTensors/src/lib/SparseArraysBase/README.md | 117 -- .../SparseArraysBase/src/SparseArraysBase.jl | 36 - .../SparseArraysBaseLinearAlgebraExt.jl | 15 - .../SparseArraysBaseSparseArraysExt.jl | 20 - .../abstractsparsearray.jl | 3 - .../abstractsparsematrix.jl | 1 - .../abstractsparsevector.jl | 1 - .../src/abstractsparsearray/arraylayouts.jl | 41 - .../src/abstractsparsearray/base.jl | 16 - .../src/abstractsparsearray/baseinterface.jl | 33 - .../src/abstractsparsearray/broadcast.jl | 4 - .../src/abstractsparsearray/cat.jl | 4 - .../src/abstractsparsearray/convert.jl | 7 - .../src/abstractsparsearray/map.jl | 42 - .../sparsearrayinterface.jl | 46 - .../wrappedabstractsparsearray.jl | 22 - .../src/sparsearraydok/arraylayouts.jl | 13 - .../src/sparsearraydok/defaults.jl | 5 - .../src/sparsearraydok/sparsearraydok.jl | 146 --- .../src/sparsearraydok/sparsematrixdok.jl | 1 - .../src/sparsearraydok/sparsevectordok.jl | 1 - .../SparseArraysBaseLinearAlgebraExt.jl | 78 -- .../src/sparsearrayinterface/arraylayouts.jl | 5 - .../src/sparsearrayinterface/base.jl | 126 -- .../src/sparsearrayinterface/broadcast.jl | 37 - .../src/sparsearrayinterface/cat.jl | 64 - .../src/sparsearrayinterface/conversion.jl | 5 - .../src/sparsearrayinterface/copyto.jl | 15 - .../src/sparsearrayinterface/densearray.jl | 12 - .../src/sparsearrayinterface/indexing.jl | 216 ---- .../src/sparsearrayinterface/interface.jl | 18 - .../interface_optional.jl | 44 - .../src/sparsearrayinterface/map.jl | 120 -- .../sparsearrayinterface/vectorinterface.jl | 28 - .../src/sparsearrayinterface/wrappers.jl | 51 - .../src/sparsearrayinterface/zero.jl | 5 - .../lib/SparseArraysBase/test/Project.toml | 7 - .../AbstractSparseArrays.jl | 74 -- .../DiagonalArrays.jl | 95 -- .../SparseArraysBaseTestUtils/Project.toml | 2 - .../SparseArraysBaseTestUtils/SparseArrays.jl | 166 --- .../SparseArraysBaseTestUtils.jl | 5 - .../src/lib/SparseArraysBase/test/runtests.jl | 5 - .../test/test_abstractsparsearray.jl | 439 ------- .../lib/SparseArraysBase/test/test_array.jl | 13 - .../test/test_diagonalarray.jl | 76 -- .../test/test_sparsearraydok.jl | 139 --- .../lib/SymmetrySectors/.JuliaFormatter.toml | 2 - .../src/lib/SymmetrySectors/Project.toml | 0 .../SymmetrySectors/src/SymmetrySectors.jl | 17 - .../lib/SymmetrySectors/src/abstractsector.jl | 114 -- .../src/namedtuple_operations.jl | 16 - .../src/sector_definitions/fib.jl | 45 - .../src/sector_definitions/ising.jl | 46 - .../src/sector_definitions/o2.jl | 75 -- .../src/sector_definitions/su.jl | 175 --- .../src/sector_definitions/su2k.jl | 27 - .../src/sector_definitions/trivial.jl | 38 - .../src/sector_definitions/u1.jl | 31 - .../src/sector_definitions/zn.jl | 25 - .../lib/SymmetrySectors/src/sector_product.jl | 238 ---- .../lib/SymmetrySectors/src/symmetry_style.jl | 17 - .../src/lib/SymmetrySectors/test/runtests.jl | 12 - .../SymmetrySectors/test/test_fusion_rules.jl | 287 ----- .../test/test_sector_product.jl | 622 ---------- .../test/test_simple_sectors.jl | 215 ---- .../src/lib/TagSets/.JuliaFormatter.toml | 2 - NDTensors/src/lib/TagSets/README.md | 20 - .../src/lib/TagSets/examples/benchmark.jl | 47 - NDTensors/src/lib/TagSets/src/TagSets.jl | 89 -- NDTensors/src/lib/TagSets/test/runtests.jl | 35 - .../lib/TensorAlgebra/.JuliaFormatter.toml | 2 - NDTensors/src/lib/TensorAlgebra/Project.toml | 3 - .../TensorAlgebraGradedAxesExt/Project.toml | 0 .../src/TensorAlgebraGradedAxesExt.jl | 8 - .../test/Project.toml | 7 - .../test/runtests.jl | 7 - .../test/test_basics.jl | 30 - .../test/test_contract.jl | 34 - .../src/BaseExtensions/BaseExtensions.jl | 4 - .../src/BaseExtensions/indexin.jl | 5 - .../src/BaseExtensions/permutedims.jl | 20 - .../LinearAlgebraExtensions.jl | 3 - .../src/LinearAlgebraExtensions/qr.jl | 68 -- .../lib/TensorAlgebra/src/TensorAlgebra.jl | 14 - .../TensorAlgebra/src/blockedpermutation.jl | 192 --- .../src/contract/allocate_output.jl | 83 -- .../src/contract/blockedperms.jl | 32 - .../TensorAlgebra/src/contract/contract.jl | 120 -- .../contract/contract_matricize/contract.jl | 57 - .../src/contract/output_labels.jl | 21 - .../src/lib/TensorAlgebra/src/fusedims.jl | 69 -- .../src/lib/TensorAlgebra/src/splitdims.jl | 68 -- .../src/lib/TensorAlgebra/test/Project.toml | 9 - .../src/lib/TensorAlgebra/test/runtests.jl | 4 - .../src/lib/TensorAlgebra/test/test_basics.jl | 199 ---- .../.JuliaFormatter.toml | 2 - .../src/TypeParameterAccessors.jl | 21 - .../src/abstractposition.jl | 3 - .../src/abstracttypeparameter.jl | 12 - .../src/base/abstractarray.jl | 95 -- .../TypeParameterAccessors/src/base/array.jl | 2 - .../src/base/linearalgebra.jl | 25 - .../src/base/similartype.jl | 88 -- .../src/base/stridedviews.jl | 3 - .../src/default_parameters.jl | 62 - .../TypeParameterAccessors/src/interface.jl | 22 - .../src/is_parameter_specified.jl | 5 - .../lib/TypeParameterAccessors/src/ndims.jl | 6 - .../TypeParameterAccessors/src/parameter.jl | 3 - .../TypeParameterAccessors/src/parameters.jl | 18 - .../TypeParameterAccessors/src/position.jl | 11 - .../src/set_parameters.jl | 46 - .../src/specify_parameters.jl | 30 - .../TypeParameterAccessors/src/to_unionall.jl | 17 - .../src/type_parameters.jl | 17 - .../src/unspecify_parameters.jl | 45 - .../TypeParameterAccessors/test/Project.toml | 4 - .../TypeParameterAccessors/test/runtests.jl | 10 - .../test/test_basics.jl | 85 -- .../test/test_custom_types.jl | 78 -- .../test/test_defaults.jl | 75 -- .../test/test_similartype.jl | 26 - .../test/test_wrappers.jl | 121 -- .../test/utils/test_inferred.jl | 28 - .../UnallocatedArrays/.JuliaFormatter.toml | 2 - NDTensors/src/lib/UnallocatedArrays/README.md | 4 - .../src/UnallocatedArrays.jl | 11 - .../src/abstractfill/abstractfill.jl | 22 - .../src/abstractunallocatedarray.jl | 62 - .../lib/UnallocatedArrays/src/broadcast.jl | 28 - .../lib/UnallocatedArrays/src/set_types.jl | 14 - .../UnallocatedArrays/src/unallocatedfill.jl | 67 -- .../UnallocatedArrays/src/unallocatedzeros.jl | 88 -- .../lib/UnallocatedArrays/test/Project.toml | 5 - .../lib/UnallocatedArrays/test/runtests.jl | 326 ------ .../lib/UnspecifiedTypes/.JuliaFormatter.toml | 2 - NDTensors/src/lib/UnspecifiedTypes/README.md | 3 - NDTensors/src/lib/UnspecifiedTypes/TODO.md | 6 - .../UnspecifiedTypes/src/UnspecifiedTypes.jl | 11 - .../UnspecifiedTypes/src/unspecifiedarray.jl | 1 - .../UnspecifiedTypes/src/unspecifiednumber.jl | 5 - .../UnspecifiedTypes/src/unspecifiedzero.jl | 39 - .../src/lib/UnspecifiedTypes/test/runtests.jl | 6 - 329 files changed, 18137 deletions(-) delete mode 100644 NDTensors/src/lib/AllocateData/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/AllocateData/README.md delete mode 100644 NDTensors/src/lib/AllocateData/src/AllocateData.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/AllocateDataLinearAlgebraExt.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/diagonal.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/hermitian.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/allocate.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/base.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/defaults.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/initializers.jl delete mode 100644 NDTensors/src/lib/AllocateData/src/to_axis.jl delete mode 100644 NDTensors/src/lib/AllocateData/test/Project.toml delete mode 100644 NDTensors/src/lib/AllocateData/test/runtests.jl delete mode 100644 NDTensors/src/lib/BaseExtensions/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/BaseExtensions/src/BaseExtensions.jl delete mode 100644 NDTensors/src/lib/BaseExtensions/src/replace.jl delete mode 100644 NDTensors/src/lib/BaseExtensions/test/Project.toml delete mode 100644 NDTensors/src/lib/BaseExtensions/test/runtests.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/BlockSparseArrays/Project.toml delete mode 100644 NDTensors/src/lib/BlockSparseArrays/README.md delete mode 100644 NDTensors/src/lib/BlockSparseArrays/examples/Project.toml delete mode 100644 NDTensors/src/lib/BlockSparseArrays/examples/README.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysAdaptExt/src/BlockSparseArraysAdaptExt.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/BlockSparseArraysGradedAxesExt.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/reducewhile.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/Project.toml delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/runtests.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/src/BlockSparseArraysTensorAlgebraExt.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/Project.toml delete mode 100644 NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/runtests.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/BlockArraysExtensions/BlockArraysExtensions.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/BlockArraysSparseArraysBaseExt/BlockArraysSparseArraysBaseExt.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/BlockSparseArrays.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsearray.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsematrix.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsevector.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/arraylayouts.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/broadcast.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/cat.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/linearalgebra.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/map.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/sparsearrayinterface.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/views.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/backup/qr.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/blocksparsearray.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/defaults.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/arraylayouts.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blocksparsearrayinterface.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blockzero.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/broadcast.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/cat.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/linearalgebra.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/map.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/views.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/test/Project.toml delete mode 100644 NDTensors/src/lib/BlockSparseArrays/test/TestBlockSparseArraysUtils.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/test/runtests.jl delete mode 100644 NDTensors/src/lib/BlockSparseArrays/test/test_basics.jl delete mode 100644 NDTensors/src/lib/BroadcastMapConversion/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/BroadcastMapConversion/src/BroadcastMapConversion.jl delete mode 100644 NDTensors/src/lib/BroadcastMapConversion/test/runtests.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/DiagonalArrays/README.md delete mode 100644 NDTensors/src/lib/DiagonalArrays/examples/Project.toml delete mode 100644 NDTensors/src/lib/DiagonalArrays/examples/README.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/DiagonalArrays.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/abstractdiagonalarray.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/arraylayouts.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/diagonalarraydiaginterface.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/sparsearrayinterface.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diaginterface/defaults.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindex.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindices.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diaginterface/diaginterface.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diagonalarray/arraylayouts.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalarray.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalmatrix.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalvector.jl delete mode 100644 NDTensors/src/lib/DiagonalArrays/test/Project.toml delete mode 100644 NDTensors/src/lib/DiagonalArrays/test/runtests.jl delete mode 100644 NDTensors/src/lib/GradedAxes/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/GradedAxes/src/GradedAxes.jl delete mode 100644 NDTensors/src/lib/GradedAxes/src/blockedunitrange.jl delete mode 100644 NDTensors/src/lib/GradedAxes/src/dual.jl delete mode 100644 NDTensors/src/lib/GradedAxes/src/fusion.jl delete mode 100644 NDTensors/src/lib/GradedAxes/src/gradedunitrange.jl delete mode 100644 NDTensors/src/lib/GradedAxes/src/gradedunitrangedual.jl delete mode 100644 NDTensors/src/lib/GradedAxes/src/labelledunitrangedual.jl delete mode 100644 NDTensors/src/lib/GradedAxes/src/onetoone.jl delete mode 100644 NDTensors/src/lib/GradedAxes/test/Project.toml delete mode 100644 NDTensors/src/lib/GradedAxes/test/runtests.jl delete mode 100644 NDTensors/src/lib/GradedAxes/test/test_basics.jl delete mode 100644 NDTensors/src/lib/GradedAxes/test/test_dual.jl delete mode 100644 NDTensors/src/lib/GradedAxes/test/test_tensor_product.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/LabelledNumbers/src/LabelledNumbers.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/src/LabelledNumbersBlockArraysExt.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/src/labelled_interface.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/src/labelledarray.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/src/labelledinteger.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/src/labellednumber.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/src/labelledunitrange.jl delete mode 100644 NDTensors/src/lib/LabelledNumbers/test/Project.toml delete mode 100644 NDTensors/src/lib/LabelledNumbers/test/runtests.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/NamedDimsArrays/README.md delete mode 100644 NDTensors/src/lib/NamedDimsArrays/examples/example_readme.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/NamedDimsArraysAdaptExt.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/adapt_structure.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/Project.toml delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/runtests.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/NamedDimsArraysSparseArraysBaseExt.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/densearray.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/Project.toml delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/runtests.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/NamedDimsArraysTensorAlgebraExt.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/contract.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/eigen.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/fusedims.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/qr.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/svd.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/Project.toml delete mode 100644 NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/runtests.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/generate_readme.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/NamedDimsArrays.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsarray.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsmatrix.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsvector.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/abstractnamedint.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/abstractnamedunitrange.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/broadcast.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/broadcast_shape.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/constructors.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/map.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/name.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/nameddimsarray.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/namedint.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/namedunitrange.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/permutedims.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/promote_shape.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/randname.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/similar.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/src/traits.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/Project.toml delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/runtests.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/test_NDTensorsNamedDimsArraysExt.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysAdaptExt.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysSparseArraysBaseExt.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysTensorAlgebraExt.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/test_basic.jl delete mode 100644 NDTensors/src/lib/NamedDimsArrays/test/test_tensoralgebra.jl delete mode 100644 NDTensors/src/lib/NestedPermutedDimsArrays/src/NestedPermutedDimsArrays.jl delete mode 100644 NDTensors/src/lib/NestedPermutedDimsArrays/test/Project.toml delete mode 100644 NDTensors/src/lib/NestedPermutedDimsArrays/test/runtests.jl delete mode 100644 NDTensors/src/lib/SmallVectors/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/SmallVectors/README.md delete mode 100644 NDTensors/src/lib/SmallVectors/src/BaseExt/insertstyle.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/BaseExt/sort.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/BaseExt/sortedunique.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/BaseExt/thawfreeze.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/SmallVectors.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/abstractarray/insert.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/abstractsmallvector/abstractsmallvector.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/abstractsmallvector/deque.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/msmallvector/msmallvector.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/msmallvector/thawfreeze.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/smallvector/insertstyle.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/smallvector/smallvector.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/smallvector/thawfreeze.jl delete mode 100644 NDTensors/src/lib/SmallVectors/src/subsmallvector/subsmallvector.jl delete mode 100644 NDTensors/src/lib/SmallVectors/test/runtests.jl delete mode 100644 NDTensors/src/lib/SortedSets/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/SortedSets/src/BaseExt/sorted.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/DictionariesExt/insert.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/DictionariesExt/isinsertable.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/SmallVectorsDictionariesExt/interface.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/SortedSets.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/SortedSetsSmallVectorsExt/smallset.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/abstractset.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/abstractwrappedset.jl delete mode 100644 NDTensors/src/lib/SortedSets/src/sortedset.jl delete mode 100644 NDTensors/src/lib/SortedSets/test/runtests.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/SparseArraysBase/README.md delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/SparseArraysBase.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseLinearAlgebraExt.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseSparseArraysExt.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsearray.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsematrix.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsevector.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/arraylayouts.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/base.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/baseinterface.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/broadcast.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/cat.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/convert.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/map.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/sparsearrayinterface.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/wrappedabstractsparsearray.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/arraylayouts.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/defaults.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsearraydok.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsematrixdok.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsevectordok.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/SparseArraysBaseLinearAlgebraExt.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/arraylayouts.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/base.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/broadcast.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/cat.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/conversion.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/copyto.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/densearray.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/indexing.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface_optional.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/map.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/vectorinterface.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/wrappers.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/zero.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/Project.toml delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/AbstractSparseArrays.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/DiagonalArrays.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/Project.toml delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArrays.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArraysBaseTestUtils.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/runtests.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/test_abstractsparsearray.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/test_array.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/test_diagonalarray.jl delete mode 100644 NDTensors/src/lib/SparseArraysBase/test/test_sparsearraydok.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/SymmetrySectors/Project.toml delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/SymmetrySectors.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/abstractsector.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/namedtuple_operations.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/fib.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/ising.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/o2.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su2k.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/trivial.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/u1.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_definitions/zn.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/sector_product.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/src/symmetry_style.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/test/runtests.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/test/test_fusion_rules.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl delete mode 100644 NDTensors/src/lib/SymmetrySectors/test/test_simple_sectors.jl delete mode 100644 NDTensors/src/lib/TagSets/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/TagSets/README.md delete mode 100644 NDTensors/src/lib/TagSets/examples/benchmark.jl delete mode 100644 NDTensors/src/lib/TagSets/src/TagSets.jl delete mode 100644 NDTensors/src/lib/TagSets/test/runtests.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/TensorAlgebra/Project.toml delete mode 100644 NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/Project.toml delete mode 100644 NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/src/TensorAlgebraGradedAxesExt.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/Project.toml delete mode 100644 NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/runtests.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_basics.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_contract.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/BaseExtensions.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/indexin.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/permutedims.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/LinearAlgebraExtensions.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/qr.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/TensorAlgebra.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/blockedpermutation.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/contract/allocate_output.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/contract/blockedperms.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/contract/contract.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/contract/contract_matricize/contract.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/contract/output_labels.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/fusedims.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/src/splitdims.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/test/Project.toml delete mode 100644 NDTensors/src/lib/TensorAlgebra/test/runtests.jl delete mode 100644 NDTensors/src/lib/TensorAlgebra/test/test_basics.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/abstractposition.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/abstracttypeparameter.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/base/abstractarray.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/base/array.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/base/linearalgebra.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/base/similartype.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/base/stridedviews.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/default_parameters.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/interface.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/is_parameter_specified.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/ndims.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/parameter.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/parameters.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/position.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/set_parameters.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/specify_parameters.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/to_unionall.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/type_parameters.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/src/unspecify_parameters.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/Project.toml delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/test_basics.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/test_custom_types.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/test_defaults.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/test_similartype.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/test_wrappers.jl delete mode 100644 NDTensors/src/lib/TypeParameterAccessors/test/utils/test_inferred.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/UnallocatedArrays/README.md delete mode 100644 NDTensors/src/lib/UnallocatedArrays/src/UnallocatedArrays.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/src/abstractfill/abstractfill.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/src/abstractunallocatedarray.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/src/broadcast.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/src/set_types.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/src/unallocatedfill.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/src/unallocatedzeros.jl delete mode 100644 NDTensors/src/lib/UnallocatedArrays/test/Project.toml delete mode 100644 NDTensors/src/lib/UnallocatedArrays/test/runtests.jl delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/.JuliaFormatter.toml delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/README.md delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/TODO.md delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/src/UnspecifiedTypes.jl delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedarray.jl delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/src/unspecifiednumber.jl delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedzero.jl delete mode 100644 NDTensors/src/lib/UnspecifiedTypes/test/runtests.jl diff --git a/NDTensors/src/lib/AllocateData/.JuliaFormatter.toml b/NDTensors/src/lib/AllocateData/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/AllocateData/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/AllocateData/README.md b/NDTensors/src/lib/AllocateData/README.md deleted file mode 100644 index a0c5264c67..0000000000 --- a/NDTensors/src/lib/AllocateData/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# AllocateData.jl - -Generic interface for allocating data, such as array data. - -## See also - -- https://juliaobjects.github.io/ConstructionBase.jl -- https://github.com/oschulz/HeterogeneousComputing.jl -- https://github.com/JuliaGPU/KernelAbstractions.jl -- https://github.com/JuliaLang/julia/issues/11557 -- https://github.com/JuliaLang/julia/issues/18161 -- https://github.com/JuliaLang/julia/issues/22218 -- https://github.com/JuliaLang/julia/issues/25107 -- https://github.com/JuliaArrays/ArrayInterface.jl/issues/130 -- https://github.com/JuliaArrays/StaticArrays.jl/issues/32 diff --git a/NDTensors/src/lib/AllocateData/src/AllocateData.jl b/NDTensors/src/lib/AllocateData/src/AllocateData.jl deleted file mode 100644 index 03943c5c92..0000000000 --- a/NDTensors/src/lib/AllocateData/src/AllocateData.jl +++ /dev/null @@ -1,8 +0,0 @@ -module AllocateData -include("to_axis.jl") -include("initializers.jl") -include("defaults.jl") -include("allocate.jl") -include("base.jl") -include("AllocateDataLinearAlgebraExt/AllocateDataLinearAlgebraExt.jl") -end diff --git a/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/AllocateDataLinearAlgebraExt.jl b/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/AllocateDataLinearAlgebraExt.jl deleted file mode 100644 index b44d41caa3..0000000000 --- a/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/AllocateDataLinearAlgebraExt.jl +++ /dev/null @@ -1,4 +0,0 @@ -module AllocateDataLinearAlgebraExt -include("diagonal.jl") -include("hermitian.jl") -end diff --git a/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/diagonal.jl b/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/diagonal.jl deleted file mode 100644 index e3a85414ae..0000000000 --- a/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/diagonal.jl +++ /dev/null @@ -1,16 +0,0 @@ -using Compat: allequal -using LinearAlgebra: LinearAlgebra, Diagonal -using ..AllocateData: AllocateData, to_dim - -function LinearAlgebra.Diagonal{T}( - ::AllocateData.UndefInitializer, axes::Tuple{Vararg{AbstractUnitRange,2}} -) where {T} - dims = to_dim.(axes) - @assert allequal(dims) - diag_dim = first(dims) - if VERSION < v"1.7.0-DEV.986" - # https://github.com/JuliaLang/julia/pull/38282 - return Diagonal(Vector{T}(Base.undef, diag_dim)) - end - return Diagonal{T}(Base.undef, diag_dim) -end diff --git a/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/hermitian.jl b/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/hermitian.jl deleted file mode 100644 index b3fb75da2a..0000000000 --- a/NDTensors/src/lib/AllocateData/src/AllocateDataLinearAlgebraExt/hermitian.jl +++ /dev/null @@ -1,19 +0,0 @@ -using LinearAlgebra: LinearAlgebra, Hermitian -using ..AllocateData: AllocateData, to_dim - -function (arraytype::Type{<:LinearAlgebra.Hermitian})( - ::AllocateData.UndefInitializer, axes::Tuple{Vararg{AbstractUnitRange,2}} -) - # TODO: Check the parent type of `arraytype`. - a = Array{eltype(arraytype)}(AllocateData.undef, axes) - return Hermitian(a) -end - -## TODO: For some reason this is broken, and gives an error: -## ERROR: UndefVarError: `T` not defined -## function LinearAlgebra.Hermitian{T}( -## ::AllocateData.UndefInitializer, axes::Tuple{Vararg{AbstractUnitRange,2}} -## ) where {T} -## a = Array{T}(AllocateData.undef, axes) -## return Hermitian(a) -## end diff --git a/NDTensors/src/lib/AllocateData/src/allocate.jl b/NDTensors/src/lib/AllocateData/src/allocate.jl deleted file mode 100644 index 1d7f492bae..0000000000 --- a/NDTensors/src/lib/AllocateData/src/allocate.jl +++ /dev/null @@ -1,38 +0,0 @@ -# Allocate undefined memory. -function allocate( - arraytype::Type{<:AbstractArray}, - ::UndefInitializer, - axes::Tuple{Vararg{AbstractUnitRange}}, -) - # Defaults to `undef` constructor, like `Base.similar`. - return arraytype(undef, axes) -end - -function allocate( - arraytype::Type{<:AbstractArray}, initializer::AbstractInitializer, dims::Tuple -) - return allocate(arraytype, initializer, to_axis.(dims)) -end - -# TODO: Move to `allocate_zeros`. -# Allocate an array filled with zeros. -function allocate(arraytype::Type{<:AbstractArray}, ::ZeroInitializer, axes::Tuple) - a = allocate(arraytype, axes) - # TODO: Use `VectorInterface.zerovector!!`. - a .= zero(eltype(a)) - return a -end - -function allocate_zeros(arraytype::Type{<:AbstractArray}, axes::Tuple) - return allocate(arraytype, zero_init, axes) -end - -# Default initializes undefined memory -function allocate(arraytype::Type{<:AbstractArray}, axes::Tuple) - return allocate(arraytype, default_initializer(arraytype), axes) -end - -# Default initializes undefined memory -function allocate(axes::Tuple) - return allocate(default_arraytype(), axes) -end diff --git a/NDTensors/src/lib/AllocateData/src/base.jl b/NDTensors/src/lib/AllocateData/src/base.jl deleted file mode 100644 index 840b7603e6..0000000000 --- a/NDTensors/src/lib/AllocateData/src/base.jl +++ /dev/null @@ -1,11 +0,0 @@ -# TODO: Move to `AllocatedDataBaseExt`. - -# `Base.UndefInitializer` -function allocate(arraytype::Type{<:AbstractArray}, ::Base.UndefInitializer, axes::Tuple) - return allocate(arraytype, undef, axes) -end - -# Work around limited `Array` constructors (don't accept `axes`) -function Base.Array{T}(::UndefInitializer, axes::Tuple{Vararg{AbstractUnitRange}}) where {T} - return Array{T}(Base.undef, to_dim.(axes)) -end diff --git a/NDTensors/src/lib/AllocateData/src/defaults.jl b/NDTensors/src/lib/AllocateData/src/defaults.jl deleted file mode 100644 index c14a1a558a..0000000000 --- a/NDTensors/src/lib/AllocateData/src/defaults.jl +++ /dev/null @@ -1,4 +0,0 @@ -default_initializer(::Type{<:AbstractArray}) = undef -default_eltype() = Float64 -default_arraytype(elt::Type) = Array{elt} -default_arraytype() = default_arraytype(default_eltype()) diff --git a/NDTensors/src/lib/AllocateData/src/initializers.jl b/NDTensors/src/lib/AllocateData/src/initializers.jl deleted file mode 100644 index 80b3700214..0000000000 --- a/NDTensors/src/lib/AllocateData/src/initializers.jl +++ /dev/null @@ -1,29 +0,0 @@ -# Like: -# undef = UndefBlocksInitializer() -# undef_blocks = UndefBlocksInitializer() -abstract type AbstractInitializer end - -struct ZeroInitializer <: AbstractInitializer end -const zero_init = ZeroInitializer() - -# Equivalent to `Base.UndefUnitializer` and `Base.undef`, -# but a subtype of `AbstractInitializer`. -struct UndefInitializer <: AbstractInitializer end -const undef = UndefInitializer() - -# TODO: Move to `AllocateDataBaseExt`. -# Forward constructors to Base constructors. -function (arraytype::Type{<:AbstractArray})(::AllocateData.UndefInitializer, axes::Tuple) - return arraytype(Base.undef, axes) -end - -# TODO: Move to `AllocateDataBlockArraysExt`. -using BlockArrays: BlockArrays - -struct UndefBlocksInitializer <: AbstractInitializer end -const undef_blocks = UndefBlocksInitializer() - -# TODO: Move to `AllocateDataBlockArraysExt`. -base_initializer(::BlockArrays.UndefBlocksInitializer) = BlockArrays.undef_blocks - -# TODO: Add `rand_init`, `randn_init`? diff --git a/NDTensors/src/lib/AllocateData/src/to_axis.jl b/NDTensors/src/lib/AllocateData/src/to_axis.jl deleted file mode 100644 index 27d4e85b3c..0000000000 --- a/NDTensors/src/lib/AllocateData/src/to_axis.jl +++ /dev/null @@ -1,16 +0,0 @@ -# Convert dimension to axis -to_axis(dim::Int) = Base.OneTo(dim) -to_axis(dim::Integer) = to_axis(Int(dim)) - -function to_dim(axis::AbstractUnitRange) - # Assume 1-based indexing - @assert isone(first(axis)) - return length(axis) -end - -# TODO: Move to `AllocateDataBlockArraysExt`. -using BlockArrays: blockedrange - -# Blocked dimension/axis -to_axis(dim::Vector{Int}) = blockedrange(dim) -to_axis(dim::Vector{<:Integer}) = blockedrange(Int.(dim)) diff --git a/NDTensors/src/lib/AllocateData/test/Project.toml b/NDTensors/src/lib/AllocateData/test/Project.toml deleted file mode 100644 index ef491a529c..0000000000 --- a/NDTensors/src/lib/AllocateData/test/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/AllocateData/test/runtests.jl b/NDTensors/src/lib/AllocateData/test/runtests.jl deleted file mode 100644 index b824651feb..0000000000 --- a/NDTensors/src/lib/AllocateData/test/runtests.jl +++ /dev/null @@ -1,39 +0,0 @@ -@eval module $(gensym()) -using NDTensors.AllocateData: AllocateData, allocate, allocate_zeros, zero_init -using LinearAlgebra: Diagonal, Hermitian -using NDTensors.DiagonalArrays: DiagonalArray -using NDTensors.BlockSparseArrays: BlockSparseArray -using NDTensors.SparseArraysBase: SparseArrayDOK -using Test: @test, @testset, @test_broken, @test_throws - -const arraytypes = ( - Array, Diagonal, Hermitian, DiagonalArray, BlockSparseArray, SparseArrayDOK -) -const elts = (Float32, Float64, ComplexF32, ComplexF64) -const initializerss = ((undef,), (AllocateData.undef,), (zero_init,), ()) -const axess = ((2, 2), (1:2, 1:2)) -@testset "AllocateData (arraytype=$arraytype, eltype=$elt, initializer=$initializers, axes=$axes)" for arraytype in - arraytypes, - elt in elts, - initializers in initializerss, - axes in axess - - a = allocate(arraytype{elt}, initializers..., axes) - @test a isa arraytype{elt} - @test ndims(a) == length(axes) - @test size(a) == (2, 2) - if !isempty(initializers) && only(initializers) isa AllocateData.ZeroInitializer - @test iszero(a) - end - a = allocate_zeros(arraytype{elt}, axes) - @test a isa arraytype{elt} - @test ndims(a) == length(axes) - @test size(a) == (2, 2) - @test iszero(a) - if !(arraytype <: BlockSparseArray) - @test_throws AssertionError allocate(arraytype{elt}, (1:2, 0:2)) - else - @test_broken error("Constructor should throw error for non-one-based axes.") - end -end -end diff --git a/NDTensors/src/lib/BaseExtensions/.JuliaFormatter.toml b/NDTensors/src/lib/BaseExtensions/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/BaseExtensions/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/BaseExtensions/src/BaseExtensions.jl b/NDTensors/src/lib/BaseExtensions/src/BaseExtensions.jl deleted file mode 100644 index 747f3ac675..0000000000 --- a/NDTensors/src/lib/BaseExtensions/src/BaseExtensions.jl +++ /dev/null @@ -1,3 +0,0 @@ -module BaseExtensions -include("replace.jl") -end diff --git a/NDTensors/src/lib/BaseExtensions/src/replace.jl b/NDTensors/src/lib/BaseExtensions/src/replace.jl deleted file mode 100644 index 9749f85a7a..0000000000 --- a/NDTensors/src/lib/BaseExtensions/src/replace.jl +++ /dev/null @@ -1,32 +0,0 @@ -replace(collection, replacements::Pair...) = Base.replace(collection, replacements...) -@static if VERSION < v"1.7.0-DEV.15" - # https://github.com/JuliaLang/julia/pull/38216 - # TODO: Add to `Compat.jl` or delete when we drop Julia 1.6 support. - # `replace` for Tuples. - function _replace(f::Base.Callable, t::Tuple, count::Int) - return if count == 0 || isempty(t) - t - else - x = f(t[1]) - (x, _replace(f, Base.tail(t), count - !==(x, t[1]))...) - end - end - - function replace(f::Base.Callable, t::Tuple; count::Integer=typemax(Int)) - return _replace(f, t, Base.check_count(count)) - end - - function _replace(t::Tuple, count::Int, old_new::Tuple{Vararg{Pair}}) - return _replace(t, count) do x - Base.@_inline_meta - for o_n in old_new - isequal(first(o_n), x) && return last(o_n) - end - return x - end - end - - function replace(t::Tuple, old_new::Pair...; count::Integer=typemax(Int)) - return _replace(t, Base.check_count(count), old_new) - end -end diff --git a/NDTensors/src/lib/BaseExtensions/test/Project.toml b/NDTensors/src/lib/BaseExtensions/test/Project.toml deleted file mode 100644 index 90187321ef..0000000000 --- a/NDTensors/src/lib/BaseExtensions/test/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" diff --git a/NDTensors/src/lib/BaseExtensions/test/runtests.jl b/NDTensors/src/lib/BaseExtensions/test/runtests.jl deleted file mode 100644 index d29334d85f..0000000000 --- a/NDTensors/src/lib/BaseExtensions/test/runtests.jl +++ /dev/null @@ -1,15 +0,0 @@ -using SafeTestsets: @safetestset - -@safetestset "BaseExtensions" begin - using NDTensors.BaseExtensions: BaseExtensions - using Test: @test, @testset - @testset "replace $(typeof(collection))" for collection in - (["a", "b", "c"], ("a", "b", "c")) - r1 = BaseExtensions.replace(collection, "b" => "d") - @test r1 == typeof(collection)(["a", "d", "c"]) - @test typeof(r1) === typeof(collection) - r2 = BaseExtensions.replace(collection, "b" => "d", "a" => "e") - @test r2 == typeof(collection)(["e", "d", "c"]) - @test typeof(r2) === typeof(collection) - end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/.JuliaFormatter.toml b/NDTensors/src/lib/BlockSparseArrays/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/BlockSparseArrays/Project.toml b/NDTensors/src/lib/BlockSparseArrays/Project.toml deleted file mode 100644 index 4b6396f4a0..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/NDTensors/src/lib/BlockSparseArrays/README.md b/NDTensors/src/lib/BlockSparseArrays/README.md deleted file mode 100644 index dd74c97225..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/README.md +++ /dev/null @@ -1,192 +0,0 @@ -# BlockSparseArrays.jl - -A Julia `BlockSparseArray` type based on the `BlockArrays.jl` interface. - -It wraps an elementwise `SparseArray` type that uses a dictionary-of-keys -to store non-zero values, specifically a `Dictionary` from `Dictionaries.jl`. -`BlockArrays` reinterprets the `SparseArray` as a blocked data structure. - -````julia -using NDTensors.BlockSparseArrays -using BlockArrays: BlockArrays, blockedrange -using Test - -function main() - # Block dimensions - i1 = [2, 3] - i2 = [2, 3] - - i_axes = (blockedrange(i1), blockedrange(i2)) - - function block_size(axes, block) - return length.(getindex.(axes, BlockArrays.Block.(block.n))) - end - - # Data - nz_blocks = BlockArrays.Block.([(1, 1), (2, 2)]) - nz_block_sizes = [block_size(i_axes, nz_block) for nz_block in nz_blocks] - nz_block_lengths = prod.(nz_block_sizes) - - # Blocks with discontiguous underlying data - d_blocks = randn.(nz_block_sizes) - - # Blocks with contiguous underlying data - # d_data = PseudoBlockVector(randn(sum(nz_block_lengths)), nz_block_lengths) - # d_blocks = [reshape(@view(d_data[Block(i)]), block_size(i_axes, nz_blocks[i])) for i in 1:length(nz_blocks)] - - B = BlockSparseArray(nz_blocks, d_blocks, i_axes) - - # Access a block - B[BlockArrays.Block(1, 1)] - - # Access a non-zero block, returns a zero matrix - B[BlockArrays.Block(1, 2)] - - # Set a zero block - B[BlockArrays.Block(1, 2)] = randn(2, 3) - - # Matrix multiplication (not optimized for sparsity yet) - @test B * B ≈ Array(B) * Array(B) - - permuted_B = permutedims(B, (2, 1)) - @test permuted_B isa BlockSparseArray - @test permuted_B == permutedims(Array(B), (2, 1)) - - @test B + B ≈ Array(B) + Array(B) - @test 2B ≈ 2Array(B) - - @test reshape(B, ([4, 6, 6, 9],)) isa BlockSparseArray{<:Any,1} - - return nothing -end - -main() -```` - -# BlockSparseArrays.jl and BlockArrays.jl interface - -````julia -using NDTensors.BlockSparseArrays -using BlockArrays: BlockArrays - -i1 = [2, 3] -i2 = [2, 3] -B = BlockSparseArray{Float64}(i1, i2) -B[BlockArrays.Block(1, 1)] = randn(2, 2) -B[BlockArrays.Block(2, 2)] = randn(3, 3) - -# Minimal interface - -# Specifies the block structure -@show collect.(BlockArrays.blockaxes(axes(B, 1))) - -# Index range of a block -@show axes(B, 1)[BlockArrays.Block(1)] - -# Last index of each block -@show BlockArrays.blocklasts(axes(B, 1)) - -# Find the block containing the index -@show BlockArrays.findblock(axes(B, 1), 3) - -# Retrieve a block -@show B[BlockArrays.Block(1, 1)] -@show BlockArrays.viewblock(B, BlockArrays.Block(1, 1)) - -# Check block bounds -@show BlockArrays.blockcheckbounds(B, 2, 2) -@show BlockArrays.blockcheckbounds(B, BlockArrays.Block(2, 2)) - -# Derived interface - -# Specifies the block structure -@show collect(Iterators.product(BlockArrays.blockaxes(B)...)) - -# Iterate over block views -@show sum.(BlockArrays.eachblock(B)) - -# Reshape into 1-d -@show BlockArrays.blockvec(B)[BlockArrays.Block(1)] - -# Array-of-array view -@show BlockArrays.blocks(B)[1, 1] == B[BlockArrays.Block(1, 1)] - -# Access an index within a block -@show B[BlockArrays.Block(1, 1)[1, 1]] == B[1, 1] -```` - -# Proposals for interfaces based on `BlockArrays.jl`, `SparseArrays`, and `BlockSparseArrays.jl` - -```julia -# BlockSparseArray interface - -# Define `eachblockindex` -eachblockindex(B::BlockArrays.AbstractBlockArray) = Iterators.product(BlockArrays.blockaxes(B)...) - -eachblockindex(B::BlockArrays.AbstractBlockArray, b::Block) # indices in a block - -blocksize(B::BlockArrays.AbstractBlockArray, b::Block) # size of a block -blocksize(axes, b::Block) # size of a block - -blocklength(B::BlockArrays.AbstractBlockArray, b::Block) # length of a block -blocklength(axes, b::Block) # length of a block - -# Other functions -BlockArrays.blocksize(B) # number of blocks in each dimension -BlockArrays.blocksizes(B) # length of blocks in each dimension - -tuple_block(Block(2, 2)) == (Block(2), Block(2)) # Block.(b.n) -blocksize(axes, b::Block) = map(axis -> length(axis[Block(b.n)]), axes) -blocksize(B, Block(2, 2)) = size(B[Block(2, 2)]) # size of a specified block - -# SparseArrays interface - -findnz(S) # outputs nonzero keys and values (SparseArrayKit.nonzero_pairs) -nonzeros(S) # vector of structural nonzeros (SparseArrayKit.nonzero_values) -nnz(S) # number of nonzero values (SparseArrayKit.nonzero_length) -rowvals(S) # row that each nonzero value in `nonzeros(S)` is in -nzrange(S, c) # range of linear indices into `nonzeros(S)` for values in column `c` -findall(!iszero, S) # CartesianIndices of numerical nonzeros -issparse(S) -sparse(A) # convert to sparse -dropzeros!(S) -droptol!(S, tol) - -# BlockSparseArrays.jl + SparseArrays - -blockfindnz(B) # outputs nonzero block indices/keys and block views -blocknonzeros(B) -blocknnz(S) -blockfindall(!iszero, B) -isblocksparse(B) -blocksparse(A) -blockdropzeros!(B) -blockdroptol!(B, tol) - -# SparseArrayKit.jl interface - -nonzero_pairs(a) # SparseArrays.findnz -nonzero_keys(a) # SparseArrays.? -nonzero_values(a) # SparseArrays.nonzeros -nonzero_length(a) # SparseArrays.nnz - -# BlockSparseArrays.jl + SparseArrayKit.jl interface - -block_nonzero_pairs -block_nonzero_keys -block_nonzero_values -block_nonzero_length -``` - -You can generate this README with: -```julia -using Literate -using NDTensors.BlockSparseArrays -dir = joinpath(pkgdir(BlockSparseArrays), "src", "BlockSparseArrays") -Literate.markdown(joinpath(dir, "examples", "README.jl"), dir; flavor=Literate.CommonMarkFlavor()) -``` - ---- - -*This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).* - diff --git a/NDTensors/src/lib/BlockSparseArrays/examples/Project.toml b/NDTensors/src/lib/BlockSparseArrays/examples/Project.toml deleted file mode 100644 index d1bf575ce0..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/examples/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/BlockSparseArrays/examples/README.jl b/NDTensors/src/lib/BlockSparseArrays/examples/README.jl deleted file mode 100644 index 9fff22ae7b..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/examples/README.jl +++ /dev/null @@ -1,206 +0,0 @@ -# # BlockSparseArrays.jl -# -# A Julia `BlockSparseArray` type based on the `BlockArrays.jl` interface. -# -# It wraps an elementwise `SparseArray` type that uses a dictionary-of-keys -# to store non-zero values, specifically a `Dictionary` from `Dictionaries.jl`. -# `BlockArrays` reinterprets the `SparseArray` as a blocked data structure. - -using BlockArrays: BlockArrays, PseudoBlockVector, blockedrange -using NDTensors.BlockSparseArrays: BlockSparseArray, block_stored_length -using Test: @test, @test_broken - -function main() - Block = BlockArrays.Block - - ## Block dimensions - i1 = [2, 3] - i2 = [2, 3] - - i_axes = (blockedrange(i1), blockedrange(i2)) - - function block_size(axes, block) - return length.(getindex.(axes, BlockArrays.Block.(block.n))) - end - - ## Data - nz_blocks = Block.([(1, 1), (2, 2)]) - nz_block_sizes = [block_size(i_axes, nz_block) for nz_block in nz_blocks] - nz_block_lengths = prod.(nz_block_sizes) - - ## Blocks with contiguous underlying data - d_data = PseudoBlockVector(randn(sum(nz_block_lengths)), nz_block_lengths) - d_blocks = [ - reshape(@view(d_data[Block(i)]), block_size(i_axes, nz_blocks[i])) for - i in 1:length(nz_blocks) - ] - b = BlockSparseArray(nz_blocks, d_blocks, i_axes) - - @test block_stored_length(b) == 2 - - ## Blocks with discontiguous underlying data - d_blocks = randn.(nz_block_sizes) - b = BlockSparseArray(nz_blocks, d_blocks, i_axes) - - @test block_stored_length(b) == 2 - - ## Access a block - @test b[Block(1, 1)] == d_blocks[1] - - ## Access a zero block, returns a zero matrix - @test b[Block(1, 2)] == zeros(2, 3) - - ## Set a zero block - a₁₂ = randn(2, 3) - b[Block(1, 2)] = a₁₂ - @test b[Block(1, 2)] == a₁₂ - - ## Matrix multiplication (not optimized for sparsity yet) - @test b * b ≈ Array(b) * Array(b) - - permuted_b = permutedims(b, (2, 1)) - ## TODO: Fix this, broken. - @test_broken permuted_b isa BlockSparseArray - @test permuted_b == permutedims(Array(b), (2, 1)) - - @test b + b ≈ Array(b) + Array(b) - @test b + b isa BlockSparseArray - @test block_stored_length(b + b) == 2 - - scaled_b = 2b - @test scaled_b ≈ 2Array(b) - ## TODO: Fix this, broken. - @test_broken scaled_b isa BlockSparseArray - - ## TODO: Fix this, broken. - @test_broken reshape(b, ([4, 6, 6, 9],)) isa BlockSparseArray{<:Any,1} - - return nothing -end - -main() - -# # BlockSparseArrays.jl and BlockArrays.jl interface - -using BlockArrays: BlockArrays -using NDTensors.BlockSparseArrays: BlockSparseArray - -i1 = [2, 3] -i2 = [2, 3] -B = BlockSparseArray{Float64}(i1, i2) -B[BlockArrays.Block(1, 1)] = randn(2, 2) -B[BlockArrays.Block(2, 2)] = randn(3, 3) - -## Minimal interface - -## Specifies the block structure -@show collect.(BlockArrays.blockaxes(axes(B, 1))) - -## Index range of a block -@show axes(B, 1)[BlockArrays.Block(1)] - -## Last index of each block -@show BlockArrays.blocklasts(axes(B, 1)) - -## Find the block containing the index -@show BlockArrays.findblock(axes(B, 1), 3) - -## Retrieve a block -@show B[BlockArrays.Block(1, 1)] -@show BlockArrays.viewblock(B, BlockArrays.Block(1, 1)) - -## Check block bounds -@show BlockArrays.blockcheckbounds(B, 2, 2) -@show BlockArrays.blockcheckbounds(B, BlockArrays.Block(2, 2)) - -## Derived interface - -## Specifies the block structure -@show collect(Iterators.product(BlockArrays.blockaxes(B)...)) - -## Iterate over block views -@show sum.(BlockArrays.eachblock(B)) - -## Reshape into 1-d -@show BlockArrays.blockvec(B)[BlockArrays.Block(1)] - -## Array-of-array view -@show BlockArrays.blocks(B)[1, 1] == B[BlockArrays.Block(1, 1)] - -## Access an index within a block -@show B[BlockArrays.Block(1, 1)[1, 1]] == B[1, 1] - -# # Proposals for interfaces based on `BlockArrays.jl`, `SparseArrays`, and `BlockSparseArrays.jl` - -#= -```julia -# BlockSparseArray interface - -# Define `eachblockindex` -eachblockindex(B::BlockArrays.AbstractBlockArray) = Iterators.product(BlockArrays.blockaxes(B)...) - -eachblockindex(B::BlockArrays.AbstractBlockArray, b::Block) # indices in a block - -blocksize(B::BlockArrays.AbstractBlockArray, b::Block) # size of a block -blocksize(axes, b::Block) # size of a block - -blocklength(B::BlockArrays.AbstractBlockArray, b::Block) # length of a block -blocklength(axes, b::Block) # length of a block - -# Other functions -BlockArrays.blocksize(B) # number of blocks in each dimension -BlockArrays.blocksizes(B) # length of blocks in each dimension - -tuple_block(Block(2, 2)) == (Block(2), Block(2)) # Block.(b.n) -blocksize(axes, b::Block) = map(axis -> length(axis[Block(b.n)]), axes) -blocksize(B, Block(2, 2)) = size(B[Block(2, 2)]) # size of a specified block - -# SparseArrays interface - -findnz(S) # outputs nonzero keys and values (SparseArrayKit.nonzero_pairs) -nonzeros(S) # vector of structural nonzeros (SparseArrayKit.nonzero_values) -nnz(S) # number of nonzero values (SparseArrayKit.nonzero_length) -rowvals(S) # row that each nonzero value in `nonzeros(S)` is in -nzrange(S, c) # range of linear indices into `nonzeros(S)` for values in column `c` -findall(!iszero, S) # CartesianIndices of numerical nonzeros -issparse(S) -sparse(A) # convert to sparse -dropzeros!(S) -droptol!(S, tol) - -# BlockSparseArrays.jl + SparseArrays - -blockfindnz(B) # outputs nonzero block indices/keys and block views -blocknonzeros(B) -blocknnz(S) -blockfindall(!iszero, B) -isblocksparse(B) -blocksparse(A) -blockdropzeros!(B) -blockdroptol!(B, tol) - -# SparseArrayKit.jl interface - -nonzero_pairs(a) # SparseArrays.findnz -nonzero_keys(a) # SparseArrays.? -nonzero_values(a) # SparseArrays.nonzeros -nonzero_length(a) # SparseArrays.nnz - -# BlockSparseArrays.jl + SparseArrayKit.jl interface - -block_nonzero_pairs -block_nonzero_keys -block_nonzero_values -block_nonzero_length -``` -=# - -#= -You can generate this README with: -```julia -using Literate -using NDTensors.BlockSparseArrays -dir = joinpath(pkgdir(BlockSparseArrays), "src", "BlockSparseArrays") -Literate.markdown(joinpath(dir, "examples", "README.jl"), dir; flavor=Literate.CommonMarkFlavor()) -``` -=# diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysAdaptExt/src/BlockSparseArraysAdaptExt.jl b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysAdaptExt/src/BlockSparseArraysAdaptExt.jl deleted file mode 100644 index 68cbf05e35..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysAdaptExt/src/BlockSparseArraysAdaptExt.jl +++ /dev/null @@ -1,5 +0,0 @@ -module BlockSparseArraysAdaptExt -using Adapt: Adapt, adapt -using ..BlockSparseArrays: AbstractBlockSparseArray, map_stored_blocks -Adapt.adapt_structure(to, x::AbstractBlockSparseArray) = map_stored_blocks(adapt(to), x) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/BlockSparseArraysGradedAxesExt.jl b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/BlockSparseArraysGradedAxesExt.jl deleted file mode 100644 index 85fcaab49f..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/BlockSparseArraysGradedAxesExt.jl +++ /dev/null @@ -1,156 +0,0 @@ -module BlockSparseArraysGradedAxesExt -using BlockArrays: - AbstractBlockVector, - AbstractBlockedUnitRange, - Block, - BlockIndexRange, - blockedrange, - blocks -using ..BlockSparseArrays: - BlockSparseArrays, - AbstractBlockSparseArray, - AbstractBlockSparseMatrix, - BlockSparseArray, - BlockSparseMatrix, - BlockSparseVector, - block_merge -using ...GradedAxes: - GradedAxes, - AbstractGradedUnitRange, - OneToOne, - blockmergesortperm, - blocksortperm, - dual, - invblockperm, - nondual, - tensor_product -using LinearAlgebra: Adjoint, Transpose -using ...TensorAlgebra: - TensorAlgebra, FusionStyle, BlockReshapeFusion, SectorFusion, fusedims, splitdims - -# TODO: Make a `ReduceWhile` library. -include("reducewhile.jl") - -TensorAlgebra.FusionStyle(::AbstractGradedUnitRange) = SectorFusion() - -# TODO: Need to implement this! Will require implementing -# `block_merge(a::AbstractUnitRange, blockmerger::BlockedUnitRange)`. -function BlockSparseArrays.block_merge( - a::AbstractGradedUnitRange, blockmerger::AbstractBlockedUnitRange -) - return a -end - -# Sort the blocks by sector and then merge the common sectors. -function block_mergesort(a::AbstractArray) - I = blockmergesortperm.(axes(a)) - return a[I...] -end - -function TensorAlgebra.fusedims( - ::SectorFusion, a::AbstractArray, axes::AbstractUnitRange... -) - # First perform a fusion using a block reshape. - a_reshaped = fusedims(BlockReshapeFusion(), a, axes...) - # Sort the blocks by sector and merge the equivalent sectors. - return block_mergesort(a_reshaped) -end - -function TensorAlgebra.splitdims( - ::SectorFusion, a::AbstractArray, split_axes::AbstractUnitRange... -) - # First, fuse axes to get `blockmergesortperm`. - # Then unpermute the blocks. - axes_prod = - groupreducewhile(tensor_product, split_axes, ndims(a); init=OneToOne()) do i, axis - return length(axis) ≤ length(axes(a, i)) - end - blockperms = invblockperm.(blocksortperm.(axes_prod)) - # TODO: This is doing extra copies of the blocks, - # use `@view a[axes_prod...]` instead. - # That will require implementing some reindexing logic - # for this combination of slicing. - a_unblocked = a[axes_prod...] - a_blockpermed = a_unblocked[blockperms...] - return splitdims(BlockReshapeFusion(), a_blockpermed, split_axes...) -end - -# This is a temporary fix for `eachindex` being broken for BlockSparseArrays -# with mixed dual and non-dual axes. This shouldn't be needed once -# GradedAxes is rewritten using BlockArrays v1. -# TODO: Delete this once GradedAxes is rewritten. -function Base.eachindex(a::AbstractBlockSparseArray) - return CartesianIndices(nondual.(axes(a))) -end - -# TODO: Handle this through some kind of trait dispatch, maybe -# a `SymmetryStyle`-like trait to check if the block sparse -# matrix has graded axes. -function Base.axes(a::Adjoint{<:Any,<:AbstractBlockSparseMatrix}) - return dual.(reverse(axes(a'))) -end - -# This definition is only needed since calls like -# `a[[Block(1), Block(2)]]` where `a isa AbstractGradedUnitRange` -# returns a `BlockSparseVector` instead of a `BlockVector` -# due to limitations in the `BlockArray` type not allowing -# axes with non-Int element types. -# TODO: Remove this once that issue is fixed, -# see https://github.com/JuliaArrays/BlockArrays.jl/pull/405. -using BlockArrays: BlockRange -using NDTensors.LabelledNumbers: label -function GradedAxes.blocklabels(a::BlockSparseVector) - return map(BlockRange(a)) do block - return label(blocks(a)[Int(block)]) - end -end - -# This is a temporary fix for `show` being broken for BlockSparseArrays -# with mixed dual and non-dual axes. This shouldn't be needed once -# GradedAxes is rewritten using BlockArrays v1. -# TODO: Delete this once GradedAxes is rewritten. -function blocksparse_show( - io::IO, mime::MIME"text/plain", a::AbstractArray, axes_a::Tuple; kwargs... -) - println(io, "typeof(axes) = ", typeof(axes_a), "\n") - println( - io, - "Warning: To temporarily circumvent a bug in printing BlockSparseArrays with mixtures of dual and non-dual axes, the types of the dual axes printed below might not be accurate. The types printed above this message are the correct ones.\n", - ) - return invoke(show, Tuple{IO,MIME"text/plain",AbstractArray}, io, mime, a; kwargs...) -end - -# This is a temporary fix for `show` being broken for BlockSparseArrays -# with mixed dual and non-dual axes. This shouldn't be needed once -# GradedAxes is rewritten using BlockArrays v1. -# TODO: Delete this once GradedAxes is rewritten. -function Base.show(io::IO, mime::MIME"text/plain", a::BlockSparseArray; kwargs...) - axes_a = axes(a) - a_nondual = BlockSparseArray(blocks(a), nondual.(axes(a))) - return blocksparse_show(io, mime, a_nondual, axes_a; kwargs...) -end - -# This is a temporary fix for `show` being broken for BlockSparseArrays -# with mixed dual and non-dual axes. This shouldn't be needed once -# GradedAxes is rewritten using BlockArrays v1. -# TODO: Delete this once GradedAxes is rewritten. -function Base.show( - io::IO, mime::MIME"text/plain", a::Adjoint{<:Any,<:BlockSparseMatrix}; kwargs... -) - axes_a = axes(a) - a_nondual = BlockSparseArray(blocks(a'), dual.(nondual.(axes(a'))))' - return blocksparse_show(io, mime, a_nondual, axes_a; kwargs...) -end - -# This is a temporary fix for `show` being broken for BlockSparseArrays -# with mixed dual and non-dual axes. This shouldn't be needed once -# GradedAxes is rewritten using BlockArrays v1. -# TODO: Delete this once GradedAxes is rewritten. -function Base.show( - io::IO, mime::MIME"text/plain", a::Transpose{<:Any,<:BlockSparseMatrix}; kwargs... -) - axes_a = axes(a) - a_nondual = tranpose(BlockSparseArray(transpose(blocks(a)), nondual.(axes(a)))) - return blocksparse_show(io, mime, a_nondual, axes_a; kwargs...) -end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/reducewhile.jl b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/reducewhile.jl deleted file mode 100644 index 661c95e340..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/src/reducewhile.jl +++ /dev/null @@ -1,34 +0,0 @@ -""" - reducewhile(f, op, collection, state) - -reducewhile(x -> length(x) < 3, vcat, ["a", "b", "c", "d"], 2; init=String[]) == - (["b", "c"], 4) -""" -function reducewhile(f, op, collection, state; init) - prev_result = init - prev_state = state - result = prev_result - while f(result) - prev_result = result - prev_state = state - value_and_state = iterate(collection, state) - isnothing(value_and_state) && break - value, state = value_and_state - result = op(result, value) - end - return prev_result, prev_state -end - -""" - groupreducewhile(f, op, collection, ngroups) - -groupreducewhile((i, x) -> length(x) ≤ i, vcat, ["a", "b", "c", "d", "e", "f"], 3; init=String[]) == - (["a"], ["b", "c"], ["d", "e", "f"]) -""" -function groupreducewhile(f, op, collection, ngroups; init) - state = firstindex(collection) - return ntuple(ngroups) do group_number - result, state = reducewhile(x -> f(group_number, x), op, collection, state; init) - return result - end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/Project.toml b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/Project.toml deleted file mode 100644 index d1bf575ce0..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/runtests.jl b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/runtests.jl deleted file mode 100644 index 2c2a504df5..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysGradedAxesExt/test/runtests.jl +++ /dev/null @@ -1,322 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using BlockArrays: - AbstractBlockArray, Block, BlockedOneTo, blockedrange, blocklengths, blocksize -using NDTensors.BlockSparseArrays: BlockSparseArray, block_stored_length -using NDTensors.GradedAxes: - GradedAxes, - GradedOneTo, - GradedUnitRange, - GradedUnitRangeDual, - blocklabels, - dual, - gradedrange, - isdual -using NDTensors.LabelledNumbers: label -using NDTensors.SparseArraysBase: stored_length -using NDTensors.SymmetrySectors: U1 -using NDTensors.TensorAlgebra: fusedims, splitdims -using LinearAlgebra: adjoint -using Random: randn! -function blockdiagonal!(f, a::AbstractArray) - for i in 1:minimum(blocksize(a)) - b = Block(ntuple(Returns(i), ndims(a))) - a[b] = f(a[b]) - end - return a -end - -const elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) -@testset "BlockSparseArraysGradedAxesExt (eltype=$elt)" for elt in elts - @testset "map" begin - d1 = gradedrange([U1(0) => 2, U1(1) => 2]) - d2 = gradedrange([U1(0) => 2, U1(1) => 2]) - a = BlockSparseArray{elt}(d1, d2, d1, d2) - blockdiagonal!(randn!, a) - @test axes(a, 1) isa GradedOneTo - @test axes(view(a, 1:4, 1:4, 1:4, 1:4), 1) isa GradedOneTo - - for b in (a + a, 2 * a) - @test size(b) == (4, 4, 4, 4) - @test blocksize(b) == (2, 2, 2, 2) - @test blocklengths.(axes(b)) == ([2, 2], [2, 2], [2, 2], [2, 2]) - @test stored_length(b) == 32 - @test block_stored_length(b) == 2 - for i in 1:ndims(a) - @test axes(b, i) isa GradedOneTo - end - @test label(axes(b, 1)[Block(1)]) == U1(0) - @test label(axes(b, 1)[Block(2)]) == U1(1) - @test Array(b) isa Array{elt} - @test Array(b) == b - @test 2 * Array(a) == b - end - - # Test mixing graded axes and dense axes - # in addition/broadcasting. - for b in (a + Array(a), Array(a) + a) - @test size(b) == (4, 4, 4, 4) - @test blocksize(b) == (2, 2, 2, 2) - @test blocklengths.(axes(b)) == ([2, 2], [2, 2], [2, 2], [2, 2]) - @test stored_length(b) == 256 - @test block_stored_length(b) == 16 - for i in 1:ndims(a) - @test axes(b, i) isa BlockedOneTo{Int} - end - @test Array(a) isa Array{elt} - @test Array(a) == a - @test 2 * Array(a) == b - end - - b = a[2:3, 2:3, 2:3, 2:3] - @test size(b) == (2, 2, 2, 2) - @test blocksize(b) == (2, 2, 2, 2) - @test stored_length(b) == 2 - @test block_stored_length(b) == 2 - for i in 1:ndims(a) - @test axes(b, i) isa GradedOneTo - end - @test label(axes(b, 1)[Block(1)]) == U1(0) - @test label(axes(b, 1)[Block(2)]) == U1(1) - @test Array(a) isa Array{elt} - @test Array(a) == a - end - # TODO: Add tests for various slicing operations. - @testset "fusedims" begin - d1 = gradedrange([U1(0) => 1, U1(1) => 1]) - d2 = gradedrange([U1(0) => 1, U1(1) => 1]) - a = BlockSparseArray{elt}(d1, d2, d1, d2) - blockdiagonal!(randn!, a) - m = fusedims(a, (1, 2), (3, 4)) - for ax in axes(m) - @test ax isa GradedOneTo - @test blocklabels(ax) == [U1(0), U1(1), U1(2)] - end - for I in CartesianIndices(m) - if I ∈ CartesianIndex.([(1, 1), (4, 4)]) - @test !iszero(m[I]) - else - @test iszero(m[I]) - end - end - @test a[1, 1, 1, 1] == m[1, 1] - @test a[2, 2, 2, 2] == m[4, 4] - @test blocksize(m) == (3, 3) - @test a == splitdims(m, (d1, d2), (d1, d2)) - end - - @testset "dual axes" begin - r = gradedrange([U1(0) => 2, U1(1) => 2]) - for ax in ((r, r), (dual(r), r), (r, dual(r)), (dual(r), dual(r))) - a = BlockSparseArray{elt}(ax...) - @views for b in [Block(1, 1), Block(2, 2)] - a[b] = randn(elt, size(a[b])) - end - for dim in 1:ndims(a) - @test typeof(ax[dim]) === typeof(axes(a, dim)) - @test isdual(ax[dim]) == isdual(axes(a, dim)) - end - @test @view(a[Block(1, 1)])[1, 1] == a[1, 1] - @test @view(a[Block(1, 1)])[2, 1] == a[2, 1] - @test @view(a[Block(1, 1)])[1, 2] == a[1, 2] - @test @view(a[Block(1, 1)])[2, 2] == a[2, 2] - @test @view(a[Block(2, 2)])[1, 1] == a[3, 3] - @test @view(a[Block(2, 2)])[2, 1] == a[4, 3] - @test @view(a[Block(2, 2)])[1, 2] == a[3, 4] - @test @view(a[Block(2, 2)])[2, 2] == a[4, 4] - @test @view(a[Block(1, 1)])[1:2, 1:2] == a[1:2, 1:2] - @test @view(a[Block(2, 2)])[1:2, 1:2] == a[3:4, 3:4] - a_dense = Array(a) - @test eachindex(a) == CartesianIndices(size(a)) - for I in eachindex(a) - @test a[I] == a_dense[I] - end - @test axes(a') == dual.(reverse(axes(a))) - - @test isdual(axes(a', 1)) ≠ isdual(axes(a, 2)) - @test isdual(axes(a', 2)) ≠ isdual(axes(a, 1)) - @test isnothing(show(devnull, MIME("text/plain"), a)) - - # Check preserving dual in tensor algebra. - for b in (a + a, 2 * a, 3 * a - a) - @test Array(b) ≈ 2 * Array(a) - for dim in 1:ndims(a) - @test isdual(axes(b, dim)) == isdual(axes(a, dim)) - end - end - - @test isnothing(show(devnull, MIME("text/plain"), @view(a[Block(1, 1)]))) - @test @view(a[Block(1, 1)]) == a[Block(1, 1)] - end - - @testset "GradedOneTo" begin - r = gradedrange([U1(0) => 2, U1(1) => 2]) - a = BlockSparseArray{elt}(r, r) - @views for i in [Block(1, 1), Block(2, 2)] - a[i] = randn(elt, size(a[i])) - end - b = 2 * a - @test block_stored_length(b) == 2 - @test Array(b) == 2 * Array(a) - for i in 1:2 - @test axes(b, i) isa GradedOneTo - @test axes(a[:, :], i) isa GradedOneTo - end - - I = [Block(1)[1:1]] - @test a[I, :] isa AbstractBlockArray - @test a[:, I] isa AbstractBlockArray - @test size(a[I, I]) == (1, 1) - @test !isdual(axes(a[I, I], 1)) - end - - @testset "GradedUnitRange" begin - r = gradedrange([U1(0) => 2, U1(1) => 2])[1:3] - a = BlockSparseArray{elt}(r, r) - @views for i in [Block(1, 1), Block(2, 2)] - a[i] = randn(elt, size(a[i])) - end - b = 2 * a - @test block_stored_length(b) == 2 - @test Array(b) == 2 * Array(a) - for i in 1:2 - @test axes(b, i) isa GradedUnitRange - @test axes(a[:, :], i) isa GradedUnitRange - end - - I = [Block(1)[1:1]] - @test a[I, :] isa AbstractBlockArray - @test axes(a[I, :], 1) isa GradedOneTo - @test axes(a[I, :], 2) isa GradedUnitRange - - @test a[:, I] isa AbstractBlockArray - @test axes(a[:, I], 2) isa GradedOneTo - @test axes(a[:, I], 1) isa GradedUnitRange - @test size(a[I, I]) == (1, 1) - @test !isdual(axes(a[I, I], 1)) - end - - # Test case when all axes are dual. - @testset "dual GradedOneTo" begin - r = gradedrange([U1(-1) => 2, U1(1) => 2]) - a = BlockSparseArray{elt}(dual(r), dual(r)) - @views for i in [Block(1, 1), Block(2, 2)] - a[i] = randn(elt, size(a[i])) - end - b = 2 * a - @test block_stored_length(b) == 2 - @test Array(b) == 2 * Array(a) - for i in 1:2 - @test axes(b, i) isa GradedUnitRangeDual - @test axes(a[:, :], i) isa GradedUnitRangeDual - end - I = [Block(1)[1:1]] - @test a[I, :] isa AbstractBlockArray - @test a[:, I] isa AbstractBlockArray - @test size(a[I, I]) == (1, 1) - @test isdual(axes(a[I, :], 2)) - @test isdual(axes(a[:, I], 1)) - @test isdual(axes(a[I, :], 1)) - @test isdual(axes(a[:, I], 2)) - @test isdual(axes(a[I, I], 1)) - @test isdual(axes(a[I, I], 2)) - end - - @testset "dual GradedUnitRange" begin - r = gradedrange([U1(0) => 2, U1(1) => 2])[1:3] - a = BlockSparseArray{elt}(dual(r), dual(r)) - @views for i in [Block(1, 1), Block(2, 2)] - a[i] = randn(elt, size(a[i])) - end - b = 2 * a - @test block_stored_length(b) == 2 - @test Array(b) == 2 * Array(a) - for i in 1:2 - @test axes(b, i) isa GradedUnitRangeDual - @test axes(a[:, :], i) isa GradedUnitRangeDual - end - - I = [Block(1)[1:1]] - @test a[I, :] isa AbstractBlockArray - @test a[:, I] isa AbstractBlockArray - @test size(a[I, I]) == (1, 1) - @test isdual(axes(a[I, :], 2)) - @test isdual(axes(a[:, I], 1)) - @test isdual(axes(a[I, :], 1)) - @test isdual(axes(a[:, I], 2)) - @test isdual(axes(a[I, I], 1)) - @test isdual(axes(a[I, I], 2)) - end - - @testset "dual BlockedUnitRange" begin # self dual - r = blockedrange([2, 2]) - a = BlockSparseArray{elt}(dual(r), dual(r)) - @views for i in [Block(1, 1), Block(2, 2)] - a[i] = randn(elt, size(a[i])) - end - b = 2 * a - @test block_stored_length(b) == 2 - @test Array(b) == 2 * Array(a) - @test a[:, :] isa BlockSparseArray - for i in 1:2 - @test axes(b, i) isa BlockedOneTo - @test axes(a[:, :], i) isa BlockedOneTo - end - - I = [Block(1)[1:1]] - @test a[I, :] isa BlockSparseArray - @test a[:, I] isa BlockSparseArray - @test size(a[I, I]) == (1, 1) - @test !isdual(axes(a[I, I], 1)) - end - - # Test case when all axes are dual from taking the adjoint. - for r in ( - gradedrange([U1(0) => 2, U1(1) => 2]), - gradedrange([U1(0) => 2, U1(1) => 2])[begin:end], - ) - a = BlockSparseArray{elt}(r, r) - @views for i in [Block(1, 1), Block(2, 2)] - a[i] = randn(elt, size(a[i])) - end - b = 2 * a' - @test block_stored_length(b) == 2 - @test Array(b) == 2 * Array(a)' - for ax in axes(b) - @test ax isa typeof(dual(r)) - end - - @test !isdual(axes(a, 1)) - @test !isdual(axes(a, 2)) - @test isdual(axes(a', 1)) - @test isdual(axes(a', 2)) - @test isdual(axes(b, 1)) - @test isdual(axes(b, 2)) - @test isdual(axes(copy(a'), 1)) - @test isdual(axes(copy(a'), 2)) - - I = [Block(1)[1:1]] - @test size(b[I, :]) == (1, 4) - @test size(b[:, I]) == (4, 1) - @test size(b[I, I]) == (1, 1) - end - end - @testset "Matrix multiplication" begin - r = gradedrange([U1(0) => 2, U1(1) => 3]) - a1 = BlockSparseArray{elt}(dual(r), r) - a1[Block(1, 2)] = randn(elt, size(@view(a1[Block(1, 2)]))) - a1[Block(2, 1)] = randn(elt, size(@view(a1[Block(2, 1)]))) - a2 = BlockSparseArray{elt}(dual(r), r) - a2[Block(1, 2)] = randn(elt, size(@view(a2[Block(1, 2)]))) - a2[Block(2, 1)] = randn(elt, size(@view(a2[Block(2, 1)]))) - @test Array(a1 * a2) ≈ Array(a1) * Array(a2) - @test Array(a1' * a2') ≈ Array(a1') * Array(a2') - - a2 = BlockSparseArray{elt}(r, dual(r)) - a2[Block(1, 2)] = randn(elt, size(@view(a2[Block(1, 2)]))) - a2[Block(2, 1)] = randn(elt, size(@view(a2[Block(2, 1)]))) - @test Array(a1' * a2) ≈ Array(a1') * Array(a2) - @test Array(a1 * a2') ≈ Array(a1) * Array(a2') - end -end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/src/BlockSparseArraysTensorAlgebraExt.jl b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/src/BlockSparseArraysTensorAlgebraExt.jl deleted file mode 100644 index 74ebd6593c..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/src/BlockSparseArraysTensorAlgebraExt.jl +++ /dev/null @@ -1,24 +0,0 @@ -module BlockSparseArraysTensorAlgebraExt -using BlockArrays: AbstractBlockedUnitRange -using ..BlockSparseArrays: AbstractBlockSparseArray, block_reshape -using ...GradedAxes: tensor_product -using ...TensorAlgebra: TensorAlgebra, FusionStyle, BlockReshapeFusion - -function TensorAlgebra.:⊗(a1::AbstractBlockedUnitRange, a2::AbstractBlockedUnitRange) - return tensor_product(a1, a2) -end - -TensorAlgebra.FusionStyle(::AbstractBlockedUnitRange) = BlockReshapeFusion() - -function TensorAlgebra.fusedims( - ::BlockReshapeFusion, a::AbstractArray, axes::AbstractUnitRange... -) - return block_reshape(a, axes) -end - -function TensorAlgebra.splitdims( - ::BlockReshapeFusion, a::AbstractArray, axes::AbstractUnitRange... -) - return block_reshape(a, axes) -end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/Project.toml b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/Project.toml deleted file mode 100644 index d1bf575ce0..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/runtests.jl b/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/runtests.jl deleted file mode 100644 index e5c1e5069e..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/ext/BlockSparseArraysTensorAlgebraExt/test/runtests.jl +++ /dev/null @@ -1,17 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using NDTensors.BlockSparseArrays: BlockSparseArray -using NDTensors.TensorAlgebra: contract -using NDTensors.SparseArraysBase: densearray -@testset "BlockSparseArraysTensorAlgebraExt (eltype=$elt)" for elt in ( - Float32, Float64, Complex{Float32}, Complex{Float64} -) - a1 = BlockSparseArray{elt}([1, 2], [2, 3], [3, 2]) - a2 = BlockSparseArray{elt}([2, 2], [3, 2], [2, 3]) - a_dest, dimnames_dest = contract(a1, (1, -1, -2), a2, (2, -2, -1)) - a_dest_dense, dimnames_dest_dense = contract( - densearray(a1), (1, -1, -2), densearray(a2), (2, -2, -1) - ) - @test a_dest ≈ a_dest_dense -end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/BlockArraysExtensions/BlockArraysExtensions.jl b/NDTensors/src/lib/BlockSparseArrays/src/BlockArraysExtensions/BlockArraysExtensions.jl deleted file mode 100644 index c57906fdac..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/BlockArraysExtensions/BlockArraysExtensions.jl +++ /dev/null @@ -1,591 +0,0 @@ -using ArrayLayouts: ArrayLayouts, MemoryLayout, sub_materialize -using BlockArrays: - BlockArrays, - AbstractBlockArray, - AbstractBlockVector, - Block, - BlockIndex, - BlockIndexRange, - BlockRange, - BlockSlice, - BlockVector, - BlockedOneTo, - BlockedUnitRange, - BlockedVector, - block, - blockaxes, - blockedrange, - blockindex, - blocks, - findblock, - findblockindex -using Compat: allequal -using Dictionaries: Dictionary, Indices -using ..GradedAxes: blockedunitrange_getindices, to_blockindices -using ..SparseArraysBase: SparseArraysBase, stored_length, stored_indices - -# A return type for `blocks(array)` when `array` isn't blocked. -# Represents a vector with just that single block. -struct SingleBlockView{T,N,Array<:AbstractArray{T,N}} <: AbstractArray{T,N} - array::Array -end -blocks_maybe_single(a) = blocks(a) -blocks_maybe_single(a::Array) = SingleBlockView(a) -function Base.getindex(a::SingleBlockView{<:Any,N}, index::Vararg{Int,N}) where {N} - @assert all(isone, index) - return a.array -end - -# A wrapper around a potentially blocked array that is not blocked. -struct NonBlockedArray{T,N,Array<:AbstractArray{T,N}} <: AbstractArray{T,N} - array::Array -end -Base.size(a::NonBlockedArray) = size(a.array) -Base.getindex(a::NonBlockedArray{<:Any,N}, I::Vararg{Integer,N}) where {N} = a.array[I...] -# Views of `NonBlockedArray`/`NonBlockedVector` are eager. -# This fixes an issue in Julia 1.11 where reindexing defaults to using views. -# TODO: Maybe reconsider this design, and allows views to work in slicing. -Base.view(a::NonBlockedArray, I...) = a[I...] -BlockArrays.blocks(a::NonBlockedArray) = SingleBlockView(a.array) -const NonBlockedVector{T,Array} = NonBlockedArray{T,1,Array} -NonBlockedVector(array::AbstractVector) = NonBlockedArray(array) - -# BlockIndices works around an issue that the indices of BlockSlice -# are restricted to AbstractUnitRange{Int}. -struct BlockIndices{B,T<:Integer,I<:AbstractVector{T}} <: AbstractVector{T} - blocks::B - indices::I -end -for f in (:axes, :unsafe_indices, :axes1, :first, :last, :size, :length, :unsafe_length) - @eval Base.$f(S::BlockIndices) = Base.$f(S.indices) -end -Base.getindex(S::BlockIndices, i::Integer) = getindex(S.indices, i) -function Base.getindex(S::BlockIndices, i::BlockSlice{<:Block{1}}) - # TODO: Check that `i.indices` is consistent with `S.indices`. - # It seems like this isn't handling the case where `i` is a - # subslice of a block correctly (i.e. it ignores `i.indices`). - @assert length(S.indices[Block(i)]) == length(i.indices) - return BlockSlice(S.blocks[Int(Block(i))], S.indices[Block(i)]) -end - -# This is used in slicing like: -# a = BlockSparseArray{Float64}([2, 2, 2, 2], [2, 2, 2, 2]) -# I = BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]) -# a[I, I] -function Base.getindex( - S::BlockIndices{<:AbstractBlockVector{<:Block{1}}}, i::BlockSlice{<:Block{1}} -) - # TODO: Check for conistency of indices. - # Wrapping the indices in `NonBlockedVector` reinterprets the blocked indices - # as a single block, since the result shouldn't be blocked. - return NonBlockedVector(BlockIndices(S.blocks[Block(i)], S.indices[Block(i)])) -end -function Base.getindex( - S::BlockIndices{<:BlockedVector{<:Block{1},<:BlockRange{1}}}, i::BlockSlice{<:Block{1}} -) - return i -end -# Views of `BlockIndices` are eager. -# This fixes an issue in Julia 1.11 where reindexing defaults to using views. -Base.view(S::BlockIndices, i) = S[i] - -# Used in indexing such as: -# ```julia -# a = BlockSparseArray{Float64}([2, 2, 2, 2], [2, 2, 2, 2]) -# I = BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]) -# b = @view a[I, I] -# @view b[Block(1, 1)[1:2, 2:2]] -# ``` -# This is similar to the definition: -# blocksparse_to_indices(a, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}}) -function Base.getindex( - a::NonBlockedVector{<:Integer,<:BlockIndices}, I::UnitRange{<:Integer} -) - ax = only(axes(a.array.indices)) - brs = to_blockindices(ax, I) - inds = blockedunitrange_getindices(ax, I) - return NonBlockedVector(a.array[BlockSlice(brs, inds)]) -end - -function Base.getindex(S::BlockIndices, i::BlockSlice{<:BlockRange{1}}) - # TODO: Check that `i.indices` is consistent with `S.indices`. - # TODO: Turn this into a `blockedunitrange_getindices` definition. - subblocks = S.blocks[Int.(i.block)] - subindices = mortar( - map(1:length(i.block)) do I - r = blocks(i.indices)[I] - return S.indices[first(r)]:S.indices[last(r)] - end, - ) - return BlockIndices(subblocks, subindices) -end - -# Used when performing slices like: -# @views a[[Block(2), Block(1)]][2:4, 2:4] -function Base.getindex(S::BlockIndices, i::BlockSlice{<:BlockVector{<:BlockIndex{1}}}) - subblocks = mortar( - map(blocks(i.block)) do br - return S.blocks[Int(Block(br))][only(br.indices)] - end, - ) - subindices = mortar( - map(blocks(i.block)) do br - S.indices[br] - end, - ) - return BlockIndices(subblocks, subindices) -end - -# Similar to the definition of `BlockArrays.BlockSlices`: -# ```julia -# const BlockSlices = Union{Base.Slice,BlockSlice{<:BlockRange{1}}} -# ``` -# but includes `BlockIndices`, where the blocks aren't contiguous. -const BlockSliceCollection = Union{ - Base.Slice,BlockSlice{<:BlockRange{1}},BlockIndices{<:Vector{<:Block{1}}} -} -const SubBlockSliceCollection = BlockIndices{ - <:BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}} -} - -# TODO: This is type piracy. This is used in `reindex` when making -# views of blocks of sliced block arrays, for example: -# ```julia -# a = BlockSparseArray{elt}(undef, ([2, 3], [2, 3])) -# b = @view a[[Block(1)[1:1], Block(2)[1:2]], [Block(1)[1:1], Block(2)[1:2]]] -# b[Block(1, 1)] -# ``` -# Without this change, BlockArrays has the slicing behavior: -# ```julia -# julia> mortar([Block(1)[1:1], Block(2)[1:2]])[BlockSlice(Block(2), 2:3)] -# 2-element Vector{BlockIndex{1, Tuple{Int64}, Tuple{Int64}}}: -# Block(2)[1] -# Block(2)[2] -# ``` -# while with this change it has the slicing behavior: -# ```julia -# julia> mortar([Block(1)[1:1], Block(2)[1:2]])[BlockSlice(Block(2), 2:3)] -# Block(2)[1:2] -# ``` -# i.e. it preserves the types of the blocks better. Upstream this fix to -# BlockArrays.jl. Also consider overloading `reindex` so that it calls -# a custom `getindex` function to avoid type piracy in the meantime. -# Also fix this in BlockArrays: -# ```julia -# julia> mortar([Block(1)[1:1], Block(2)[1:2]])[Block(2)] -# 2-element Vector{BlockIndex{1, Tuple{Int64}, Tuple{Int64}}}: -# Block(2)[1] -# Block(2)[2] -# ``` -function Base.getindex( - a::BlockVector{<:BlockIndex{1},<:AbstractVector{<:BlockIndexRange{1}}}, - I::BlockSlice{<:Block{1}}, -) - # Check that the block slice corresponds to the correct block. - @assert I.indices == only(axes(a))[Block(I)] - return blocks(a)[Int(Block(I))] -end - -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices) - return error("Not implemented") -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices::AbstractUnitRange) - return only(axes(blockedunitrange_getindices(a, indices))) -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices::BlockSlice{<:BlockRange{1}}) - return sub_axis(a, indices.block) -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices::BlockSlice{<:Block{1}}) - return sub_axis(a, Block(indices)) -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices::BlockSlice{<:BlockIndexRange{1}}) - return sub_axis(a, indices.block) -end - -function sub_axis(a::AbstractUnitRange, indices::BlockIndices) - return sub_axis(a, indices.blocks) -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices::Block) - return only(axes(blockedunitrange_getindices(a, indices))) -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices::BlockIndexRange) - return only(axes(blockedunitrange_getindices(a, indices))) -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# Outputs a `BlockUnitRange`. -function sub_axis(a::AbstractUnitRange, indices::AbstractVector{<:Block}) - return blockedrange([length(a[index]) for index in indices]) -end - -# TODO: Use `GradedAxes.blockedunitrange_getindices`. -# TODO: Merge blocks. -function sub_axis(a::AbstractUnitRange, indices::BlockVector{<:Block}) - # `collect` is needed here, otherwise a `PseudoBlockVector` is - # constructed. - return blockedrange([length(a[index]) for index in collect(indices)]) -end - -# TODO: Use `Tuple` conversion once -# BlockArrays.jl PR is merged. -block_to_cartesianindex(b::Block) = CartesianIndex(b.n) - -function blocks_to_cartesianindices(i::Indices{<:Block}) - return block_to_cartesianindex.(i) -end - -function blocks_to_cartesianindices(d::Dictionary{<:Block}) - return Dictionary(blocks_to_cartesianindices(eachindex(d)), d) -end - -function block_reshape(a::AbstractArray, dims::Tuple{Vararg{Vector{Int}}}) - return block_reshape(a, blockedrange.(dims)) -end - -function block_reshape(a::AbstractArray, dims::Vararg{Vector{Int}}) - return block_reshape(a, dims) -end - -tuple_oneto(n) = ntuple(identity, n) - -function block_reshape(a::AbstractArray, axes::Tuple{Vararg{AbstractUnitRange}}) - reshaped_blocks_a = reshape(blocks(a), blocklength.(axes)) - reshaped_a = similar(a, axes) - for I in stored_indices(reshaped_blocks_a) - block_size_I = map(i -> length(axes[i][Block(I[i])]), tuple_oneto(length(axes))) - # TODO: Better converter here. - reshaped_a[Block(Tuple(I))] = reshape(reshaped_blocks_a[I], block_size_I) - end - return reshaped_a -end - -function block_reshape(a::AbstractArray, axes::Vararg{AbstractUnitRange}) - return block_reshape(a, axes) -end - -function cartesianindices(axes::Tuple, b::Block) - return CartesianIndices(ntuple(dim -> axes[dim][Tuple(b)[dim]], length(axes))) -end - -# Get the range within a block. -function blockindexrange(axis::AbstractUnitRange, r::AbstractUnitRange) - bi1 = findblockindex(axis, first(r)) - bi2 = findblockindex(axis, last(r)) - b = block(bi1) - # Range must fall within a single block. - @assert b == block(bi2) - i1 = blockindex(bi1) - i2 = blockindex(bi2) - return b[i1:i2] -end - -function blockindexrange( - axes::Tuple{Vararg{AbstractUnitRange,N}}, I::CartesianIndices{N} -) where {N} - brs = blockindexrange.(axes, I.indices) - b = Block(block.(brs)) - rs = map(br -> only(br.indices), brs) - return b[rs...] -end - -function blockindexrange(a::AbstractArray, I::CartesianIndices) - return blockindexrange(axes(a), I) -end - -# Get the blocks the range spans across. -function blockrange(axis::AbstractUnitRange, r::UnitRange) - return findblock(axis, first(r)):findblock(axis, last(r)) -end - -# Occurs when slicing with `a[2:4, 2:4]`. -function blockrange(axis::BlockedOneTo{<:Integer}, r::BlockedUnitRange{<:Integer}) - # TODO: Check the blocks are commensurate. - return findblock(axis, first(r)):findblock(axis, last(r)) -end - -function blockrange(axis::AbstractUnitRange, r::Int) - ## return findblock(axis, r) - return error("Slicing with integer values isn't supported.") -end - -function blockrange(axis::AbstractUnitRange, r::AbstractVector{<:Block{1}}) - for b in r - @assert b ∈ blockaxes(axis, 1) - end - return r -end - -# This handles changing the blocking, for example: -# a = BlockSparseArray{Float64}([2, 2, 2, 2], [2, 2, 2, 2]) -# I = blockedrange([4, 4]) -# a[I, I] -# TODO: Generalize to `AbstractBlockedUnitRange`. -function blockrange(axis::BlockedOneTo{<:Integer}, r::BlockedOneTo{<:Integer}) - # TODO: Probably this is incorrect and should be something like: - # return findblock(axis, first(r)):findblock(axis, last(r)) - return only(blockaxes(r)) -end - -# This handles block merging: -# a = BlockSparseArray{Float64}([2, 2, 2, 2], [2, 2, 2, 2]) -# I = BlockedVector(Block.(1:4), [2, 2]) -# I = BlockVector(Block.(1:4), [2, 2]) -# I = BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]) -# I = BlockVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]) -# a[I, I] -function blockrange(axis::BlockedOneTo{<:Integer}, r::AbstractBlockVector{<:Block{1}}) - for b in r - @assert b ∈ blockaxes(axis, 1) - end - return only(blockaxes(r)) -end - -using BlockArrays: BlockSlice -function blockrange(axis::AbstractUnitRange, r::BlockSlice) - return blockrange(axis, r.block) -end - -function blockrange(a::AbstractUnitRange, r::BlockIndices) - return blockrange(a, r.blocks) -end - -function blockrange(axis::AbstractUnitRange, r::Block{1}) - return r:r -end - -function blockrange(axis::AbstractUnitRange, r::BlockIndexRange) - return Block(r):Block(r) -end - -function blockrange(axis::AbstractUnitRange, r::AbstractVector{<:BlockIndexRange{1}}) - return error("Slicing not implemented for range of type `$(typeof(r))`.") -end - -function blockrange( - axis::AbstractUnitRange, - r::BlockVector{<:BlockIndex{1},<:AbstractVector{<:BlockIndexRange{1}}}, -) - return map(b -> Block(b), blocks(r)) -end - -# This handles slicing with `:`/`Colon()`. -function blockrange(axis::AbstractUnitRange, r::Base.Slice) - # TODO: Maybe use `BlockRange`, but that doesn't output - # the same thing. - return only(blockaxes(axis)) -end - -function blockrange(axis::AbstractUnitRange, r::NonBlockedVector) - return Block(1):Block(1) -end - -function blockrange(axis::AbstractUnitRange, r) - return error("Slicing not implemented for range of type `$(typeof(r))`.") -end - -# This takes a range of indices `indices` of array `a` -# and maps it to the range of indices within block `block`. -function blockindices(a::AbstractArray, block::Block, indices::Tuple) - return blockindices(axes(a), block, indices) -end - -function blockindices(axes::Tuple, block::Block, indices::Tuple) - return blockindices.(axes, Tuple(block), indices) -end - -function blockindices(axis::AbstractUnitRange, block::Block, indices::AbstractUnitRange) - indices_within_block = intersect(indices, axis[block]) - if iszero(length(indices_within_block)) - # Falls outside of block - return 1:0 - end - return only(blockindexrange(axis, indices_within_block).indices) -end - -# This catches the case of `Vector{<:Block{1}}`. -# `BlockRange` gets wrapped in a `BlockSlice`, which is handled properly -# by the version with `indices::AbstractUnitRange`. -# TODO: This should get fixed in a better way inside of `BlockArrays`. -function blockindices( - axis::AbstractUnitRange, block::Block, indices::AbstractVector{<:Block{1}} -) - if block ∉ indices - # Falls outside of block - return 1:0 - end - return Base.OneTo(length(axis[block])) -end - -function blockindices(a::AbstractUnitRange, b::Block, r::BlockIndices) - return blockindices(a, b, r.blocks) -end - -function blockindices( - a::AbstractUnitRange, - b::Block, - r::BlockVector{<:BlockIndex{1},<:AbstractVector{<:BlockIndexRange{1}}}, -) - # TODO: Change to iterate over `BlockRange(r)` - # once https://github.com/JuliaArrays/BlockArrays.jl/issues/404 - # is fixed. - for bl in blocks(r) - if b == Block(bl) - return only(bl.indices) - end - end - return error("Block not found.") -end - -function cartesianindices(a::AbstractArray, b::Block) - return cartesianindices(axes(a), b) -end - -# Output which blocks of `axis` are contained within the unit range `range`. -# The start and end points must match. -function findblocks(axis::AbstractUnitRange, range::AbstractUnitRange) - # TODO: Add a test that the start and end points of the ranges match. - return findblock(axis, first(range)):findblock(axis, last(range)) -end - -function block_stored_indices(a::AbstractArray) - return Block.(Tuple.(stored_indices(blocks(a)))) -end - -_block(indices) = block(indices) -_block(indices::CartesianIndices) = Block(ntuple(Returns(1), ndims(indices))) - -function combine_axes(as::Vararg{Tuple}) - @assert allequal(length.(as)) - ndims = length(first(as)) - return ntuple(ndims) do dim - dim_axes = map(a -> a[dim], as) - return reduce(BlockArrays.combine_blockaxes, dim_axes) - end -end - -# Returns `BlockRange` -# Convert the block of the axes to blocks of the subaxes. -function subblocks(axes::Tuple, subaxes::Tuple, block::Block) - @assert length(axes) == length(subaxes) - return BlockRange( - ntuple(length(axes)) do dim - findblocks(subaxes[dim], axes[dim][Tuple(block)[dim]]) - end, - ) -end - -# Returns `Vector{<:Block}` -function subblocks(axes::Tuple, subaxes::Tuple, blocks) - return mapreduce(vcat, blocks; init=eltype(blocks)[]) do block - return vec(subblocks(axes, subaxes, block)) - end -end - -# Returns `Vector{<:CartesianIndices}` -function blocked_cartesianindices(axes::Tuple, subaxes::Tuple, blocks) - return map(subblocks(axes, subaxes, blocks)) do block - return cartesianindices(subaxes, block) - end -end - -# Represents a view of a block of a blocked array. -struct BlockView{T,N,Array<:AbstractArray{T,N}} <: AbstractArray{T,N} - array::Array - block::Tuple{Vararg{Block{1,Int},N}} -end -function Base.axes(a::BlockView) - # TODO: Try to avoid conversion to `Base.OneTo{Int}`, or just convert - # the element type to `Int` with `Int.(...)`. - # When the axes of `a.array` are `GradedOneTo`, the block is `LabelledUnitRange`, - # which has element type `LabelledInteger`. That causes conversion problems - # in some generic Base Julia code, for example when printing `BlockView`. - return ntuple(ndims(a)) do dim - return Base.OneTo{Int}(only(axes(axes(a.array, dim)[a.block[dim]]))) - end -end -function Base.size(a::BlockView) - return length.(axes(a)) -end -function Base.getindex(a::BlockView{<:Any,N}, index::Vararg{Int,N}) where {N} - return blocks(a.array)[Int.(a.block)...][index...] -end -function Base.setindex!(a::BlockView{<:Any,N}, value, index::Vararg{Int,N}) where {N} - blocks(a.array)[Int.(a.block)...] = blocks(a.array)[Int.(a.block)...] - blocks(a.array)[Int.(a.block)...][index...] = value - return a -end - -function SparseArraysBase.stored_length(a::BlockView) - # TODO: Store whether or not the block is stored already as - # a Bool in `BlockView`. - I = CartesianIndex(Int.(a.block)) - # TODO: Use `block_stored_indices`. - if I ∈ stored_indices(blocks(a.array)) - return stored_length(blocks(a.array)[I]) - end - return 0 -end - -## # Allow more fine-grained control: -## function ArrayLayouts.sub_materialize(layout, a::BlockView, ax) -## return blocks(a.array)[Int.(a.block)...] -## end -## function ArrayLayouts.sub_materialize(layout, a::BlockView) -## return sub_materialize(layout, a, axes(a)) -## end -## function ArrayLayouts.sub_materialize(a::BlockView) -## return sub_materialize(MemoryLayout(a), a) -## end -function ArrayLayouts.sub_materialize(a::BlockView) - return blocks(a.array)[Int.(a.block)...] -end - -function view!(a::AbstractArray{<:Any,N}, index::Block{N}) where {N} - return view!(a, Tuple(index)...) -end -function view!(a::AbstractArray{<:Any,N}, index::Vararg{Block{1},N}) where {N} - blocks(a)[Int.(index)...] = blocks(a)[Int.(index)...] - return blocks(a)[Int.(index)...] -end - -function view!(a::AbstractArray{<:Any,N}, index::BlockIndexRange{N}) where {N} - # TODO: Is there a better code pattern for this? - indices = ntuple(N) do dim - return Tuple(Block(index))[dim][index.indices[dim]] - end - return view!(a, indices...) -end -function view!(a::AbstractArray{<:Any,N}, index::Vararg{BlockIndexRange{1},N}) where {N} - b = view!(a, Block.(index)...) - r = map(index -> only(index.indices), index) - return @view b[r...] -end - -using MacroTools: @capture -using NDTensors.SparseArraysBase: is_getindex_expr -macro view!(expr) - if !is_getindex_expr(expr) - error("@view must be used with getindex syntax (as `@view! a[i,j,...]`)") - end - @capture(expr, array_[indices__]) - return :(view!($(esc(array)), $(esc.(indices)...))) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/BlockArraysSparseArraysBaseExt/BlockArraysSparseArraysBaseExt.jl b/NDTensors/src/lib/BlockSparseArrays/src/BlockArraysSparseArraysBaseExt/BlockArraysSparseArraysBaseExt.jl deleted file mode 100644 index 56b0080d92..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/BlockArraysSparseArraysBaseExt/BlockArraysSparseArraysBaseExt.jl +++ /dev/null @@ -1,11 +0,0 @@ -using BlockArrays: AbstractBlockArray, BlocksView -using ..SparseArraysBase: SparseArraysBase, stored_length - -function SparseArraysBase.stored_length(a::AbstractBlockArray) - return sum(b -> stored_length(b), blocks(a); init=zero(Int)) -end - -# TODO: Handle `BlocksView` wrapping a sparse array? -function SparseArraysBase.storage_indices(a::BlocksView) - return CartesianIndices(a) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/BlockSparseArrays.jl b/NDTensors/src/lib/BlockSparseArrays/src/BlockSparseArrays.jl deleted file mode 100644 index 576fe03ce6..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/BlockSparseArrays.jl +++ /dev/null @@ -1,28 +0,0 @@ -module BlockSparseArrays -include("BlockArraysExtensions/BlockArraysExtensions.jl") -include("blocksparsearrayinterface/blocksparsearrayinterface.jl") -include("blocksparsearrayinterface/linearalgebra.jl") -include("blocksparsearrayinterface/blockzero.jl") -include("blocksparsearrayinterface/broadcast.jl") -include("blocksparsearrayinterface/map.jl") -include("blocksparsearrayinterface/arraylayouts.jl") -include("blocksparsearrayinterface/views.jl") -include("blocksparsearrayinterface/cat.jl") -include("abstractblocksparsearray/abstractblocksparsearray.jl") -include("abstractblocksparsearray/wrappedabstractblocksparsearray.jl") -include("abstractblocksparsearray/abstractblocksparsematrix.jl") -include("abstractblocksparsearray/abstractblocksparsevector.jl") -include("abstractblocksparsearray/views.jl") -include("abstractblocksparsearray/arraylayouts.jl") -include("abstractblocksparsearray/sparsearrayinterface.jl") -include("abstractblocksparsearray/broadcast.jl") -include("abstractblocksparsearray/map.jl") -include("abstractblocksparsearray/linearalgebra.jl") -include("abstractblocksparsearray/cat.jl") -include("blocksparsearray/defaults.jl") -include("blocksparsearray/blocksparsearray.jl") -include("BlockArraysSparseArraysBaseExt/BlockArraysSparseArraysBaseExt.jl") -include("../ext/BlockSparseArraysTensorAlgebraExt/src/BlockSparseArraysTensorAlgebraExt.jl") -include("../ext/BlockSparseArraysGradedAxesExt/src/BlockSparseArraysGradedAxesExt.jl") -include("../ext/BlockSparseArraysAdaptExt/src/BlockSparseArraysAdaptExt.jl") -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsearray.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsearray.jl deleted file mode 100644 index cfe1ef5ab6..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsearray.jl +++ /dev/null @@ -1,78 +0,0 @@ -using BlockArrays: - BlockArrays, AbstractBlockArray, Block, BlockIndex, BlockedUnitRange, blocks -using ..SparseArraysBase: sparse_getindex, sparse_setindex! - -# TODO: Delete this. This function was replaced -# by `stored_length` but is still used in `NDTensors`. -function nonzero_keys end - -abstract type AbstractBlockSparseArray{T,N} <: AbstractBlockArray{T,N} end - -## Base `AbstractArray` interface - -Base.axes(::AbstractBlockSparseArray) = error("Not implemented") - -# TODO: Add some logic to unwrapping wrapped arrays. -# TODO: Decide what a good default is. -blockstype(arraytype::Type{<:AbstractBlockSparseArray}) = SparseArrayDOK{AbstractArray} -function blockstype(arraytype::Type{<:AbstractBlockSparseArray{T}}) where {T} - return SparseArrayDOK{AbstractArray{T}} -end -function blockstype(arraytype::Type{<:AbstractBlockSparseArray{T,N}}) where {T,N} - return SparseArrayDOK{AbstractArray{T,N},N} -end - -# Specialized in order to fix ambiguity error with `BlockArrays`. -function Base.getindex(a::AbstractBlockSparseArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return blocksparse_getindex(a, I...) -end - -# Specialized in order to fix ambiguity error with `BlockArrays`. -function Base.getindex(a::AbstractBlockSparseArray{<:Any,0}) - return blocksparse_getindex(a) -end - -## # Fix ambiguity error with `BlockArrays`. -## function Base.getindex(a::AbstractBlockSparseArray{<:Any,N}, I::Block{N}) where {N} -## return ArrayLayouts.layout_getindex(a, I) -## end -## -## # Fix ambiguity error with `BlockArrays`. -## function Base.getindex(a::AbstractBlockSparseArray{<:Any,1}, I::Block{1}) -## return ArrayLayouts.layout_getindex(a, I) -## end -## -## # Fix ambiguity error with `BlockArrays`. -## function Base.getindex(a::AbstractBlockSparseArray, I::Vararg{AbstractVector}) -## ## return blocksparse_getindex(a, I...) -## return ArrayLayouts.layout_getindex(a, I...) -## end - -# Specialized in order to fix ambiguity error with `BlockArrays`. -function Base.setindex!( - a::AbstractBlockSparseArray{<:Any,N}, value, I::Vararg{Int,N} -) where {N} - blocksparse_setindex!(a, value, I...) - return a -end - -# Fix ambiguity error. -function Base.setindex!(a::AbstractBlockSparseArray{<:Any,0}, value) - blocksparse_setindex!(a, value) - return a -end - -function Base.setindex!( - a::AbstractBlockSparseArray{<:Any,N}, value, I::Vararg{Block{1},N} -) where {N} - blocksize = ntuple(dim -> length(axes(a, dim)[I[dim]]), N) - if size(value) ≠ blocksize - throw( - DimensionMismatch( - "Trying to set block $(Block(Int.(I)...)), which has a size $blocksize, with data of size $(size(value)).", - ), - ) - end - blocks(a)[Int.(I)...] = value - return a -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsematrix.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsematrix.jl deleted file mode 100644 index 0c2c578781..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsematrix.jl +++ /dev/null @@ -1 +0,0 @@ -const AbstractBlockSparseMatrix{T} = AbstractBlockSparseArray{T,2} diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsevector.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsevector.jl deleted file mode 100644 index ae1441c5a8..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/abstractblocksparsevector.jl +++ /dev/null @@ -1 +0,0 @@ -const AbstractBlockSparseVector{T} = AbstractBlockSparseArray{T,1} diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/arraylayouts.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/arraylayouts.jl deleted file mode 100644 index 4e79b8fb81..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/arraylayouts.jl +++ /dev/null @@ -1,53 +0,0 @@ -using ArrayLayouts: ArrayLayouts, DualLayout, MemoryLayout, MulAdd -using BlockArrays: BlockLayout -using ..SparseArraysBase: SparseLayout -using ..TypeParameterAccessors: parenttype, similartype - -function ArrayLayouts.MemoryLayout(arraytype::Type{<:AnyAbstractBlockSparseArray}) - outer_layout = typeof(MemoryLayout(blockstype(arraytype))) - inner_layout = typeof(MemoryLayout(blocktype(arraytype))) - return BlockLayout{outer_layout,inner_layout}() -end - -# TODO: Generalize to `BlockSparseVectorLike`/`AnyBlockSparseVector`. -function ArrayLayouts.MemoryLayout( - arraytype::Type{<:Adjoint{<:Any,<:AbstractBlockSparseVector}} -) - return DualLayout{typeof(MemoryLayout(parenttype(arraytype)))}() -end -# TODO: Generalize to `BlockSparseVectorLike`/`AnyBlockSparseVector`. -function ArrayLayouts.MemoryLayout( - arraytype::Type{<:Transpose{<:Any,<:AbstractBlockSparseVector}} -) - return DualLayout{typeof(MemoryLayout(parenttype(arraytype)))}() -end - -function Base.similar( - mul::MulAdd{<:BlockLayout{<:SparseLayout},<:BlockLayout{<:SparseLayout},<:Any,<:Any,A,B}, - elt::Type, - axes, -) where {A,B} - # TODO: Check that this equals `similartype(blocktype(B), elt, axes)`, - # or maybe promote them? - output_blocktype = similartype(blocktype(A), elt, axes) - return similar(BlockSparseArray{elt,length(axes),output_blocktype}, axes) -end - -# Materialize a SubArray view. -function ArrayLayouts.sub_materialize(layout::BlockLayout{<:SparseLayout}, a, axes) - # TODO: Define `blocktype`/`blockstype` for `SubArray` wrapping `BlockSparseArray`. - # TODO: Use `similar`? - blocktype_a = blocktype(parent(a)) - a_dest = BlockSparseArray{eltype(a),length(axes),blocktype_a}(axes) - a_dest .= a - return a_dest -end - -# Materialize a SubArray view. -function ArrayLayouts.sub_materialize( - layout::BlockLayout{<:SparseLayout}, a, axes::Tuple{Vararg{Base.OneTo}} -) - a_dest = blocktype(a)(undef, length.(axes)) - a_dest .= a - return a_dest -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/broadcast.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/broadcast.jl deleted file mode 100644 index 96841be6f1..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/broadcast.jl +++ /dev/null @@ -1,48 +0,0 @@ -using BlockArrays: AbstractBlockedUnitRange, BlockSlice -using Base.Broadcast: Broadcast - -function Broadcast.BroadcastStyle(arraytype::Type{<:AnyAbstractBlockSparseArray}) - return BlockSparseArrayStyle{ndims(arraytype)}() -end - -# Fix ambiguity error with `BlockArrays`. -function Broadcast.BroadcastStyle( - arraytype::Type{ - <:SubArray{ - <:Any, - <:Any, - <:AbstractBlockSparseArray, - <:Tuple{BlockSlice{<:Any,<:Any,<:AbstractBlockedUnitRange},Vararg{Any}}, - }, - }, -) - return BlockSparseArrayStyle{ndims(arraytype)}() -end -function Broadcast.BroadcastStyle( - arraytype::Type{ - <:SubArray{ - <:Any, - <:Any, - <:AbstractBlockSparseArray, - <:Tuple{ - BlockSlice{<:Any,<:Any,<:AbstractBlockedUnitRange}, - BlockSlice{<:Any,<:Any,<:AbstractBlockedUnitRange}, - Vararg{Any}, - }, - }, - }, -) - return BlockSparseArrayStyle{ndims(arraytype)}() -end -function Broadcast.BroadcastStyle( - arraytype::Type{ - <:SubArray{ - <:Any, - <:Any, - <:AbstractBlockSparseArray, - <:Tuple{Any,BlockSlice{<:Any,<:Any,<:AbstractBlockedUnitRange},Vararg{Any}}, - }, - }, -) - return BlockSparseArrayStyle{ndims(arraytype)}() -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/cat.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/cat.jl deleted file mode 100644 index 3023037113..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/cat.jl +++ /dev/null @@ -1,7 +0,0 @@ -# TODO: Change to `AnyAbstractBlockSparseArray`. -function Base.cat(as::AnyAbstractBlockSparseArray...; dims) - # TODO: Use `sparse_cat` instead, currently - # that erroneously allocates too many blocks that are - # zero and shouldn't be stored. - return blocksparse_cat(as...; dims) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/linearalgebra.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/linearalgebra.jl deleted file mode 100644 index 144ea47593..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/linearalgebra.jl +++ /dev/null @@ -1,18 +0,0 @@ -using LinearAlgebra: Adjoint, Transpose - -# Like: https://github.com/JuliaLang/julia/blob/v1.11.1/stdlib/LinearAlgebra/src/transpose.jl#L184 -# but also takes the dual of the axes. -# Fixes an issue raised in: -# https://github.com/ITensor/ITensors.jl/issues/1336#issuecomment-2353434147 -function Base.copy(a::Adjoint{T,<:AbstractBlockSparseMatrix{T}}) where {T} - a_dest = similar(parent(a), axes(a)) - a_dest .= a - return a_dest -end - -# More efficient than the generic `LinearAlgebra` version. -function Base.copy(a::Transpose{T,<:AbstractBlockSparseMatrix{T}}) where {T} - a_dest = similar(parent(a), axes(a)) - a_dest .= a - return a_dest -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/map.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/map.jl deleted file mode 100644 index 30ca37c53b..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/map.jl +++ /dev/null @@ -1,151 +0,0 @@ -using ArrayLayouts: LayoutArray -using BlockArrays: blockisequal -using LinearAlgebra: Adjoint, Transpose -using ..SparseArraysBase: - SparseArraysBase, - SparseArrayStyle, - sparse_map!, - sparse_copy!, - sparse_copyto!, - sparse_permutedims!, - sparse_mapreduce, - sparse_iszero, - sparse_isreal - -# Returns `Vector{<:CartesianIndices}` -function union_stored_blocked_cartesianindices(as::Vararg{AbstractArray}) - combined_axes = combine_axes(axes.(as)...) - stored_blocked_cartesianindices_as = map(as) do a - return blocked_cartesianindices(axes(a), combined_axes, block_stored_indices(a)) - end - return ∪(stored_blocked_cartesianindices_as...) -end - -# This is used by `map` to get the output axes. -# This is type piracy, try to avoid this, maybe requires defining `map`. -## Base.promote_shape(a1::Tuple{Vararg{BlockedUnitRange}}, a2::Tuple{Vararg{BlockedUnitRange}}) = combine_axes(a1, a2) - -reblock(a) = a - -# If the blocking of the slice doesn't match the blocking of the -# parent array, reblock according to the blocking of the parent array. -function reblock( - a::SubArray{<:Any,<:Any,<:AbstractBlockSparseArray,<:Tuple{Vararg{AbstractUnitRange}}} -) - # TODO: This relies on the behavior that slicing a block sparse - # array with a UnitRange inherits the blocking of the underlying - # block sparse array, we might change that default behavior - # so this might become something like `@blocked parent(a)[...]`. - return @view parent(a)[UnitRange{Int}.(parentindices(a))...] -end - -function reblock( - a::SubArray{<:Any,<:Any,<:AbstractBlockSparseArray,<:Tuple{Vararg{NonBlockedArray}}} -) - return @view parent(a)[map(I -> I.array, parentindices(a))...] -end - -function reblock( - a::SubArray{ - <:Any, - <:Any, - <:AbstractBlockSparseArray, - <:Tuple{Vararg{BlockIndices{<:AbstractBlockVector{<:Block{1}}}}}, - }, -) - # Remove the blocking. - return @view parent(a)[map(I -> Vector(I.blocks), parentindices(a))...] -end - -# TODO: Rewrite this so that it takes the blocking structure -# made by combining the blocking of the axes (i.e. the blocking that -# is used to determine `union_stored_blocked_cartesianindices(...)`). -# `reblock` is a partial solution to that, but a bit ad-hoc. -# TODO: Move to `blocksparsearrayinterface/map.jl`. -function SparseArraysBase.sparse_map!( - ::BlockSparseArrayStyle, f, a_dest::AbstractArray, a_srcs::Vararg{AbstractArray} -) - a_dest, a_srcs = reblock(a_dest), reblock.(a_srcs) - for I in union_stored_blocked_cartesianindices(a_dest, a_srcs...) - BI_dest = blockindexrange(a_dest, I) - BI_srcs = map(a_src -> blockindexrange(a_src, I), a_srcs) - # TODO: Investigate why this doesn't work: - # block_dest = @view a_dest[_block(BI_dest)] - block_dest = blocks_maybe_single(a_dest)[Int.(Tuple(_block(BI_dest)))...] - # TODO: Investigate why this doesn't work: - # block_srcs = ntuple(i -> @view(a_srcs[i][_block(BI_srcs[i])]), length(a_srcs)) - block_srcs = ntuple(length(a_srcs)) do i - return blocks_maybe_single(a_srcs[i])[Int.(Tuple(_block(BI_srcs[i])))...] - end - subblock_dest = @view block_dest[BI_dest.indices...] - subblock_srcs = ntuple(i -> @view(block_srcs[i][BI_srcs[i].indices...]), length(a_srcs)) - # TODO: Use `map!!` to handle immutable blocks. - map!(f, subblock_dest, subblock_srcs...) - # Replace the entire block, handles initializing new blocks - # or if blocks are immutable. - blocks(a_dest)[Int.(Tuple(_block(BI_dest)))...] = block_dest - end - return a_dest -end - -# TODO: Implement this. -# function SparseArraysBase.sparse_mapreduce(::BlockSparseArrayStyle, f, a_dest::AbstractArray, a_srcs::Vararg{AbstractArray}) -# end - -function Base.map!(f, a_dest::AbstractArray, a_srcs::Vararg{AnyAbstractBlockSparseArray}) - sparse_map!(f, a_dest, a_srcs...) - return a_dest -end - -function Base.map(f, as::Vararg{AnyAbstractBlockSparseArray}) - return f.(as...) -end - -function Base.copy!(a_dest::AbstractArray, a_src::AnyAbstractBlockSparseArray) - sparse_copy!(a_dest, a_src) - return a_dest -end - -function Base.copyto!(a_dest::AbstractArray, a_src::AnyAbstractBlockSparseArray) - sparse_copyto!(a_dest, a_src) - return a_dest -end - -# Fix ambiguity error -function Base.copyto!(a_dest::LayoutArray, a_src::AnyAbstractBlockSparseArray) - sparse_copyto!(a_dest, a_src) - return a_dest -end - -function Base.copyto!( - a_dest::AbstractMatrix, a_src::Transpose{T,<:AbstractBlockSparseMatrix{T}} -) where {T} - sparse_copyto!(a_dest, a_src) - return a_dest -end - -function Base.copyto!( - a_dest::AbstractMatrix, a_src::Adjoint{T,<:AbstractBlockSparseMatrix{T}} -) where {T} - sparse_copyto!(a_dest, a_src) - return a_dest -end - -function Base.permutedims!(a_dest, a_src::AnyAbstractBlockSparseArray, perm) - sparse_permutedims!(a_dest, a_src, perm) - return a_dest -end - -function Base.mapreduce(f, op, as::Vararg{AnyAbstractBlockSparseArray}; kwargs...) - return sparse_mapreduce(f, op, as...; kwargs...) -end - -# TODO: Why isn't this calling `mapreduce` already? -function Base.iszero(a::AnyAbstractBlockSparseArray) - return sparse_iszero(blocks(a)) -end - -# TODO: Why isn't this calling `mapreduce` already? -function Base.isreal(a::AnyAbstractBlockSparseArray) - return sparse_isreal(blocks(a)) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/sparsearrayinterface.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/sparsearrayinterface.jl deleted file mode 100644 index 31dbca27e7..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/sparsearrayinterface.jl +++ /dev/null @@ -1,38 +0,0 @@ -using BlockArrays: Block -using ..SparseArraysBase: SparseArraysBase, sparse_storage, stored_indices - -# Structure storing the block sparse storage -struct BlockSparseStorage{Arr<:AbstractBlockSparseArray} - array::Arr -end - -function blockindex_to_cartesianindex(a::AbstractArray, blockindex) - return CartesianIndex(getindex.(axes(a), getindex.(Block.(blockindex.I), blockindex.α))) -end - -function Base.keys(s::BlockSparseStorage) - stored_blockindices = Iterators.map(stored_indices(blocks(s.array))) do I - block_axes = axes(blocks(s.array)[I]) - blockindices = Block(Tuple(I))[block_axes...] - return Iterators.map( - blockindex -> blockindex_to_cartesianindex(s.array, blockindex), blockindices - ) - end - return Iterators.flatten(stored_blockindices) -end - -function Base.values(s::BlockSparseStorage) - return Iterators.map(I -> s.array[I], eachindex(s)) -end - -function Base.iterate(s::BlockSparseStorage, args...) - return iterate(values(s), args...) -end - -function SparseArraysBase.sparse_storage(a::AbstractBlockSparseArray) - return BlockSparseStorage(a) -end - -function SparseArraysBase.stored_length(a::AnyAbstractBlockSparseArray) - return sum(stored_length, sparse_storage(blocks(a)); init=zero(Int)) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/views.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/views.jl deleted file mode 100644 index 7283b850d3..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/views.jl +++ /dev/null @@ -1,294 +0,0 @@ -using BlockArrays: - AbstractBlockedUnitRange, - BlockArrays, - Block, - BlockIndexRange, - BlockedVector, - blocklength, - blocksize, - viewblock - -# This splits `BlockIndexRange{N}` into -# `NTuple{N,BlockIndexRange{1}}`. -# TODO: Move to `BlockArraysExtensions`. -to_tuple(x) = Tuple(x) -function to_tuple(x::BlockIndexRange{N}) where {N} - blocks = Tuple(Block(x)) - n = length(blocks) - return ntuple(dim -> blocks[dim][x.indices[dim]], n) -end - -# Override the default definition of `BlockArrays.blocksize`, -# which is incorrect for certain slices. -function BlockArrays.blocksize(a::SubArray{<:Any,<:Any,<:AnyAbstractBlockSparseArray}) - return blocklength.(axes(a)) -end -function BlockArrays.blocksize( - a::SubArray{<:Any,<:Any,<:AnyAbstractBlockSparseArray}, i::Int -) - # TODO: Maybe use `blocklength(axes(a, i))` which would be a bit faster. - return blocksize(a)[i] -end - -# These definitions circumvent some generic definitions in BlockArrays.jl: -# https://github.com/JuliaArrays/BlockArrays.jl/blob/master/src/views.jl -# which don't handle subslices of blocks properly. -function Base.view( - a::SubArray{ - <:Any,N,<:AnyAbstractBlockSparseArray,<:Tuple{Vararg{BlockSlice{<:BlockRange{1}},N}} - }, - I::Block{N}, -) where {N} - return blocksparse_view(a, I) -end -function Base.view( - a::SubArray{ - <:Any,N,<:AnyAbstractBlockSparseArray,<:Tuple{Vararg{BlockSlice{<:BlockRange{1}},N}} - }, - I::Vararg{Block{1},N}, -) where {N} - return blocksparse_view(a, I...) -end -function Base.view( - V::SubArray{<:Any,1,<:AnyAbstractBlockSparseArray,<:Tuple{BlockSlice{<:BlockRange{1}}}}, - I::Block{1}, -) - return blocksparse_view(a, I) -end - -# Specialized code for getting the view of a block. -function BlockArrays.viewblock( - a::AbstractBlockSparseArray{<:Any,N}, block::Block{N} -) where {N} - return viewblock(a, Tuple(block)...) -end - -# TODO: Define `blocksparse_viewblock`. -function BlockArrays.viewblock( - a::AbstractBlockSparseArray{<:Any,N}, block::Vararg{Block{1},N} -) where {N} - I = CartesianIndex(Int.(block)) - # TODO: Use `block_stored_indices`. - if I ∈ stored_indices(blocks(a)) - return blocks(a)[I] - end - return BlockView(a, block) -end - -# Specialized code for getting the view of a subblock. -function Base.view( - a::AbstractBlockSparseArray{<:Any,N}, block::BlockIndexRange{N} -) where {N} - return view(a, to_tuple(block)...) -end - -# Specialized code for getting the view of a subblock. -function Base.view( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N}}, I::BlockIndexRange{N} -) where {T,N} - return view(a, to_tuple(I)...) -end -function Base.view(a::AbstractBlockSparseArray{<:Any,N}, I::Vararg{Block{1},N}) where {N} - return viewblock(a, I...) -end - -# TODO: Move to `GradedAxes` or `BlockArraysExtensions`. -to_block(I::Block{1}) = I -to_block(I::BlockIndexRange{1}) = Block(I) -to_block_indices(I::Block{1}) = Colon() -to_block_indices(I::BlockIndexRange{1}) = only(I.indices) - -function Base.view( - a::AbstractBlockSparseArray{<:Any,N}, I::Vararg{Union{Block{1},BlockIndexRange{1}},N} -) where {N} - return @views a[to_block.(I)...][to_block_indices.(I)...] -end - -function Base.view( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N}}, I::Vararg{Block{1},N} -) where {T,N} - return viewblock(a, I...) -end -function Base.view( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N}}, - I::Vararg{Union{Block{1},BlockIndexRange{1}},N}, -) where {T,N} - return @views a[to_block.(I)...][to_block_indices.(I)...] -end -# Generic fallback. -function BlockArrays.viewblock( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N}}, I::Vararg{Block{1},N} -) where {T,N} - return Base.invoke(view, Tuple{AbstractArray,Vararg{Any}}, a, I...) -end - -function Base.view( - a::SubArray{ - T, - N, - <:AbstractBlockSparseArray{T,N}, - <:Tuple{Vararg{Union{BlockSliceCollection,SubBlockSliceCollection},N}}, - }, - block::Union{Block{N},BlockIndexRange{N}}, -) where {T,N} - return viewblock(a, block) -end -function Base.view( - a::SubArray{ - T, - N, - <:AbstractBlockSparseArray{T,N}, - <:Tuple{Vararg{Union{BlockSliceCollection,SubBlockSliceCollection},N}}, - }, - block::Vararg{Union{Block{1},BlockIndexRange{1}},N}, -) where {T,N} - return viewblock(a, block...) -end -function BlockArrays.viewblock( - a::SubArray{ - T, - N, - <:AbstractBlockSparseArray{T,N}, - <:Tuple{Vararg{Union{BlockSliceCollection,SubBlockSliceCollection},N}}, - }, - block::Union{Block{N},BlockIndexRange{N}}, -) where {T,N} - return viewblock(a, to_tuple(block)...) -end - -# Fixes ambiguity error with `AnyAbstractBlockSparseArray` definition. -function Base.view( - a::SubArray{ - T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockSlice{<:BlockRange{1}},N}} - }, - block::Block{N}, -) where {T,N} - return viewblock(a, block) -end -# Fixes ambiguity error with `AnyAbstractBlockSparseArray` definition. -function Base.view( - a::SubArray{ - T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockSlice{<:BlockRange{1}},N}} - }, - block::Vararg{Block{1},N}, -) where {T,N} - return viewblock(a, block...) -end - -# XXX: TODO: Distinguish if a sub-view of the block needs to be taken! -# Define a new `SubBlockSlice` which is used in: -# `blocksparse_to_indices(a, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}})` -# in `blocksparsearrayinterface/blocksparsearrayinterface.jl`. -# TODO: Define `blocksparse_viewblock`. -function BlockArrays.viewblock( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockSliceCollection,N}}}, - block::Vararg{Block{1},N}, -) where {T,N} - I = CartesianIndex(Int.(block)) - # TODO: Use `block_stored_indices`. - if I ∈ stored_indices(blocks(a)) - return blocks(a)[I] - end - return BlockView(parent(a), Block.(Base.reindex(parentindices(blocks(a)), Tuple(I)))) -end - -function to_blockindexrange( - a::BlockIndices{<:BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}}}, - I::Block{1}, -) - # TODO: Ideally we would just use `a.blocks[I]` but that doesn't - # work right now. - return blocks(a.blocks)[Int(I)] -end -function to_blockindexrange( - a::Base.Slice{<:AbstractBlockedUnitRange{<:Integer}}, I::Block{1} -) - @assert I in only(blockaxes(a.indices)) - return I -end - -function BlockArrays.viewblock( - a::SubArray{ - T, - N, - <:AbstractBlockSparseArray{T,N}, - <:Tuple{Vararg{Union{BlockSliceCollection,SubBlockSliceCollection},N}}, - }, - block::Vararg{Block{1},N}, -) where {T,N} - brs = ntuple(dim -> to_blockindexrange(parentindices(a)[dim], block[dim]), ndims(a)) - return @view parent(a)[brs...] -end - -# TODO: Define `blocksparse_viewblock`. -function BlockArrays.viewblock( - a::SubArray{ - T, - N, - <:AbstractBlockSparseArray{T,N}, - <:Tuple{Vararg{Union{BlockSliceCollection,SubBlockSliceCollection},N}}, - }, - block::Vararg{BlockIndexRange{1},N}, -) where {T,N} - return view(viewblock(a, Block.(block)...), map(b -> only(b.indices), block)...) -end - -# Block slice of the result of slicing `@view a[2:5, 2:5]`. -# TODO: Move this to `BlockArraysExtensions`. -const BlockedSlice = BlockSlice{ - <:BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}} -} - -function Base.view( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockedSlice,N}}}, - block::Union{Block{N},BlockIndexRange{N}}, -) where {T,N} - return viewblock(a, block) -end -function Base.view( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockedSlice,N}}}, - block::Vararg{Union{Block{1},BlockIndexRange{1}},N}, -) where {T,N} - return viewblock(a, block...) -end -function BlockArrays.viewblock( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockedSlice,N}}}, - block::Union{Block{N},BlockIndexRange{N}}, -) where {T,N} - return viewblock(a, to_tuple(block)...) -end -# TODO: Define `blocksparse_viewblock`. -function BlockArrays.viewblock( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockedSlice,N}}}, - I::Vararg{Block{1},N}, -) where {T,N} - # TODO: Use `reindex`, `to_indices`, etc. - brs = ntuple(ndims(a)) do dim - # TODO: Ideally we would use this but it outputs a Vector, - # not a range: - # return parentindices(a)[dim].block[I[dim]] - return blocks(parentindices(a)[dim].block)[Int(I[dim])] - end - return @view parent(a)[brs...] -end -# TODO: Define `blocksparse_viewblock`. -function BlockArrays.viewblock( - a::SubArray{T,N,<:AbstractBlockSparseArray{T,N},<:Tuple{Vararg{BlockedSlice,N}}}, - block::Vararg{BlockIndexRange{1},N}, -) where {T,N} - return view(viewblock(a, Block.(block)...), map(b -> only(b.indices), block)...) -end - -# migrate wrapper layer for viewing `adjoint` and `transpose`. -for (f, F) in ((:adjoint, :Adjoint), (:transpose, :Transpose)) - @eval begin - function Base.view(A::$F{<:Any,<:AbstractBlockSparseVector}, b::Block{1}) - return $f(view(parent(A), b)) - end - - Base.view(A::$F{<:Any,<:AbstractBlockSparseMatrix}, b::Block{2}) = view(A, Tuple(b)...) - function Base.view(A::$F{<:Any,<:AbstractBlockSparseMatrix}, b1::Block{1}, b2::Block{1}) - return $f(view(parent(A), b2, b1)) - end - end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl b/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl deleted file mode 100644 index c961f67e5a..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl +++ /dev/null @@ -1,310 +0,0 @@ -using Adapt: Adapt, WrappedArray -using BlockArrays: - BlockArrays, - AbstractBlockVector, - AbstractBlockedUnitRange, - BlockIndexRange, - BlockRange, - blockedrange, - mortar, - unblock -using SplitApplyCombine: groupcount -using ..TypeParameterAccessors: similartype - -const WrappedAbstractBlockSparseArray{T,N} = WrappedArray{ - T,N,AbstractBlockSparseArray,AbstractBlockSparseArray{T,N} -} - -# TODO: Rename `AnyBlockSparseArray`. -const AnyAbstractBlockSparseArray{T,N} = Union{ - <:AbstractBlockSparseArray{T,N},<:WrappedAbstractBlockSparseArray{T,N} -} - -# a[1:2, 1:2] -function Base.to_indices( - a::AnyAbstractBlockSparseArray, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}} -) - return blocksparse_to_indices(a, inds, I) -end - -# a[[Block(2), Block(1)], [Block(2), Block(1)]] -function Base.to_indices( - a::AnyAbstractBlockSparseArray, inds, I::Tuple{Vector{<:Block{1}},Vararg{Any}} -) - return blocksparse_to_indices(a, inds, I) -end - -# a[BlockVector([Block(2), Block(1)], [2]), BlockVector([Block(2), Block(1)], [2])] -# a[BlockedVector([Block(2), Block(1)], [2]), BlockedVector([Block(2), Block(1)], [2])] -function Base.to_indices( - a::AnyAbstractBlockSparseArray, - inds, - I::Tuple{AbstractBlockVector{<:Block{1}},Vararg{Any}}, -) - return blocksparse_to_indices(a, inds, I) -end - -# a[mortar([Block(1)[1:2], Block(2)[1:3]])] -function Base.to_indices( - a::AnyAbstractBlockSparseArray, - inds, - I::Tuple{BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}},Vararg{Any}}, -) - return blocksparse_to_indices(a, inds, I) -end - -# a[[Block(1)[1:2], Block(2)[1:2]], [Block(1)[1:2], Block(2)[1:2]]] -function Base.to_indices( - a::AnyAbstractBlockSparseArray, inds, I::Tuple{Vector{<:BlockIndexRange{1}},Vararg{Any}} -) - return to_indices(a, inds, (mortar(I[1]), Base.tail(I)...)) -end - -# BlockArrays `AbstractBlockArray` interface -BlockArrays.blocks(a::AnyAbstractBlockSparseArray) = blocksparse_blocks(a) - -# Fix ambiguity error with `BlockArrays` -using BlockArrays: BlockSlice -function BlockArrays.blocks( - a::SubArray{<:Any,<:Any,<:AbstractBlockSparseArray,<:Tuple{Vararg{BlockSlice}}} -) - return blocksparse_blocks(a) -end - -using ..TypeParameterAccessors: parenttype -function blockstype(arraytype::Type{<:WrappedAbstractBlockSparseArray}) - return blockstype(parenttype(arraytype)) -end - -blocktype(a::AnyAbstractBlockSparseArray) = eltype(blocks(a)) -blocktype(arraytype::Type{<:AnyAbstractBlockSparseArray}) = eltype(blockstype(arraytype)) - -using ArrayLayouts: ArrayLayouts -function Base.getindex( - a::AnyAbstractBlockSparseArray{<:Any,N}, I::CartesianIndices{N} -) where {N} - return ArrayLayouts.layout_getindex(a, I) -end -function Base.getindex( - a::AnyAbstractBlockSparseArray{<:Any,N}, I::Vararg{AbstractUnitRange{<:Integer},N} -) where {N} - return ArrayLayouts.layout_getindex(a, I...) -end -# TODO: Define `AnyBlockSparseMatrix`. -function Base.getindex( - a::AnyAbstractBlockSparseArray{<:Any,2}, I::Vararg{AbstractUnitRange{<:Integer},2} -) - return ArrayLayouts.layout_getindex(a, I...) -end -# Fixes ambiguity error. -function Base.getindex(a::AnyAbstractBlockSparseArray{<:Any,0}) - return ArrayLayouts.layout_getindex(a) -end - -# TODO: Define `blocksparse_isassigned`. -function Base.isassigned( - a::AnyAbstractBlockSparseArray{<:Any,N}, index::Vararg{Block{1},N} -) where {N} - return isassigned(blocks(a), Int.(index)...) -end - -# Fix ambiguity error. -function Base.isassigned(a::AnyAbstractBlockSparseArray{<:Any,0}) - return isassigned(blocks(a)) -end - -function Base.isassigned(a::AnyAbstractBlockSparseArray{<:Any,N}, index::Block{N}) where {N} - return isassigned(a, Tuple(index)...) -end - -# TODO: Define `blocksparse_isassigned`. -function Base.isassigned( - a::AnyAbstractBlockSparseArray{<:Any,N}, index::Vararg{BlockIndex{1},N} -) where {N} - b = block.(index) - return isassigned(a, b...) && isassigned(@view(a[b...]), blockindex.(index)...) -end - -function Base.setindex!( - a::AnyAbstractBlockSparseArray{<:Any,N}, value, I::BlockIndex{N} -) where {N} - blocksparse_setindex!(a, value, I) - return a -end -# Fixes ambiguity error with BlockArrays.jl -function Base.setindex!(a::AnyAbstractBlockSparseArray{<:Any,1}, value, I::BlockIndex{1}) - blocksparse_setindex!(a, value, I) - return a -end - -function Base.fill!(a::AbstractBlockSparseArray, value) - if iszero(value) - # This drops all of the blocks. - sparse_zero!(blocks(a)) - return a - end - blocksparse_fill!(a, value) - return a -end - -function Base.fill!(a::AnyAbstractBlockSparseArray, value) - # TODO: Even if `iszero(value)`, this doesn't drop - # blocks from `a`, and additionally allocates - # new blocks filled with zeros, unlike - # `fill!(a::AbstractBlockSparseArray, value)`. - # Consider changing that behavior when possible. - blocksparse_fill!(a, value) - return a -end - -# Needed by `BlockArrays` matrix multiplication interface -function Base.similar( - arraytype::Type{<:AnyAbstractBlockSparseArray}, - axes::Tuple{Vararg{AbstractUnitRange{<:Integer}}}, -) - return similar(arraytype, eltype(arraytype), axes) -end - -# Fixes ambiguity error. -function Base.similar( - arraytype::Type{<:AnyAbstractBlockSparseArray}, axes::Tuple{Base.OneTo,Vararg{Base.OneTo}} -) - return similar(arraytype, eltype(arraytype), axes) -end - -# Needed by `BlockArrays` matrix multiplication interface -# TODO: This fixes an ambiguity error with `OffsetArrays.jl`, but -# is only appears to be needed in older versions of Julia like v1.6. -# Delete once we drop support for older versions of Julia. -function Base.similar( - arraytype::Type{<:AnyAbstractBlockSparseArray}, - axes::Tuple{AbstractUnitRange{<:Integer},Vararg{AbstractUnitRange{<:Integer}}}, -) - return similar(arraytype, eltype(arraytype), axes) -end - -# Fixes ambiguity error with `BlockArrays`. -function Base.similar( - arraytype::Type{<:AnyAbstractBlockSparseArray}, - axes::Tuple{AbstractBlockedUnitRange{<:Integer},Vararg{AbstractUnitRange{<:Integer}}}, -) - return similar(arraytype, eltype(arraytype), axes) -end - -# Fixes ambiguity error with `BlockArrays`. -function Base.similar( - arraytype::Type{<:AnyAbstractBlockSparseArray}, - axes::Tuple{ - AbstractUnitRange{<:Integer}, - AbstractBlockedUnitRange{<:Integer}, - Vararg{AbstractUnitRange{<:Integer}}, - }, -) - return similar(arraytype, eltype(arraytype), axes) -end - -# Needed for disambiguation -function Base.similar( - arraytype::Type{<:AnyAbstractBlockSparseArray}, - axes::Tuple{Vararg{AbstractBlockedUnitRange{<:Integer}}}, -) - return similar(arraytype, eltype(arraytype), axes) -end - -function blocksparse_similar(a, elt::Type, axes::Tuple) - return BlockSparseArray{elt,length(axes),similartype(blocktype(a), elt, axes)}( - undef, axes - ) -end - -# Needed by `BlockArrays` matrix multiplication interface -# TODO: Define a `blocksparse_similar` function. -function Base.similar( - arraytype::Type{<:AnyAbstractBlockSparseArray}, - elt::Type, - axes::Tuple{Vararg{AbstractUnitRange{<:Integer}}}, -) - return blocksparse_similar(arraytype, elt, axes) -end - -# TODO: Define a `blocksparse_similar` function. -function Base.similar( - a::AnyAbstractBlockSparseArray, - elt::Type, - axes::Tuple{Vararg{AbstractUnitRange{<:Integer}}}, -) - return blocksparse_similar(a, elt, axes) -end - -# Fixes ambiguity error. -function Base.similar(a::AnyAbstractBlockSparseArray, elt::Type, axes::Tuple{}) - return blocksparse_similar(a, elt, axes) -end - -# Fixes ambiguity error with `BlockArrays`. -function Base.similar( - a::AnyAbstractBlockSparseArray, - elt::Type, - axes::Tuple{ - AbstractBlockedUnitRange{<:Integer},Vararg{AbstractBlockedUnitRange{<:Integer}} - }, -) - return blocksparse_similar(a, elt, axes) -end - -# Fixes ambiguity error with `OffsetArrays`. -function Base.similar( - a::AnyAbstractBlockSparseArray, - elt::Type, - axes::Tuple{AbstractUnitRange{<:Integer},Vararg{AbstractUnitRange{<:Integer}}}, -) - return blocksparse_similar(a, elt, axes) -end - -# Fixes ambiguity error with `BlockArrays`. -function Base.similar( - a::AnyAbstractBlockSparseArray, - elt::Type, - axes::Tuple{AbstractBlockedUnitRange{<:Integer},Vararg{AbstractUnitRange{<:Integer}}}, -) - return blocksparse_similar(a, elt, axes) -end - -# Fixes ambiguity errors with BlockArrays. -function Base.similar( - a::AnyAbstractBlockSparseArray, - elt::Type, - axes::Tuple{ - AbstractUnitRange{<:Integer}, - AbstractBlockedUnitRange{<:Integer}, - Vararg{AbstractUnitRange{<:Integer}}, - }, -) - return blocksparse_similar(a, elt, axes) -end - -# Fixes ambiguity error with `StaticArrays`. -function Base.similar( - a::AnyAbstractBlockSparseArray, elt::Type, axes::Tuple{Base.OneTo,Vararg{Base.OneTo}} -) - return blocksparse_similar(a, elt, axes) -end - -# TODO: Implement this in a more generic way using a smarter `copyto!`, -# which is ultimately what `Array{T,N}(::AbstractArray{<:Any,N})` calls. -# These are defined for now to avoid scalar indexing issues when there -# are blocks on GPU. -function Base.Array{T,N}(a::AnyAbstractBlockSparseArray{<:Any,N}) where {T,N} - # First make it dense, then move to CPU. - # Directly copying to CPU causes some issues with - # scalar indexing on GPU which we have to investigate. - a_dest = similartype(blocktype(a), T)(undef, size(a)) - a_dest .= a - return Array{T,N}(a_dest) -end -function Base.Array{T}(a::AnyAbstractBlockSparseArray) where {T} - return Array{T,ndims(a)}(a) -end -function Base.Array(a::AnyAbstractBlockSparseArray) - return Array{eltype(a)}(a) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/backup/qr.jl b/NDTensors/src/lib/BlockSparseArrays/src/backup/qr.jl deleted file mode 100644 index 4cd4527358..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/backup/qr.jl +++ /dev/null @@ -1,143 +0,0 @@ -using ...SparseArraysBase: SparseArrayDOK - -# Check if the matrix has 1 or fewer entries -# per row/column. -function is_permutation_matrix(a::SparseMatrixCSC) - return all(col -> length(nzrange(a, col)) ≤ 1, axes(a, 2)) -end - -# Check if the matrix has 1 or fewer entries -# per row/column. -function is_permutation_matrix(a::SparseArrayDOK{<:Any,2}) - keys = collect(Iterators.map(Tuple, nonzero_keys(a))) - I = first.(keys) - J = last.(keys) - return allunique(I) && allunique(J) -end - -function findnonzerorows(a::SparseMatrixCSC, col) - return view(a.rowval, a.colptr[col]:(a.colptr[col + 1] - 1)) -end - -# TODO: Is this already defined? -function SparseArrays.SparseMatrixCSC(a::SparseArrayDOK{<:Any,2}) - # Not defined: - # a_csc = SparseMatrixCSC{eltype(a)}(size(a)) - a_csc = spzeros(eltype(a), size(a)) - for I in nonzero_keys(a) - a_csc[I] = a[I] - end - return a_csc -end - -# TODO: Is this already defined? -# Get the sparse structure of a SparseArray as a SparseMatrixCSC. -function sparse_structure( - structure_type::Type{<:SparseMatrixCSC}, a::SparseArrayDOK{<:Any,2} -) - # Idealy would work but a bit too complicated for `map` right now: - # return SparseMatrixCSC(map(x -> iszero(x) ? false : true, a)) - # TODO: Change to `spzeros(Bool, size(a))`. - a_structure = structure_type(spzeros(Bool, size(a)...)) - for I in nonzero_keys(a) - i, j = Tuple(I) - a_structure[i, j] = true - end - return a_structure -end - -# Get the sparsity structure as a `SparseMatrixCSC` with values -# of `true` where there are structural nonzero blocks and `false` -# otherwise. -function block_sparse_structure(structure_type::Type, a::BlockSparseArray{<:Any,2}) - return sparse_structure(structure_type, blocks(a)) -end - -function is_block_permutation_matrix(a::BlockSparseArray{<:Any,2}) - return is_permutation_matrix(blocks(a)) -end - -qr_rank(alg::Algorithm"thin", a::AbstractArray{<:Any,2}) = minimum(size(a)) - -# m × n → (m × min(m, n)) ⋅ (min(m, n) × n) -function qr_block_sparse_structure(alg::Algorithm"thin", a::BlockSparseArray{<:Any,2}) - axes_row, axes_col = axes(a) - a_csc = block_sparse_structure(SparseMatrixCSC, a) - F = qr(float(a_csc)) - # Outputs full Q - # q_csc = sparse(F.Q[invperm(F.prow), :]) - q_csc = (F.Q * sparse(I, size(a_csc, 1), minimum(size(a_csc))))[invperm(F.prow), :] - r_csc = F.R[:, invperm(F.pcol)] - nblocks = size(q_csc, 2) - @assert nblocks == size(r_csc, 1) - a_sparse = blocks(a) - blocklengths_qr = Vector{Int}(undef, nblocks) - for I in nonzero_keys(a_sparse) - i, k = Tuple(I) - # Get the nonzero columns associated - # with the given row. - j = only(findnonzerorows(r_csc, k)) - # @assert is_structural_nonzero(r, j, k) - # @assert is_structural_nonzero(q, i, j) - blocklengths_qr[j] = qr_rank(alg, @view(a[BlockArrays.Block(i, k)])) - end - axes_qr = blockedrange(blocklengths_qr) - axes_q = (axes(a, 1), axes_qr) - axes_r = (axes_qr, axes(a, 2)) - # TODO: Come up with a better format to ouput. - # TODO: Get `axes_qr` as a permutation of the - # axes of `axes(a, 2)` to preserve sectors - # when using symmetric tensors. - return q_csc, axes_q, r_csc, axes_r -end - -# m × n → (m × m) ⋅ (m × n) -function qr_block_sparse_structure(alg::Algorithm"full", a::BlockSparseArray{<:Any,2}) - return error("Not implemented") -end - -function qr_blocks(a, structure_r, block_a) - i, k = block_a.n - j = only(findnonzerorows(structure_r, k)) - return BlockArrays.Block(i, j), BlockArrays.Block(j, k) -end - -# Block-preserving QR. -function LinearAlgebra.qr(a::BlockSparseArray{<:Any,2}; alg="thin") - return qr(Algorithm(alg), a) -end - -# Block-preserving QR. -function LinearAlgebra.qr(alg::Algorithm, a::BlockSparseArray{<:Any,2}) - if !is_block_permutation_matrix(a) - # Must have 1 or fewer blocks per row/column. - println("Block sparsity structure is:") - display(nonzero_blockkeys(a)) - error("Not a block permutation matrix") - end - eltype_a = eltype(a) - # TODO: `structure_q` isn't needed. - structure_q, axes_q, structure_r, axes_r = qr_block_sparse_structure(alg, a) - # TODO: Make this generic to GPU, use `similar`. - q = BlockSparseArray{eltype_a}(axes_q) - r = BlockSparseArray{eltype_a}(axes_r) - for block_a in nonzero_blockkeys(a) - # TODO: Make thin or full depending on `alg`. - q_b, r_b = qr(a[block_a]) - # Determine the block of Q and R - # TODO: Do the block locations change for `alg="full"`? - block_q, block_r = qr_blocks(a, structure_r, block_a) - - # TODO Make this generic to GPU. - q[block_q] = Matrix(q_b) - r[block_r] = r_b - end - # TODO: If `alg="full"`, fill in blocks of `q` - # with random unitaries. - # Which blocks should be filled? Seems to be based - # on the QNs... - # Maybe fill diagonal blocks. - # TODO: Also store `structure_r` in some way - # since that is needed for permuting the QNs. - return q, r -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/blocksparsearray.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/blocksparsearray.jl deleted file mode 100644 index 19de9fd0ab..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/blocksparsearray.jl +++ /dev/null @@ -1,199 +0,0 @@ -using BlockArrays: BlockArrays, Block, BlockedUnitRange, blockedrange, blocklength -using Dictionaries: Dictionary -using ..SparseArraysBase: SparseArrayDOK - -# TODO: Delete this. -## using BlockArrays: blocks - -struct BlockSparseArray{ - T, - N, - A<:AbstractArray{T,N}, - Blocks<:AbstractArray{A,N}, - Axes<:Tuple{Vararg{AbstractUnitRange,N}}, -} <: AbstractBlockSparseArray{T,N} - blocks::Blocks - axes::Axes -end - -# TODO: Can this definition be shortened? -const BlockSparseMatrix{T,A<:AbstractMatrix{T},Blocks<:AbstractMatrix{A},Axes<:Tuple{AbstractUnitRange,AbstractUnitRange}} = BlockSparseArray{ - T,2,A,Blocks,Axes -} - -# TODO: Can this definition be shortened? -const BlockSparseVector{T,A<:AbstractVector{T},Blocks<:AbstractVector{A},Axes<:Tuple{AbstractUnitRange}} = BlockSparseArray{ - T,1,A,Blocks,Axes -} - -function BlockSparseArray( - block_data::Dictionary{<:Block{N},<:AbstractArray{<:Any,N}}, - axes::Tuple{Vararg{AbstractUnitRange,N}}, -) where {N} - blocks = default_blocks(block_data, axes) - return BlockSparseArray(blocks, axes) -end - -function BlockSparseArray( - block_indices::Vector{<:Block{N}}, - block_data::Vector{<:AbstractArray{<:Any,N}}, - axes::Tuple{Vararg{AbstractUnitRange,N}}, -) where {N} - return BlockSparseArray(Dictionary(block_indices, block_data), axes) -end - -function BlockSparseArray{T,N,A,Blocks}( - blocks::AbstractArray{<:AbstractArray{T,N},N}, axes::Tuple{Vararg{AbstractUnitRange,N}} -) where {T,N,A<:AbstractArray{T,N},Blocks<:AbstractArray{A,N}} - return BlockSparseArray{T,N,A,Blocks,typeof(axes)}(blocks, axes) -end - -function BlockSparseArray{T,N,A}( - blocks::AbstractArray{<:AbstractArray{T,N},N}, axes::Tuple{Vararg{AbstractUnitRange,N}} -) where {T,N,A<:AbstractArray{T,N}} - return BlockSparseArray{T,N,A,typeof(blocks)}(blocks, axes) -end - -function BlockSparseArray{T,N}( - blocks::AbstractArray{<:AbstractArray{T,N},N}, axes::Tuple{Vararg{AbstractUnitRange,N}} -) where {T,N} - return BlockSparseArray{T,N,eltype(blocks),typeof(blocks),typeof(axes)}(blocks, axes) -end - -function BlockSparseArray{T,N}( - block_data::Dictionary{Block{N,Int},<:AbstractArray{T,N}}, - axes::Tuple{Vararg{AbstractUnitRange,N}}, -) where {T,N} - blocks = default_blocks(block_data, axes) - return BlockSparseArray{T,N}(blocks, axes) -end - -function BlockSparseArray{T,N,A}( - axes::Tuple{Vararg{AbstractUnitRange,N}} -) where {T,N,A<:AbstractArray{T,N}} - blocks = default_blocks(A, axes) - return BlockSparseArray{T,N,A}(blocks, axes) -end - -function BlockSparseArray{T,N,A}( - axes::Vararg{AbstractUnitRange,N} -) where {T,N,A<:AbstractArray{T,N}} - return BlockSparseArray{T,N,A}(axes) -end - -function BlockSparseArray{T,N,A}( - dims::Tuple{Vararg{Vector{Int},N}} -) where {T,N,A<:AbstractArray{T,N}} - return BlockSparseArray{T,N,A}(blockedrange.(dims)) -end - -# Fix ambiguity error. -function BlockSparseArray{T,0,A}(axes::Tuple{}) where {T,A<:AbstractArray{T,0}} - blocks = default_blocks(A, axes) - return BlockSparseArray{T,0,A}(blocks, axes) -end - -function BlockSparseArray{T,N,A}( - dims::Vararg{Vector{Int},N} -) where {T,N,A<:AbstractArray{T,N}} - return BlockSparseArray{T,N,A}(dims) -end - -function BlockSparseArray{T,N}(axes::Tuple{Vararg{AbstractUnitRange,N}}) where {T,N} - return BlockSparseArray{T,N,default_arraytype(T, axes)}(axes) -end - -function BlockSparseArray{T,N}(axes::Vararg{AbstractUnitRange,N}) where {T,N} - return BlockSparseArray{T,N}(axes) -end - -function BlockSparseArray{T,0}(axes::Tuple{}) where {T} - return BlockSparseArray{T,0,default_arraytype(T, axes)}(axes) -end - -function BlockSparseArray{T,N}(dims::Tuple{Vararg{Vector{Int},N}}) where {T,N} - return BlockSparseArray{T,N}(blockedrange.(dims)) -end - -function BlockSparseArray{T,N}(dims::Vararg{Vector{Int},N}) where {T,N} - return BlockSparseArray{T,N}(dims) -end - -function BlockSparseArray{T}(dims::Tuple{Vararg{Vector{Int}}}) where {T} - return BlockSparseArray{T,length(dims)}(dims) -end - -function BlockSparseArray{T}(axes::Tuple{Vararg{AbstractUnitRange}}) where {T} - return BlockSparseArray{T,length(axes)}(axes) -end - -function BlockSparseArray{T}(axes::Tuple{}) where {T} - return BlockSparseArray{T,length(axes)}(axes) -end - -function BlockSparseArray{T}(dims::Vararg{Vector{Int}}) where {T} - return BlockSparseArray{T}(dims) -end - -function BlockSparseArray{T}(axes::Vararg{AbstractUnitRange}) where {T} - return BlockSparseArray{T}(axes) -end - -function BlockSparseArray{T}() where {T} - return BlockSparseArray{T}(()) -end - -# undef -function BlockSparseArray{T,N,A,Blocks}( - ::UndefInitializer, args... -) where {T,N,A<:AbstractArray{T,N},Blocks<:AbstractArray{A,N}} - return BlockSparseArray{T,N,A,Blocks}(args...) -end - -function BlockSparseArray{T,N,A}( - ::UndefInitializer, args... -) where {T,N,A<:AbstractArray{T,N}} - return BlockSparseArray{T,N,A}(args...) -end - -function BlockSparseArray{T,N}(::UndefInitializer, args...) where {T,N} - return BlockSparseArray{T,N}(args...) -end - -function BlockSparseArray{T}(::UndefInitializer, args...) where {T} - return BlockSparseArray{T}(args...) -end - -# Base `AbstractArray` interface -Base.axes(a::BlockSparseArray) = a.axes - -# BlockArrays `AbstractBlockArray` interface. -# This is used by `blocks(::AnyAbstractBlockSparseArray)`. -blocksparse_blocks(a::BlockSparseArray) = a.blocks - -# TODO: Use `TypeParameterAccessors`. -function blockstype( - arraytype::Type{<:BlockSparseArray{T,N,A,Blocks}} -) where {T,N,A<:AbstractArray{T,N},Blocks<:AbstractArray{A,N}} - return Blocks -end -function blockstype( - arraytype::Type{<:BlockSparseArray{T,N,A}} -) where {T,N,A<:AbstractArray{T,N}} - return SparseArrayDOK{A,N} -end -function blockstype(arraytype::Type{<:BlockSparseArray{T,N}}) where {T,N} - return SparseArrayDOK{AbstractArray{T,N},N} -end -function blockstype(arraytype::Type{<:BlockSparseArray{T}}) where {T} - return SparseArrayDOK{AbstractArray{T}} -end -blockstype(arraytype::Type{<:BlockSparseArray}) = SparseArrayDOK{AbstractArray} - -## # Base interface -## function Base.similar( -## a::AbstractBlockSparseArray, elt::Type, axes::Tuple{Vararg{BlockedUnitRange}} -## ) -## # TODO: Preserve GPU data! -## return BlockSparseArray{elt}(undef, axes) -## end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/defaults.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/defaults.jl deleted file mode 100644 index ab126aaa15..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearray/defaults.jl +++ /dev/null @@ -1,42 +0,0 @@ -using BlockArrays: Block -using Dictionaries: Dictionary -using ..SparseArraysBase: SparseArrayDOK - -# Construct the sparse structure storing the blocks -function default_blockdata( - block_data::Dictionary{<:CartesianIndex{N},<:AbstractArray{<:Any,N}}, - axes::Tuple{Vararg{AbstractUnitRange,N}}, -) where {N} - return error() -end - -function default_blocks( - block_indices::Vector{<:Block{N}}, - block_data::Vector{<:AbstractArray{<:Any,N}}, - axes::Tuple{Vararg{AbstractUnitRange,N}}, -) where {N} - return default_blocks(Dictionary(block_indices, block_data), axes) -end - -function default_blocks( - block_data::Dictionary{<:Block{N},<:AbstractArray{<:Any,N}}, - axes::Tuple{Vararg{AbstractUnitRange,N}}, -) where {N} - return default_blocks(blocks_to_cartesianindices(block_data), axes) -end - -function default_arraytype(elt::Type, axes::Tuple{Vararg{AbstractUnitRange}}) - return Array{elt,length(axes)} -end - -function default_blocks(blocktype::Type, axes::Tuple{Vararg{AbstractUnitRange}}) - block_data = Dictionary{Block{length(axes),Int},blocktype}() - return default_blocks(block_data, axes) -end - -function default_blocks( - block_data::Dictionary{<:CartesianIndex{N},<:AbstractArray{<:Any,N}}, - axes::Tuple{Vararg{AbstractUnitRange,N}}, -) where {N} - return SparseArrayDOK(block_data, blocklength.(axes), BlockZero(axes)) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/arraylayouts.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/arraylayouts.jl deleted file mode 100644 index f7d02ae554..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/arraylayouts.jl +++ /dev/null @@ -1,48 +0,0 @@ -using ArrayLayouts: ArrayLayouts, Dot, MatMulMatAdd, MatMulVecAdd, MulAdd -using BlockArrays: BlockLayout -using ..SparseArraysBase: SparseLayout -using LinearAlgebra: dot, mul! - -function blocksparse_muladd!( - α::Number, a1::AbstractArray, a2::AbstractArray, β::Number, a_dest::AbstractArray -) - mul!(blocks(a_dest), blocks(a1), blocks(a2), α, β) - return a_dest -end - -function blocksparse_matmul!(m::MulAdd) - α, a1, a2, β, a_dest = m.α, m.A, m.B, m.β, m.C - blocksparse_muladd!(α, a1, a2, β, a_dest) - return a_dest -end - -function ArrayLayouts.materialize!( - m::MatMulMatAdd{ - <:BlockLayout{<:SparseLayout}, - <:BlockLayout{<:SparseLayout}, - <:BlockLayout{<:SparseLayout}, - }, -) - blocksparse_matmul!(m) - return m.C -end -function ArrayLayouts.materialize!( - m::MatMulVecAdd{ - <:BlockLayout{<:SparseLayout}, - <:BlockLayout{<:SparseLayout}, - <:BlockLayout{<:SparseLayout}, - }, -) - blocksparse_matmul!(m) - return m.C -end - -function blocksparse_dot(a1::AbstractArray, a2::AbstractArray) - # TODO: Add a check that the blocking of `a1` and `a2` are - # the same, or the same up to a reshape. - return dot(blocks(a1), blocks(a2)) -end - -function Base.copy(d::Dot{<:BlockLayout{<:SparseLayout},<:BlockLayout{<:SparseLayout}}) - return blocksparse_dot(d.A, d.B) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blocksparsearrayinterface.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blocksparsearrayinterface.jl deleted file mode 100644 index 4e9b85a958..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ /dev/null @@ -1,274 +0,0 @@ -using BlockArrays: - AbstractBlockVector, - Block, - BlockIndex, - BlockRange, - BlockSlice, - BlockVector, - BlockedUnitRange, - BlockedVector, - block, - blockcheckbounds, - blocklengths, - blocks, - findblockindex -using LinearAlgebra: Adjoint, Transpose -using ..SparseArraysBase: perm, iperm, stored_length, sparse_zero! - -blocksparse_blocks(a::AbstractArray) = error("Not implemented") - -blockstype(a::AbstractArray) = blockstype(typeof(a)) - -function blocksparse_getindex(a::AbstractArray{<:Any,N}, I::Vararg{Int,N}) where {N} - @boundscheck checkbounds(a, I...) - return a[findblockindex.(axes(a), I)...] -end - -# Fix ambiguity error. -function blocksparse_getindex(a::AbstractArray{<:Any,0}) - # TODO: Use `Block()[]` once https://github.com/JuliaArrays/BlockArrays.jl/issues/430 - # is fixed. - return a[BlockIndex{0,Tuple{},Tuple{}}((), ())] -end - -# a[1:2, 1:2] -# TODO: This definition means that the result of slicing a block sparse array -# with a non-blocked unit range is blocked. We may want to change that behavior, -# and make that explicit with `@blocked a[1:2, 1:2]`. See the discussion in -# https://github.com/JuliaArrays/BlockArrays.jl/issues/347 and also -# https://github.com/ITensor/ITensors.jl/issues/1336. -function blocksparse_to_indices(a, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}}) - bs1 = to_blockindices(inds[1], I[1]) - I1 = BlockSlice(bs1, blockedunitrange_getindices(inds[1], I[1])) - return (I1, to_indices(a, Base.tail(inds), Base.tail(I))...) -end - -# Special case when there is no blocking. -function blocksparse_to_indices( - a, - inds::Tuple{Base.OneTo{<:Integer},Vararg{Any}}, - I::Tuple{UnitRange{<:Integer},Vararg{Any}}, -) - return (inds[1][I[1]], to_indices(a, Base.tail(inds), Base.tail(I))...) -end - -# a[[Block(2), Block(1)], [Block(2), Block(1)]] -function blocksparse_to_indices(a, inds, I::Tuple{Vector{<:Block{1}},Vararg{Any}}) - I1 = BlockIndices(I[1], blockedunitrange_getindices(inds[1], I[1])) - return (I1, to_indices(a, Base.tail(inds), Base.tail(I))...) -end - -# a[mortar([Block(1)[1:2], Block(2)[1:3]]), mortar([Block(1)[1:2], Block(2)[1:3]])] -# a[[Block(1)[1:2], Block(2)[1:3]], [Block(1)[1:2], Block(2)[1:3]]] -function blocksparse_to_indices( - a, inds, I::Tuple{BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}},Vararg{Any}} -) - I1 = BlockIndices(I[1], blockedunitrange_getindices(inds[1], I[1])) - return (I1, to_indices(a, Base.tail(inds), Base.tail(I))...) -end - -# a[BlockVector([Block(2), Block(1)], [2]), BlockVector([Block(2), Block(1)], [2])] -# Permute and merge blocks. -# TODO: This isn't merging blocks yet, that needs to be implemented that. -function blocksparse_to_indices( - a, inds, I::Tuple{AbstractBlockVector{<:Block{1}},Vararg{Any}} -) - I1 = BlockIndices(I[1], blockedunitrange_getindices(inds[1], I[1])) - return (I1, to_indices(a, Base.tail(inds), Base.tail(I))...) -end - -# TODO: Need to implement this! -function block_merge end - -function blocksparse_setindex!(a::AbstractArray{<:Any,N}, value, I::Vararg{Int,N}) where {N} - @boundscheck checkbounds(a, I...) - a[findblockindex.(axes(a), I)...] = value - return a -end - -# Fix ambiguity error. -function blocksparse_setindex!(a::AbstractArray{<:Any,0}, value) - # TODO: Use `Block()[]` once https://github.com/JuliaArrays/BlockArrays.jl/issues/430 - # is fixed. - a[BlockIndex{0,Tuple{},Tuple{}}((), ())] = value - return a -end - -function blocksparse_setindex!(a::AbstractArray{<:Any,N}, value, I::BlockIndex{N}) where {N} - i = Int.(Tuple(block(I))) - a_b = blocks(a)[i...] - a_b[I.α...] = value - # Set the block, required if it is structurally zero. - blocks(a)[i...] = a_b - return a -end - -# Fix ambiguity error. -function blocksparse_setindex!(a::AbstractArray{<:Any,0}, value, I::BlockIndex{0}) - a_b = blocks(a)[] - a_b[] = value - # Set the block, required if it is structurally zero. - blocks(a)[] = a_b - return a -end - -function blocksparse_fill!(a::AbstractArray, value) - for b in BlockRange(a) - # We can't use: - # ```julia - # a[b] .= value - # ``` - # since that would lead to a stack overflow, - # because broadcasting calls `fill!`. - - # TODO: Ideally we would use: - # ```julia - # @view!(a[b]) .= value - # ``` - # but that doesn't work on `SubArray` right now. - - # This line is needed to instantiate blocks - # that aren't instantiated yet. Maybe - # we can make this work without this line? - blocks(a)[Int.(Tuple(b))...] = blocks(a)[Int.(Tuple(b))...] - blocks(a)[Int.(Tuple(b))...] .= value - end - return a -end - -function block_stored_length(a::AbstractArray) - return stored_length(blocks(a)) -end - -# BlockArrays - -using ..SparseArraysBase: SparseArraysBase, AbstractSparseArray, AbstractSparseMatrix - -_perm(::PermutedDimsArray{<:Any,<:Any,perm}) where {perm} = perm -_invperm(::PermutedDimsArray{<:Any,<:Any,<:Any,invperm}) where {invperm} = invperm -_getindices(t::Tuple, indices) = map(i -> t[i], indices) -_getindices(i::CartesianIndex, indices) = CartesianIndex(_getindices(Tuple(i), indices)) - -# Represents the array of arrays of a `PermutedDimsArray` -# wrapping a block spare array, i.e. `blocks(array)` where `a` is a `PermutedDimsArray`. -struct SparsePermutedDimsArrayBlocks{ - T,N,BlockType<:AbstractArray{T,N},Array<:PermutedDimsArray{T,N} -} <: AbstractSparseArray{BlockType,N} - array::Array -end -function blocksparse_blocks(a::PermutedDimsArray) - return SparsePermutedDimsArrayBlocks{eltype(a),ndims(a),blocktype(parent(a)),typeof(a)}(a) -end -function Base.size(a::SparsePermutedDimsArrayBlocks) - return _getindices(size(blocks(parent(a.array))), _perm(a.array)) -end -function Base.getindex( - a::SparsePermutedDimsArrayBlocks{<:Any,N}, index::Vararg{Int,N} -) where {N} - return PermutedDimsArray( - blocks(parent(a.array))[_getindices(index, _invperm(a.array))...], _perm(a.array) - ) -end -function SparseArraysBase.stored_indices(a::SparsePermutedDimsArrayBlocks) - return map(I -> _getindices(I, _perm(a.array)), stored_indices(blocks(parent(a.array)))) -end -# TODO: Either make this the generic interface or define -# `SparseArraysBase.sparse_storage`, which is used -# to defined this. -function SparseArraysBase.stored_length(a::SparsePermutedDimsArrayBlocks) - return length(stored_indices(a)) -end -function SparseArraysBase.sparse_storage(a::SparsePermutedDimsArrayBlocks) - return error("Not implemented") -end - -reverse_index(index) = reverse(index) -reverse_index(index::CartesianIndex) = CartesianIndex(reverse(Tuple(index))) - -blocksparse_blocks(a::Transpose) = transpose(blocks(parent(a))) -blocksparse_blocks(a::Adjoint) = adjoint(blocks(parent(a))) - -# Represents the array of arrays of a `SubArray` -# wrapping a block spare array, i.e. `blocks(array)` where `a` is a `SubArray`. -struct SparseSubArrayBlocks{T,N,BlockType<:AbstractArray{T,N},Array<:SubArray{T,N}} <: - AbstractSparseArray{BlockType,N} - array::Array -end -function blocksparse_blocks(a::SubArray) - return SparseSubArrayBlocks{eltype(a),ndims(a),blocktype(parent(a)),typeof(a)}(a) -end -# TODO: Define this as `blockrange(a::AbstractArray, indices::Tuple{Vararg{AbstractUnitRange}})`. -function blockrange(a::SparseSubArrayBlocks) - blockranges = blockrange.(axes(parent(a.array)), a.array.indices) - return map(blockrange -> Int.(blockrange), blockranges) -end -function Base.axes(a::SparseSubArrayBlocks) - return Base.OneTo.(length.(blockrange(a))) -end -function Base.size(a::SparseSubArrayBlocks) - return length.(axes(a)) -end -function Base.getindex(a::SparseSubArrayBlocks{<:Any,N}, I::Vararg{Int,N}) where {N} - # TODO: Should this be defined as `@view a.array[Block(I)]` instead? - return @view a.array[Block(I)] - - ## parent_blocks = @view blocks(parent(a.array))[blockrange(a)...] - ## parent_block = parent_blocks[I...] - ## # TODO: Define this using `blockrange(a::AbstractArray, indices::Tuple{Vararg{AbstractUnitRange}})`. - ## block = Block(ntuple(i -> blockrange(a)[i][I[i]], ndims(a))) - ## return @view parent_block[blockindices(parent(a.array), block, a.array.indices)...] -end -# TODO: This should be handled by generic `AbstractSparseArray` code. -function Base.getindex(a::SparseSubArrayBlocks{<:Any,N}, I::CartesianIndex{N}) where {N} - return a[Tuple(I)...] -end -function Base.setindex!(a::SparseSubArrayBlocks{<:Any,N}, value, I::Vararg{Int,N}) where {N} - parent_blocks = @view blocks(parent(a.array))[blockrange(a)...] - # TODO: The following line is required to instantiate - # uninstantiated blocks, maybe use `@view!` instead, - # or some other code pattern. - parent_blocks[I...] = parent_blocks[I...] - # TODO: Define this using `blockrange(a::AbstractArray, indices::Tuple{Vararg{AbstractUnitRange}})`. - block = Block(ntuple(i -> blockrange(a)[i][I[i]], ndims(a))) - return parent_blocks[I...][blockindices(parent(a.array), block, a.array.indices)...] = - value -end -function Base.isassigned(a::SparseSubArrayBlocks{<:Any,N}, I::Vararg{Int,N}) where {N} - if CartesianIndex(I) ∉ CartesianIndices(a) - return false - end - # TODO: Implement this properly. - return true -end -function SparseArraysBase.stored_indices(a::SparseSubArrayBlocks) - return stored_indices(view(blocks(parent(a.array)), blockrange(a)...)) -end -# TODO: Either make this the generic interface or define -# `SparseArraysBase.sparse_storage`, which is used -# to defined this. -SparseArraysBase.stored_length(a::SparseSubArrayBlocks) = length(stored_indices(a)) - -## struct SparseSubArrayBlocksStorage{Array<:SparseSubArrayBlocks} -## array::Array -## end -function SparseArraysBase.sparse_storage(a::SparseSubArrayBlocks) - return map(I -> a[I], stored_indices(a)) -end - -function SparseArraysBase.getindex_zero_function(a::SparseSubArrayBlocks) - # TODO: Base it off of `getindex_zero_function(blocks(parent(a.array))`, but replace the - # axes with `axes(a.array)`. - return BlockZero(axes(a.array)) -end - -to_blocks_indices(I::BlockSlice{<:BlockRange{1}}) = Int.(I.block) -to_blocks_indices(I::BlockIndices{<:Vector{<:Block{1}}}) = Int.(I.blocks) - -function blocksparse_blocks( - a::SubArray{<:Any,<:Any,<:Any,<:Tuple{Vararg{BlockSliceCollection}}} -) - return @view blocks(parent(a))[map(to_blocks_indices, parentindices(a))...] -end - -using BlockArrays: BlocksView -SparseArraysBase.stored_length(a::BlocksView) = length(a) diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blockzero.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blockzero.jl deleted file mode 100644 index 25665acd63..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/blockzero.jl +++ /dev/null @@ -1,45 +0,0 @@ -using BlockArrays: Block, blockedrange - -# Extensions to BlockArrays.jl -blocktuple(b::Block) = Block.(b.n) -inttuple(b::Block) = b.n - -# The size of a block -function block_size(axes::Tuple{Vararg{AbstractUnitRange}}, block::Block) - return length.(getindex.(axes, blocktuple(block))) -end - -# The size of a block -function block_size(blockinds::Tuple{Vararg{AbstractVector}}, block::Block) - return block_size(blockedrange.(blockinds), block) -end - -struct BlockZero{Axes} - axes::Axes -end - -function (f::BlockZero)(a::AbstractArray, I) - return f(eltype(a), I) -end - -function (f::BlockZero)(arraytype::Type{<:SubArray{<:Any,<:Any,P}}, I) where {P} - return f(P, I) -end - -function (f::BlockZero)(arraytype::Type{<:AbstractArray}, I) - # TODO: Make sure this works for sparse or block sparse blocks, immutable - # blocks, diagonal blocks, etc.! - blck_size = block_size(f.axes, Block(Tuple(I))) - blck_type = similartype(arraytype, blck_size) - return fill!(blck_type(undef, blck_size), false) -end - -# Fallback so that `SparseArray` with scalar elements works. -function (f::BlockZero)(blocktype::Type{<:Number}, I) - return zero(blocktype) -end - -# Fallback to Array if it is abstract -function (f::BlockZero)(arraytype::Type{AbstractArray{T,N}}, I) where {T,N} - return f(Array{T,N}, I) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/broadcast.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/broadcast.jl deleted file mode 100644 index 7ce8d024ef..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/broadcast.jl +++ /dev/null @@ -1,39 +0,0 @@ -using Base.Broadcast: BroadcastStyle, AbstractArrayStyle, DefaultArrayStyle, Broadcasted -using ..BroadcastMapConversion: map_function, map_args - -struct BlockSparseArrayStyle{N} <: AbstractArrayStyle{N} end - -# Define for new sparse array types. -# function Broadcast.BroadcastStyle(arraytype::Type{<:MyBlockSparseArray}) -# return BlockSparseArrayStyle{ndims(arraytype)}() -# end - -BlockSparseArrayStyle(::Val{N}) where {N} = BlockSparseArrayStyle{N}() -BlockSparseArrayStyle{M}(::Val{N}) where {M,N} = BlockSparseArrayStyle{N}() - -Broadcast.BroadcastStyle(a::BlockSparseArrayStyle, ::DefaultArrayStyle{0}) = a -function Broadcast.BroadcastStyle( - ::BlockSparseArrayStyle{N}, a::DefaultArrayStyle -) where {N} - return BroadcastStyle(DefaultArrayStyle{N}(), a) -end -function Broadcast.BroadcastStyle( - ::BlockSparseArrayStyle{N}, ::Broadcast.Style{Tuple} -) where {N} - return DefaultArrayStyle{N}() -end - -function Base.similar(bc::Broadcasted{<:BlockSparseArrayStyle}, elt::Type) - # TODO: Make sure this handles GPU arrays properly. - return similar(first(map_args(bc)), elt, combine_axes(axes.(map_args(bc))...)) -end - -# Broadcasting implementation -function Base.copyto!( - dest::AbstractArray{<:Any,N}, bc::Broadcasted{BlockSparseArrayStyle{N}} -) where {N} - # convert to map - # flatten and only keep the AbstractArray arguments - sparse_map!(map_function(bc), dest, map_args(bc)...) - return dest -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/cat.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/cat.jl deleted file mode 100644 index b2d6596bd5..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/cat.jl +++ /dev/null @@ -1,26 +0,0 @@ -using BlockArrays: AbstractBlockedUnitRange, blockedrange, blocklengths -using NDTensors.SparseArraysBase: SparseArraysBase, allocate_cat_output, sparse_cat! - -# TODO: Maybe move to `SparseArraysBaseBlockArraysExt`. -# TODO: Handle dual graded unit ranges, for example in a new `SparseArraysBaseGradedAxesExt`. -function SparseArraysBase.axis_cat( - a1::AbstractBlockedUnitRange, a2::AbstractBlockedUnitRange -) - return blockedrange(vcat(blocklengths(a1), blocklengths(a2))) -end - -# that erroneously allocates too many blocks that are -# zero and shouldn't be stored. -function blocksparse_cat!(a_dest::AbstractArray, as::AbstractArray...; dims) - sparse_cat!(blocks(a_dest), blocks.(as)...; dims) - return a_dest -end - -# TODO: Delete this in favor of `sparse_cat`, currently -# that erroneously allocates too many blocks that are -# zero and shouldn't be stored. -function blocksparse_cat(as::AbstractArray...; dims) - a_dest = allocate_cat_output(as...; dims) - blocksparse_cat!(a_dest, as...; dims) - return a_dest -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/linearalgebra.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/linearalgebra.jl deleted file mode 100644 index ac7f566a93..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/linearalgebra.jl +++ /dev/null @@ -1,12 +0,0 @@ -using LinearAlgebra: mul! - -function blocksparse_mul!( - a_dest::AbstractMatrix, - a1::AbstractMatrix, - a2::AbstractMatrix, - α::Number=true, - β::Number=false, -) - mul!(blocks(a_dest), blocks(a1), blocks(a2), α, β) - return a_dest -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/map.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/map.jl deleted file mode 100644 index 2d537cdbf7..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/map.jl +++ /dev/null @@ -1,19 +0,0 @@ -function map_stored_blocks(f, a::AbstractArray) - # TODO: Implement this as: - # ```julia - # mapped_blocks = SparseArraysInterface.map_stored(f, blocks(a)) - # BlockSparseArray(mapped_blocks, axes(a)) - # ``` - # TODO: `block_stored_indices` should output `Indices` storing - # the stored Blocks, not a `Dictionary` from cartesian indices - # to Blocks. - bs = collect(block_stored_indices(a)) - ds = map(b -> f(@view(a[b])), bs) - # We manually specify the block type using `Base.promote_op` - # since `a[b]` may not be inferrable. For example, if `blocktype(a)` - # is `Diagonal{Float64,Vector{Float64}}`, the non-stored blocks are `Matrix{Float64}` - # since they can't necessarily by `Diagonal` if there are rectangular blocks. - mapped_blocks = Dictionary{eltype(bs),eltype(ds)}(bs, ds) - # TODO: Use `similartype(typeof(a), eltype(eltype(mapped_blocks)))(...)`. - return BlockSparseArray(mapped_blocks, axes(a)) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/views.jl b/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/views.jl deleted file mode 100644 index 8e43f2625b..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/src/blocksparsearrayinterface/views.jl +++ /dev/null @@ -1,3 +0,0 @@ -function blocksparse_view(a, I...) - return Base.invoke(view, Tuple{AbstractArray,Vararg{Any}}, a, I...) -end diff --git a/NDTensors/src/lib/BlockSparseArrays/test/Project.toml b/NDTensors/src/lib/BlockSparseArrays/test/Project.toml deleted file mode 100644 index b0460803d3..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/test/Project.toml +++ /dev/null @@ -1,6 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" -GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" -JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" diff --git a/NDTensors/src/lib/BlockSparseArrays/test/TestBlockSparseArraysUtils.jl b/NDTensors/src/lib/BlockSparseArrays/test/TestBlockSparseArraysUtils.jl deleted file mode 100644 index 36f453986b..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/test/TestBlockSparseArraysUtils.jl +++ /dev/null @@ -1,15 +0,0 @@ -module TestBlockSparseArraysUtils -using BlockArrays: BlockRange - -function set_blocks!(a::AbstractArray, f::Function, blocks::Function) - set_blocks!(a, f, filter(blocks, BlockRange(a))) - return a -end - -function set_blocks!(a::AbstractArray, f::Function, blocks::Vector) - for b in blocks - a[b] = f(eltype(a), size(@view(a[b]))) - end - return a -end -end diff --git a/NDTensors/src/lib/BlockSparseArrays/test/runtests.jl b/NDTensors/src/lib/BlockSparseArrays/test/runtests.jl deleted file mode 100644 index 2a8e2c5db9..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/test/runtests.jl +++ /dev/null @@ -1,5 +0,0 @@ -@eval module $(gensym()) -include("test_basics.jl") -include("../ext/BlockSparseArraysTensorAlgebraExt/test/runtests.jl") -include("../ext/BlockSparseArraysGradedAxesExt/test/runtests.jl") -end diff --git a/NDTensors/src/lib/BlockSparseArrays/test/test_basics.jl b/NDTensors/src/lib/BlockSparseArrays/test/test_basics.jl deleted file mode 100644 index 13eda130c2..0000000000 --- a/NDTensors/src/lib/BlockSparseArrays/test/test_basics.jl +++ /dev/null @@ -1,1033 +0,0 @@ -@eval module $(gensym()) -using BlockArrays: - Block, - BlockIndexRange, - BlockRange, - BlockSlice, - BlockVector, - BlockedOneTo, - BlockedUnitRange, - BlockedVector, - blockedrange, - blocklength, - blocklengths, - blocksize, - blocksizes, - mortar -using Compat: @compat -using GPUArraysCore: @allowscalar -using LinearAlgebra: Adjoint, Transpose, dot, mul!, norm -using NDTensors.BlockSparseArrays: - @view!, - BlockSparseArray, - BlockSparseMatrix, - BlockSparseVector, - BlockView, - block_stored_length, - block_reshape, - block_stored_indices, - blockstype, - blocktype, - view! -using NDTensors.GPUArraysCoreExtensions: cpu -using NDTensors.SparseArraysBase: stored_length -using NDTensors.SparseArraysBase: SparseArrayDOK, SparseMatrixDOK, SparseVectorDOK -using NDTensors.TensorAlgebra: contract -using Test: @test, @test_broken, @test_throws, @testset, @inferred -include("TestBlockSparseArraysUtils.jl") - -using NDTensors: NDTensors -include(joinpath(pkgdir(NDTensors), "test", "NDTensorsTestUtils", "NDTensorsTestUtils.jl")) -using .NDTensorsTestUtils: devices_list, is_supported_eltype -@testset "BlockSparseArrays (dev=$dev, eltype=$elt)" for dev in devices_list(copy(ARGS)), - elt in (Float32, Float64, Complex{Float32}, Complex{Float64}) - - if !is_supported_eltype(dev, elt) - continue - end - @testset "Broken" begin - # TODO: Fix this and turn it into a proper test. - a = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a[Block(1, 1)] = dev(randn(elt, 2, 2)) - a[Block(2, 2)] = dev(randn(elt, 3, 3)) - @test_broken a[:, 4] - - # TODO: Fix this and turn it into a proper test. - a = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a[Block(1, 1)] = dev(randn(elt, 2, 2)) - a[Block(2, 2)] = dev(randn(elt, 3, 3)) - @test_broken a[:, [2, 4]] - @test_broken a[[3, 5], [2, 4]] - - # TODO: Fix this and turn it into a proper test. - a = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a[Block(1, 1)] = dev(randn(elt, 2, 2)) - a[Block(2, 2)] = dev(randn(elt, 3, 3)) - @allowscalar @test a[2:4, 4] == Array(a)[2:4, 4] - @test_broken a[4, 2:4] - - @test a[Block(1), :] isa BlockSparseArray{elt} - @test adjoint(a) isa Adjoint{elt,<:BlockSparseArray} - @test_broken adjoint(a)[Block(1), :] isa Adjoint{elt,<:BlockSparseArray} - # could also be directly a BlockSparseArray - end - @testset "Constructors" begin - # BlockSparseMatrix - bs = ([2, 3], [3, 4]) - for T in ( - BlockSparseArray{elt}, - BlockSparseArray{elt,2}, - BlockSparseMatrix{elt}, - BlockSparseArray{elt,2,Matrix{elt}}, - BlockSparseMatrix{elt,Matrix{elt}}, - ## BlockSparseArray{elt,2,Matrix{elt},SparseMatrixDOK{Matrix{elt}}}, # TODO - ## BlockSparseMatrix{elt,Matrix{elt},SparseMatrixDOK{Matrix{elt}}}, # TODO - ) - for args in ( - bs, - (bs,), - blockedrange.(bs), - (blockedrange.(bs),), - (undef, bs), - (undef, bs...), - (undef, blockedrange.(bs)), - (undef, blockedrange.(bs)...), - ) - a = T(args...) - @test eltype(a) == elt - @test blocktype(a) == Matrix{elt} - @test blockstype(a) <: SparseMatrixDOK{Matrix{elt}} - @test blocklengths.(axes(a)) == ([2, 3], [3, 4]) - @test iszero(a) - @test iszero(block_stored_length(a)) - @test iszero(stored_length(a)) - end - end - - # BlockSparseVector - bs = ([2, 3],) - for T in ( - BlockSparseArray{elt}, - BlockSparseArray{elt,1}, - BlockSparseVector{elt}, - BlockSparseArray{elt,1,Vector{elt}}, - BlockSparseVector{elt,Vector{elt}}, - ## BlockSparseArray{elt,1,Vector{elt},SparseVectorDOK{Vector{elt}}}, # TODO - ## BlockSparseVector{elt,Vector{elt},SparseVectorDOK{Vector{elt}}}, # TODO - ) - for args in ( - bs, - (bs,), - blockedrange.(bs), - (blockedrange.(bs),), - (undef, bs), - (undef, bs...), - (undef, blockedrange.(bs)), - (undef, blockedrange.(bs)...), - ) - a = T(args...) - @test eltype(a) == elt - @test blocktype(a) == Vector{elt} - @test blockstype(a) <: SparseVectorDOK{Vector{elt}} - @test blocklengths.(axes(a)) == ([2, 3],) - @test iszero(a) - @test iszero(block_stored_length(a)) - @test iszero(stored_length(a)) - end - end - end - @testset "Basics" begin - a = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - @allowscalar @test a == dev( - BlockSparseArray{elt}(blockedrange([2, 3]), blockedrange([2, 3])) - ) - @test eltype(a) === elt - @test axes(a) == (1:5, 1:5) - @test all(aᵢ -> aᵢ isa BlockedOneTo, axes(a)) - @test blocklength.(axes(a)) == (2, 2) - @test blocksize(a) == (2, 2) - @test size(a) == (5, 5) - @test block_stored_length(a) == 0 - @test iszero(a) - @allowscalar @test all(I -> iszero(a[I]), eachindex(a)) - @test_throws DimensionMismatch a[Block(1, 1)] = randn(elt, 2, 3) - - a = BlockSparseArray{elt}([2, 3], [2, 3]) - a[3, 3] = 33 - @test eltype(a) === elt - @test axes(a) == (1:5, 1:5) - @test all(aᵢ -> aᵢ isa BlockedOneTo, axes(a)) - @test blocklength.(axes(a)) == (2, 2) - @test blocksize(a) == (2, 2) - @test size(a) == (5, 5) - @test block_stored_length(a) == 1 - @test !iszero(a) - @test a[3, 3] == 33 - @test all(eachindex(a)) do I - if I == CartesianIndex(3, 3) - a[I] == 33 - else - iszero(a[I]) - end - end - - a[3, 3] = NaN - @test isnan(norm(a)) - - # Empty constructor - for a in (dev(BlockSparseArray{elt}()), dev(BlockSparseArray{elt}(undef))) - @test size(a) == () - @test isone(length(a)) - @test blocksize(a) == () - @test blocksizes(a) == fill(()) - @test iszero(block_stored_length(a)) - @test iszero(@allowscalar(a[])) - @test iszero(@allowscalar(a[CartesianIndex()])) - @test a[Block()] == dev(fill(0)) - @test iszero(@allowscalar(a[Block()][])) - # Broken: - ## @test b[Block()[]] == 2 - for b in ( - (b = copy(a); @allowscalar b[] = 2; b), - (b = copy(a); @allowscalar b[CartesianIndex()] = 2; b), - ) - @test size(b) == () - @test isone(length(b)) - @test blocksize(b) == () - @test blocksizes(b) == fill(()) - @test isone(block_stored_length(b)) - @test @allowscalar(b[]) == 2 - @test @allowscalar(b[CartesianIndex()]) == 2 - @test b[Block()] == dev(fill(2)) - @test @allowscalar(b[Block()][]) == 2 - # Broken: - ## @test b[Block()[]] == 2 - end - end - - @testset "Transpose" begin - a = dev(BlockSparseArray{elt}([2, 2], [3, 3, 1])) - a[Block(1, 1)] = dev(randn(elt, 2, 3)) - a[Block(2, 3)] = dev(randn(elt, 2, 1)) - - at = @inferred transpose(a) - @test at isa Transpose - @test size(at) == reverse(size(a)) - @test blocksize(at) == reverse(blocksize(a)) - @test stored_length(at) == stored_length(a) - @test block_stored_length(at) == block_stored_length(a) - for bind in block_stored_indices(a) - bindt = Block(reverse(Int.(Tuple(bind)))) - @test bindt in block_stored_indices(at) - end - - @test @views(at[Block(1, 1)]) == transpose(a[Block(1, 1)]) - @test @views(at[Block(1, 1)]) isa Transpose - @test @views(at[Block(3, 2)]) == transpose(a[Block(2, 3)]) - # TODO: BlockView == AbstractArray calls scalar code - @test @allowscalar @views(at[Block(1, 2)]) == transpose(a[Block(2, 1)]) - @test @views(at[Block(1, 2)]) isa Transpose - end - - @testset "Adjoint" begin - a = dev(BlockSparseArray{elt}([2, 2], [3, 3, 1])) - a[Block(1, 1)] = dev(randn(elt, 2, 3)) - a[Block(2, 3)] = dev(randn(elt, 2, 1)) - - at = @inferred adjoint(a) - @test at isa Adjoint - @test size(at) == reverse(size(a)) - @test blocksize(at) == reverse(blocksize(a)) - @test stored_length(at) == stored_length(a) - @test block_stored_length(at) == block_stored_length(a) - for bind in block_stored_indices(a) - bindt = Block(reverse(Int.(Tuple(bind)))) - @test bindt in block_stored_indices(at) - end - - @test @views(at[Block(1, 1)]) == adjoint(a[Block(1, 1)]) - @test @views(at[Block(1, 1)]) isa Adjoint - @test @views(at[Block(3, 2)]) == adjoint(a[Block(2, 3)]) - # TODO: BlockView == AbstractArray calls scalar code - @test @allowscalar @views(at[Block(1, 2)]) == adjoint(a[Block(2, 1)]) - @test @views(at[Block(1, 2)]) isa Adjoint - end - end - @testset "Tensor algebra" begin - a = dev(BlockSparseArray{elt}(undef, ([2, 3], [3, 4]))) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = dev(randn(elt, size(a[b]))) - end - @test eltype(a) == elt - @test block_stored_length(a) == 2 - @test stored_length(a) == 2 * 4 + 3 * 3 - - # TODO: Broken on GPU. - if dev ≠ cpu - a = dev(BlockSparseArray{elt}([2, 3], [3, 4])) - @test_broken a[Block(1, 2)] .= 2 - end - - # TODO: Broken on GPU. - a = BlockSparseArray{elt}([2, 3], [3, 4]) - a[Block(1, 2)] .= 2 - @test eltype(a) == elt - @test all(==(2), a[Block(1, 2)]) - @test iszero(a[Block(1, 1)]) - @test iszero(a[Block(2, 1)]) - @test iszero(a[Block(2, 2)]) - @test block_stored_length(a) == 1 - @test stored_length(a) == 2 * 4 - - # TODO: Broken on GPU. - if dev ≠ cpu - a = dev(BlockSparseArray{elt}([2, 3], [3, 4])) - @test_broken a[Block(1, 2)] .= 0 - end - - # TODO: Broken on GPU. - a = BlockSparseArray{elt}([2, 3], [3, 4]) - a[Block(1, 2)] .= 0 - @test eltype(a) == elt - @test iszero(a[Block(1, 1)]) - @test iszero(a[Block(2, 1)]) - @test iszero(a[Block(1, 2)]) - @test iszero(a[Block(2, 2)]) - @test block_stored_length(a) == 1 - @test stored_length(a) == 2 * 4 - - a = dev(BlockSparseArray{elt}(undef, ([2, 3], [3, 4]))) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = dev(randn(elt, size(a[b]))) - end - b = similar(a, complex(elt)) - @test eltype(b) == complex(eltype(a)) - @test iszero(b) - @test block_stored_length(b) == 0 - @test stored_length(b) == 0 - @test size(b) == size(a) - @test blocksize(b) == blocksize(a) - - a = dev(BlockSparseArray{elt}([2, 3], [3, 4])) - b = @view a[[Block(2), Block(1)], [Block(2), Block(1)]] - c = @view b[Block(1, 1)] - @test iszero(a) - @test iszero(stored_length(a)) - @test iszero(b) - @test iszero(stored_length(b)) - # TODO: Broken on GPU. - @test iszero(c) broken = dev ≠ cpu - @test iszero(stored_length(c)) - @allowscalar a[5, 7] = 1 - @test !iszero(a) - @test stored_length(a) == 3 * 4 - @test !iszero(b) - @test stored_length(b) == 3 * 4 - # TODO: Broken on GPU. - @test !iszero(c) broken = dev ≠ cpu - @test stored_length(c) == 3 * 4 - d = @view a[1:4, 1:6] - @test iszero(d) - @test stored_length(d) == 2 * 3 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = copy(a) - b[1, 1] = 11 - @test b[1, 1] == 11 - @test a[1, 1] ≠ 11 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = copy(a) - b .*= 2 - @test b ≈ 2a - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = copy(a) - b ./= 2 - @test b ≈ a / 2 - - a = dev(BlockSparseArray{elt}(undef, ([2, 3], [3, 4]))) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = dev(randn(elt, size(a[b]))) - end - b = 2 * a - @allowscalar @test Array(b) ≈ 2 * Array(a) - @test eltype(b) == elt - @test block_stored_length(b) == 2 - @test stored_length(b) == 2 * 4 + 3 * 3 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = (2 + 3im) * a - @test Array(b) ≈ (2 + 3im) * Array(a) - @test eltype(b) == complex(elt) - @test block_stored_length(b) == 2 - @test stored_length(b) == 2 * 4 + 3 * 3 - - a = dev(BlockSparseArray{elt}(undef, ([2, 3], [3, 4]))) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = dev(randn(elt, size(a[b]))) - end - b = a + a - @allowscalar @test Array(b) ≈ 2 * Array(a) - @test eltype(b) == elt - @test block_stored_length(b) == 2 - @test stored_length(b) == 2 * 4 + 3 * 3 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - x = BlockSparseArray{elt}(undef, ([3, 4], [2, 3])) - @views for b in [Block(1, 2), Block(2, 1)] - x[b] = randn(elt, size(x[b])) - end - b = a .+ a .+ 3 .* PermutedDimsArray(x, (2, 1)) - @test Array(b) ≈ 2 * Array(a) + 3 * permutedims(Array(x), (2, 1)) - @test eltype(b) == elt - @test block_stored_length(b) == 2 - @test stored_length(b) == 2 * 4 + 3 * 3 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = permutedims(a, (2, 1)) - @test Array(b) ≈ permutedims(Array(a), (2, 1)) - @test eltype(b) == elt - @test block_stored_length(b) == 2 - @test stored_length(b) == 2 * 4 + 3 * 3 - - a = dev(BlockSparseArray{elt}([1, 1, 1], [1, 2, 3], [2, 2, 1], [1, 2, 1])) - a[Block(3, 2, 2, 3)] = dev(randn(elt, 1, 2, 2, 1)) - perm = (2, 3, 4, 1) - for b in (PermutedDimsArray(a, perm), permutedims(a, perm)) - @test Array(b) == permutedims(Array(a), perm) - @test issetequal(block_stored_indices(b), [Block(2, 2, 3, 3)]) - @test @allowscalar b[Block(2, 2, 3, 3)] == permutedims(a[Block(3, 2, 2, 3)], perm) - end - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = map(x -> 2x, a) - @test Array(b) ≈ 2 * Array(a) - @test eltype(b) == elt - @test size(b) == size(a) - @test blocksize(b) == (2, 2) - @test block_stored_length(b) == 2 - @test stored_length(b) == 2 * 4 + 3 * 3 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = a[[Block(2), Block(1)], [Block(2), Block(1)]] - @test b[Block(1, 1)] == a[Block(2, 2)] - @test b[Block(1, 2)] == a[Block(2, 1)] - @test b[Block(2, 1)] == a[Block(1, 2)] - @test b[Block(2, 2)] == a[Block(1, 1)] - @test size(b) == size(a) - @test blocksize(b) == (2, 2) - @test stored_length(b) == stored_length(a) - @test block_stored_length(b) == 2 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = a[Block(1):Block(2), Block(1):Block(2)] - @test b == a - @test size(b) == size(a) - @test blocksize(b) == (2, 2) - @test stored_length(b) == stored_length(a) - @test block_stored_length(b) == 2 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = a[Block(1):Block(1), Block(1):Block(2)] - @test b == Array(a)[1:2, 1:end] - @test b[Block(1, 1)] == a[Block(1, 1)] - @test b[Block(1, 2)] == a[Block(1, 2)] - @test size(b) == (2, 7) - @test blocksize(b) == (1, 2) - @test stored_length(b) == stored_length(a[Block(1, 2)]) - @test block_stored_length(b) == 1 - - a = dev(BlockSparseArray{elt}(undef, ([2, 3], [3, 4]))) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = dev(randn(elt, size(a[b]))) - end - for b in (a[2:4, 2:4], @view(a[2:4, 2:4])) - @allowscalar @test b == Array(a)[2:4, 2:4] - @test size(b) == (3, 3) - @test blocksize(b) == (2, 2) - @test stored_length(b) == 1 * 1 + 2 * 2 - @test block_stored_length(b) == 2 - for f in (getindex, view) - # TODO: Broken on GPU. - @allowscalar begin - @test size(f(b, Block(1, 1))) == (1, 2) - @test size(f(b, Block(2, 1))) == (2, 2) - @test size(f(b, Block(1, 2))) == (1, 1) - @test size(f(b, Block(2, 2))) == (2, 1) - @test f(b, Block(1, 1)) == a[Block(1, 1)[2:2, 2:3]] - @test f(b, Block(2, 1)) == a[Block(2, 1)[1:2, 2:3]] - @test f(b, Block(1, 2)) == a[Block(1, 2)[2:2, 1:1]] - @test f(b, Block(2, 2)) == a[Block(2, 2)[1:2, 1:1]] - end - end - end - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = a[Block(2, 1)[1:2, 2:3]] - @test b == Array(a)[3:4, 2:3] - @test size(b) == (2, 2) - @test blocksize(b) == (1, 1) - @test stored_length(b) == 2 * 2 - @test block_stored_length(b) == 1 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = PermutedDimsArray(a, (2, 1)) - @test block_stored_length(b) == 2 - @test Array(b) == permutedims(Array(a), (2, 1)) - c = 2 * b - @test block_stored_length(c) == 2 - @test Array(c) == 2 * permutedims(Array(a), (2, 1)) - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = a' - @test block_stored_length(b) == 2 - @test Array(b) == Array(a)' - c = 2 * b - @test block_stored_length(c) == 2 - @test Array(c) == 2 * Array(a)' - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = transpose(a) - @test block_stored_length(b) == 2 - @test Array(b) == transpose(Array(a)) - c = 2 * b - @test block_stored_length(c) == 2 - @test Array(c) == 2 * transpose(Array(a)) - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = a[Block(1), Block(1):Block(2)] - @test size(b) == (2, 7) - @test blocksize(b) == (1, 2) - @test b[Block(1, 1)] == a[Block(1, 1)] - @test b[Block(1, 2)] == a[Block(1, 2)] - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = copy(a) - x = randn(elt, size(@view(a[Block(2, 2)]))) - b[Block(2), Block(2)] = x - @test b[Block(2, 2)] == x - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = copy(a) - b[Block(1, 1)] .= 1 - @test b[Block(1, 1)] == trues(blocksizes(b)[1, 1]) - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - b = @view a[Block(2, 2)] - @test size(b) == (3, 4) - for i in parentindices(b) - @test i isa Base.OneTo{Int} - end - @test parentindices(b)[1] == 1:3 - @test parentindices(b)[2] == 1:4 - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - b = @view a[Block(2, 2)[1:2, 2:2]] - @test size(b) == (2, 1) - for i in parentindices(b) - @test i isa UnitRange{Int} - end - @test parentindices(b)[1] == 1:2 - @test parentindices(b)[2] == 2:2 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - x = randn(elt, 1, 2) - @view(a[Block(2, 2)])[1:1, 1:2] = x - @test a[Block(2, 2)][1:1, 1:2] == x - @test @view(a[Block(2, 2)])[1:1, 1:2] == x - @test a[3:3, 4:5] == x - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - x = randn(elt, 1, 2) - @views a[Block(2, 2)][1:1, 1:2] = x - @test a[Block(2, 2)][1:1, 1:2] == x - @test @view(a[Block(2, 2)])[1:1, 1:2] == x - @test a[3:3, 4:5] == x - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - b = @views a[Block(2, 2)][1:2, 2:3] - @test b isa SubArray{<:Any,<:Any,<:BlockView} - for i in parentindices(b) - @test i isa UnitRange{Int} - end - x = randn(elt, 2, 2) - b .= x - @test a[Block(2, 2)[1:2, 2:3]] == x - @test a[Block(2, 2)[1:2, 2:3]] == b - @test block_stored_length(a) == 1 - - a = BlockSparseArray{elt}([2, 3], [2, 3]) - @views for b in [Block(1, 1), Block(2, 2)] - a[b] = randn(elt, size(a[b])) - end - for I in (Block.(1:2), [Block(1), Block(2)]) - b = @view a[I, I] - for I in CartesianIndices(a) - @test b[I] == a[I] - end - for block in BlockRange(a) - @test b[block] == a[block] - end - end - - a = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - @views for b in [Block(1, 1), Block(2, 2)] - # TODO: Use `blocksizes(a)[Int.(Tuple(b))...]` once available. - a[b] = dev(randn(elt, size(a[b]))) - end - for I in ([Block(2), Block(1)],) - b = @view a[I, I] - @test b[Block(1, 1)] == a[Block(2, 2)] - @test b[Block(2, 1)] == a[Block(1, 2)] - @test b[Block(1, 2)] == a[Block(2, 1)] - @test b[Block(2, 2)] == a[Block(1, 1)] - @allowscalar begin - @test b[1, 1] == a[3, 3] - @test b[4, 4] == a[1, 1] - b[4, 4] = 44 - @test b[4, 4] == 44 - end - end - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - b = a[Block(2):Block(2), Block(1):Block(2)] - @test block_stored_length(b) == 1 - @test b == Array(a)[3:5, 1:end] - - a = BlockSparseArray{elt}(undef, ([2, 3, 4], [2, 3, 4])) - # TODO: Define `block_diagindices`. - @views for b in [Block(1, 1), Block(2, 2), Block(3, 3)] - a[b] = randn(elt, size(a[b])) - end - for (I1, I2) in ( - (mortar([Block(2)[2:3], Block(3)[1:3]]), mortar([Block(2)[2:3], Block(3)[2:3]])), - ([Block(2)[2:3], Block(3)[1:3]], [Block(2)[2:3], Block(3)[2:3]]), - ) - for b in (a[I1, I2], @view(a[I1, I2])) - # TODO: Rename `block_stored_length`. - @test block_stored_length(b) == 2 - @test b[Block(1, 1)] == a[Block(2, 2)[2:3, 2:3]] - @test b[Block(2, 2)] == a[Block(3, 3)[1:3, 2:3]] - end - end - - a = dev(BlockSparseArray{elt}(undef, ([3, 3], [3, 3]))) - # TODO: Define `block_diagindices`. - @views for b in [Block(1, 1), Block(2, 2)] - a[b] = dev(randn(elt, size(a[b]))) - end - I = mortar([Block(1)[1:2], Block(2)[1:2]]) - b = a[:, I] - @test b[Block(1, 1)] == a[Block(1, 1)][:, 1:2] - @test b[Block(2, 1)] == a[Block(2, 1)][:, 1:2] - @test b[Block(1, 2)] == a[Block(1, 2)][:, 1:2] - @test b[Block(2, 2)] == a[Block(2, 2)][:, 1:2] - @test blocklengths.(axes(b)) == ([3, 3], [2, 2]) - # TODO: Rename `block_stored_length`. - @test blocksize(b) == (2, 2) - @test block_stored_length(b) == 2 - - a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4])) - @views for b in [Block(1, 2), Block(2, 1)] - a[b] = randn(elt, size(a[b])) - end - @test isassigned(a, 1, 1) - @test isassigned(a, 1, 1, 1) - @test !isassigned(a, 1, 1, 2) - @test isassigned(a, 5, 7) - @test isassigned(a, 5, 7, 1) - @test !isassigned(a, 5, 7, 2) - @test !isassigned(a, 0, 1) - @test !isassigned(a, 5, 8) - @test isassigned(a, Block(1), Block(1)) - @test isassigned(a, Block(2), Block(2)) - @test !isassigned(a, Block(1), Block(0)) - @test !isassigned(a, Block(3), Block(2)) - @test isassigned(a, Block(1, 1)) - @test isassigned(a, Block(2, 2)) - @test !isassigned(a, Block(1, 0)) - @test !isassigned(a, Block(3, 2)) - @test isassigned(a, Block(1)[1], Block(1)[1]) - @test isassigned(a, Block(2)[3], Block(2)[4]) - @test !isassigned(a, Block(1)[0], Block(1)[1]) - @test !isassigned(a, Block(2)[3], Block(2)[5]) - @test !isassigned(a, Block(1)[1], Block(0)[1]) - @test !isassigned(a, Block(3)[3], Block(2)[4]) - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - @test iszero(a) - @test iszero(block_stored_length(a)) - fill!(a, 0) - @test iszero(a) - @test iszero(block_stored_length(a)) - fill!(a, 2) - @test !iszero(a) - @test all(==(2), a) - @test block_stored_length(a) == 4 - fill!(a, 0) - @test iszero(a) - @test iszero(block_stored_length(a)) - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - @test iszero(a) - @test iszero(block_stored_length(a)) - a .= 0 - @test iszero(a) - @test iszero(block_stored_length(a)) - a .= 2 - @test !iszero(a) - @test all(==(2), a) - @test block_stored_length(a) == 4 - a .= 0 - @test iszero(a) - @test iszero(block_stored_length(a)) - - # TODO: Broken on GPU. - a = BlockSparseArray{elt}([2, 3], [3, 4]) - for I in (Block.(1:2), [Block(1), Block(2)]) - b = @view a[I, I] - x = randn(elt, 3, 4) - b[Block(2, 2)] = x - # These outputs a block of zeros, - # for some reason the block - # is not getting set. - # I think the issue is that: - # ```julia - # @view(@view(a[I, I]))[Block(1, 1)] - # ``` - # creates a doubly-wrapped SubArray - # instead of flattening down to a - # single SubArray wrapper. - @test a[Block(2, 2)] == x - @test b[Block(2, 2)] == x - end - - function f1() - a = BlockSparseArray{elt}([2, 3], [3, 4]) - b = @view a[[Block(2), Block(1)], [Block(2), Block(1)]] - x = randn(elt, 3, 4) - b[Block(1, 1)] .= x - return (; a, b, x) - end - function f2() - a = BlockSparseArray{elt}([2, 3], [3, 4]) - b = @view a[[Block(2), Block(1)], [Block(2), Block(1)]] - x = randn(elt, 3, 4) - b[Block(1, 1)] = x - return (; a, b, x) - end - for abx in (f1(), f2()) - @compat (; a, b, x) = abx - @test b isa SubArray{<:Any,<:Any,<:BlockSparseArray} - @test block_stored_length(b) == 1 - @test b[Block(1, 1)] == x - @test @view(b[Block(1, 1)]) isa Matrix{elt} - for blck in [Block(2, 1), Block(1, 2), Block(2, 2)] - @test iszero(b[blck]) - end - @test block_stored_length(a) == 1 - @test a[Block(2, 2)] == x - for blck in [Block(1, 1), Block(2, 1), Block(1, 2)] - @test iszero(a[blck]) - end - @test_throws DimensionMismatch b[Block(1, 1)] .= randn(2, 3) - end - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - b = @views a[[Block(2), Block(1)], [Block(2), Block(1)]][Block(2, 1)] - @test iszero(b) - @test size(b) == (2, 4) - x = randn(elt, 2, 4) - b .= x - @test b == x - @test a[Block(1, 2)] == x - @test block_stored_length(a) == 1 - - a = BlockSparseArray{elt}([4, 3, 2], [4, 3, 2]) - @views for B in [Block(1, 1), Block(2, 2), Block(3, 3)] - a[B] = randn(elt, size(a[B])) - end - b = @view a[[Block(3), Block(2), Block(1)], [Block(3), Block(2), Block(1)]] - @test b isa SubArray{<:Any,<:Any,<:BlockSparseArray} - c = @view b[4:8, 4:8] - @test c isa SubArray{<:Any,<:Any,<:BlockSparseArray} - @test size(c) == (5, 5) - @test block_stored_length(c) == 2 - @test blocksize(c) == (2, 2) - @test blocklengths.(axes(c)) == ([2, 3], [2, 3]) - @test size(c[Block(1, 1)]) == (2, 2) - @test c[Block(1, 1)] == a[Block(2, 2)[2:3, 2:3]] - @test size(c[Block(2, 2)]) == (3, 3) - @test c[Block(2, 2)] == a[Block(1, 1)[1:3, 1:3]] - @test size(c[Block(2, 1)]) == (3, 2) - @test iszero(c[Block(2, 1)]) - @test size(c[Block(1, 2)]) == (2, 3) - @test iszero(c[Block(1, 2)]) - - x = randn(elt, 3, 3) - c[Block(2, 2)] = x - @test c[Block(2, 2)] == x - @test a[Block(1, 1)[1:3, 1:3]] == x - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - b = @view a[[Block(2), Block(1)], [Block(2), Block(1)]] - for index in parentindices(@view(b[Block(1, 1)])) - @test index isa Base.OneTo{Int} - end - - a = BlockSparseArray{elt}([2, 3], [3, 4]) - a[Block(1, 1)] = randn(elt, 2, 3) - b = @view a[Block(1, 1)[1:2, 1:1]] - @test b isa SubArray{elt,2,Matrix{elt}} - for i in parentindices(b) - @test i isa UnitRange{Int} - end - - a = BlockSparseArray{elt}([2, 2, 2, 2], [2, 2, 2, 2]) - @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] - a[I] = randn(elt, size(a[I])) - end - for I in (blockedrange([4, 4]), BlockedVector(Block.(1:4), [2, 2])) - b = @view a[I, I] - @test copy(b) == a - @test blocksize(b) == (2, 2) - @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) - # TODO: Fix in Julia 1.11 (https://github.com/ITensor/ITensors.jl/pull/1539). - if VERSION < v"1.11-" - @test b[Block(1, 1)] == a[Block.(1:2), Block.(1:2)] - @test b[Block(2, 1)] == a[Block.(3:4), Block.(1:2)] - @test b[Block(1, 2)] == a[Block.(1:2), Block.(3:4)] - @test b[Block(2, 2)] == a[Block.(3:4), Block.(3:4)] - end - c = @view b[Block(2, 2)] - @test blocksize(c) == (1, 1) - @test c == a[Block.(3:4), Block.(3:4)] - end - - a = BlockSparseArray{elt}([2, 3], [2, 3]) - a[Block(1, 1)] = randn(elt, 2, 2) - a[Block(2, 2)] = randn(elt, 3, 3) - for I in (mortar([Block(1)[2:2], Block(2)[2:3]]), [Block(1)[2:2], Block(2)[2:3]]) - b = @view a[:, I] - @test b == Array(a)[:, [2, 4, 5]] - end - - # Merge and permute blocks. - a = BlockSparseArray{elt}([2, 2, 2, 2], [2, 2, 2, 2]) - @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] - a[I] = randn(elt, size(a[I])) - end - for I in ( - BlockVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), - BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), - ) - b = @view a[I, I] - J = [Block(4), Block(3), Block(2), Block(1)] - @test b == a[J, J] - @test copy(b) == a[J, J] - @test blocksize(b) == (2, 2) - @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) - @test b[Block(1, 1)] == Array(a)[[7, 8, 5, 6], [7, 8, 5, 6]] - c = @views b[Block(1, 1)][2:3, 2:3] - @test c == Array(a)[[8, 5], [8, 5]] - @test copy(c) == Array(a)[[8, 5], [8, 5]] - c = @view b[Block(1, 1)[2:3, 2:3]] - @test c == Array(a)[[8, 5], [8, 5]] - @test copy(c) == Array(a)[[8, 5], [8, 5]] - end - - # TODO: Add more tests of this, it may - # only be working accidentally. - a = BlockSparseArray{elt}([2, 3], [2, 3]) - a[Block(1, 1)] = randn(elt, 2, 2) - a[Block(2, 2)] = randn(elt, 3, 3) - @test a[2:4, 4] == Array(a)[2:4, 4] - # TODO: Fix this. - @test_broken a[4, 2:4] == Array(a)[4, 2:4] - end - @testset "view!" begin - for blk in ((Block(2, 2),), (Block(2), Block(2))) - a = BlockSparseArray{elt}([2, 3], [2, 3]) - b = view!(a, blk...) - x = randn(elt, 3, 3) - b .= x - @test b == x - @test a[blk...] == x - @test @view(a[blk...]) == x - @test view!(a, blk...) == x - @test @view!(a[blk...]) == x - end - for blk in ((Block(2, 2),), (Block(2), Block(2))) - a = BlockSparseArray{elt}([2, 3], [2, 3]) - b = @view! a[blk...] - x = randn(elt, 3, 3) - b .= x - @test b == x - @test a[blk...] == x - @test @view(a[blk...]) == x - @test view!(a, blk...) == x - @test @view!(a[blk...]) == x - end - for blk in ((Block(2, 2)[2:3, 1:2],), (Block(2)[2:3], Block(2)[1:2])) - a = BlockSparseArray{elt}([2, 3], [2, 3]) - b = view!(a, blk...) - x = randn(elt, 2, 2) - b .= x - @test b == x - @test a[blk...] == x - @test @view(a[blk...]) == x - @test view!(a, blk...) == x - @test @view!(a[blk...]) == x - end - for blk in ((Block(2, 2)[2:3, 1:2],), (Block(2)[2:3], Block(2)[1:2])) - a = BlockSparseArray{elt}([2, 3], [2, 3]) - b = @view! a[blk...] - x = randn(elt, 2, 2) - b .= x - @test b == x - @test a[blk...] == x - @test @view(a[blk...]) == x - @test view!(a, blk...) == x - @test @view!(a[blk...]) == x - end - end - @testset "LinearAlgebra" begin - a1 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a1[Block(1, 1)] = dev(randn(elt, size(@view(a1[Block(1, 1)])))) - a2 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a2[Block(1, 1)] = dev(randn(elt, size(@view(a1[Block(1, 1)])))) - a_dest = a1 * a2 - @allowscalar @test Array(a_dest) ≈ Array(a1) * Array(a2) - @test a_dest isa BlockSparseArray{elt} - @test block_stored_length(a_dest) == 1 - end - @testset "Matrix multiplication" begin - a1 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a1[Block(1, 2)] = dev(randn(elt, size(@view(a1[Block(1, 2)])))) - a1[Block(2, 1)] = dev(randn(elt, size(@view(a1[Block(2, 1)])))) - a2 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a2[Block(1, 2)] = dev(randn(elt, size(@view(a2[Block(1, 2)])))) - a2[Block(2, 1)] = dev(randn(elt, size(@view(a2[Block(2, 1)])))) - for (a1′, a2′) in ((a1, a2), (a1', a2), (a1, a2'), (a1', a2')) - a_dest = a1′ * a2′ - @allowscalar @test Array(a_dest) ≈ Array(a1′) * Array(a2′) - end - end - @testset "Dot product" begin - a1 = dev(BlockSparseArray{elt}([2, 3, 4])) - a1[Block(1)] = dev(randn(elt, size(@view(a1[Block(1)])))) - a1[Block(3)] = dev(randn(elt, size(@view(a1[Block(3)])))) - a2 = dev(BlockSparseArray{elt}([2, 3, 4])) - a2[Block(2)] = dev(randn(elt, size(@view(a1[Block(2)])))) - a2[Block(3)] = dev(randn(elt, size(@view(a1[Block(3)])))) - @test a1' * a2 ≈ Array(a1)' * Array(a2) - @test dot(a1, a2) ≈ a1' * a2 - end - @testset "cat" begin - a1 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a1[Block(2, 1)] = dev(randn(elt, size(@view(a1[Block(2, 1)])))) - a2 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a2[Block(1, 2)] = dev(randn(elt, size(@view(a2[Block(1, 2)])))) - - a_dest = cat(a1, a2; dims=1) - @test block_stored_length(a_dest) == 2 - @test blocklengths.(axes(a_dest)) == ([2, 3, 2, 3], [2, 3]) - @test issetequal(block_stored_indices(a_dest), [Block(2, 1), Block(3, 2)]) - @test a_dest[Block(2, 1)] == a1[Block(2, 1)] - @test a_dest[Block(3, 2)] == a2[Block(1, 2)] - - a_dest = cat(a1, a2; dims=2) - @test block_stored_length(a_dest) == 2 - @test blocklengths.(axes(a_dest)) == ([2, 3], [2, 3, 2, 3]) - @test issetequal(block_stored_indices(a_dest), [Block(2, 1), Block(1, 4)]) - @test a_dest[Block(2, 1)] == a1[Block(2, 1)] - @test a_dest[Block(1, 4)] == a2[Block(1, 2)] - - a_dest = cat(a1, a2; dims=(1, 2)) - @test block_stored_length(a_dest) == 2 - @test blocklengths.(axes(a_dest)) == ([2, 3, 2, 3], [2, 3, 2, 3]) - @test issetequal(block_stored_indices(a_dest), [Block(2, 1), Block(3, 4)]) - @test a_dest[Block(2, 1)] == a1[Block(2, 1)] - @test a_dest[Block(3, 4)] == a2[Block(1, 2)] - end - @testset "TensorAlgebra" begin - a1 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a1[Block(1, 1)] = dev(randn(elt, size(@view(a1[Block(1, 1)])))) - a2 = dev(BlockSparseArray{elt}([2, 3], [2, 3])) - a2[Block(1, 1)] = dev(randn(elt, size(@view(a1[Block(1, 1)])))) - # TODO: Make this work, requires customization of `TensorAlgebra.fusedims` and - # `TensorAlgebra.splitdims` in terms of `BlockSparseArrays.block_reshape`, - # and customization of `TensorAlgebra.:⊗` in terms of `GradedAxes.tensor_product`. - a_dest, dimnames_dest = contract(a1, (1, -1), a2, (-1, 2)) - @allowscalar begin - a_dest_dense, dimnames_dest_dense = contract(Array(a1), (1, -1), Array(a2), (-1, 2)) - @test a_dest ≈ a_dest_dense - end - end - @testset "block_reshape" begin - a = dev(BlockSparseArray{elt}(undef, ([3, 4], [2, 3]))) - a[Block(1, 2)] = dev(randn(elt, size(@view(a[Block(1, 2)])))) - a[Block(2, 1)] = dev(randn(elt, size(@view(a[Block(2, 1)])))) - b = block_reshape(a, [6, 8, 9, 12]) - @test reshape(a[Block(1, 2)], 9) == b[Block(3)] - @test reshape(a[Block(2, 1)], 8) == b[Block(2)] - @test block_stored_length(b) == 2 - @test stored_length(b) == 17 - end -end -end diff --git a/NDTensors/src/lib/BroadcastMapConversion/.JuliaFormatter.toml b/NDTensors/src/lib/BroadcastMapConversion/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/BroadcastMapConversion/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/BroadcastMapConversion/src/BroadcastMapConversion.jl b/NDTensors/src/lib/BroadcastMapConversion/src/BroadcastMapConversion.jl deleted file mode 100644 index 6edf0ae2f7..0000000000 --- a/NDTensors/src/lib/BroadcastMapConversion/src/BroadcastMapConversion.jl +++ /dev/null @@ -1,48 +0,0 @@ -module BroadcastMapConversion -# Convert broadcast call to map call by capturing array arguments -# with `map_args` and creating a map function with `map_function`. -# Logic from https://github.com/Jutho/Strided.jl/blob/v2.0.4/src/broadcast.jl. - -using Base.Broadcast: Broadcasted - -const WrappedScalarArgs = Union{AbstractArray{<:Any,0},Ref{<:Any}} - -function map_args(bc::Broadcasted, rest...) - return (map_args(bc.args...)..., map_args(rest...)...) -end -map_args(a::AbstractArray, rest...) = (a, map_args(rest...)...) -map_args(a, rest...) = map_args(rest...) -map_args() = () - -struct MapFunction{F,Args<:Tuple} - f::F - args::Args -end -struct Arg end - -# construct MapFunction -function map_function(bc::Broadcasted) - args = map_function_tuple(bc.args) - return MapFunction(bc.f, args) -end -map_function_tuple(t::Tuple{}) = t -map_function_tuple(t::Tuple) = (map_function(t[1]), map_function_tuple(Base.tail(t))...) -map_function(a::WrappedScalarArgs) = a[] -map_function(a::AbstractArray) = Arg() -map_function(a) = a - -# Evaluate MapFunction -(f::MapFunction)(args...) = apply(f, args)[1] -function apply(f::MapFunction, args) - args, newargs = apply_tuple(f.args, args) - return f.f(args...), newargs -end -apply(a::Arg, args::Tuple) = args[1], Base.tail(args) -apply(a, args) = a, args -apply_tuple(t::Tuple{}, args) = t, args -function apply_tuple(t::Tuple, args) - t1, newargs1 = apply(t[1], args) - ttail, newargs = apply_tuple(Base.tail(t), newargs1) - return (t1, ttail...), newargs -end -end diff --git a/NDTensors/src/lib/BroadcastMapConversion/test/runtests.jl b/NDTensors/src/lib/BroadcastMapConversion/test/runtests.jl deleted file mode 100644 index 92e5d6ae41..0000000000 --- a/NDTensors/src/lib/BroadcastMapConversion/test/runtests.jl +++ /dev/null @@ -1,14 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using NDTensors.BroadcastMapConversion: map_function, map_args -@testset "BroadcastMapConversion" begin - using Base.Broadcast: Broadcasted - c = 2.2 - a = randn(2, 3) - b = randn(2, 3) - bc = Broadcasted(*, (c, a)) - @test copy(bc) ≈ c * a ≈ map(map_function(bc), map_args(bc)...) - bc = Broadcasted(+, (a, b)) - @test copy(bc) ≈ a + b ≈ map(map_function(bc), map_args(bc)...) -end -end diff --git a/NDTensors/src/lib/DiagonalArrays/.JuliaFormatter.toml b/NDTensors/src/lib/DiagonalArrays/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/DiagonalArrays/README.md b/NDTensors/src/lib/DiagonalArrays/README.md deleted file mode 100644 index 1043d095f7..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# DiagonalArrays.jl - -A Julia `DiagonalArray` type. - -````julia -using NDTensors.DiagonalArrays: - DiagonalArray, DiagonalMatrix, DiagIndex, DiagIndices, diaglength, isdiagindex -using Test - -function main() - d = DiagonalMatrix([1.0, 2.0, 3.0]) - @test eltype(d) == Float64 - @test diaglength(d) == 3 - @test size(d) == (3, 3) - @test d[1, 1] == 1 - @test d[2, 2] == 2 - @test d[3, 3] == 3 - @test d[1, 2] == 0 - - d = DiagonalArray([1.0, 2.0, 3.0], 3, 4, 5) - @test eltype(d) == Float64 - @test diaglength(d) == 3 - @test d[1, 1, 1] == 1 - @test d[2, 2, 2] == 2 - @test d[3, 3, 3] == 3 - @test d[1, 2, 1] == 0 - - d[2, 2, 2] = 22 - @test d[2, 2, 2] == 22 - - d_r = reshape(d, 3, 20) - @test size(d_r) == (3, 20) - @test all(I -> d_r[I] == d[I], LinearIndices(d)) - - @test length(d[DiagIndices(:)]) == 3 - @test Array(d) == d - @test d[DiagIndex(2)] == d[2, 2, 2] - - d[DiagIndex(2)] = 222 - @test d[2, 2, 2] == 222 - - a = randn(3, 4, 5) - new_diag = randn(3) - a[DiagIndices(:)] = new_diag - d[DiagIndices(:)] = a[DiagIndices(:)] - - @test a[DiagIndices(:)] == new_diag - @test d[DiagIndices(:)] == new_diag - - permuted_d = permutedims(d, (3, 2, 1)) - @test permuted_d isa DiagonalArray - @test permuted_d[DiagIndices(:)] == d[DiagIndices(:)] - @test size(d) == (3, 4, 5) - @test size(permuted_d) == (5, 4, 3) - for I in eachindex(d) - if !isdiagindex(d, I) - @test iszero(d[I]) - else - @test !iszero(d[I]) - end - end - - mapped_d = map(x -> 2x, d) - @test mapped_d isa DiagonalArray - @test mapped_d == map(x -> 2x, Array(d)) - - return nothing -end - -main() -```` - -You can generate this README with: -```julia -using Literate -using NDTensors.DiagonalArrays -dir = joinpath(pkgdir(DiagonalArrays), "src", "lib", "DiagonalArrays") -Literate.markdown(joinpath(dir, "examples", "README.jl"), dir; flavor=Literate.CommonMarkFlavor()) -``` - ---- - -*This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).* - diff --git a/NDTensors/src/lib/DiagonalArrays/examples/Project.toml b/NDTensors/src/lib/DiagonalArrays/examples/Project.toml deleted file mode 100644 index b46e6ac7ac..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/examples/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/DiagonalArrays/examples/README.jl b/NDTensors/src/lib/DiagonalArrays/examples/README.jl deleted file mode 100644 index 074adec5c9..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/examples/README.jl +++ /dev/null @@ -1,79 +0,0 @@ -# # DiagonalArrays.jl -# -# A Julia `DiagonalArray` type. - -using NDTensors.DiagonalArrays: - DiagonalArray, DiagonalMatrix, DiagIndex, DiagIndices, diaglength, isdiagindex -using Test - -function main() - d = DiagonalMatrix([1.0, 2.0, 3.0]) - @test eltype(d) == Float64 - @test diaglength(d) == 3 - @test size(d) == (3, 3) - @test d[1, 1] == 1 - @test d[2, 2] == 2 - @test d[3, 3] == 3 - @test d[1, 2] == 0 - - d = DiagonalArray([1.0, 2.0, 3.0], 3, 4, 5) - @test eltype(d) == Float64 - @test diaglength(d) == 3 - @test d[1, 1, 1] == 1 - @test d[2, 2, 2] == 2 - @test d[3, 3, 3] == 3 - @test d[1, 2, 1] == 0 - - d[2, 2, 2] = 22 - @test d[2, 2, 2] == 22 - - d_r = reshape(d, 3, 20) - @test size(d_r) == (3, 20) - @test all(I -> d_r[I] == d[I], LinearIndices(d)) - - @test length(d[DiagIndices(:)]) == 3 - @test Array(d) == d - @test d[DiagIndex(2)] == d[2, 2, 2] - - d[DiagIndex(2)] = 222 - @test d[2, 2, 2] == 222 - - a = randn(3, 4, 5) - new_diag = randn(3) - a[DiagIndices(:)] = new_diag - d[DiagIndices(:)] = a[DiagIndices(:)] - - @test a[DiagIndices(:)] == new_diag - @test d[DiagIndices(:)] == new_diag - - permuted_d = permutedims(d, (3, 2, 1)) - @test permuted_d isa DiagonalArray - @test permuted_d[DiagIndices(:)] == d[DiagIndices(:)] - @test size(d) == (3, 4, 5) - @test size(permuted_d) == (5, 4, 3) - for I in eachindex(d) - if !isdiagindex(d, I) - @test iszero(d[I]) - else - @test !iszero(d[I]) - end - end - - mapped_d = map(x -> 2x, d) - @test mapped_d isa DiagonalArray - @test mapped_d == map(x -> 2x, Array(d)) - - return nothing -end - -main() - -#= -You can generate this README with: -```julia -using Literate -using NDTensors.DiagonalArrays -dir = joinpath(pkgdir(DiagonalArrays), "src", "lib", "DiagonalArrays") -Literate.markdown(joinpath(dir, "examples", "README.jl"), dir; flavor=Literate.CommonMarkFlavor()) -``` -=# diff --git a/NDTensors/src/lib/DiagonalArrays/src/DiagonalArrays.jl b/NDTensors/src/lib/DiagonalArrays/src/DiagonalArrays.jl deleted file mode 100644 index 94566ebd88..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/DiagonalArrays.jl +++ /dev/null @@ -1,14 +0,0 @@ -module DiagonalArrays -include("diaginterface/defaults.jl") -include("diaginterface/diaginterface.jl") -include("diaginterface/diagindex.jl") -include("diaginterface/diagindices.jl") -include("abstractdiagonalarray/abstractdiagonalarray.jl") -include("abstractdiagonalarray/sparsearrayinterface.jl") -include("abstractdiagonalarray/diagonalarraydiaginterface.jl") -include("abstractdiagonalarray/arraylayouts.jl") -include("diagonalarray/diagonalarray.jl") -include("diagonalarray/diagonalmatrix.jl") -include("diagonalarray/diagonalvector.jl") -include("diagonalarray/arraylayouts.jl") -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/abstractdiagonalarray.jl b/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/abstractdiagonalarray.jl deleted file mode 100644 index 8180a61472..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/abstractdiagonalarray.jl +++ /dev/null @@ -1,3 +0,0 @@ -using ..SparseArraysBase: AbstractSparseArray - -abstract type AbstractDiagonalArray{T,N} <: AbstractSparseArray{T,N} end diff --git a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/arraylayouts.jl b/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/arraylayouts.jl deleted file mode 100644 index d8f0b41dbe..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/arraylayouts.jl +++ /dev/null @@ -1,7 +0,0 @@ -using ArrayLayouts: ArrayLayouts -using ..SparseArraysBase: AbstractSparseLayout - -abstract type AbstractDiagonalLayout <: AbstractSparseLayout end -struct DiagonalLayout <: AbstractDiagonalLayout end - -ArrayLayouts.MemoryLayout(::Type{<:AbstractDiagonalArray}) = DiagonalLayout() diff --git a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/diagonalarraydiaginterface.jl b/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/diagonalarraydiaginterface.jl deleted file mode 100644 index bcc2c81cbd..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/diagonalarraydiaginterface.jl +++ /dev/null @@ -1,23 +0,0 @@ -using ..SparseArraysBase: SparseArraysBase, StorageIndex, StorageIndices - -SparseArraysBase.StorageIndex(i::DiagIndex) = StorageIndex(index(i)) - -function Base.getindex(a::AbstractDiagonalArray, i::DiagIndex) - return a[StorageIndex(i)] -end - -function Base.setindex!(a::AbstractDiagonalArray, value, i::DiagIndex) - a[StorageIndex(i)] = value - return a -end - -SparseArraysBase.StorageIndices(i::DiagIndices) = StorageIndices(indices(i)) - -function Base.getindex(a::AbstractDiagonalArray, i::DiagIndices) - return a[StorageIndices(i)] -end - -function Base.setindex!(a::AbstractDiagonalArray, value, i::DiagIndices) - a[StorageIndices(i)] = value - return a -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/sparsearrayinterface.jl b/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/sparsearrayinterface.jl deleted file mode 100644 index 98762bbbca..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/abstractdiagonalarray/sparsearrayinterface.jl +++ /dev/null @@ -1,22 +0,0 @@ -using Compat: Returns, allequal -using ..SparseArraysBase: SparseArraysBase - -# `SparseArraysBase` interface -function SparseArraysBase.index_to_storage_index( - a::AbstractDiagonalArray{<:Any,N}, I::CartesianIndex{N} -) where {N} - !allequal(Tuple(I)) && return nothing - return first(Tuple(I)) -end - -function SparseArraysBase.storage_index_to_index(a::AbstractDiagonalArray, I) - return CartesianIndex(ntuple(Returns(I), ndims(a))) -end - -## # 1-dimensional case can be `AbstractDiagonalArray`. -## function SparseArraysBase.sparse_similar( -## a::AbstractDiagonalArray, elt::Type, dims::Tuple{Int} -## ) -## # TODO: Handle preserving zero element function. -## return similar(a, elt, dims) -## end diff --git a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/defaults.jl b/NDTensors/src/lib/DiagonalArrays/src/diaginterface/defaults.jl deleted file mode 100644 index 39e9395eb6..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/defaults.jl +++ /dev/null @@ -1,3 +0,0 @@ -using Compat: Returns - -default_size(diag::AbstractVector, n) = ntuple(Returns(length(diag)), n) diff --git a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindex.jl b/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindex.jl deleted file mode 100644 index e177e80697..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindex.jl +++ /dev/null @@ -1,14 +0,0 @@ -# Represents a linear offset along the diagonal -struct DiagIndex{I} - i::I -end -index(i::DiagIndex) = i.i - -function Base.getindex(a::AbstractArray, i::DiagIndex) - return getdiagindex(a, index(i)) -end - -function Base.setindex!(a::AbstractArray, value, i::DiagIndex) - setdiagindex!(a, value, index(i)) - return a -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindices.jl b/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindices.jl deleted file mode 100644 index 08590d148e..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diagindices.jl +++ /dev/null @@ -1,14 +0,0 @@ -# Represents a set of linear offsets along the diagonal -struct DiagIndices{I} - i::I -end -indices(i::DiagIndices) = i.i - -function Base.getindex(a::AbstractArray, I::DiagIndices) - return getdiagindices(a, indices(I)) -end - -function Base.setindex!(a::AbstractArray, value, i::DiagIndices) - setdiagindices!(a, value, indices(i)) - return a -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diaginterface.jl b/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diaginterface.jl deleted file mode 100644 index 19092010a4..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diaginterface/diaginterface.jl +++ /dev/null @@ -1,57 +0,0 @@ -using Compat: allequal - -diaglength(a::AbstractArray{<:Any,0}) = 1 - -function diaglength(a::AbstractArray) - return minimum(size(a)) -end - -function isdiagindex(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N} - @boundscheck checkbounds(a, I) - return allequal(Tuple(I)) -end - -function diagstride(a::AbstractArray) - s = 1 - p = 1 - for i in 1:(ndims(a) - 1) - p *= size(a, i) - s += p - end - return s -end - -function diagindices(a::AbstractArray) - maxdiag = LinearIndices(a)[CartesianIndex(ntuple(Returns(diaglength(a)), ndims(a)))] - return 1:diagstride(a):maxdiag -end - -function diagindices(a::AbstractArray{<:Any,0}) - return Base.OneTo(1) -end - -function diagview(a::AbstractArray) - return @view a[diagindices(a)] -end - -function getdiagindex(a::AbstractArray, i::Integer) - return diagview(a)[i] -end - -function setdiagindex!(a::AbstractArray, v, i::Integer) - diagview(a)[i] = v - return a -end - -function getdiagindices(a::AbstractArray, I) - return @view diagview(a)[I] -end - -function getdiagindices(a::AbstractArray, I::Colon) - return diagview(a) -end - -function setdiagindices!(a::AbstractArray, v, i::Colon) - diagview(a) .= v - return a -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/arraylayouts.jl b/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/arraylayouts.jl deleted file mode 100644 index 7f365db0f2..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/arraylayouts.jl +++ /dev/null @@ -1,11 +0,0 @@ -using ArrayLayouts: MulAdd - -# Default sparse array type for `AbstractDiagonalLayout`. -default_diagonalarraytype(elt::Type) = DiagonalArray{elt} - -# TODO: Preserve GPU memory! Implement `CuSparseArrayLayout`, `MtlSparseLayout`? -function Base.similar( - ::MulAdd{<:AbstractDiagonalLayout,<:AbstractDiagonalLayout}, elt::Type, axes -) - return similar(default_diagonalarraytype(elt), axes) -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalarray.jl b/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalarray.jl deleted file mode 100644 index 6f3fc95ff3..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalarray.jl +++ /dev/null @@ -1,107 +0,0 @@ -using ..SparseArraysBase: Zero, getindex_zero_function -# TODO: Put into `DiagonalArraysSparseArraysBaseExt`? -using ..SparseArraysBase: SparseArraysBase, SparseArrayDOK - -struct DiagonalArray{T,N,Diag<:AbstractVector{T},Zero} <: AbstractDiagonalArray{T,N} - diag::Diag - dims::NTuple{N,Int} - zero::Zero -end - -function DiagonalArray{T,N}( - diag::AbstractVector{T}, d::Tuple{Vararg{Int,N}}, zero=Zero() -) where {T,N} - return DiagonalArray{T,N,typeof(diag),typeof(zero)}(diag, d, zero) -end - -function DiagonalArray{T,N}( - diag::AbstractVector, d::Tuple{Vararg{Int,N}}, zero=Zero() -) where {T,N} - return DiagonalArray{T,N}(T.(diag), d, zero) -end - -function DiagonalArray{T,N}(diag::AbstractVector, d::Vararg{Int,N}) where {T,N} - return DiagonalArray{T,N}(diag, d) -end - -function DiagonalArray{T}( - diag::AbstractVector, d::Tuple{Vararg{Int,N}}, zero=Zero() -) where {T,N} - return DiagonalArray{T,N}(diag, d, zero) -end - -function DiagonalArray{T}(diag::AbstractVector, d::Vararg{Int,N}) where {T,N} - return DiagonalArray{T,N}(diag, d) -end - -function DiagonalArray(diag::AbstractVector{T}, d::Tuple{Vararg{Int,N}}) where {T,N} - return DiagonalArray{T,N}(diag, d) -end - -function DiagonalArray(diag::AbstractVector{T}, d::Vararg{Int,N}) where {T,N} - return DiagonalArray{T,N}(diag, d) -end - -# Infer size from diagonal -function DiagonalArray{T,N}(diag::AbstractVector) where {T,N} - return DiagonalArray{T,N}(diag, default_size(diag, N)) -end - -function DiagonalArray{<:Any,N}(diag::AbstractVector{T}) where {T,N} - return DiagonalArray{T,N}(diag) -end - -# undef -function DiagonalArray{T,N}( - ::UndefInitializer, d::Tuple{Vararg{Int,N}}, zero=Zero() -) where {T,N} - return DiagonalArray{T,N}(Vector{T}(undef, minimum(d)), d, zero) -end - -function DiagonalArray{T,N}(::UndefInitializer, d::Vararg{Int,N}) where {T,N} - return DiagonalArray{T,N}(undef, d) -end - -function DiagonalArray{T}( - ::UndefInitializer, d::Tuple{Vararg{Int,N}}, zero=Zero() -) where {T,N} - return DiagonalArray{T,N}(undef, d, zero) -end - -# Axes version -function DiagonalArray{T}( - ::UndefInitializer, axes::Tuple{Vararg{AbstractUnitRange,N}}, zero=Zero() -) where {T,N} - @assert all(isone, first.(axes)) - return DiagonalArray{T,N}(undef, length.(axes), zero) -end - -function DiagonalArray{T}(::UndefInitializer, d::Vararg{Int,N}) where {T,N} - return DiagonalArray{T,N}(undef, d) -end - -# Minimal `AbstractArray` interface -Base.size(a::DiagonalArray) = a.dims - -function Base.similar(a::DiagonalArray, elt::Type, dims::Tuple{Vararg{Int}}) - # TODO: Preserve zero element function. - return DiagonalArray{elt}(undef, dims, getindex_zero_function(a)) -end - -# Minimal `SparseArraysBase` interface -SparseArraysBase.sparse_storage(a::DiagonalArray) = a.diag - -# `SparseArraysBase` -# Defines similar when the output can't be `DiagonalArray`, -# such as in `reshape`. -# TODO: Put into `DiagonalArraysSparseArraysBaseExt`? -# TODO: Special case 2D to output `SparseMatrixCSC`? -function SparseArraysBase.sparse_similar( - a::DiagonalArray, elt::Type, dims::Tuple{Vararg{Int}} -) - return SparseArrayDOK{elt}(undef, dims, getindex_zero_function(a)) -end - -function SparseArraysBase.getindex_zero_function(a::DiagonalArray) - return a.zero -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalmatrix.jl b/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalmatrix.jl deleted file mode 100644 index 873410db78..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalmatrix.jl +++ /dev/null @@ -1,5 +0,0 @@ -const DiagonalMatrix{T,Diag,Zero} = DiagonalArray{T,2,Diag,Zero} - -function DiagonalMatrix(diag::AbstractVector) - return DiagonalArray{<:Any,2}(diag) -end diff --git a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalvector.jl b/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalvector.jl deleted file mode 100644 index 40e35e409d..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/src/diagonalarray/diagonalvector.jl +++ /dev/null @@ -1,5 +0,0 @@ -const DiagonalVector{T,Diag,Zero} = DiagonalArray{T,1,Diag,Zero} - -function DiagonalVector(diag::AbstractVector) - return DiagonalArray{<:Any,1}(diag) -end diff --git a/NDTensors/src/lib/DiagonalArrays/test/Project.toml b/NDTensors/src/lib/DiagonalArrays/test/Project.toml deleted file mode 100644 index 9b1d5ccd25..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/test/Project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[deps] -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" diff --git a/NDTensors/src/lib/DiagonalArrays/test/runtests.jl b/NDTensors/src/lib/DiagonalArrays/test/runtests.jl deleted file mode 100644 index af439730e9..0000000000 --- a/NDTensors/src/lib/DiagonalArrays/test/runtests.jl +++ /dev/null @@ -1,59 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset, @test_broken -using NDTensors.DiagonalArrays: DiagonalArrays, DiagonalArray, DiagonalMatrix, diaglength -using NDTensors.SparseArraysBase: SparseArrayDOK -using NDTensors.SparseArraysBase: stored_length -@testset "Test NDTensors.DiagonalArrays" begin - @testset "README" begin - @test include( - joinpath( - pkgdir(DiagonalArrays), "src", "lib", "DiagonalArrays", "examples", "README.jl" - ), - ) isa Any - end - @testset "DiagonalArray (eltype=$elt)" for elt in - (Float32, Float64, ComplexF32, ComplexF64) - @testset "Basics" begin - a = fill(one(elt), 2, 3) - @test diaglength(a) == 2 - a = fill(one(elt)) - @test diaglength(a) == 1 - end - @testset "Matrix multiplication" begin - a1 = DiagonalArray{elt}(undef, (2, 3)) - a1[1, 1] = 11 - a1[2, 2] = 22 - a2 = DiagonalArray{elt}(undef, (3, 4)) - a2[1, 1] = 11 - a2[2, 2] = 22 - a2[3, 3] = 33 - a_dest = a1 * a2 - # TODO: Use `densearray` to make generic to GPU. - @test Array(a_dest) ≈ Array(a1) * Array(a2) - # TODO: Make this work with `ArrayLayouts`. - @test stored_length(a_dest) == 2 - @test a_dest isa DiagonalMatrix{elt} - - # TODO: Make generic to GPU, use `allocate_randn`? - a2 = randn(elt, (3, 4)) - a_dest = a1 * a2 - # TODO: Use `densearray` to make generic to GPU. - @test Array(a_dest) ≈ Array(a1) * Array(a2) - @test stored_length(a_dest) == 8 - @test a_dest isa Matrix{elt} - - a2 = SparseArrayDOK{elt}(3, 4) - a2[1, 1] = 11 - a2[2, 2] = 22 - a2[3, 3] = 33 - a_dest = a1 * a2 - # TODO: Use `densearray` to make generic to GPU. - @test Array(a_dest) ≈ Array(a1) * Array(a2) - # TODO: Define `SparseMatrixDOK`. - # TODO: Make this work with `ArrayLayouts`. - @test stored_length(a_dest) == 2 - @test a_dest isa SparseArrayDOK{elt,2} - end - end -end -end diff --git a/NDTensors/src/lib/GradedAxes/.JuliaFormatter.toml b/NDTensors/src/lib/GradedAxes/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/GradedAxes/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/GradedAxes/src/GradedAxes.jl b/NDTensors/src/lib/GradedAxes/src/GradedAxes.jl deleted file mode 100644 index ba17c175f0..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/GradedAxes.jl +++ /dev/null @@ -1,9 +0,0 @@ -module GradedAxes -include("blockedunitrange.jl") -include("gradedunitrange.jl") -include("dual.jl") -include("labelledunitrangedual.jl") -include("gradedunitrangedual.jl") -include("onetoone.jl") -include("fusion.jl") -end diff --git a/NDTensors/src/lib/GradedAxes/src/blockedunitrange.jl b/NDTensors/src/lib/GradedAxes/src/blockedunitrange.jl deleted file mode 100644 index d913dd60ab..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/blockedunitrange.jl +++ /dev/null @@ -1,186 +0,0 @@ -using BlockArrays: - BlockArrays, - AbstractBlockVector, - AbstractBlockedUnitRange, - Block, - BlockIndex, - BlockIndexRange, - BlockRange, - BlockSlice, - BlockVector, - BlockedOneTo, - BlockedUnitRange, - BlockedVector, - block, - blockindex, - findblock, - findblockindex - -# Custom `BlockedUnitRange` constructor that takes a unit range -# and a set of block lengths, similar to `BlockArray(::AbstractArray, blocklengths...)`. -function blockedunitrange(a::AbstractUnitRange, blocklengths) - blocklengths_shifted = copy(blocklengths) - blocklengths_shifted[1] += (first(a) - 1) - blocklasts = cumsum(blocklengths_shifted) - return BlockArrays._BlockedUnitRange(first(a), blocklasts) -end - -# TODO: Move this to a `BlockArraysExtensions` library. -# TODO: Rename this. `BlockArrays.findblock(a, k)` finds the -# block of the value `k`, while this finds the block of the index `k`. -# This could make use of the `BlockIndices` object, i.e. `block(BlockIndices(a)[index])`. -function blockedunitrange_findblock(a::AbstractBlockedUnitRange, index::Integer) - @boundscheck index in 1:length(a) || throw(BoundsError(a, index)) - return @inbounds findblock(a, index + first(a) - 1) -end - -# TODO: Move this to a `BlockArraysExtensions` library. -# TODO: Rename this. `BlockArrays.findblockindex(a, k)` finds the -# block index of the value `k`, while this finds the block index of the index `k`. -# This could make use of the `BlockIndices` object, i.e. `BlockIndices(a)[index]`. -function blockedunitrange_findblockindex(a::AbstractBlockedUnitRange, index::Integer) - @boundscheck index in 1:length(a) || throw(BoundsError()) - return @inbounds findblockindex(a, index + first(a) - 1) -end - -function blockedunitrange_getindices(a::AbstractUnitRange, indices) - return a[indices] -end - -# TODO: Move this to a `BlockArraysExtensions` library. -# Like `a[indices]` but preserves block structure. -# TODO: Consider calling this something else, for example -# `blocked_getindex`. See the discussion here: -# https://github.com/JuliaArrays/BlockArrays.jl/issues/347 -function blockedunitrange_getindices( - a::AbstractBlockedUnitRange, indices::AbstractUnitRange{<:Integer} -) - first_blockindex = blockedunitrange_findblockindex(a, first(indices)) - last_blockindex = blockedunitrange_findblockindex(a, last(indices)) - first_block = block(first_blockindex) - last_block = block(last_blockindex) - blocklengths = if first_block == last_block - [length(indices)] - else - map(first_block:last_block) do block - if block == first_block - return length(a[first_block]) - blockindex(first_blockindex) + 1 - end - if block == last_block - return blockindex(last_blockindex) - end - return length(a[block]) - end - end - return blockedunitrange(indices .+ (first(a) - 1), blocklengths) -end - -# TODO: Make sure this handles block labels (AbstractGradedUnitRange) correctly. -# TODO: Make a special case for `BlockedVector{<:Block{1},<:BlockRange{1}}`? -# For example: -# ```julia -# blocklengths = map(bs -> sum(b -> length(a[b]), bs), blocks(indices)) -# return blockedrange(blocklengths) -# ``` -function blockedunitrange_getindices( - a::AbstractBlockedUnitRange, indices::AbstractBlockVector{<:Block{1}} -) - blks = map(bs -> mortar(map(b -> a[b], bs)), blocks(indices)) - # We pass `length.(blks)` to `mortar` in order - # to pass block labels to the axes of the output, - # if they exist. This makes it so that - # `only(axes(a[indices])) isa `GradedUnitRange` - # if `a isa `GradedUnitRange`, for example. - # Note there is a more specialized definition: - # ```julia - # function blockedunitrange_getindices( - # a::AbstractGradedUnitRange, indices::AbstractBlockVector{<:Block{1}} - # ) - # ``` - # that does a better job of preserving labels, since `length` - # may drop labels for certain block types. - return mortar(blks, length.(blks)) -end - -# TODO: Move this to a `BlockArraysExtensions` library. -function blockedunitrange_getindices(a::AbstractBlockedUnitRange, indices::BlockIndexRange) - return a[block(indices)][only(indices.indices)] -end - -# TODO: Move this to a `BlockArraysExtensions` library. -function blockedunitrange_getindices(a::AbstractBlockedUnitRange, indices::BlockSlice) - # TODO: Is this a good definition? It ignores `indices.indices`. - return a[indices.block] -end - -# TODO: Move this to a `BlockArraysExtensions` library. -function blockedunitrange_getindices( - a::AbstractBlockedUnitRange, indices::Vector{<:Integer} -) - return map(index -> a[index], indices) -end - -# TODO: Move this to a `BlockArraysExtensions` library. -# TODO: Make a special definition for `BlockedVector{<:Block{1}}` in order -# to merge blocks. -function blockedunitrange_getindices( - a::AbstractBlockedUnitRange, indices::AbstractVector{<:Union{Block{1},BlockIndexRange{1}}} -) - # Without converting `indices` to `Vector`, - # mapping `indices` outputs a `BlockVector` - # which is harder to reason about. - blocks = map(index -> a[index], Vector(indices)) - # We pass `length.(blocks)` to `mortar` in order - # to pass block labels to the axes of the output, - # if they exist. This makes it so that - # `only(axes(a[indices])) isa `GradedUnitRange` - # if `a isa `GradedUnitRange`, for example. - return mortar(blocks, length.(blocks)) -end - -# TODO: Move this to a `BlockArraysExtensions` library. -function blockedunitrange_getindices(a::AbstractBlockedUnitRange, indices::Block{1}) - return a[indices] -end - -function blockedunitrange_getindices( - a::AbstractBlockedUnitRange, - indices::BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}}, -) - return mortar(map(b -> a[b], blocks(indices))) -end - -# TODO: Move this to a `BlockArraysExtensions` library. -function blockedunitrange_getindices(a::AbstractBlockedUnitRange, indices) - return error("Not implemented.") -end - -# The blocks of the corresponding slice. -_blocks(a::AbstractUnitRange, indices) = error("Not implemented") -function _blocks(a::AbstractUnitRange, indices::AbstractUnitRange) - return findblock(a, first(indices)):findblock(a, last(indices)) -end -function _blocks(a::AbstractUnitRange, indices::BlockRange) - return indices -end - -# Slice `a` by `I`, returning a: -# `BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}}` -# with the `BlockIndex{1}` corresponding to each value of `I`. -function to_blockindices(a::AbstractBlockedUnitRange{<:Integer}, I::UnitRange{<:Integer}) - return mortar( - map(blocks(blockedunitrange_getindices(a, I))) do r - bi_first = findblockindex(a, first(r)) - bi_last = findblockindex(a, last(r)) - @assert block(bi_first) == block(bi_last) - return block(bi_first)[blockindex(bi_first):blockindex(bi_last)] - end, - ) -end - -# This handles non-blocked slices. -# For example: -# a = BlockSparseArray{Float64}([2, 2, 2, 2]) -# I = BlockedVector(Block.(1:4), [2, 2]) -# @views a[I][Block(1)] -to_blockindices(a::Base.OneTo{<:Integer}, I::UnitRange{<:Integer}) = I diff --git a/NDTensors/src/lib/GradedAxes/src/dual.jl b/NDTensors/src/lib/GradedAxes/src/dual.jl deleted file mode 100644 index 877ba1a857..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/dual.jl +++ /dev/null @@ -1,15 +0,0 @@ -# default behavior: any object is self-dual -dual(x) = x -nondual(r::AbstractUnitRange) = r -isdual(::AbstractUnitRange) = false - -using NDTensors.LabelledNumbers: - LabelledStyle, IsLabelled, NotLabelled, label, labelled, unlabel - -dual(i::LabelledInteger) = labelled(unlabel(i), dual(label(i))) -label_dual(x) = label_dual(LabelledStyle(x), x) -label_dual(::NotLabelled, x) = x -label_dual(::IsLabelled, x) = labelled(unlabel(x), dual(label(x))) - -flip(a::AbstractUnitRange) = dual(label_dual(a)) -flip(g::AbstractGradedUnitRange) = dual(gradedrange(label_dual.(blocklengths(g)))) diff --git a/NDTensors/src/lib/GradedAxes/src/fusion.jl b/NDTensors/src/lib/GradedAxes/src/fusion.jl deleted file mode 100644 index 2e893ec1db..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/fusion.jl +++ /dev/null @@ -1,112 +0,0 @@ -using BlockArrays: AbstractBlockedUnitRange, blocklengths - -# https://github.com/ITensor/ITensors.jl/blob/v0.3.57/NDTensors/src/lib/GradedAxes/src/tensor_product.jl -# https://en.wikipedia.org/wiki/Tensor_product -# https://github.com/KeitaNakamura/Tensorial.jl -function tensor_product( - a1::AbstractUnitRange, - a2::AbstractUnitRange, - a3::AbstractUnitRange, - a_rest::Vararg{AbstractUnitRange}, -) - return foldl(tensor_product, (a1, a2, a3, a_rest...)) -end - -flip_dual(r::AbstractUnitRange) = r -flip_dual(r::GradedUnitRangeDual) = flip(r) -function tensor_product(a1::AbstractUnitRange, a2::AbstractUnitRange) - return tensor_product(flip_dual(a1), flip_dual(a2)) -end - -function tensor_product(a1::Base.OneTo, a2::Base.OneTo) - return Base.OneTo(length(a1) * length(a2)) -end - -function tensor_product(::OneToOne, a2::AbstractUnitRange) - return a2 -end - -function tensor_product(a1::AbstractUnitRange, ::OneToOne) - return a1 -end - -function tensor_product(::OneToOne, ::OneToOne) - return OneToOne() -end - -function fuse_labels(x, y) - return error( - "`fuse_labels` not implemented for object of type `$(typeof(x))` and `$(typeof(y))`." - ) -end - -function fuse_blocklengths(x::Integer, y::Integer) - # return blocked unit range to keep non-abelian interface - return blockedrange([x * y]) -end - -using ..LabelledNumbers: LabelledInteger, label, labelled, unlabel -function fuse_blocklengths(x::LabelledInteger, y::LabelledInteger) - # return blocked unit range to keep non-abelian interface - return blockedrange([labelled(x * y, fuse_labels(label(x), label(y)))]) -end - -using BlockArrays: blockedrange, blocks -function tensor_product(a1::AbstractBlockedUnitRange, a2::AbstractBlockedUnitRange) - nested = map(Iterators.flatten((Iterators.product(blocks(a1), blocks(a2)),))) do it - return mapreduce(length, fuse_blocklengths, it) - end - new_blocklengths = mapreduce(blocklengths, vcat, nested) - return blockedrange(new_blocklengths) -end - -# convention: sort GradedUnitRangeDual according to nondual blocks -function blocksortperm(a::AbstractUnitRange) - return Block.(sortperm(blocklabels(nondual(a)))) -end - -using BlockArrays: Block, BlockVector -using SplitApplyCombine: groupcount -# Get the permutation for sorting, then group by common elements. -# groupsortperm([2, 1, 2, 3]) == [[2], [1, 3], [4]] -function groupsortperm(v; kwargs...) - perm = sortperm(v; kwargs...) - v_sorted = @view v[perm] - group_lengths = collect(groupcount(identity, v_sorted)) - return BlockVector(perm, group_lengths) -end - -# Used by `TensorAlgebra.splitdims` in `BlockSparseArraysGradedAxesExt`. -# Get the permutation for sorting, then group by common elements. -# groupsortperm([2, 1, 2, 3]) == [[2], [1, 3], [4]] -function blockmergesortperm(a::AbstractUnitRange) - return Block.(groupsortperm(blocklabels(nondual(a)))) -end - -# Used by `TensorAlgebra.splitdims` in `BlockSparseArraysGradedAxesExt`. -invblockperm(a::Vector{<:Block{1}}) = Block.(invperm(Int.(a))) - -function blockmergesort(g::AbstractGradedUnitRange) - glabels = blocklabels(g) - gblocklengths = blocklengths(g) - new_blocklengths = map(sort(unique(glabels))) do la - return labelled(sum(gblocklengths[findall(==(la), glabels)]; init=0), la) - end - return gradedrange(new_blocklengths) -end - -blockmergesort(g::GradedUnitRangeDual) = flip(blockmergesort(flip(g))) -blockmergesort(g::AbstractUnitRange) = g - -# fusion_product produces a sorted, non-dual GradedUnitRange -function fusion_product(g1, g2) - return blockmergesort(tensor_product(g1, g2)) -end - -fusion_product(g::AbstractUnitRange) = blockmergesort(g) -fusion_product(g::GradedUnitRangeDual) = fusion_product(flip(g)) - -# recursive fusion_product. Simpler than reduce + fix type stability issues with reduce -function fusion_product(g1, g2, g3...) - return fusion_product(fusion_product(g1, g2), g3...) -end diff --git a/NDTensors/src/lib/GradedAxes/src/gradedunitrange.jl b/NDTensors/src/lib/GradedAxes/src/gradedunitrange.jl deleted file mode 100644 index 76eaf42692..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/gradedunitrange.jl +++ /dev/null @@ -1,384 +0,0 @@ -using BlockArrays: - BlockArrays, - AbstractBlockVector, - AbstractBlockedUnitRange, - Block, - BlockIndex, - BlockRange, - BlockSlice, - BlockVector, - BlockedOneTo, - BlockedUnitRange, - blockedrange, - BlockIndexRange, - blockfirsts, - blockisequal, - blocklength, - blocklengths, - findblock, - findblockindex, - mortar, - sortedunion -using Compat: allequal -using FillArrays: Fill -using ..LabelledNumbers: - LabelledNumbers, - LabelledInteger, - LabelledUnitRange, - label, - label_type, - labelled, - labelled_isequal, - unlabel - -abstract type AbstractGradedUnitRange{T,BlockLasts} <: - AbstractBlockedUnitRange{T,BlockLasts} end - -struct GradedUnitRange{T,BlockLasts<:Vector{T}} <: AbstractGradedUnitRange{T,BlockLasts} - first::T - lasts::BlockLasts -end - -struct GradedOneTo{T,BlockLasts<:Vector{T}} <: AbstractGradedUnitRange{T,BlockLasts} - lasts::BlockLasts - - # assume that lasts is sorted, no checks carried out here - function GradedOneTo(lasts::BlockLasts) where {T<:Integer,BlockLasts<:AbstractVector{T}} - Base.require_one_based_indexing(lasts) - isempty(lasts) || first(lasts) >= 0 || throw(ArgumentError("blocklasts must be >= 0")) - return new{T,BlockLasts}(lasts) - end - function GradedOneTo(lasts::BlockLasts) where {T<:Integer,BlockLasts<:Tuple{T,Vararg{T}}} - first(lasts) >= 0 || throw(ArgumentError("blocklasts must be >= 0")) - return new{T,BlockLasts}(lasts) - end -end - -function Base.show(io::IO, ::MIME"text/plain", g::AbstractGradedUnitRange) - v = map(b -> label(b) => unlabel(b), blocks(g)) - println(io, typeof(g)) - return print(io, join(repr.(v), '\n')) -end - -function Base.show(io::IO, g::AbstractGradedUnitRange) - v = map(b -> label(b) => unlabel(b), blocks(g)) - return print(io, nameof(typeof(g)), '[', join(repr.(v), ", "), ']') -end - -# == is just a range comparison that ignores labels. Need dedicated function to check equality. -struct NoLabel end -blocklabels(r::AbstractUnitRange) = Fill(NoLabel(), blocklength(r)) -blocklabels(la::LabelledUnitRange) = [label(la)] - -function LabelledNumbers.labelled_isequal(a1::AbstractUnitRange, a2::AbstractUnitRange) - return blockisequal(a1, a2) && (blocklabels(a1) == blocklabels(a2)) -end - -function space_isequal(a1::AbstractUnitRange, a2::AbstractUnitRange) - return (isdual(a1) == isdual(a2)) && labelled_isequal(a1, a2) -end - -# needed in BlockSparseArrays -function Base.AbstractUnitRange{T}( - a::AbstractGradedUnitRange{<:LabelledInteger{T}} -) where {T} - return unlabel_blocks(a) -end - -# TODO: Use `TypeParameterAccessors`. -Base.eltype(::Type{<:GradedUnitRange{T}}) where {T} = T -LabelledNumbers.label_type(g::AbstractGradedUnitRange) = label_type(typeof(g)) -LabelledNumbers.label_type(T::Type{<:AbstractGradedUnitRange}) = label_type(eltype(T)) - -function gradedrange(lblocklengths::AbstractVector{<:LabelledInteger}) - brange = blockedrange(unlabel.(lblocklengths)) - lblocklasts = labelled.(blocklasts(brange), label.(lblocklengths)) - return GradedOneTo(lblocklasts) -end - -# To help with generic code. -function BlockArrays.blockedrange(lblocklengths::AbstractVector{<:LabelledInteger}) - return gradedrange(lblocklengths) -end - -Base.last(a::AbstractGradedUnitRange) = isempty(a.lasts) ? first(a) - 1 : last(a.lasts) - -function gradedrange(lblocklengths::AbstractVector{<:Pair{<:Any,<:Integer}}) - return gradedrange(labelled.(last.(lblocklengths), first.(lblocklengths))) -end - -function labelled_blocks(a::BlockedOneTo, labels) - # TODO: Use `blocklasts(a)`? That might - # cause a recursive loop. - return GradedOneTo(labelled.(a.lasts, labels)) -end -function labelled_blocks(a::BlockedUnitRange, labels) - # TODO: Use `first(a)` and `blocklasts(a)`? Those might - # cause a recursive loop. - return GradedUnitRange(labelled(a.first, labels[1]), labelled.(a.lasts, labels)) -end - -function BlockArrays.findblock(a::AbstractGradedUnitRange, index::Integer) - return blockedunitrange_findblock(unlabel_blocks(a), index) -end - -function blockedunitrange_findblock(a::AbstractGradedUnitRange, index::Integer) - return blockedunitrange_findblock(unlabel_blocks(a), index) -end - -function blockedunitrange_findblockindex(a::AbstractGradedUnitRange, index::Integer) - return blockedunitrange_findblockindex(unlabel_blocks(a), index) -end - -function BlockArrays.findblockindex(a::AbstractGradedUnitRange, index::Integer) - return blockedunitrange_findblockindex(unlabel_blocks(a), index) -end - -## Block label interface - -# Internal function -function get_label(a::AbstractUnitRange, index::Block{1}) - return label(blocklasts(a)[Int(index)]) -end - -# Internal function -function get_label(a::AbstractUnitRange, index::Integer) - return get_label(a, blockedunitrange_findblock(a, index)) -end - -function blocklabels(a::AbstractBlockVector) - return map(BlockRange(a)) do block - return label(@view(a[block])) - end -end - -function blocklabels(a::AbstractBlockedUnitRange) - # Using `a.lasts` here since that is what is stored - # inside of `BlockedUnitRange`, maybe change that. - # For example, it could be something like: - # - # map(BlockRange(a)) do block - # return label(@view(a[block])) - # end - # - return label.(a.lasts) -end - -# TODO: This relies on internals of `BlockArrays`, maybe redesign -# to try to avoid that. -# TODO: Define `set_grades`, `set_sector_labels`, `set_labels`. -function unlabel_blocks(a::GradedOneTo) - # TODO: Use `blocklasts(a)`. - return BlockedOneTo(unlabel.(a.lasts)) -end -function unlabel_blocks(a::GradedUnitRange) - return BlockArrays._BlockedUnitRange(a.first, unlabel.(a.lasts)) -end - -## BlockedUnitRange interface - -function Base.axes(ga::AbstractGradedUnitRange) - return map(axes(unlabel_blocks(ga))) do a - return labelled_blocks(a, blocklabels(ga)) - end -end - -function gradedunitrange_blockfirsts(a::AbstractGradedUnitRange) - return labelled.(blockfirsts(unlabel_blocks(a)), blocklabels(a)) -end -function BlockArrays.blockfirsts(a::AbstractGradedUnitRange) - return gradedunitrange_blockfirsts(a) -end - -function BlockArrays.blocklasts(a::AbstractGradedUnitRange) - return labelled.(blocklasts(unlabel_blocks(a)), blocklabels(a)) -end - -function BlockArrays.blocklengths(a::AbstractGradedUnitRange) - return labelled.(blocklengths(unlabel_blocks(a)), blocklabels(a)) -end - -function gradedunitrange_first(a::AbstractUnitRange) - return labelled(first(unlabel_blocks(a)), label(a[Block(1)])) -end -function Base.first(a::AbstractGradedUnitRange) - return gradedunitrange_first(a) -end - -Base.iterate(a::AbstractGradedUnitRange) = isempty(a) ? nothing : (first(a), first(a)) -function Base.iterate(a::AbstractGradedUnitRange, i) - i == last(a) && return nothing - next = a[i + step(a)] - return (next, next) -end - -function firstblockindices(a::AbstractGradedUnitRange) - return labelled.(firstblockindices(unlabel_blocks(a)), blocklabels(a)) -end - -function blockedunitrange_getindices(a::AbstractGradedUnitRange, index::Block{1}) - return labelled(unlabel_blocks(a)[index], get_label(a, index)) -end - -function blockedunitrange_getindices(a::AbstractGradedUnitRange, indices::Vector{<:Integer}) - return map(index -> a[index], indices) -end - -function blockedunitrange_getindices( - a::AbstractGradedUnitRange, - indices::BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}}, -) - return mortar(map(b -> a[b], blocks(indices))) -end - -function blockedunitrange_getindices(a::AbstractGradedUnitRange, index) - return labelled(unlabel_blocks(a)[index], get_label(a, index)) -end - -function blockedunitrange_getindices(a::AbstractGradedUnitRange, indices::BlockIndexRange) - return a[block(indices)][only(indices.indices)] -end - -function blockedunitrange_getindices( - a::AbstractGradedUnitRange, indices::AbstractVector{<:Union{Block{1},BlockIndexRange{1}}} -) - # Without converting `indices` to `Vector`, - # mapping `indices` outputs a `BlockVector` - # which is harder to reason about. - blocks = map(index -> a[index], Vector(indices)) - # We pass `length.(blocks)` to `mortar` in order - # to pass block labels to the axes of the output, - # if they exist. This makes it so that - # `only(axes(a[indices])) isa `GradedUnitRange` - # if `a isa `GradedUnitRange`, for example. - return mortar(blocks, length.(blocks)) -end - -# The block labels of the corresponding slice. -function blocklabels(a::AbstractUnitRange, indices) - return map(_blocks(a, indices)) do block - return label(a[block]) - end -end - -function blockedunitrange_getindices( - ga::AbstractGradedUnitRange, indices::AbstractUnitRange{<:Integer} -) - a_indices = blockedunitrange_getindices(unlabel_blocks(ga), indices) - return labelled_blocks(a_indices, blocklabels(ga, indices)) -end - -function blockedunitrange_getindices(a::AbstractGradedUnitRange, indices::BlockSlice) - return a[indices.block] -end - -function blockedunitrange_getindices(ga::AbstractGradedUnitRange, indices::BlockRange) - return labelled_blocks(unlabel_blocks(ga)[indices], blocklabels(ga, indices)) -end - -function blockedunitrange_getindices(a::AbstractGradedUnitRange, indices::BlockIndex{1}) - return a[block(indices)][blockindex(indices)] -end - -function Base.getindex(a::AbstractGradedUnitRange, index::Integer) - return labelled(unlabel_blocks(a)[index], get_label(a, index)) -end - -function Base.getindex(a::AbstractGradedUnitRange, index::Block{1}) - return blockedunitrange_getindices(a, index) -end - -function Base.getindex(a::AbstractGradedUnitRange, indices::BlockIndexRange) - return blockedunitrange_getindices(a, indices) -end - -# fix ambiguities -function Base.getindex( - a::AbstractGradedUnitRange, indices::BlockArrays.BlockRange{1,<:Tuple{Base.OneTo}} -) - return blockedunitrange_getindices(a, indices) -end -function Base.getindex( - a::AbstractGradedUnitRange, indices::BlockRange{1,<:Tuple{AbstractUnitRange{Int}}} -) - return blockedunitrange_getindices(a, indices) -end - -function Base.getindex(a::AbstractGradedUnitRange, indices::BlockIndex{1}) - return blockedunitrange_getindices(a, indices) -end - -# Fixes ambiguity issues with: -# ```julia -# getindex(::BlockedUnitRange, ::BlockSlice) -# getindex(::GradedUnitRange, ::AbstractUnitRange{<:Integer}) -# getindex(::GradedUnitRange, ::Any) -# getindex(::AbstractUnitRange, ::AbstractUnitRange{<:Integer}) -# ``` -function Base.getindex(a::AbstractGradedUnitRange, indices::BlockSlice) - return blockedunitrange_getindices(a, indices) -end - -function Base.getindex(a::AbstractGradedUnitRange, indices) - return blockedunitrange_getindices(a, indices) -end - -function Base.getindex(a::AbstractGradedUnitRange, indices::AbstractUnitRange{<:Integer}) - return blockedunitrange_getindices(a, indices) -end - -# This fixes an issue that `combine_blockaxes` was promoting -# the element type of the axes to `Integer` in broadcasting operations -# that mixed dense and graded axes. -# TODO: Maybe come up with a more general solution. -function BlockArrays.combine_blockaxes( - a1::AbstractGradedUnitRange{<:LabelledInteger{T}}, a2::AbstractUnitRange{T} -) where {T<:Integer} - combined_blocklasts = sort!(union(unlabel.(blocklasts(a1)), blocklasts(a2))) - return BlockedOneTo(combined_blocklasts) -end -function BlockArrays.combine_blockaxes( - a1::AbstractUnitRange{T}, a2::AbstractGradedUnitRange{<:LabelledInteger{T}} -) where {T<:Integer} - return BlockArrays.combine_blockaxes(a2, a1) -end - -# preserve labels inside combine_blockaxes -function BlockArrays.combine_blockaxes(a::GradedOneTo, b::GradedOneTo) - return GradedOneTo(sortedunion(blocklasts(a), blocklasts(b))) -end -function BlockArrays.combine_blockaxes(a::GradedUnitRange, b::GradedUnitRange) - new_blocklasts = sortedunion(blocklasts(a), blocklasts(b)) - new_first = labelled(oneunit(eltype(new_blocklasts)), label(first(new_blocklasts))) - return GradedUnitRange(new_first, new_blocklasts) -end - -# preserve axes in SubArray -Base.axes(S::Base.Slice{<:AbstractGradedUnitRange}) = (S.indices,) - -# Version of length that checks that all blocks have the same label -# and returns a labelled length with that label. -function labelled_length(a::AbstractBlockVector{<:Integer}) - blocklabels = label.(blocks(a)) - @assert allequal(blocklabels) - return labelled(unlabel(length(a)), first(blocklabels)) -end - -# TODO: Make sure this handles block labels (AbstractGradedUnitRange) correctly. -# TODO: Make a special case for `BlockedVector{<:Block{1},<:BlockRange{1}}`? -# For example: -# ```julia -# blocklengths = map(bs -> sum(b -> length(a[b]), bs), blocks(indices)) -# return blockedrange(blocklengths) -# ``` -function blockedunitrange_getindices( - a::AbstractGradedUnitRange, indices::AbstractBlockVector{<:Block{1}} -) - blks = map(bs -> mortar(map(b -> a[b], bs)), blocks(indices)) - # We pass `length.(blks)` to `mortar` in order - # to pass block labels to the axes of the output, - # if they exist. This makes it so that - # `only(axes(a[indices])) isa `GradedUnitRange` - # if `a isa `GradedUnitRange`, for example. - return mortar(blks, labelled_length.(blks)) -end diff --git a/NDTensors/src/lib/GradedAxes/src/gradedunitrangedual.jl b/NDTensors/src/lib/GradedAxes/src/gradedunitrangedual.jl deleted file mode 100644 index a16da982f9..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/gradedunitrangedual.jl +++ /dev/null @@ -1,134 +0,0 @@ -struct GradedUnitRangeDual{ - T,BlockLasts,NondualUnitRange<:AbstractGradedUnitRange{T,BlockLasts} -} <: AbstractGradedUnitRange{T,BlockLasts} - nondual_unitrange::NondualUnitRange -end - -dual(a::AbstractGradedUnitRange) = GradedUnitRangeDual(a) -nondual(a::GradedUnitRangeDual) = a.nondual_unitrange -dual(a::GradedUnitRangeDual) = nondual(a) -flip(a::GradedUnitRangeDual) = dual(flip(nondual(a))) -isdual(::GradedUnitRangeDual) = true -## TODO: Define this to instantiate a dual unit range. -## materialize_dual(a::GradedUnitRangeDual) = materialize_dual(nondual(a)) - -Base.first(a::GradedUnitRangeDual) = label_dual(first(nondual(a))) -Base.last(a::GradedUnitRangeDual) = label_dual(last(nondual(a))) -Base.step(a::GradedUnitRangeDual) = label_dual(step(nondual(a))) - -Base.view(a::GradedUnitRangeDual, index::Block{1}) = a[index] - -function blockedunitrange_getindices( - a::GradedUnitRangeDual, indices::AbstractUnitRange{<:Integer} -) - return dual(getindex(nondual(a), indices)) -end - -using BlockArrays: Block, BlockIndexRange, BlockRange - -function blockedunitrange_getindices(a::GradedUnitRangeDual, indices::Integer) - return label_dual(getindex(nondual(a), indices)) -end - -function blockedunitrange_getindices(a::GradedUnitRangeDual, indices::Block{1}) - return dual(getindex(nondual(a), indices)) -end - -function blockedunitrange_getindices(a::GradedUnitRangeDual, indices::BlockRange) - return dual(getindex(nondual(a), indices)) -end - -function blockedunitrange_getindices(a::GradedUnitRangeDual, indices::BlockIndexRange) - return dual(nondual(a)[indices]) -end - -# fix ambiguity -function blockedunitrange_getindices( - a::GradedUnitRangeDual, indices::BlockRange{1,<:Tuple{AbstractUnitRange{Int}}} -) - return dual(getindex(nondual(a), indices)) -end - -function BlockArrays.blocklengths(a::GradedUnitRangeDual) - return dual.(blocklengths(nondual(a))) -end - -# TODO: Move this to a `BlockArraysExtensions` library. -function blockedunitrange_getindices( - a::GradedUnitRangeDual, indices::Vector{<:BlockIndexRange{1}} -) - # dual v axes to stay consistent with other cases where axes(v) are used - return dual_axes(blockedunitrange_getindices(nondual(a), indices)) -end - -function blockedunitrange_getindices( - a::GradedUnitRangeDual, - indices::BlockVector{<:BlockIndex{1},<:Vector{<:BlockIndexRange{1}}}, -) - # dual v axis to preserve dual information - # axes(v) will appear in axes(view(::BlockSparseArray, [Block(1)[1:1]])) - return dual_axes(blockedunitrange_getindices(nondual(a), indices)) -end - -function blockedunitrange_getindices( - a::GradedUnitRangeDual, indices::AbstractVector{<:Union{Block{1},BlockIndexRange{1}}} -) - # dual v axis to preserve dual information - # axes(v) will appear in axes(view(::BlockSparseArray, [Block(1)])) - return dual_axes(blockedunitrange_getindices(nondual(a), indices)) -end - -# Fixes ambiguity error. -function blockedunitrange_getindices( - a::GradedUnitRangeDual, indices::AbstractBlockVector{<:Block{1}} -) - v = blockedunitrange_getindices(nondual(a), indices) - # v elements are not dualled by dual_axes due to different structure. - # take element dual here. - return dual_axes(dual.(v)) -end - -function dual_axes(v::BlockVector) - # dual both v elements and v axes - block_axes = dual.(axes(v)) - return mortar(dual.(blocks(v)), block_axes) -end - -Base.axes(a::GradedUnitRangeDual) = axes(nondual(a)) - -using BlockArrays: BlockArrays, Block, BlockSlice -using NDTensors.LabelledNumbers: LabelledUnitRange -function BlockArrays.BlockSlice(b::Block, a::LabelledUnitRange) - return BlockSlice(b, unlabel(a)) -end - -using BlockArrays: BlockArrays, BlockSlice -using NDTensors.GradedAxes: GradedUnitRangeDual, dual -function BlockArrays.BlockSlice(b::Block, r::GradedUnitRangeDual) - return BlockSlice(b, dual(r)) -end - -using NDTensors.LabelledNumbers: LabelledNumbers, LabelledUnitRange, label -function Base.iterate(a::GradedUnitRangeDual, i) - i == last(a) && return nothing - return dual.(iterate(nondual(a), i)) -end - -using NDTensors.LabelledNumbers: LabelledInteger, label, labelled, unlabel -using BlockArrays: BlockArrays, blockaxes, blocklasts, combine_blockaxes, findblock -BlockArrays.blockaxes(a::GradedUnitRangeDual) = blockaxes(nondual(a)) -BlockArrays.blockfirsts(a::GradedUnitRangeDual) = label_dual.(blockfirsts(nondual(a))) -BlockArrays.blocklasts(a::GradedUnitRangeDual) = label_dual.(blocklasts(nondual(a))) -function BlockArrays.findblock(a::GradedUnitRangeDual, index::Integer) - return findblock(nondual(a), index) -end - -blocklabels(a::GradedUnitRangeDual) = dual.(blocklabels(nondual(a))) - -function BlockArrays.combine_blockaxes(a1::GradedUnitRangeDual, a2::GradedUnitRangeDual) - return dual(combine_blockaxes(nondual(a1), nondual(a2))) -end - -function unlabel_blocks(a::GradedUnitRangeDual) - return unlabel_blocks(nondual(a)) -end diff --git a/NDTensors/src/lib/GradedAxes/src/labelledunitrangedual.jl b/NDTensors/src/lib/GradedAxes/src/labelledunitrangedual.jl deleted file mode 100644 index 466d64945b..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/labelledunitrangedual.jl +++ /dev/null @@ -1,49 +0,0 @@ -# LabelledUnitRangeDual is obtained by slicing a GradedUnitRangeDual with a block - -using ..LabelledNumbers: LabelledNumbers, label, labelled, unlabel - -struct LabelledUnitRangeDual{T,NondualUnitRange<:AbstractUnitRange{T}} <: - AbstractUnitRange{T} - nondual_unitrange::NondualUnitRange -end - -dual(a::LabelledUnitRange) = LabelledUnitRangeDual(a) -nondual(a::LabelledUnitRangeDual) = a.nondual_unitrange -dual(a::LabelledUnitRangeDual) = nondual(a) -label_dual(::IsLabelled, a::LabelledUnitRangeDual) = dual(label_dual(nondual(a))) -isdual(::LabelledUnitRangeDual) = true -blocklabels(la::LabelledUnitRangeDual) = [label(la)] - -LabelledNumbers.label(a::LabelledUnitRangeDual) = dual(label(nondual(a))) -LabelledNumbers.unlabel(a::LabelledUnitRangeDual) = unlabel(nondual(a)) -LabelledNumbers.LabelledStyle(::LabelledUnitRangeDual) = IsLabelled() - -for f in [:first, :getindex, :last, :length, :step] - @eval Base.$f(a::LabelledUnitRangeDual, args...) = - labelled($f(unlabel(a), args...), label(a)) -end - -# fix ambiguities -Base.getindex(a::LabelledUnitRangeDual, i::Integer) = dual(nondual(a)[i]) -function Base.getindex(a::LabelledUnitRangeDual, indices::AbstractUnitRange{<:Integer}) - return dual(nondual(a)[indices]) -end - -function Base.iterate(a::LabelledUnitRangeDual, i) - i == last(a) && return nothing - next = convert(eltype(a), labelled(i + step(a), label(a))) - return (next, next) -end - -function Base.show(io::IO, ::MIME"text/plain", a::LabelledUnitRangeDual) - println(io, typeof(a)) - return print(io, label(a), " => ", unlabel(a)) -end - -function Base.show(io::IO, a::LabelledUnitRangeDual) - return print(io, nameof(typeof(a)), " ", label(a), " => ", unlabel(a)) -end - -function Base.AbstractUnitRange{T}(a::LabelledUnitRangeDual) where {T} - return AbstractUnitRange{T}(nondual(a)) -end diff --git a/NDTensors/src/lib/GradedAxes/src/onetoone.jl b/NDTensors/src/lib/GradedAxes/src/onetoone.jl deleted file mode 100644 index 426df396b1..0000000000 --- a/NDTensors/src/lib/GradedAxes/src/onetoone.jl +++ /dev/null @@ -1,9 +0,0 @@ -using BlockArrays: AbstractBlockedUnitRange -using ..LabelledNumbers: islabelled - -# Represents the range `1:1` or `Base.OneTo(1)`. -struct OneToOne{T} <: AbstractUnitRange{T} end -OneToOne() = OneToOne{Bool}() -Base.first(a::OneToOne) = one(eltype(a)) -Base.last(a::OneToOne) = one(eltype(a)) -BlockArrays.blockaxes(g::OneToOne) = (Block.(g),) # BlockArrays default crashes for OneToOne{Bool} diff --git a/NDTensors/src/lib/GradedAxes/test/Project.toml b/NDTensors/src/lib/GradedAxes/test/Project.toml deleted file mode 100644 index d1bf575ce0..0000000000 --- a/NDTensors/src/lib/GradedAxes/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/GradedAxes/test/runtests.jl b/NDTensors/src/lib/GradedAxes/test/runtests.jl deleted file mode 100644 index c0fdca21be..0000000000 --- a/NDTensors/src/lib/GradedAxes/test/runtests.jl +++ /dev/null @@ -1,8 +0,0 @@ -@eval module $(gensym()) -using Test: @testset -@testset "GradedAxes" begin - include("test_basics.jl") - include("test_dual.jl") - include("test_tensor_product.jl") -end -end diff --git a/NDTensors/src/lib/GradedAxes/test/test_basics.jl b/NDTensors/src/lib/GradedAxes/test/test_basics.jl deleted file mode 100644 index 90faa59b93..0000000000 --- a/NDTensors/src/lib/GradedAxes/test/test_basics.jl +++ /dev/null @@ -1,256 +0,0 @@ -@eval module $(gensym()) -using BlockArrays: - Block, - BlockRange, - BlockSlice, - BlockVector, - blockedrange, - blockfirsts, - blocklasts, - blocklength, - blocklengths, - blocks, - combine_blockaxes, - mortar -using NDTensors.GradedAxes: - GradedOneTo, GradedUnitRange, OneToOne, blocklabels, gradedrange, space_isequal -using NDTensors.LabelledNumbers: - LabelledUnitRange, islabelled, label, labelled, labelled_isequal, unlabel -using Test: @test, @test_broken, @testset - -@testset "OneToOne" begin - a0 = OneToOne() - @test a0 isa OneToOne{Bool} - @test eltype(a0) == Bool - @test length(a0) == 1 - @test labelled_isequal(a0, a0) - @test a0[1] == true - @test a0[[1]] == [true] - - @test labelled_isequal(a0, 1:1) - @test labelled_isequal(1:1, a0) - @test !labelled_isequal(a0, 1:2) - @test !labelled_isequal(1:2, a0) -end - -@testset "GradedAxes basics" begin - a0 = OneToOne() - for a in ( - blockedrange([labelled(2, "x"), labelled(3, "y")]), - gradedrange([labelled(2, "x"), labelled(3, "y")]), - gradedrange(["x" => 2, "y" => 3]), - ) - @test a isa GradedOneTo - @test labelled_isequal(a, a) - @test !labelled_isequal(a0, a) - @test !labelled_isequal(a, a0) - @test !labelled_isequal(a, 1:5) - for x in iterate(a) - @test x == 1 - @test label(x) == "x" - end - for x in iterate(a, labelled(1, "x")) - @test x == 2 - @test label(x) == "x" - end - for x in iterate(a, labelled(2, "x")) - @test x == 3 - @test label(x) == "y" - end - for x in iterate(a, labelled(3, "y")) - @test x == 4 - @test label(x) == "y" - end - for x in iterate(a, labelled(4, "y")) - @test x == 5 - @test label(x) == "y" - end - @test isnothing(iterate(a, labelled(5, "y"))) - @test labelled_isequal(a, a) - @test length(a) == 5 - @test step(a) == 1 - @test !islabelled(step(a)) - @test length(blocks(a)) == 2 - @test blocks(a)[1] == 1:2 - @test label(blocks(a)[1]) == "x" - @test blocks(a)[2] == 3:5 - @test label(blocks(a)[2]) == "y" - @test a[Block(2)] == 3:5 - @test label(a[Block(2)]) == "y" - @test a[Block(2)] isa LabelledUnitRange - @test a[4] == 4 - @test label(a[4]) == "y" - @test unlabel(a[4]) == 4 - @test blocklengths(a) == [2, 3] - @test blocklabels(a) == ["x", "y"] - @test label.(blocklengths(a)) == ["x", "y"] - @test blockfirsts(a) == [1, 3] - @test label.(blockfirsts(a)) == ["x", "y"] - @test first(a) == 1 - @test label(first(a)) == "x" - @test blocklasts(a) == [2, 5] - @test label.(blocklasts(a)) == ["x", "y"] - @test last(a) == 5 - @test label(last(a)) == "y" - @test a[Block(2)] == 3:5 - @test label(a[Block(2)]) == "y" - @test length(a[Block(2)]) == 3 - @test blocklengths(only(axes(a))) == blocklengths(a) - @test blocklabels(only(axes(a))) == blocklabels(a) - - @test axes(Base.Slice(a)) isa Tuple{typeof(a)} - @test AbstractUnitRange{Int}(a) == 1:5 - b = combine_blockaxes(a, a) - @test b isa GradedOneTo - @test b == 1:5 - @test space_isequal(b, a) - end - - # Slicing operations - x = gradedrange(["x" => 2, "y" => 3]) - a = x[2:4] - @test a isa GradedUnitRange - @test length(a) == 3 - @test blocklength(a) == 2 - @test a[Block(1)] == 2:2 - @test label(a[Block(1)]) == "x" - @test a[Block(2)] == 3:4 - @test label(a[Block(2)]) == "y" - ax = only(axes(a)) - @test ax == 1:length(a) - @test length(ax) == length(a) - @test blocklengths(ax) == blocklengths(a) - @test blocklabels(ax) == blocklabels(a) - @test blockfirsts(a) == [2, 3] - - @test AbstractUnitRange{Int}(a) == 2:4 - b = combine_blockaxes(a, a) - @test b isa GradedUnitRange - @test b == 1:4 - - @test x[[2, 4]] == [labelled(2, "x"), labelled(4, "y")] - @test labelled_isequal(x[BlockRange(1)], gradedrange(["x" => 2])) - - # Regression test for ambiguity error. - x = gradedrange(["x" => 2, "y" => 3]) - a = x[BlockSlice(Block(1), Base.OneTo(2))] - @test length(a) == 2 - @test a == 1:2 - @test blocklength(a) == 1 - # TODO: Should this be a `GradedUnitRange`, - # or maybe just a `LabelledUnitRange`? - @test a isa LabelledUnitRange - @test length(a[Block(1)]) == 2 - @test label(a) == "x" - @test a[Block(1)] == 1:2 - @test label(a[Block(1)]) == "x" - - x = gradedrange(["x" => 2, "y" => 3]) - a = x[3:4] - @test a isa GradedUnitRange - @test length(a) == 2 - @test blocklength(a) == 1 - @test a[Block(1)] == 3:4 - @test label(a[Block(1)]) == "y" - ax = only(axes(a)) - @test ax == 1:length(a) - @test length(ax) == length(a) - @test blocklengths(ax) == blocklengths(a) - @test blocklabels(ax) == blocklabels(a) - @test axes(Base.Slice(a)) isa Tuple{typeof(a)} - - x = gradedrange(["x" => 2, "y" => 3]) - a = x[2:4][1:2] - @test a isa GradedUnitRange - @test length(a) == 2 - @test blocklength(a) == 2 - @test a[Block(1)] == 2:2 - @test label(a[Block(1)]) == "x" - @test a[Block(2)] == 3:3 - @test label(a[Block(2)]) == "y" - ax = only(axes(a)) - @test ax == 1:length(a) - @test length(ax) == length(a) - @test blocklengths(ax) == blocklengths(a) - @test blocklabels(ax) == blocklabels(a) - - x = gradedrange(["x" => 2, "y" => 3]) - a = x[Block(2)[2:3]] - @test a isa LabelledUnitRange - @test length(a) == 2 - @test a == 4:5 - @test label(a) == "y" - ax = only(axes(a)) - @test ax == 1:length(a) - @test length(ax) == length(a) - @test label(ax) == label(a) - - x = gradedrange(["x" => 2, "y" => 3, "z" => 4]) - a = x[Block(2):Block(3)] - @test a isa GradedUnitRange - @test length(a) == 7 - @test blocklength(a) == 2 - @test blocklengths(a) == [3, 4] - @test blocklabels(a) == ["y", "z"] - @test a[Block(1)] == 3:5 - @test a[Block(2)] == 6:9 - ax = only(axes(a)) - @test ax == 1:length(a) - @test length(ax) == length(a) - @test blocklengths(ax) == blocklengths(a) - @test blocklabels(ax) == blocklabels(a) - - x = gradedrange(["x" => 2, "y" => 3, "z" => 4]) - a = x[[Block(3), Block(2)]] - @test a isa BlockVector - @test length(a) == 7 - @test blocklength(a) == 2 - # TODO: `BlockArrays` doesn't define `blocklengths` - # `blocklengths(::BlockVector)`, unbrake this test - # once it does. - @test_broken blocklengths(a) == [4, 3] - @test blocklabels(a) == ["z", "y"] - @test a[Block(1)] == 6:9 - @test a[Block(2)] == 3:5 - ax = only(axes(a)) - @test ax == 1:length(a) - @test length(ax) == length(a) - # TODO: Change to: - # @test blocklengths(ax) == blocklengths(a) - # once `blocklengths(::BlockVector)` is defined. - @test blocklengths(ax) == [4, 3] - @test blocklabels(ax) == blocklabels(a) - - x = gradedrange(["x" => 2, "y" => 3, "z" => 4]) - a = x[[Block(3)[2:3], Block(2)[2:3]]] - @test a isa BlockVector - @test length(a) == 4 - @test blocklength(a) == 2 - # TODO: `BlockArrays` doesn't define `blocklengths` - # for `BlockVector`, should it? - @test_broken blocklengths(a) == [2, 2] - @test blocklabels(a) == ["z", "y"] - @test a[Block(1)] == 7:8 - @test a[Block(2)] == 4:5 - ax = only(axes(a)) - @test ax == 1:length(a) - @test length(ax) == length(a) - # TODO: Change to: - # @test blocklengths(ax) == blocklengths(a) - # once `blocklengths(::BlockVector)` is defined. - @test blocklengths(ax) == [2, 2] - @test blocklabels(ax) == blocklabels(a) - - x = gradedrange(["x" => 2, "y" => 3]) - I = mortar([Block(1)[1:1]]) - a = x[I] - @test length(a) == 1 - @test label(first(a)) == "x" - - x = gradedrange(["x" => 2, "y" => 3])[1:5] - I = mortar([Block(1)[1:1]]) - a = x[I] - @test length(a) == 1 - @test label(first(a)) == "x" -end -end diff --git a/NDTensors/src/lib/GradedAxes/test/test_dual.jl b/NDTensors/src/lib/GradedAxes/test/test_dual.jl deleted file mode 100644 index f2b3072dc1..0000000000 --- a/NDTensors/src/lib/GradedAxes/test/test_dual.jl +++ /dev/null @@ -1,280 +0,0 @@ -@eval module $(gensym()) -using BlockArrays: - Block, - BlockedOneTo, - blockaxes, - blockedrange, - blockfirsts, - blockisequal, - blocklasts, - blocklength, - blocklengths, - blocks, - findblock, - mortar, - combine_blockaxes -using NDTensors.GradedAxes: - AbstractGradedUnitRange, - GradedAxes, - GradedUnitRangeDual, - LabelledUnitRangeDual, - OneToOne, - blocklabels, - blockmergesortperm, - blocksortperm, - dual, - flip, - space_isequal, - gradedrange, - isdual, - nondual -using NDTensors.LabelledNumbers: - LabelledInteger, LabelledUnitRange, label, label_type, labelled, labelled_isequal, unlabel -using Test: @test, @test_broken, @testset -struct U1 - n::Int -end -GradedAxes.dual(c::U1) = U1(-c.n) -Base.isless(c1::U1, c2::U1) = c1.n < c2.n - -@testset "AbstractUnitRange" begin - a0 = OneToOne() - @test !isdual(a0) - @test dual(a0) isa OneToOne - @test space_isequal(a0, a0) - @test labelled_isequal(a0, a0) - @test space_isequal(a0, dual(a0)) - - a = 1:3 - ad = dual(a) - @test !isdual(a) - @test !isdual(ad) - @test ad isa UnitRange - @test space_isequal(ad, a) - - a = blockedrange([2, 3]) - ad = dual(a) - @test !isdual(a) - @test !isdual(ad) - @test ad isa BlockedOneTo - @test blockisequal(ad, a) -end - -@testset "LabelledUnitRangeDual" begin - la = labelled(1:2, U1(1)) - @test la isa LabelledUnitRange - @test label(la) == U1(1) - @test blocklabels(la) == [U1(1)] - @test unlabel(la) == 1:2 - @test la == 1:2 - @test !isdual(la) - @test labelled_isequal(la, la) - @test space_isequal(la, la) - @test label_type(la) == U1 - - @test iterate(la) == (1, 1) - @test iterate(la) == (1, 1) - @test iterate(la, 1) == (2, 2) - @test isnothing(iterate(la, 2)) - - lad = dual(la) - @test lad isa LabelledUnitRangeDual - @test label(lad) == U1(-1) - @test blocklabels(lad) == [U1(-1)] - @test unlabel(lad) == 1:2 - @test lad == 1:2 - @test labelled_isequal(lad, lad) - @test space_isequal(lad, lad) - @test !labelled_isequal(la, lad) - @test !space_isequal(la, lad) - @test isdual(lad) - @test nondual(lad) === la - @test dual(lad) === la - @test label_type(lad) == U1 - - @test iterate(lad) == (1, 1) - @test iterate(lad) == (1, 1) - @test iterate(lad, 1) == (2, 2) - @test isnothing(iterate(lad, 2)) - - lad2 = lad[1:1] - @test lad2 isa LabelledUnitRangeDual - @test label(lad2) == U1(-1) - @test unlabel(lad2) == 1:1 - - laf = flip(la) - @test laf isa LabelledUnitRangeDual - @test label(laf) == U1(1) - @test unlabel(laf) == 1:2 - @test labelled_isequal(la, laf) - @test !space_isequal(la, laf) - - ladf = flip(dual(la)) - @test ladf isa LabelledUnitRange - @test label(ladf) == U1(-1) - @test unlabel(ladf) == 1:2 - - lafd = dual(flip(la)) - @test lafd isa LabelledUnitRange - @test label(lafd) == U1(-1) - @test unlabel(lafd) == 1:2 - - # check default behavior for objects without dual - la = labelled(1:2, 'x') - lad = dual(la) - @test lad isa LabelledUnitRangeDual - @test label(lad) == 'x' - @test blocklabels(lad) == ['x'] - @test unlabel(lad) == 1:2 - @test lad == 1:2 - @test labelled_isequal(lad, lad) - @test space_isequal(lad, lad) - @test labelled_isequal(la, lad) - @test !space_isequal(la, lad) - @test isdual(lad) - @test nondual(lad) === la - @test dual(lad) === la - - laf = flip(la) - @test laf isa LabelledUnitRangeDual - @test label(laf) == 'x' - @test unlabel(laf) == 1:2 - - ladf = flip(lad) - @test ladf isa LabelledUnitRange - @test label(ladf) == 'x' - @test unlabel(ladf) == 1:2 -end - -@testset "GradedUnitRangeDual" begin - for a in - [gradedrange([U1(0) => 2, U1(1) => 3]), gradedrange([U1(0) => 2, U1(1) => 3])[1:5]] - ad = dual(a) - @test ad isa GradedUnitRangeDual - @test ad isa AbstractGradedUnitRange - @test eltype(ad) == LabelledInteger{Int,U1} - @test blocklengths(ad) isa Vector - @test eltype(blocklengths(ad)) == eltype(blocklengths(a)) - - @test space_isequal(dual(ad), a) - @test space_isequal(nondual(ad), a) - @test space_isequal(nondual(a), a) - @test space_isequal(ad, ad) - @test !space_isequal(a, ad) - @test !space_isequal(ad, a) - - @test isdual(ad) - @test !isdual(a) - @test axes(Base.Slice(a)) isa Tuple{typeof(a)} - @test AbstractUnitRange{Int}(ad) == 1:5 - b = combine_blockaxes(ad, ad) - @test b isa GradedUnitRangeDual - @test b == 1:5 - @test space_isequal(b, ad) - - for x in iterate(ad) - @test x == 1 - @test label(x) == U1(0) - end - for x in iterate(ad, labelled(3, U1(-1))) - @test x == 4 - @test label(x) == U1(-1) - end - - @test blockfirsts(ad) == [labelled(1, U1(0)), labelled(3, U1(-1))] - @test blocklasts(ad) == [labelled(2, U1(0)), labelled(5, U1(-1))] - @test blocklength(ad) == 2 - @test blocklengths(ad) == [2, 3] - @test blocklabels(ad) == [U1(0), U1(-1)] - @test label.(blocklengths(ad)) == [U1(0), U1(-1)] - @test findblock(ad, 4) == Block(2) - @test only(blockaxes(ad)) == Block(1):Block(2) - @test blocks(ad) == [labelled(1:2, U1(0)), labelled(3:5, U1(-1))] - @test ad[4] == 4 - @test label(ad[4]) == U1(-1) - @test ad[2:4] == 2:4 - @test ad[2:4] isa GradedUnitRangeDual - @test label(ad[2:4][Block(2)]) == U1(-1) - @test ad[[2, 4]] == [2, 4] - @test label(ad[[2, 4]][2]) == U1(-1) - @test ad[Block(2)] == 3:5 - @test label(ad[Block(2)]) == U1(-1) - @test ad[Block(1):Block(2)][Block(2)] == 3:5 - @test label(ad[Block(1):Block(2)][Block(2)]) == U1(-1) - @test ad[[Block(2), Block(1)]][Block(1)] == 3:5 - @test label(ad[[Block(2), Block(1)]][Block(1)]) == U1(-1) - @test ad[[Block(2)[1:2], Block(1)[1:2]]][Block(1)] == 3:4 - @test label(ad[[Block(2)[1:2], Block(1)[1:2]]][Block(1)]) == U1(-1) - @test blocksortperm(a) == [Block(1), Block(2)] - @test blocksortperm(ad) == [Block(1), Block(2)] - @test blocklength(blockmergesortperm(a)) == 2 - @test blocklength(blockmergesortperm(ad)) == 2 - @test blockmergesortperm(a) == [Block(1), Block(2)] - @test blockmergesortperm(ad) == [Block(1), Block(2)] - - @test isdual(ad[Block(1)]) - @test isdual(ad[Block(1)[1:1]]) - @test ad[Block(1)] isa LabelledUnitRangeDual - @test ad[Block(1)[1:1]] isa LabelledUnitRangeDual - @test label(ad[Block(2)]) == U1(-1) - @test label(ad[Block(2)[1:1]]) == U1(-1) - - v = ad[[Block(2)[1:1]]] - @test v isa AbstractVector{LabelledInteger{Int64,U1}} - @test length(v) == 1 - @test label(first(v)) == U1(-1) - @test unlabel(first(v)) == 3 - @test isdual(v[Block(1)]) - @test isdual(axes(v, 1)) - @test blocklabels(axes(v, 1)) == [U1(-1)] - - v = ad[mortar([Block(2)[1:1]])] - @test v isa AbstractVector{LabelledInteger{Int64,U1}} - @test isdual(axes(v, 1)) # used in view(::BlockSparseVector, [Block(1)[1:1]]) - @test label(first(v)) == U1(-1) - @test unlabel(first(v)) == 3 - @test blocklabels(axes(v, 1)) == [U1(-1)] - - v = ad[[Block(2)]] - @test v isa AbstractVector{LabelledInteger{Int64,U1}} - @test isdual(axes(v, 1)) # used in view(::BlockSparseVector, [Block(1)]) - @test label(first(v)) == U1(-1) - @test unlabel(first(v)) == 3 - @test blocklabels(axes(v, 1)) == [U1(-1)] - - v = ad[mortar([[Block(2)], [Block(1)]])] - @test v isa AbstractVector{LabelledInteger{Int64,U1}} - @test isdual(axes(v, 1)) - @test label(first(v)) == U1(-1) - @test unlabel(first(v)) == 3 - @test blocklabels(axes(v, 1)) == [U1(-1), U1(0)] - end -end - -@testset "flip" begin - for a in - [gradedrange([U1(0) => 2, U1(1) => 3]), gradedrange([U1(0) => 2, U1(1) => 3])[1:5]] - ad = dual(a) - @test space_isequal(flip(a), dual(gradedrange([U1(0) => 2, U1(-1) => 3]))) - @test space_isequal(flip(ad), gradedrange([U1(0) => 2, U1(-1) => 3])) - - @test blocklabels(a) == [U1(0), U1(1)] - @test blocklabels(dual(a)) == [U1(0), U1(-1)] - @test blocklabels(flip(a)) == [U1(0), U1(1)] - @test blocklabels(flip(dual(a))) == [U1(0), U1(-1)] - @test blocklabels(dual(flip(a))) == [U1(0), U1(-1)] - - @test blocklengths(a) == [2, 3] - @test blocklengths(ad) == [2, 3] - @test blocklengths(flip(a)) == [2, 3] - @test blocklengths(flip(ad)) == [2, 3] - @test blocklengths(dual(flip(a))) == [2, 3] - - @test !isdual(a) - @test isdual(ad) - @test isdual(flip(a)) - @test !isdual(flip(ad)) - @test !isdual(dual(flip(a))) - end -end -end diff --git a/NDTensors/src/lib/GradedAxes/test/test_tensor_product.jl b/NDTensors/src/lib/GradedAxes/test/test_tensor_product.jl deleted file mode 100644 index 99e41454ff..0000000000 --- a/NDTensors/src/lib/GradedAxes/test/test_tensor_product.jl +++ /dev/null @@ -1,88 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset - -using BlockArrays: blocklength, blocklengths - -using NDTensors.GradedAxes: - GradedAxes, - GradedOneTo, - OneToOne, - dual, - fusion_product, - flip, - gradedrange, - space_isequal, - isdual, - tensor_product - -using NDTensors.LabelledNumbers: labelled_isequal - -struct U1 - n::Int -end -GradedAxes.dual(c::U1) = U1(-c.n) -Base.isless(c1::U1, c2::U1) = c1.n < c2.n -GradedAxes.fuse_labels(x::U1, y::U1) = U1(x.n + y.n) - -@testset "GradedAxes.tensor_product" begin - GradedAxes.fuse_labels(x::String, y::String) = x * y - - g0 = OneToOne() - @test labelled_isequal(g0, g0) - @test labelled_isequal(tensor_product(g0, g0), g0) - - a = gradedrange(["x" => 2, "y" => 3]) - b = tensor_product(a, a) - @test b isa GradedOneTo - @test length(b) == 25 - @test blocklength(b) == 4 - @test blocklengths(b) == [4, 6, 6, 9] - @test labelled_isequal(b, gradedrange(["xx" => 4, "yx" => 6, "xy" => 6, "yy" => 9])) - - c = tensor_product(a, a, a) - @test c isa GradedOneTo - @test length(c) == 125 - @test blocklength(c) == 8 -end - -@testset "GradedAxes.fusion_product" begin - g0 = OneToOne() - @test labelled_isequal(fusion_product(g0, g0), g0) - - a = gradedrange([U1(1) => 1, U1(2) => 3, U1(1) => 1]) - - b = fusion_product(a) - @test labelled_isequal(b, gradedrange([U1(1) => 2, U1(2) => 3])) - - c = fusion_product(a, a) - @test labelled_isequal(c, gradedrange([U1(2) => 4, U1(3) => 12, U1(4) => 9])) - - d = fusion_product(a, a, a) - @test labelled_isequal( - d, gradedrange([U1(3) => 8, U1(4) => 36, U1(5) => 54, U1(6) => 27]) - ) -end - -@testset "dual and tensor_product" begin - a = gradedrange([U1(1) => 1, U1(2) => 3, U1(1) => 1]) - ad = dual(a) - - b = fusion_product(ad) - @test b isa GradedOneTo - @test !isdual(b) - @test space_isequal(b, gradedrange([U1(-2) => 3, U1(-1) => 2])) - - c = fusion_product(ad, ad) - @test c isa GradedOneTo - @test !isdual(c) - @test space_isequal(c, gradedrange([U1(-4) => 9, U1(-3) => 12, U1(-2) => 4])) - - d = fusion_product(ad, a) - @test !isdual(d) - @test space_isequal(d, gradedrange([U1(-1) => 6, U1(0) => 13, U1(1) => 6])) - - e = fusion_product(a, ad) - @test !isdual(d) - @test space_isequal(e, d) -end -end diff --git a/NDTensors/src/lib/LabelledNumbers/.JuliaFormatter.toml b/NDTensors/src/lib/LabelledNumbers/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/LabelledNumbers/src/LabelledNumbers.jl b/NDTensors/src/lib/LabelledNumbers/src/LabelledNumbers.jl deleted file mode 100644 index 7f54a02f4f..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/src/LabelledNumbers.jl +++ /dev/null @@ -1,8 +0,0 @@ -module LabelledNumbers -include("labelled_interface.jl") -include("labellednumber.jl") -include("labelledinteger.jl") -include("labelledarray.jl") -include("labelledunitrange.jl") -include("LabelledNumbersBlockArraysExt.jl") -end diff --git a/NDTensors/src/lib/LabelledNumbers/src/LabelledNumbersBlockArraysExt.jl b/NDTensors/src/lib/LabelledNumbers/src/LabelledNumbersBlockArraysExt.jl deleted file mode 100644 index 38c8b4e555..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/src/LabelledNumbersBlockArraysExt.jl +++ /dev/null @@ -1,22 +0,0 @@ -using BlockArrays: BlockArrays, Block, blockaxes, blockfirsts, blocklasts - -# Fixes ambiguity error with: -# ```julia -# getindex(::LabelledUnitRange, ::Any...) -# getindex(::AbstractArray{<:Any,N}, ::Block{N}) where {N} -# getindex(::AbstractArray, ::Block{1}, ::Any...) -# ``` -function Base.getindex(a::LabelledUnitRange, index::Block{1}) - @boundscheck index == Block(1) || throw(BlockBoundsError(a, index)) - return a -end - -function BlockArrays.blockaxes(a::LabelledUnitRange) - return blockaxes(unlabel(a)) -end -function BlockArrays.blockfirsts(a::LabelledUnitRange) - return blockfirsts(unlabel(a)) -end -function BlockArrays.blocklasts(a::LabelledUnitRange) - return blocklasts(unlabel(a)) -end diff --git a/NDTensors/src/lib/LabelledNumbers/src/labelled_interface.jl b/NDTensors/src/lib/LabelledNumbers/src/labelled_interface.jl deleted file mode 100644 index fda9ab0ebb..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/src/labelled_interface.jl +++ /dev/null @@ -1,62 +0,0 @@ -# Labelled object interface. -abstract type LabelledStyle end -struct IsLabelled <: LabelledStyle end -struct NotLabelled <: LabelledStyle end -LabelledStyle(::Type) = NotLabelled() -LabelledStyle(object) = LabelledStyle(typeof(object)) -islabelled(::IsLabelled) = true -islabelled(::NotLabelled) = false -islabelled(object) = islabelled(LabelledStyle(object)) -label(object) = error("This object does not have a label.") -# TODO: Use `TypeParameterAccessors`. -label_type(::Type) = error("No label type defined.") -label_type(object) = typeof(label(object)) -labelled(object, label) = error("Can't add a label to this object.") -# TODO: Turn into a trait function. -function set_label(object, label) - if islabelled(object) - object = unlabel(object) - end - return labelled(object, label) -end -unlabel(object) = object -unlabel_type(type::Type) = type -unlabel_type(object) = typeof(unlabel(object)) - -set_value(x, value) = labelled(value, label(x)) - -labelled_zero(x) = set_value(x, zero(unlabel(x))) -labelled_one(x) = one(unlabel(x)) -labelled_one(type::Type) = one(unlabel_type(type)) -labelled_oneunit(x) = set_value(x, one(x)) -# TODO: Implement this for types where the label is -# encoded in the type. -labelled_oneunit(type::Type) = error("Not implemented.") - -function labelled_binary_op(f, x, y) - return labelled_binary_op(f, LabelledStyle(x), x, LabelledStyle(y), y) -end -labelled_binary_op(f, ::LabelledStyle, x, ::LabelledStyle, y) = f(unlabel(x), unlabel(y)) - -# TODO: This is only needed for older Julia versions, like Julia 1.6. -# Delete once we drop support for older Julia versions. -labelled_minus(x) = set_value(x, -unlabel(x)) - -# TODO: This is only needed for older Julia versions, like Julia 1.6. -# Delete once we drop support for older Julia versions. -labelled_hash(x, h::UInt64) = hash(unlabel(x), h) - -for (fname, f) in [ - (:mul, :*), - (:add, :+), - (:minus, :-), - (:division, :/), - (:div, :÷), - (:isequal, :isequal), - (:isless, :isless), -] - labelled_fname = Symbol(:(labelled_), fname) - @eval begin - $labelled_fname(x, y) = labelled_binary_op($f, x, y) - end -end diff --git a/NDTensors/src/lib/LabelledNumbers/src/labelledarray.jl b/NDTensors/src/lib/LabelledNumbers/src/labelledarray.jl deleted file mode 100644 index f9dbedb8b7..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/src/labelledarray.jl +++ /dev/null @@ -1,20 +0,0 @@ -struct LabelledArray{T,N,Value<:AbstractArray{T,N},Label} <: - AbstractArray{LabelledInteger{T,Label},N} - value::Value - label::Label -end -LabelledStyle(::Type{<:LabelledArray}) = IsLabelled() -label(lobject::LabelledArray) = lobject.label -# TODO: Use `TypeParameterAccessors`. -label_type(::Type{<:LabelledArray{<:Any,Label}}) where {Label} = Label -labelled(object::AbstractArray, label) = LabelledArray(object, label) -unlabel(lobject::LabelledArray) = lobject.value -unlabel_type(::Type{<:LabelledArray{Value}}) where {Value} = Value - -for f in [:axes] - @eval Base.$f(a::LabelledArray, args...) = $f(unlabel(a), args...) -end - -for f in [:first, :getindex, :last, :length] - @eval Base.$f(a::LabelledArray, args...) = labelled($f(unlabel(a), args...), label(a)) -end diff --git a/NDTensors/src/lib/LabelledNumbers/src/labelledinteger.jl b/NDTensors/src/lib/LabelledNumbers/src/labelledinteger.jl deleted file mode 100644 index 56ad8e30fc..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/src/labelledinteger.jl +++ /dev/null @@ -1,123 +0,0 @@ -struct LabelledInteger{Value<:Integer,Label} <: Integer - value::Value - label::Label -end -LabelledStyle(::Type{<:LabelledInteger}) = IsLabelled() -# TODO: Define `set_value` and `set_label`? -label(lobject::LabelledInteger) = lobject.label -# TODO: Use `TypeParameterAccessors`. -label_type(::Type{<:LabelledInteger{<:Any,Label}}) where {Label} = Label -labelled(object::Integer, label) = LabelledInteger(object, label) -unlabel(lobject::LabelledInteger) = lobject.value -unlabel_type(::Type{<:LabelledInteger{Value}}) where {Value} = Value - -# When using as shapes of arrays. -# TODO: Preserve the label? For example: -# labelled(Base.to_shape(unlabel(x)), label(x)) -Base.to_shape(x::LabelledInteger) = Base.to_shape(unlabel(x)) - -# TODO: Define `labelled_convert`. -Base.convert(type::Type{<:Number}, x::LabelledInteger) = type(unlabel(x)) -# TODO: This is only needed for older Julia versions, like Julia 1.6. -# Delete once we drop support for older Julia versions. -function Base.convert(type::Type{<:LabelledInteger}, x::LabelledInteger) - return type(unlabel(x), label(x)) -end - -# Used by `Base.hash(::Integer)`. -# TODO: Define `labelled_trailing_zeros` to be used by other -# labelled number types. -Base.trailing_zeros(x::LabelledInteger) = trailing_zeros(unlabel(x)) - -# Used by `Base.hash(::Integer)`. -# TODO: Define `labelled_right_bit_shift` to be used by other -# labelled number types. -Base.:>>(x::LabelledInteger, y::Int) = >>(unlabel(x), y) - -Base.:(==)(x::LabelledInteger, y::LabelledInteger) = labelled_isequal(x, y) -Base.:(==)(x::LabelledInteger, y::Number) = labelled_isequal(x, y) -Base.:(==)(x::Number, y::LabelledInteger) = labelled_isequal(x, y) -Base.:<(x::LabelledInteger, y::LabelledInteger) = labelled_isless(x, y) -# This is only needed on older versions of Julia, like Julia 1.6. -# TODO: Delete once we drop support for Julia 1.6. -function Base.:<=(x::LabelledInteger, y::LabelledInteger) - return labelled_isless(x, y) || labelled_isequal(x, y) -end -# TODO: Define `labelled_colon`. -(::Base.Colon)(start::LabelledInteger, stop::LabelledInteger) = unlabel(start):unlabel(stop) -Base.zero(lobject::LabelledInteger) = labelled_zero(lobject) -Base.one(lobject::LabelledInteger) = labelled_one(lobject) -Base.one(type::Type{<:LabelledInteger}) = labelled_one(type) -Base.oneunit(lobject::LabelledInteger) = labelled_oneunit(lobject) -Base.oneunit(type::Type{<:LabelledInteger}) = oneunit(unlabel_type(type)) -Base.zero(type::Type{<:LabelledInteger}) = zero(unlabel_type(type)) - -Base.Int(x::LabelledInteger) = Int(unlabel(x)) - -Base.:+(x::LabelledInteger, y::LabelledInteger) = labelled_add(x, y) -Base.:+(x::LabelledInteger, y::Number) = labelled_add(x, y) -Base.:+(x::Number, y::LabelledInteger) = labelled_add(x, y) -# Fix ambiguity error with `+(::Integer, ::Integer)`. -Base.:+(x::LabelledInteger, y::Integer) = labelled_add(x, y) -Base.:+(x::Integer, y::LabelledInteger) = labelled_add(x, y) - -Base.:-(x::LabelledInteger, y::LabelledInteger) = labelled_minus(x, y) -Base.:-(x::LabelledInteger, y::Number) = labelled_minus(x, y) -Base.:-(x::Number, y::LabelledInteger) = labelled_minus(x, y) -# Fix ambiguity error with `-(::Integer, ::Integer)`. -Base.:-(x::LabelledInteger, y::Integer) = labelled_minus(x, y) -Base.:-(x::Integer, y::LabelledInteger) = labelled_minus(x, y) - -function Base.sub_with_overflow(x::LabelledInteger, y::LabelledInteger) - return labelled_binary_op(Base.sub_with_overflow, x, y) -end - -Base.:*(x::LabelledInteger, y::LabelledInteger) = labelled_mul(x, y) -Base.:*(x::LabelledInteger, y::Number) = labelled_mul(x, y) -Base.:*(x::Number, y::LabelledInteger) = labelled_mul(x, y) -# Fix ambiguity issue with `Base` `Integer`. -Base.:*(x::LabelledInteger, y::Integer) = labelled_mul(x, y) -# Fix ambiguity issue with `Base` `Integer`. -Base.:*(x::Integer, y::LabelledInteger) = labelled_mul(x, y) - -Base.:/(x::LabelledInteger, y::Number) = labelled_division(x, y) -Base.div(x::LabelledInteger, y::Number) = labelled_div(x, y) - -# TODO: This is only needed for older Julia versions, like Julia 1.6. -# Delete once we drop support for older Julia versions. -# TODO: Define in terms of a generic `labelled_minus` function. -# TODO: Define in terms of `set_value`? -Base.:-(x::LabelledInteger) = labelled_minus(x) - -# TODO: This is only needed for older Julia versions, like Julia 1.6. -# Delete once we drop support for older Julia versions. -Base.hash(x::LabelledInteger, h::UInt64) = labelled_hash(x, h) - -using Random: AbstractRNG, default_rng -default_eltype() = Float64 -for f in [:rand, :randn] - @eval begin - function Base.$f( - rng::AbstractRNG, - elt::Type{<:Number}, - dims::Tuple{LabelledInteger,Vararg{LabelledInteger}}, - ) - return a = $f(rng, elt, unlabel.(dims)) - end - function Base.$f( - rng::AbstractRNG, - elt::Type{<:Number}, - dim1::LabelledInteger, - dims::Vararg{LabelledInteger}, - ) - return $f(rng, elt, (dim1, dims...)) - end - Base.$f(elt::Type{<:Number}, dims::Tuple{LabelledInteger,Vararg{LabelledInteger}}) = - $f(default_rng(), elt, dims) - Base.$f(elt::Type{<:Number}, dim1::LabelledInteger, dims::Vararg{LabelledInteger}) = - $f(elt, (dim1, dims...)) - Base.$f(dims::Tuple{LabelledInteger,Vararg{LabelledInteger}}) = - $f(default_eltype(), dims) - Base.$f(dim1::LabelledInteger, dims::Vararg{LabelledInteger}) = $f((dim1, dims...)) - end -end diff --git a/NDTensors/src/lib/LabelledNumbers/src/labellednumber.jl b/NDTensors/src/lib/LabelledNumbers/src/labellednumber.jl deleted file mode 100644 index 09a30a456b..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/src/labellednumber.jl +++ /dev/null @@ -1,41 +0,0 @@ -struct LabelledNumber{Value<:Number,Label} <: Number - value::Value - label::Label -end -LabelledStyle(::Type{<:LabelledNumber}) = IsLabelled() -label(lobject::LabelledNumber) = lobject.label -# TODO: Use `TypeParameterAccessors`. -label_type(::Type{<:LabelledNumber{<:Any,Label}}) where {Label} = Label -labelled(object::Number, label) = LabelledNumber(object, label) -unlabel(lobject::LabelledNumber) = lobject.value -unlabel_type(::Type{<:LabelledNumber{Value}}) where {Value} = Value - -# TODO: Define `labelled_convert`. -Base.convert(type::Type{<:Number}, x::LabelledNumber) = type(unlabel(x)) - -Base.:(==)(x::LabelledNumber, y::LabelledNumber) = labelled_isequal(x, y) -Base.:<(x::LabelledNumber, y::LabelledNumber) = labelled_isless(x < y) -# TODO: Define `labelled_colon`. -(::Base.Colon)(start::LabelledNumber, stop::LabelledNumber) = unlabel(start):unlabel(stop) -Base.zero(lobject::LabelledNumber) = labelled_zero(lobject) -Base.one(lobject::LabelledNumber) = labelled_one(lobject) -Base.one(type::Type{<:LabelledNumber}) = labelled_one(type) -Base.oneunit(lobject::LabelledNumber) = labelled_oneunit(lobject) -Base.oneunit(type::Type{<:LabelledNumber}) = error("Not implemented.") - -Base.:*(x::LabelledNumber, y::LabelledNumber) = labelled_mul(x, y) -Base.:*(x::LabelledNumber, y::Number) = labelled_mul(x, y) -Base.:*(x::Number, y::LabelledNumber) = labelled_mul(x, y) - -Base.:/(x::LabelledNumber, y::Number) = labelled_division(x, y) -Base.div(x::LabelledNumber, y::Number) = labelled_div(x, y) - -# TODO: This is only needed for older Julia versions, like Julia 1.6. -# Delete once we drop support for older Julia versions. -# TODO: Define in terms of a generic `labelled_minus` function. -# TODO: Define in terms of `set_value`? -Base.:-(x::LabelledNumber) = labelled_minus(x) - -# TODO: This is only needed for older Julia versions, like Julia 1.6. -# Delete once we drop support for older Julia versions. -Base.hash(x::LabelledNumber, h::UInt64) = labelled_hash(x, h) diff --git a/NDTensors/src/lib/LabelledNumbers/src/labelledunitrange.jl b/NDTensors/src/lib/LabelledNumbers/src/labelledunitrange.jl deleted file mode 100644 index 4f432c9226..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/src/labelledunitrange.jl +++ /dev/null @@ -1,63 +0,0 @@ -struct LabelledUnitRange{T,Value<:AbstractUnitRange{T},Label} <: - AbstractUnitRange{LabelledInteger{T,Label}} - value::Value - label::Label -end -LabelledStyle(::Type{<:LabelledUnitRange}) = IsLabelled() -label(lobject::LabelledUnitRange) = lobject.label -# TODO: Use `TypeParameterAccessors`. -label_type(::Type{<:LabelledUnitRange{<:Any,Label}}) where {Label} = Label -labelled(object::AbstractUnitRange, label) = LabelledUnitRange(object, label) -unlabel(lobject::LabelledUnitRange) = lobject.value -unlabel_type(::Type{<:LabelledUnitRange{Value}}) where {Value} = Value - -# Used by `CartesianIndices` constructor. -# TODO: Maybe reconsider this definition? Also, this should preserve -# the label if possible, currently it drops the label. -function Base.AbstractUnitRange{T}(a::LabelledUnitRange) where {T} - return AbstractUnitRange{T}(unlabel(a)) -end - -# TODO: Is this a good definition? -Base.unitrange(a::LabelledUnitRange) = a - -for f in [:first, :getindex, :last, :length, :step] - @eval Base.$f(a::LabelledUnitRange, args...) = labelled($f(unlabel(a), args...), label(a)) -end - -labelled_getindex(a, index) = labelled(unlabel(a)[index], label(a)) - -# This is required in Julia 1.11 and above since -# the generic `axes(a::AbstractRange)` definition was removed -# and replace with a generic `axes(a)` definition that -# is written in terms of `Base.unchecked_oneto`, i.e.: -# ```julia -# map(Base.unchecked_oneto, size(A)) -# ``` -# which returns a `Base.OneTo` instead of a `LabelledUnitRange`. -Base.axes(a::LabelledUnitRange) = Base.oneto.(size(a)) - -# TODO: Delete this definition, this should output a `Base.OneTo`. -Base.OneTo(stop::LabelledInteger) = labelled(Base.OneTo(unlabel(stop)), label(stop)) - -# Fix ambiguity error with `AbstractRange` definition in `Base`. -Base.getindex(a::LabelledUnitRange, index::Integer) = labelled_getindex(a, index) -# Fix ambiguity error with `AbstractRange` definition in `Base`. -function Base.getindex(a::LabelledUnitRange, indices::AbstractUnitRange{<:Integer}) - return labelled_getindex(a, indices) -end - -function Base.iterate(a::LabelledUnitRange, i) - i == last(a) && return nothing - next = convert(eltype(a), labelled(i + step(a), label(a))) - return (next, next) -end - -function Base.show(io::IO, ::MIME"text/plain", a::LabelledUnitRange) - println(io, typeof(a)) - return print(io, label(a), " => ", unlabel(a)) -end - -function Base.show(io::IO, a::LabelledUnitRange) - return print(io, nameof(typeof(a)), " ", label(a), " => ", unlabel(a)) -end diff --git a/NDTensors/src/lib/LabelledNumbers/test/Project.toml b/NDTensors/src/lib/LabelledNumbers/test/Project.toml deleted file mode 100644 index d1bf575ce0..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/LabelledNumbers/test/runtests.jl b/NDTensors/src/lib/LabelledNumbers/test/runtests.jl deleted file mode 100644 index f7b2084805..0000000000 --- a/NDTensors/src/lib/LabelledNumbers/test/runtests.jl +++ /dev/null @@ -1,132 +0,0 @@ -@eval module $(gensym()) -using LinearAlgebra: norm -using NDTensors.LabelledNumbers: - LabelledInteger, LabelledUnitRange, islabelled, label, labelled, unlabel -using Test: @test, @testset -@testset "LabelledNumbers" begin - @testset "Labelled number ($n)" for n in (2, 2.0) - x = labelled(2, "x") - @test typeof(x) == LabelledInteger{Int,String} - @test islabelled(x) - @test x == 2 - @test label(x) == "x" - @test unlabel(x) == 2 - @test !islabelled(unlabel(x)) - - @test labelled(1, "x") < labelled(2, "x") - @test !(labelled(2, "x") < labelled(2, "x")) - @test !(labelled(3, "x") < labelled(2, "x")) - - @test !(labelled(1, "x") > labelled(2, "x")) - @test !(labelled(2, "x") > labelled(2, "x")) - @test labelled(3, "x") > labelled(2, "x") - - @test labelled(1, "x") <= labelled(2, "x") - @test labelled(2, "x") <= labelled(2, "x") - @test !(labelled(3, "x") <= labelled(2, "x")) - - @test !(labelled(1, "x") >= labelled(2, "x")) - @test labelled(2, "x") >= labelled(2, "x") - @test labelled(3, "x") >= labelled(2, "x") - - @test x * 2 == 4 - @test !islabelled(x * 2) - @test 2 * x == 4 - @test !islabelled(2 * x) - @test x * x == 4 - @test !islabelled(x * x) - - @test x + 3 == 5 - @test !islabelled(x + 3) - @test 3 + x == 5 - @test !islabelled(3 + x) - @test x + x == 4 - @test !islabelled(x + x) - - @test x - 3 == -1 - @test !islabelled(x - 3) - @test 3 - x == 1 - @test !islabelled(3 - x) - @test x - x == 0 - @test !islabelled(x - x) - - @test x / 2 == 1 - @test x / 2 isa AbstractFloat - @test x / 2 isa Float64 - @test !islabelled(x / 2) - @test x ÷ 2 == 1 - @test x ÷ 2 isa Integer - @test x ÷ 2 isa Int - @test !islabelled(x ÷ 2) - @test -x == -2 - @test hash(x) == hash(2) - @test zero(x) == false - @test label(zero(x)) == "x" - @test one(x) == true - @test !islabelled(one(x)) - @test oneunit(x) == true - @test label(oneunit(x)) == "x" - @test islabelled(oneunit(x)) - @test one(typeof(x)) == true - @test !islabelled(one(typeof(x))) - end - @testset "randn" begin - d = labelled(2, "x") - - a = randn(Float32, d, d) - @test eltype(a) === Float32 - @test size(a) == (2, 2) - @test norm(a) > 0 - - a = rand(Float32, d, d) - @test eltype(a) === Float32 - @test size(a) == (2, 2) - @test norm(a) > 0 - - a = randn(d, d) - @test eltype(a) === Float64 - @test size(a) == (2, 2) - @test norm(a) > 0 - - a = rand(d, d) - @test eltype(a) === Float64 - @test size(a) == (2, 2) - @test norm(a) > 0 - end - @testset "Labelled array ($a)" for a in (collect(2:5), 2:5) - x = labelled(a, "x") - @test eltype(x) == LabelledInteger{Int,String} - @test x == 2:5 - @test label(x) == "x" - @test unlabel(x) == 2:5 - @test first(iterate(x, 3)) == 4 - @test label(first(iterate(x, 3))) == "x" - @test collect(x) == 2:5 - @test label.(collect(x)) == fill("x", 4) - @test x[2] == 3 - @test label(x[2]) == "x" - @test x[2:3] == 3:4 - @test label(x[2:3]) == "x" - @test x[[2, 4]] == [3, 5] - @test label(x[[2, 4]]) == "x" - - if x isa AbstractUnitRange - @test step(x) == true - @test islabelled(step(x)) - @test label(step(x)) == "x" - end - end -end - -using BlockArrays: Block, blockaxes, blocklength, blocklengths -@testset "LabelledNumbersBlockArraysExt" begin - x = labelled(1:2, "x") - @test blockaxes(x) == (Block.(1:1),) - @test blocklength(x) == 1 - @test blocklengths(x) == [2] - a = x[Block(1)] - @test a == 1:2 - @test a isa LabelledUnitRange - @test label(a) == "x" -end -end diff --git a/NDTensors/src/lib/NamedDimsArrays/.JuliaFormatter.toml b/NDTensors/src/lib/NamedDimsArrays/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/NamedDimsArrays/README.md b/NDTensors/src/lib/NamedDimsArrays/README.md deleted file mode 100644 index ab0c19d38f..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# NamedDimsArrays.jl - -````julia -using NDTensors.NamedDimsArrays: align, dimnames, named, unname -using NDTensors.TensorAlgebra: TensorAlgebra - -# Named dimensions -i = named(2, "i") -j = named(2, "j") -k = named(2, "k") - -# Arrays with named dimensions -na1 = randn(i, j) -na2 = randn(j, k) - -@show dimnames(na1) == ("i", "j") - -# Indexing -@show na1[j => 2, i => 1] == na1[1, 2] - -# Tensor contraction -na_dest = TensorAlgebra.contract(na1, na2) - -@show issetequal(dimnames(na_dest), ("i", "k")) -# `unname` removes the names and returns an `Array` -@show unname(na_dest, (i, k)) ≈ unname(na1) * unname(na2) - -# Permute dimensions (like `ITensors.permute`) -na1 = align(na1, (j, i)) -@show na1[i => 1, j => 2] == na1[2, 1] -```` - ---- - -*This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).* - diff --git a/NDTensors/src/lib/NamedDimsArrays/examples/example_readme.jl b/NDTensors/src/lib/NamedDimsArrays/examples/example_readme.jl deleted file mode 100644 index 389e2b3984..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/examples/example_readme.jl +++ /dev/null @@ -1,29 +0,0 @@ -# # NamedDimsArrays.jl - -using NDTensors.NamedDimsArrays: align, dimnames, named, unname -using NDTensors.TensorAlgebra: TensorAlgebra - -## Named dimensions -i = named(2, "i") -j = named(2, "j") -k = named(2, "k") - -## Arrays with named dimensions -na1 = randn(i, j) -na2 = randn(j, k) - -@show dimnames(na1) == ("i", "j") - -## Indexing -@show na1[j => 2, i => 1] == na1[1, 2] - -## Tensor contraction -na_dest = TensorAlgebra.contract(na1, na2) - -@show issetequal(dimnames(na_dest), ("i", "k")) -## `unname` removes the names and returns an `Array` -@show unname(na_dest, (i, k)) ≈ unname(na1) * unname(na2) - -## Permute dimensions (like `ITensors.permute`) -na1 = align(na1, (j, i)) -@show na1[i => 1, j => 2] == na1[2, 1] diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/NamedDimsArraysAdaptExt.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/NamedDimsArraysAdaptExt.jl deleted file mode 100644 index 027dd65ca6..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/NamedDimsArraysAdaptExt.jl +++ /dev/null @@ -1,3 +0,0 @@ -module NamedDimsArraysAdaptExt -include("adapt_structure.jl") -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/adapt_structure.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/adapt_structure.jl deleted file mode 100644 index 97c075d628..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/src/adapt_structure.jl +++ /dev/null @@ -1,6 +0,0 @@ -using Adapt: Adapt, adapt -using NDTensors.NamedDimsArrays: AbstractNamedDimsArray, dimnames, named, unname - -function Adapt.adapt_structure(to, na::AbstractNamedDimsArray) - return named(adapt(to, unname(na)), dimnames(na)) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/Project.toml b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/Project.toml deleted file mode 100644 index a970d0f894..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/runtests.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/runtests.jl deleted file mode 100644 index 733da91df2..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysAdaptExt/test/runtests.jl +++ /dev/null @@ -1,13 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using Adapt: adapt -using NDTensors.NamedDimsArrays: named -@testset "NamedDimsArraysAdaptExt (eltype=$elt)" for elt in ( - Float32, Float64, Complex{Float32}, Complex{Float64} -) - na = named(randn(2, 2), ("i", "j")) - na_complex = adapt(Array{complex(elt)}, na) - @test na ≈ na_complex - @test eltype(na_complex) === complex(elt) -end -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/NamedDimsArraysSparseArraysBaseExt.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/NamedDimsArraysSparseArraysBaseExt.jl deleted file mode 100644 index aef726d2dc..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/NamedDimsArraysSparseArraysBaseExt.jl +++ /dev/null @@ -1,3 +0,0 @@ -module NamedDimsArraysSparseArraysBaseExt -include("densearray.jl") -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/densearray.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/densearray.jl deleted file mode 100644 index db9da0c76c..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/src/densearray.jl +++ /dev/null @@ -1,8 +0,0 @@ -using ..NamedDimsArrays: AbstractNamedDimsArray, dimnames, named, unname -using ...SparseArraysBase: SparseArraysBase, densearray - -# TODO: Use `Adapt` or some kind of rewrap function like in -# ArrayInterface.jl (https://github.com/JuliaArrays/ArrayInterface.jl/issues/136) -function SparseArraysBase.densearray(na::AbstractNamedDimsArray) - return named(densearray(unname(na)), dimnames(na)) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/Project.toml b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/Project.toml deleted file mode 100644 index c13dac32a6..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/runtests.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/runtests.jl deleted file mode 100644 index bc87d642fb..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysSparseArraysBaseExt/test/runtests.jl +++ /dev/null @@ -1,12 +0,0 @@ -@eval module $(gensym()) -using LinearAlgebra: Diagonal -using Test: @test, @testset -using NDTensors.SparseArraysBase: densearray -using NDTensors.NamedDimsArrays: named, unname -@testset "NamedDimsArraysSparseArraysBaseExt (eltype=$elt)" for elt in (Float32, Float64) - na = named(Diagonal(randn(2)), ("i", "j")) - na_dense = densearray(na) - @test na ≈ na_dense - @test unname(na_dense) isa Array -end -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/NamedDimsArraysTensorAlgebraExt.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/NamedDimsArraysTensorAlgebraExt.jl deleted file mode 100644 index a397507f44..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/NamedDimsArraysTensorAlgebraExt.jl +++ /dev/null @@ -1,7 +0,0 @@ -module NamedDimsArraysTensorAlgebraExt -include("contract.jl") -include("fusedims.jl") -include("qr.jl") -include("eigen.jl") -include("svd.jl") -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/contract.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/contract.jl deleted file mode 100644 index f45391eea9..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/contract.jl +++ /dev/null @@ -1,31 +0,0 @@ -using ..NamedDimsArrays: AbstractNamedDimsArray, dimnames, named, unname -using ...TensorAlgebra: TensorAlgebra, blockedperms, contract, contract! - -function TensorAlgebra.contract!( - na_dest::AbstractNamedDimsArray, - na1::AbstractNamedDimsArray, - na2::AbstractNamedDimsArray, - α::Number=true, - β::Number=false, -) - contract!( - unname(na_dest), - dimnames(na_dest), - unname(na1), - dimnames(na1), - unname(na2), - dimnames(na2), - α, - β, - ) - return na_dest -end - -function TensorAlgebra.contract( - na1::AbstractNamedDimsArray, na2::AbstractNamedDimsArray, α::Number=true -) - a_dest, dimnames_dest = contract( - unname(na1), dimnames(na1), unname(na2), dimnames(na2), α - ) - return named(a_dest, dimnames_dest) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/eigen.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/eigen.jl deleted file mode 100644 index 31a7e6d5b1..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/eigen.jl +++ /dev/null @@ -1,47 +0,0 @@ -## using ..ITensors: IndexID -using LinearAlgebra: LinearAlgebra, Diagonal, Hermitian, eigen -## using ..NDTensors.DiagonalArrays: DiagonalMatrix -using ...NDTensors.NamedDimsArrays: AbstractNamedDimsArray, dimnames, name, unname -using ...NDTensors.RankFactorization: Spectrum, truncate!! -function LinearAlgebra.eigen( - na::Hermitian{T,<:AbstractNamedDimsArray{T}}; - mindim=nothing, - maxdim=nothing, - cutoff=nothing, - use_absolute_cutoff=nothing, - use_relative_cutoff=nothing, -) where {T<:Union{Real,Complex}} - # TODO: Handle array wrappers around - # `AbstractNamedDimsArray` more elegantly. - d, u = eigen(Hermitian(unname(parent(na)))) - - # Sort by largest to smallest eigenvalues - # TODO: Replace `cpu` with `Expose` dispatch. - p = sortperm(d; rev=true, by=abs) - d = d[p] - u = u[:, p] - - length_d = length(d) - truncerr = zero(Float64) # Make more generic - if any(!isnothing, (maxdim, cutoff)) - d, truncerr, _ = truncate!!( - d; mindim, maxdim, cutoff, use_absolute_cutoff, use_relative_cutoff - ) - length_d = length(d) - if length_d < size(u, 2) - u = u[:, 1:length_d] - end - end - spec = Spectrum(d, truncerr) - - # TODO: Handle array wrappers more generally. - names_a = dimnames(parent(na)) - # TODO: Make this more generic, handle `dag`, etc. - l = randname(names_a[1]) # IndexID(rand(UInt64), "", 0) - r = randname(names_a[2]) # IndexID(rand(UInt64), "", 0) - names_d = (l, r) - nd = named(Diagonal(d), names_d) - names_u = (names_a[2], r) - nu = named(u, names_u) - return nd, nu, spec -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/fusedims.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/fusedims.jl deleted file mode 100644 index 9b0247925e..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/fusedims.jl +++ /dev/null @@ -1,52 +0,0 @@ -using ...NDTensors.TensorAlgebra: TensorAlgebra, blockedperm, fusedims, splitdims -using ...NDTensors.TensorAlgebra.BaseExtensions: BaseExtensions - -function TensorAlgebra.blockedperm(na::AbstractNamedDimsArray, nameddim_blocks::Tuple...) - # Extract names if named dimensions or axes were passed - dimname_blocks = map(group -> name.(group), nameddim_blocks) - dimnames_a = dimnames(na) - perms = map(dimname_blocks) do dimname_block - return BaseExtensions.indexin(dimname_block, dimnames_a) - end - return blockedperm(perms...) -end - -# i, j, k, l = named.((2, 2, 2, 2), ("i", "j", "k", "l")) -# a = randn(i, j, k, l) -# fusedims(a, (i, k) => "a") -# fusedims(a, (i, k) => "a", (j, l) => "b") -# TODO: Rewrite in terms of `fusedims(a, .., (1, 3))` interface. -function TensorAlgebra.fusedims(na::AbstractNamedDimsArray, fusions::Pair...) - dimnames_fuse = map(group -> name.(group), first.(fusions)) - dimnames_fused = map(name, last.(fusions)) - if sum(length, dimnames_fuse) < ndims(na) - # Not all names are specified - dimnames_unspecified = setdiff(dimnames(na), dimnames_fuse...) - dimnames_fuse = vcat(tuple.(dimnames_unspecified), collect(dimnames_fuse)) - dimnames_fused = vcat(dimnames_unspecified, collect(dimnames_fused)) - end - perm = blockedperm(na, dimnames_fuse...) - a_fused = fusedims(unname(na), perm) - return named(a_fused, dimnames_fused) -end - -function TensorAlgebra.splitdims(na::AbstractNamedDimsArray, splitters::Pair...) - fused_names = map(name, first.(splitters)) - split_namedlengths = last.(splitters) - splitters_unnamed = map(splitters) do splitter - fused_name, split_namedlengths = splitter - fused_dim = findfirst(isequal(fused_name), dimnames(na)) - split_lengths = unname.(split_namedlengths) - return fused_dim => split_lengths - end - a_split = splitdims(unname(na), splitters_unnamed...) - names_split = Any[tuple.(dimnames(na))...] - for splitter in splitters - fused_name, split_namedlengths = splitter - fused_dim = findfirst(isequal(fused_name), dimnames(na)) - split_names = name.(split_namedlengths) - names_split[fused_dim] = split_names - end - names_split = reduce((x, y) -> (x..., y...), names_split) - return named(a_split, names_split) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/qr.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/qr.jl deleted file mode 100644 index 329b98574a..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/qr.jl +++ /dev/null @@ -1,18 +0,0 @@ -# using ..ITensors: IndexID -using LinearAlgebra: LinearAlgebra, qr -using ...NDTensors.NamedDimsArrays: AbstractNamedDimsArray, dimnames, name, randname, unname - -function LinearAlgebra.qr(na::AbstractNamedDimsArray; positive=nothing) - return qr(na, (dimnames(na, 1),), (dimnames(na, 2),); positive) -end - -function LinearAlgebra.qr( - na::AbstractNamedDimsArray, labels_codomain::Tuple, labels_domain::Tuple; positive=nothing -) - @assert isnothing(positive) || !positive - q, r = qr(unname(na), dimnames(na), name.(labels_codomain), name.(labels_domain)) - name_qr = randname(dimnames(na)[1]) - dimnames_q = (name.(labels_codomain)..., name_qr) - dimnames_r = (name_qr, name.(labels_domain)...) - return named(q, dimnames_q), named(r, dimnames_r) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/svd.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/svd.jl deleted file mode 100644 index 787f89e3f0..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/src/svd.jl +++ /dev/null @@ -1,53 +0,0 @@ -using LinearAlgebra: LinearAlgebra, svd -using ...NDTensors.RankFactorization: Spectrum, truncate!! -function LinearAlgebra.svd( - na::AbstractNamedDimsArray; - mindim=nothing, - maxdim=nothing, - cutoff=nothing, - use_absolute_cutoff=nothing, - use_relative_cutoff=nothing, - alg=nothing, - min_blockdim=nothing, -) - # TODO: Handle array wrappers around - # `AbstractNamedDimsArray` more elegantly. - USV = svd(unname(na)) - u, s, v = USV.U, USV.S, USV.Vt - - # Sort by largest to smallest eigenvalues - # TODO: Replace `cpu` with `Expose` dispatch. - p = sortperm(s; rev=true, by=abs) - u = u[:, p] - s = s[p] - v = v[p, :] - - s² = s .^ 2 - length_s = length(s) - truncerr = zero(Float64) # Make more generic - if any(!isnothing, (maxdim, cutoff)) - s², truncerr, _ = truncate!!( - s²; mindim, maxdim, cutoff, use_absolute_cutoff, use_relative_cutoff - ) - length_s = length(s²) - # TODO: Avoid this if they are already the - # correct size. - u = u[:, 1:length_s] - s = s[1:length_s] - v = v[1:length_s, :] - end - spec = Spectrum(s², truncerr) - - # TODO: Handle array wrappers more generally. - names_a = dimnames(na) - # TODO: Make this more generic, handle `dag`, etc. - l = randname(names_a[1]) # IndexID(rand(UInt64), "", 0) - r = randname(names_a[2]) # IndexID(rand(UInt64), "", 0) - names_u = (names_a[1], l) - nu = named(u, names_u) - names_s = (l, r) - ns = named(Diagonal(s), names_s) - names_v = (r, names_a[2]) - nv = named(v, names_v) - return nu, ns, nv, spec -end diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/Project.toml b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/Project.toml deleted file mode 100644 index ef491a529c..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/runtests.jl b/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/runtests.jl deleted file mode 100644 index a73edfd8c6..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/ext/NamedDimsArraysTensorAlgebraExt/test/runtests.jl +++ /dev/null @@ -1,59 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset, @test_broken -using NDTensors.NamedDimsArrays: named, unname -using NDTensors.TensorAlgebra: TensorAlgebra, contract, fusedims, splitdims -using LinearAlgebra: qr -elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) -@testset "NamedDimsArraysTensorAlgebraExt (eltype=$(elt))" for elt in elts - @testset "contract" begin - i = named(2, "i") - j = named(2, "j") - k = named(2, "k") - na1 = randn(elt, i, j) - na2 = randn(elt, j, k) - na_dest = TensorAlgebra.contract(na1, na2) - @test eltype(na_dest) === elt - @test unname(na_dest, (i, k)) ≈ unname(na1) * unname(na2) - end - @testset "fusedims" begin - i, j, k, l = named.((2, 3, 4, 5), ("i", "j", "k", "l")) - na = randn(elt, i, j, k, l) - na_fused = fusedims(na, (k, i) => "a", (j, l) => "b") - # Fuse all dimensions. - @test unname(na_fused, ("a", "b")) ≈ - reshape(unname(na, (k, i, j, l)), (unname(k) * unname(i), unname(j) * unname(l))) - na_fused = fusedims(na, (k, i) => "a") - # Fuse a subset of dimensions. - @test unname(na_fused, ("a", "j", "l")) ≈ - reshape(unname(na, (k, i, j, l)), (unname(k) * unname(i), unname(j), unname(l))) - end - @testset "splitdims" begin - a, b = named.((6, 20), ("a", "b")) - i, j, k, l = named.((2, 3, 4, 5), ("i", "j", "k", "l")) - na = randn(elt, a, b) - # Split all dimensions. - na_split = splitdims(na, "a" => (k, i), "b" => (j, l)) - @test unname(na_split, ("k", "i", "j", "l")) ≈ - reshape(unname(na, ("a", "b")), (unname(k), unname(i), unname(j), unname(l))) - # Split a subset of dimensions. - na_split = splitdims(na, "a" => (j, i)) - @test unname(na_split, ("j", "i", "b")) ≈ - reshape(unname(na, ("a", "b")), (unname(j), unname(i), unname(b))) - end - @testset "qr" begin - dims = (2, 2, 2, 2) - i, j, k, l = named.(dims, ("i", "j", "k", "l")) - - na = randn(elt, i, j) - # TODO: Should this be allowed? - # TODO: Add support for specifying new name. - q, r = qr(na) - @test q * r ≈ na - - na = randn(elt, i, j, k, l) - # TODO: Add support for specifying new name. - q, r = qr(na, (i, k), (j, l)) - @test contract(q, r) ≈ na - end -end -end diff --git a/NDTensors/src/lib/NamedDimsArrays/generate_readme.jl b/NDTensors/src/lib/NamedDimsArrays/generate_readme.jl deleted file mode 100644 index 889a16915c..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/generate_readme.jl +++ /dev/null @@ -1,10 +0,0 @@ -using Literate -using NDTensors.NamedDimsArrays: NamedDimsArrays -Literate.markdown( - joinpath( - pkgdir(NamedDimsArrays), "src", "NamedDimsArrays", "examples", "example_readme.jl" - ), - joinpath(pkgdir(NamedDimsArrays), "src", "NamedDimsArrays"); - flavor=Literate.CommonMarkFlavor(), - name="README", -) diff --git a/NDTensors/src/lib/NamedDimsArrays/src/NamedDimsArrays.jl b/NDTensors/src/lib/NamedDimsArrays/src/NamedDimsArrays.jl deleted file mode 100644 index 71d1a78c95..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/NamedDimsArrays.jl +++ /dev/null @@ -1,27 +0,0 @@ -module NamedDimsArrays -include("traits.jl") -include("name.jl") -include("randname.jl") -include("abstractnamedint.jl") -include("abstractnamedunitrange.jl") -include("abstractnameddimsarray.jl") -include("abstractnameddimsmatrix.jl") -include("abstractnameddimsvector.jl") -include("namedint.jl") -include("namedunitrange.jl") -include("nameddimsarray.jl") -include("constructors.jl") -include("similar.jl") -include("permutedims.jl") -include("promote_shape.jl") -include("map.jl") -include("broadcast_shape.jl") -include("broadcast.jl") - -# Extensions -include("../ext/NamedDimsArraysAdaptExt/src/NamedDimsArraysAdaptExt.jl") -include( - "../ext/NamedDimsArraysSparseArraysBaseExt/src/NamedDimsArraysSparseArraysBaseExt.jl" -) -include("../ext/NamedDimsArraysTensorAlgebraExt/src/NamedDimsArraysTensorAlgebraExt.jl") -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsarray.jl b/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsarray.jl deleted file mode 100644 index a73763bb90..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsarray.jl +++ /dev/null @@ -1,176 +0,0 @@ -using ..BaseExtensions: BaseExtensions -using NDTensors.TypeParameterAccessors: TypeParameterAccessors, parenttype - -# Some of the interface is inspired by: -# https://github.com/invenia/NamedDims.jl -# https://github.com/mcabbott/NamedPlus.jl - -abstract type AbstractNamedDimsArray{T,N,Parent,Names} <: AbstractArray{T,N} end - -# Required interface - -# Output the names. -# TODO: Define for `AbstractArray`. -dimnames(a::AbstractNamedDimsArray) = error("Not implemented") - -# Unwrapping the names -Base.parent(::AbstractNamedDimsArray) = error("Not implemented") - -## TODO remove TypeParameterAccessors when SetParameters is removed -function TypeParameterAccessors.position( - ::Type{<:AbstractNamedDimsArray}, ::typeof(parenttype) -) - return TypeParameterAccessors.Position(3) -end - -# Set the names of an unnamed AbstractArray -# `ndims(a) == length(names)` -# This is a constructor -## named(a::AbstractArray, names) = error("Not implemented") - -dimnames(a::AbstractNamedDimsArray, i::Int) = dimnames(a)[i] - -# Traits -# TODO: Define for `AbstractArray`. -# TODO: Define a trait type `IsNamed`. -isnamed(::AbstractNamedDimsArray) = true - -# AbstractArray interface -# TODO: Use `unname` instead of `parent`? - -# Helper function, move to `utils.jl`. -named_tuple(t::Tuple, names) = ntuple(i -> named(t[i], names[i]), length(t)) - -# TODO: Should `axes` output named axes or not? -# TODO: Use the proper type, `namedaxistype(a)`. -# Base.axes(a::AbstractNamedDimsArray) = named_tuple(axes(unname(a)), dimnames(a)) -Base.axes(a::AbstractNamedDimsArray) = axes(unname(a)) -namedaxes(a::AbstractNamedDimsArray) = named.(axes(unname(a)), dimnames(a)) -# TODO: Use the proper type, `namedlengthtype(a)`. -Base.size(a::AbstractNamedDimsArray) = size(unname(a)) -namedsize(a::AbstractNamedDimsArray) = named.(size(unname(a)), dimnames(a)) -Base.getindex(a::AbstractNamedDimsArray, I...) = unname(a)[I...] -function Base.setindex!(a::AbstractNamedDimsArray, x, I...) - unname(a)[I...] = x - return a -end - -# Derived interface - -# Output the names. -# TODO: Define for `AbstractArray`. -dimname(a::AbstractNamedDimsArray, i) = dimnames(a)[i] - -# Renaming -# Unname and set new naems -# TODO: Define for `AbstractArray`. -rename(a::AbstractNamedDimsArray, names) = named(unname(a), names) - -# replacenames(a, :i => :a, :j => :b) -# `rename` in `NamedPlus.jl`. -# TODO: Define for `AbstractArray`. -function replacenames(na::AbstractNamedDimsArray, replacements::Pair...) - # `BaseExtension.replace` needed for `Tuple` support on Julia 1.6 and older. - return named(unname(na), BaseExtensions.replace(dimnames(na), replacements...)) -end - -# Either define new names or replace names -# TODO: Define for `AbstractArray`, use `isnamed` trait -# to add names or replace names. -setnames(a::AbstractArray, names) = named(a, names) -setnames(a::AbstractNamedDimsArray, names) = rename(a, names) - -# TODO: Move to `utils.jl` file. -# TODO: Use `Base.indexin`? -function getperm(x, y) - return map(yᵢ -> findfirst(isequal(yᵢ), x), y) -end - -# TODO: Define for `AbstractArray`, use `isnamed` trait? -function get_name_perm(a::AbstractNamedDimsArray, names::Tuple) - # TODO: Call `getperm(dimnames(a), dimnames(namedints))`. - return getperm(dimnames(a), names) -end - -# Fixes ambiguity error -# TODO: Define for `AbstractArray`, use `isnamed` trait? -function get_name_perm(a::AbstractNamedDimsArray, names::Tuple{}) - # TODO: Call `getperm(dimnames(a), dimnames(namedints))`. - @assert iszero(ndims(a)) - return () -end - -# TODO: Define for `AbstractArray`, use `isnamed` trait? -function get_name_perm( - a::AbstractNamedDimsArray, namedints::Tuple{Vararg{AbstractNamedInt}} -) - # TODO: Call `getperm(dimnames(a), dimnames(namedints))`. - return getperm(namedsize(a), namedints) -end - -# TODO: Define for `AbstractArray`, use `isnamed` trait? -function get_name_perm( - a::AbstractNamedDimsArray, new_namedaxes::Tuple{Vararg{AbstractNamedUnitRange}} -) - # TODO: Call `getperm(dimnames(a), dimnames(namedints))`. - return getperm(namedaxes(a), new_namedaxes) -end - -# Indexing -# a[:i => 2, :j => 3] -# TODO: Write a generic version using `dim`. -# TODO: Define a `NamedIndex` or `NamedInt` type for indexing? -# Base.getindex(a::AbstractArray, I::NamedInt...) -function Base.getindex(a::AbstractNamedDimsArray, I::Pair...) - perm = get_name_perm(a, first.(I)) - i = last.(I) - return unname(a)[map(p -> i[p], perm)...] -end - -# a[:i => 2, :j => 3] = 12 -# TODO: Write a generic version using `dim`. -# TODO: Define a `NamedIndex` or `NamedInt` type for indexing? -function Base.setindex!(a::AbstractNamedDimsArray, value, I::Pair...) - perm = get_name_perm(a, first.(I)) - i = last.(I) - unname(a)[map(p -> i[p], perm)...] = value - return a -end - -# Output the dimension of the specified name. -dim(a::AbstractNamedDimsArray, name) = findfirst(==(name), dimnames(a)) - -# Output the dimensions of the specified names. -dims(a::AbstractNamedDimsArray, names) = map(name -> dim(a, name), names) - -# Unwrapping the names -# TODO: Use `isnamed` trait. -unname(a::AbstractNamedDimsArray) = parent(a) -unname(a::AbstractArray) = a - -# Permute into a certain order. -# align(a, (:j, :k, :i)) -# Like `named(nameless(a, names), names)` -# TODO: Use `isnamed` trait. -function align(na::AbstractNamedDimsArray, names) - perm = get_name_perm(na, names) - # TODO: Avoid permutation if it is a trivial permutation? - # return typeof(a)(permutedims(unname(a), perm), names) - return permutedims(na, perm) -end - -# Unwrapping names and permuting -# nameless(a, (:j, :i)) -# Could just call `unname`? -## nameless(a::AbstractNamedDimsArray, names) = unname(align(a, names)) -# TODO: Use `isnamed` trait. -unname(a::AbstractNamedDimsArray, names) = unname(align(a, names)) - -# In `TensorAlgebra` this this `fuse` and `unfuse`, -# in `NDTensors`/`ITensors` this is `combine` and `uncombine`. -# t = split(g, :n => (j=4, k=5)) -# join(t, (:i, :k) => :χ) - -# TensorAlgebra -# contract, fusedims, unfusedims, qr, eigen, svd, add, etc. -# Some of these can simply wrap `TensorAlgebra.jl` functions. diff --git a/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsmatrix.jl b/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsmatrix.jl deleted file mode 100644 index 5090e9842d..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsmatrix.jl +++ /dev/null @@ -1 +0,0 @@ -const AbstractNamedDimsMatrix{T,Parent,Names} = AbstractNamedDimsArray{T,2,Parent,Names} diff --git a/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsvector.jl b/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsvector.jl deleted file mode 100644 index d1f7b677cd..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/abstractnameddimsvector.jl +++ /dev/null @@ -1 +0,0 @@ -const AbstractNamedDimsVector{T,Parent,Names} = AbstractNamedDimsArray{T,1,Parent,Names} diff --git a/NDTensors/src/lib/NamedDimsArrays/src/abstractnamedint.jl b/NDTensors/src/lib/NamedDimsArrays/src/abstractnamedint.jl deleted file mode 100644 index 0c3851caef..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/abstractnamedint.jl +++ /dev/null @@ -1,41 +0,0 @@ -abstract type AbstractNamedInt{Value,Name} <: Integer end - -# Interface -unname(i::AbstractNamedInt) = error("Not implemented") -name(i::AbstractNamedInt) = error("Not implemented") - -# Derived -unname(::Type{<:AbstractNamedInt{Value}}) where {Value} = Value - -# Integer interface -# TODO: Should this make a random name, or require defining a way -# to combine names? -Base.:*(i1::AbstractNamedInt, i2::AbstractNamedInt) = unname(i1) * unname(i2) -Base.:-(i::AbstractNamedInt) = typeof(i)(-unname(i), name(i)) - -# TODO: Define for `NamedInt`, `NamedUnitRange` fallback? -# Base.OneTo(stop::AbstractNamedInt) = namedoneto(stop) -## nameduniterange_type(::Type{<:AbstractNamedInt}) = error("Not implemented") - -# TODO: Use conversion from `AbstractNamedInt` to `AbstractNamedUnitRange` -# instead of general `named`. -# Base.OneTo(stop::AbstractNamedInt) = namedoneto(stop) -Base.OneTo(stop::AbstractNamedInt) = named(Base.OneTo(unname(stop)), name(stop)) - -# TODO: Is this needed? -# Include the name as well? -Base.:<(i1::AbstractNamedInt, i2::AbstractNamedInt) = unname(i1) < unname(i2) -## Base.zero(type::Type{<:AbstractNamedInt}) = zero(unname(type)) - -function Base.promote_rule(type1::Type{<:AbstractNamedInt}, type2::Type{<:Integer}) - return promote_type(unname(type1), type2) -end -(type::Type{<:Integer})(i::AbstractNamedInt) = type(unname(i)) -# TODO: Use conversion from `AbstractNamedInt` to `AbstractNamedUnitRange` -# instead of general `named`. -function Base.oftype(i1::AbstractNamedInt, i2::Integer) - return named(convert(typeof(unname(i1)), i2), name(i1)) -end - -# Traits -isnamed(::AbstractNamedInt) = true diff --git a/NDTensors/src/lib/NamedDimsArrays/src/abstractnamedunitrange.jl b/NDTensors/src/lib/NamedDimsArrays/src/abstractnamedunitrange.jl deleted file mode 100644 index d2d5630d28..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/abstractnamedunitrange.jl +++ /dev/null @@ -1,35 +0,0 @@ -abstract type AbstractNamedUnitRange{T,Value<:AbstractUnitRange{T},Name} <: - AbstractUnitRange{T} end - -# Required interface -unname(::AbstractNamedUnitRange) = error("Not implemented") -name(::AbstractNamedUnitRange) = error("Not implemented") - -# Traits -isnamed(::AbstractNamedUnitRange) = true - -# Unit range -Base.first(i::AbstractNamedUnitRange) = first(unname(i)) -Base.last(i::AbstractNamedUnitRange) = last(unname(i)) -Base.length(i::AbstractNamedUnitRange) = named(length(unname(i)), name(i)) - -# TODO: Use `isnamed` trait? -dimnames(a::Tuple{Vararg{AbstractNamedUnitRange}}) = name.(a) - -unname(a::Tuple{Vararg{AbstractNamedUnitRange}}) = unname.(a) -unname(a::Tuple{Vararg{AbstractNamedUnitRange}}, names) = unname(align(a, names)) - -function named(as::Tuple{Vararg{AbstractUnitRange}}, names) - return ntuple(j -> named(as[j], names[j]), length(as)) -end - -function get_name_perm(a::Tuple{Vararg{AbstractNamedUnitRange}}, names::Tuple) - return getperm(dimnames(a), names) -end - -# Permute into a certain order. -# align(a, (:j, :k, :i)) -function align(a::Tuple{Vararg{AbstractNamedUnitRange}}, names) - perm = get_name_perm(a, names) - return map(j -> a[j], perm) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/broadcast.jl b/NDTensors/src/lib/NamedDimsArrays/src/broadcast.jl deleted file mode 100644 index d2c1198272..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/broadcast.jl +++ /dev/null @@ -1,49 +0,0 @@ -using Base.Broadcast: BroadcastStyle, AbstractArrayStyle, DefaultArrayStyle, Broadcasted -using ..BroadcastMapConversion: map_function, map_args - -struct NamedDimsArrayStyle{N} <: AbstractArrayStyle{N} end - -function Broadcast.BroadcastStyle(::Type{<:AbstractNamedDimsArray{<:Any,N}}) where {N} - return NamedDimsArrayStyle{N}() -end - -NamedDimsArrayStyle(::Val{N}) where {N} = NamedDimsArrayStyle{N}() -NamedDimsArrayStyle{M}(::Val{N}) where {M,N} = NamedDimsArrayStyle{N}() - -Broadcast.BroadcastStyle(a::NamedDimsArrayStyle, ::DefaultArrayStyle{0}) = a -function Broadcast.BroadcastStyle(::NamedDimsArrayStyle{N}, a::DefaultArrayStyle) where {N} - return BroadcastStyle(DefaultArrayStyle{N}(), a) -end -function Broadcast.BroadcastStyle( - ::NamedDimsArrayStyle{N}, ::Broadcast.Style{Tuple} -) where {N} - return DefaultArrayStyle{N}() -end - -# TODO: Is this needed? -# Define `output_names`, like `allocate_output`. -# function dimnames(bc::Broadcasted{<:NamedDimsArrayStyle}) -# return dimnames(first(map_args(bc))) -# end - -function Broadcast.check_broadcast_axes(shp, a::AbstractNamedDimsArray) - # Unles we output named axes from `axes(::NamedDimsArray)`, - # this check won't make sense since it has to check up - # to an unknown permutation. - return nothing -end - -# TODO: Use `allocate_output`, share logic with `map`. -function Base.similar(bc::Broadcasted{<:NamedDimsArrayStyle}, elt::Type) - return similar(first(map_args(bc)), elt) -end - -# Broadcasting implementation -function Base.copyto!( - dest::AbstractNamedDimsArray{<:Any,N}, bc::Broadcasted{NamedDimsArrayStyle{N}} -) where {N} - # convert to map - # flatten and only keep the AbstractArray arguments - map!(map_function(bc), dest, map_args(bc)...) - return dest -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/broadcast_shape.jl b/NDTensors/src/lib/NamedDimsArrays/src/broadcast_shape.jl deleted file mode 100644 index ad6986190f..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/broadcast_shape.jl +++ /dev/null @@ -1,24 +0,0 @@ -using Base.Broadcast: Broadcast, broadcast_shape, combine_axes - -# TODO: Have `axes` output named axes so Base functions "just work". -function Broadcast.combine_axes(na1::AbstractNamedDimsArray, nas::AbstractNamedDimsArray...) - return broadcast_shape(namedaxes(na1), combine_axes(nas...)) -end -function Broadcast.combine_axes(na1::AbstractNamedDimsArray, na2::AbstractNamedDimsArray) - return broadcast_shape(namedaxes(na1), namedaxes(na2)) -end -Broadcast.combine_axes(na::AbstractNamedDimsArray) = namedaxes(na) - -function Broadcast.broadcast_shape( - na1::Tuple{Vararg{AbstractNamedUnitRange}}, - na2::Tuple{Vararg{AbstractNamedUnitRange}}, - nas::Tuple{Vararg{AbstractNamedUnitRange}}..., -) - return broadcast_shape(broadcast_shape(shape, shape1), shapes...) -end - -function Broadcast.broadcast_shape( - na1::Tuple{Vararg{AbstractNamedUnitRange}}, na2::Tuple{Vararg{AbstractNamedUnitRange}} -) - return promote_shape(na1, na2) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/constructors.jl b/NDTensors/src/lib/NamedDimsArrays/src/constructors.jl deleted file mode 100644 index 9e167beea0..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/constructors.jl +++ /dev/null @@ -1,48 +0,0 @@ -using Random: AbstractRNG, default_rng - -# TODO: Use `AbstractNamedUnitRange`, determine the `AbstractNamedDimsArray` -# from a default value. Useful for distinguishing between `NamedDimsArray` -# and `ITensor`. -# Convenient constructors -default_eltype() = Float64 -for f in [:rand, :randn] - @eval begin - function Base.$f( - rng::AbstractRNG, elt::Type{<:Number}, dims::Tuple{NamedInt,Vararg{NamedInt}} - ) - a = $f(rng, elt, unname.(dims)) - return named(a, name.(dims)) - end - function Base.$f( - rng::AbstractRNG, elt::Type{<:Number}, dim1::NamedInt, dims::Vararg{NamedInt} - ) - return $f(rng, elt, (dim1, dims...)) - end - Base.$f(elt::Type{<:Number}, dims::Tuple{NamedInt,Vararg{NamedInt}}) = - $f(default_rng(), elt, dims) - Base.$f(elt::Type{<:Number}, dim1::NamedInt, dims::Vararg{NamedInt}) = - $f(elt, (dim1, dims...)) - Base.$f(dims::Tuple{NamedInt,Vararg{NamedInt}}) = $f(default_eltype(), dims) - Base.$f(dim1::NamedInt, dims::Vararg{NamedInt}) = $f((dim1, dims...)) - end -end -for f in [:zeros, :ones] - @eval begin - function Base.$f(elt::Type{<:Number}, dims::Tuple{NamedInt,Vararg{NamedInt}}) - a = $f(elt, unname.(dims)) - return named(a, name.(dims)) - end - function Base.$f(elt::Type{<:Number}, dim1::NamedInt, dims::Vararg{NamedInt}) - return $f(elt, (dim1, dims...)) - end - Base.$f(dims::Tuple{NamedInt,Vararg{NamedInt}}) = $f(default_eltype(), dims) - Base.$f(dim1::NamedInt, dims::Vararg{NamedInt}) = $f((dim1, dims...)) - end -end -function Base.fill(value, dims::Tuple{NamedInt,Vararg{NamedInt}}) - a = fill(value, unname.(dims)) - return named(a, name.(dims)) -end -function Base.fill(value, dim1::NamedInt, dims::Vararg{NamedInt}) - return fill(value, (dim1, dims...)) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/map.jl b/NDTensors/src/lib/NamedDimsArrays/src/map.jl deleted file mode 100644 index d7b38575ec..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/map.jl +++ /dev/null @@ -1,14 +0,0 @@ -# TODO: Handle maybe-mutation. -# TODO: Handle permutations more efficiently by fusing with `f`. -function Base.map!(f, na_dest::AbstractNamedDimsArray, nas::AbstractNamedDimsArray...) - a_dest = unname(na_dest) - as = map(na -> unname(na, dimnames(na_dest)), nas) - map!(f, a_dest, as...) - return na_dest -end - -function Base.map(f, nas::AbstractNamedDimsArray...) - na_dest = similar(first(nas)) - map!(f, na_dest, nas...) - return na_dest -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/name.jl b/NDTensors/src/lib/NamedDimsArrays/src/name.jl deleted file mode 100644 index 07613ddb28..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/name.jl +++ /dev/null @@ -1,2 +0,0 @@ -# In general an object is a name -name(x) = x diff --git a/NDTensors/src/lib/NamedDimsArrays/src/nameddimsarray.jl b/NDTensors/src/lib/NamedDimsArrays/src/nameddimsarray.jl deleted file mode 100644 index 5727c5366a..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/nameddimsarray.jl +++ /dev/null @@ -1,114 +0,0 @@ -function _NamedDimsArray end - -struct NamedDimsArray{T,N,Arr<:AbstractArray{T,N},Names<:Tuple{Vararg{Any,N}}} <: - AbstractNamedDimsArray{T,N,Arr,Names} - array::Arr - names::Names - global @inline function _NamedDimsArray(array::AbstractArray, names) - elt = eltype(array) - n = ndims(array) - names_tuple = Tuple{Vararg{Any,n}}(names) - arraytype = typeof(array) - namestype = typeof(names_tuple) - return new{elt,n,arraytype,namestype}(array, names_tuple) - end - - # TODO: Delete, maybe this aligns according to the new names? - global @inline function _NamedDimsArray(array::NamedDimsArray, names) - return error("Not implemented, already named.") - end -end - -function NamedDimsArray{T,N,Arr,Names}( - a::AbstractArray, names -) where {T,N,Arr<:AbstractArray{T,N},Names} - return _NamedDimsArray(convert(Arr, a), convert(Names, names)) -end - -# TODO: Combine with other constructor definitions. -function NamedDimsArray{T,N,Arr,Names}( - a::AbstractArray, names::Tuple{} -) where {T,N,Arr<:AbstractArray{T,N},Names} - return _NamedDimsArray(convert(Arr, a), convert(Names, names)) -end - -NamedDimsArray(a::AbstractArray, names) = _NamedDimsArray(a, names) - -# TODO: Check size consistency -# TODO: Combine with other constructor definitions. -function NamedDimsArray{T,N,Arr,Names}( - a::AbstractArray, namedsize::Tuple{Vararg{AbstractNamedInt}} -) where {T,N,Arr<:AbstractArray{T,N},Names} - @assert size(a) == unname.(namedsize) - return _NamedDimsArray(convert(Arr, a), convert(Names, name.(namedsize))) -end - -# TODO: Check axes consistency -# TODO: Combine with other constructor definitions. -function NamedDimsArray{T,N,Arr,Names}( - a::AbstractArray, namedaxes::Tuple{Vararg{AbstractNamedUnitRange}} -) where {T,N,Arr<:AbstractArray{T,N},Names} - @assert axes(a) == unname.(namedaxes) - return _NamedDimsArray(convert(Arr, a), convert(Names, name.(namedaxes))) -end - -# Required interface - -# Output the names. -dimnames(a::NamedDimsArray) = a.names - -# Unwrapping the names -Base.parent(a::NamedDimsArray) = a.array - -# Set the names of an unnamed AbstractArray -function named(a::AbstractArray, names) - @assert ndims(a) == length(names) - return NamedDimsArray(a, names) -end - -# TODO: Use `Undefs.jl` instead. -function undefs(arraytype::Type{<:AbstractArray}, axes::Tuple{Vararg{AbstractUnitRange}}) - return arraytype(undef, length.(axes)) -end - -# TODO: Use `AbstractNamedUnitRange`, determine the `AbstractNamedDimsArray` -# from a default value. Useful for distinguishing between `NamedDimsArray` -# and `ITensor`. -function undefs(arraytype::Type{<:AbstractArray}, axes::Tuple{Vararg{NamedUnitRange}}) - array = undefs(arraytype, unname.(axes)) - names = name.(axes) - return named(array, names) -end - -# TODO: Use `AbstractNamedUnitRange`, determine the `AbstractNamedDimsArray` -# from a default value. Useful for distinguishing between `NamedDimsArray` -# and `ITensor`. -function Base.similar( - arraytype::Type{<:AbstractArray}, axes::Tuple{NamedUnitRange,Vararg{NamedUnitRange}} -) - # TODO: Use `unname`? - return undefs(arraytype, axes) -end - -# TODO: Define `NamedInt`, `NamedUnitRange`, `NamedVector <: AbstractVector`, etc. -# See https://github.com/mcabbott/NamedPlus.jl/blob/v0.0.5/src/int.jl. - -# TODO: Define `similar_name`, with shorthand `sim`, that makes a random name. -# Used in matrix/tensor factorizations. - -# TODO: Think about how to interact with array wrapper types, see: -# https://github.com/mcabbott/NamedPlus.jl/blob/v0.0.5/src/recursion.jl - -# TODO: What should `size` and `axes` output? Could output tuples -# of `NamedInt` and `NamedUnitRange`. - -# TODO: Construct from `NamedInt` or `NamedUnitRange` in standard -# array constructors, like `zeros`, `rand`, `randn`, `undefs`, etc. -# See https://mkitti.github.io/Undefs.jl/stable/, -# https://github.com/mkitti/ArrayAllocators.jl - -# TODO: Define `ArrayConstructors.randn`, `ArrayConstructors.rand`, -# `ArrayConstructors.zeros`, `ArrayConstructors.fill`, etc. -# for generic constructors accepting `CuArray`, `Array`, etc. -# Also could defign allocator types, `https://github.com/JuliaGPU/KernelAbstractions.jl` -# and `https://docs.juliahub.com/General/HeterogeneousComputing/stable/`. diff --git a/NDTensors/src/lib/NamedDimsArrays/src/namedint.jl b/NDTensors/src/lib/NamedDimsArrays/src/namedint.jl deleted file mode 100644 index 13b8a88141..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/namedint.jl +++ /dev/null @@ -1,28 +0,0 @@ -struct NamedInt{Value,Name} <: AbstractNamedInt{Value,Name} - value::Value - name::Name -end - -## Needs a `default_name(nametype::Type)` function. -## NamedInt{Value,Name}(i::Integer) where {Value,Name} = NamedInt{Value,Name}(i, default_name(Name)) - -# Interface -unname(i::NamedInt) = i.value -name(i::NamedInt) = i.name - -# Convenient constructor -named(i::Integer, name) = NamedInt(i, name) - -# TODO: Use `isnamed` trait? -dimnames(a::Tuple{Vararg{AbstractNamedInt}}) = name.(a) - -function get_name_perm(a::Tuple{Vararg{AbstractNamedInt}}, names::Tuple) - return getperm(dimnames(a), names) -end - -# Permute into a certain order. -# align(a, (:j, :k, :i)) -function align(a::Tuple{Vararg{AbstractNamedInt}}, names) - perm = get_name_perm(a, names) - return map(j -> a[j], perm) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/namedunitrange.jl b/NDTensors/src/lib/NamedDimsArrays/src/namedunitrange.jl deleted file mode 100644 index 44867eae3e..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/namedunitrange.jl +++ /dev/null @@ -1,12 +0,0 @@ -struct NamedUnitRange{T,Value<:AbstractUnitRange{T},Name} <: - AbstractNamedUnitRange{T,Value,Name} - value::Value - name::Name -end - -# Interface -unname(i::NamedUnitRange) = i.value -name(i::NamedUnitRange) = i.name - -# Constructor -named(i::AbstractUnitRange, name) = NamedUnitRange(i, name) diff --git a/NDTensors/src/lib/NamedDimsArrays/src/permutedims.jl b/NDTensors/src/lib/NamedDimsArrays/src/permutedims.jl deleted file mode 100644 index 5e81a3bfd7..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/permutedims.jl +++ /dev/null @@ -1,4 +0,0 @@ -function Base.permutedims(na::AbstractNamedDimsArray, perm) - names = map(j -> dimnames(na)[j], perm) - return named(permutedims(unname(na), perm), names) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/promote_shape.jl b/NDTensors/src/lib/NamedDimsArrays/src/promote_shape.jl deleted file mode 100644 index 84fe517ecf..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/promote_shape.jl +++ /dev/null @@ -1,12 +0,0 @@ -function Base.promote_shape(na1::AbstractNamedDimsArray, na2::AbstractNamedDimsArray) - return promote_shape(namedaxes(na1), namedaxes(na2)) -end - -function Base.promote_shape( - na1::Tuple{Vararg{AbstractNamedUnitRange}}, na2::Tuple{Vararg{AbstractNamedUnitRange}} -) - a1 = unname(na1) - a2 = unname(na2, dimnames(na1)) - a_promoted = promote_shape(a1, a2) - return named(a_promoted, dimnames(na1)) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/randname.jl b/NDTensors/src/lib/NamedDimsArrays/src/randname.jl deleted file mode 100644 index 1143ff4ceb..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/randname.jl +++ /dev/null @@ -1,5 +0,0 @@ -using Random: randstring - -randname(::Any) = error("Not implemented") - -randname(::String) = randstring() diff --git a/NDTensors/src/lib/NamedDimsArrays/src/similar.jl b/NDTensors/src/lib/NamedDimsArrays/src/similar.jl deleted file mode 100644 index 441afecd19..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/similar.jl +++ /dev/null @@ -1,49 +0,0 @@ -# `similar` - -# Preserve the names -Base.similar(na::AbstractNamedDimsArray) = named(similar(unname(na)), dimnames(na)) -function Base.similar(na::AbstractNamedDimsArray, elt::Type) - return named(similar(unname(na), elt), dimnames(na)) -end - -# Remove the names -# TODO: Make versions taking `NamedUnitRange` and `NamedInt`. -function Base.similar(na::AbstractNamedDimsArray, elt::Type, dims::Tuple{Vararg{Int64}}) - return similar(unname(na), elt, dims) -end - -# Remove the names -# TODO: Make versions taking `NamedUnitRange` and `NamedInt`. -function Base.similar( - na::AbstractNamedDimsArray, elt::Type, dims::Tuple{Integer,Vararg{Integer}} -) - return similar(unname(na), elt, dims) -end - -# Remove the names -# TODO: Make versions taking `NamedUnitRange` and `NamedInt`. -function Base.similar( - na::AbstractNamedDimsArray, - elt::Type, - dims::Tuple{Union{Integer,Base.OneTo},Vararg{Union{Integer,Base.OneTo}}}, -) - return similar(unname(na), elt, dims) -end - -# Remove the names -# TODO: Make versions taking `NamedUnitRange` and `NamedInt`. -function Base.similar( - na::AbstractNamedDimsArray, elt::Type, dims::Union{Integer,AbstractUnitRange}... -) - return similar(unname(na), elt, dims...) -end - -# Remove the names -# TODO: Make versions taking `NamedUnitRange` and `NamedInt`. -Base.similar(na::AbstractNamedDimsArray, dims::Tuple) = similar(unname(na), dims) - -# Remove the names -# TODO: Make versions taking `NamedUnitRange` and `NamedInt`. -function Base.similar(na::AbstractNamedDimsArray, dims::Union{Integer,AbstractUnitRange}...) - return similar(unname(na), dims...) -end diff --git a/NDTensors/src/lib/NamedDimsArrays/src/traits.jl b/NDTensors/src/lib/NamedDimsArrays/src/traits.jl deleted file mode 100644 index c971ae7a86..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/src/traits.jl +++ /dev/null @@ -1 +0,0 @@ -isnamed(::Any) = false diff --git a/NDTensors/src/lib/NamedDimsArrays/test/Project.toml b/NDTensors/src/lib/NamedDimsArrays/test/Project.toml deleted file mode 100644 index 18bbc81308..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" diff --git a/NDTensors/src/lib/NamedDimsArrays/test/runtests.jl b/NDTensors/src/lib/NamedDimsArrays/test/runtests.jl deleted file mode 100644 index df2a0fba66..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/runtests.jl +++ /dev/null @@ -1,11 +0,0 @@ -using Test: @testset - -@testset "NamedDimsArrays" begin - filenames = filter(readdir(@__DIR__)) do filename - startswith("test_")(filename) && endswith(".jl")(filename) - end - @testset "Test $(@__DIR__)/$filename" for filename in filenames - println("Running $(@__DIR__)/$filename") - @time include(filename) - end -end diff --git a/NDTensors/src/lib/NamedDimsArrays/test/test_NDTensorsNamedDimsArraysExt.jl b/NDTensors/src/lib/NamedDimsArrays/test/test_NDTensorsNamedDimsArraysExt.jl deleted file mode 100644 index 06eeb0c6e0..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/test_NDTensorsNamedDimsArraysExt.jl +++ /dev/null @@ -1,33 +0,0 @@ -@eval module $(gensym()) -using NDTensors.NamedDimsArrays: NamedDimsArray, dimnames -using NDTensors: NDTensors -using Test: @test, @testset - -@testset "NDTensorsNamedDimsArraysExt" begin - elt = Float64 - - a = NamedDimsArray(randn(elt, 2, 2), ("i", "j")) - b = NDTensors.similar(a) - @test b isa NamedDimsArray{elt} - @test eltype(b) === elt - @test dimnames(b) == ("i", "j") - @test size(b) == (2, 2) - - a = NamedDimsArray(randn(elt, 2, 2), ("i", "j")) - b = NDTensors.similar(a, Float32) - @test b isa NamedDimsArray{Float32} - @test eltype(b) === Float32 - @test dimnames(b) == ("i", "j") - @test size(b) == (2, 2) - - a = NamedDimsArray(randn(elt, 2, 2), ("i", "j")) - b = copy(a) - α = randn(elt) - b = NDTensors.fill!!(b, α) - @test b isa NamedDimsArray{elt} - @test eltype(b) === elt - @test dimnames(b) == ("i", "j") - @test size(b) == (2, 2) - @test all(==(α), b) -end -end diff --git a/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysAdaptExt.jl b/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysAdaptExt.jl deleted file mode 100644 index 10ffe6fb7d..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysAdaptExt.jl +++ /dev/null @@ -1,5 +0,0 @@ -using Test: @testset - -@testset "NamedDimsArrays $(@__FILE__)" begin - include("../ext/NamedDimsArraysAdaptExt/test/runtests.jl") -end diff --git a/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysSparseArraysBaseExt.jl b/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysSparseArraysBaseExt.jl deleted file mode 100644 index 5cd5ef6498..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysSparseArraysBaseExt.jl +++ /dev/null @@ -1,5 +0,0 @@ -using Test: @testset - -@testset "NamedDimsArrays $(@__FILE__)" begin - include("../ext/NamedDimsArraysSparseArraysBaseExt/test/runtests.jl") -end diff --git a/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysTensorAlgebraExt.jl b/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysTensorAlgebraExt.jl deleted file mode 100644 index da5e5dd230..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/test_NamedDimsArraysTensorAlgebraExt.jl +++ /dev/null @@ -1,5 +0,0 @@ -using Test: @testset - -@testset "NamedDimsArrays $(@__FILE__)" begin - include("../ext/NamedDimsArraysTensorAlgebraExt/test/runtests.jl") -end diff --git a/NDTensors/src/lib/NamedDimsArrays/test/test_basic.jl b/NDTensors/src/lib/NamedDimsArrays/test/test_basic.jl deleted file mode 100644 index 480e9a259a..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/test_basic.jl +++ /dev/null @@ -1,108 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using NDTensors.NamedDimsArrays: - NamedDimsArrays, - NamedDimsArray, - align, - dimnames, - isnamed, - named, - namedaxes, - namedsize, - unname - -@testset "NamedDimsArrays $(@__FILE__)" begin - @testset "Basic functionality" begin - a = randn(3, 4) - na = named(a, ("i", "j")) - # TODO: Just call this `size`? - i, j = namedsize(na) - # TODO: Just call `namedaxes`? - ai, aj = namedaxes(na) - @test !isnamed(a) - @test isnamed(na) - @test dimnames(na) == ("i", "j") - @test na[1, 1] == a[1, 1] - na[1, 1] = 11 - @test na[1, 1] == 11 - # TODO: Should `size` output `namedsize`? - @test size(na) == (3, 4) - @test namedsize(na) == (named(3, "i"), named(4, "j")) - @test length(na) == 12 - # TODO: Should `axes` output `namedaxes`? - @test axes(na) == (1:3, 1:4) - @test namedaxes(na) == (named(1:3, "i"), named(1:4, "j")) - @test randn(named(3, "i"), named(4, "j")) isa NamedDimsArray - @test na["i" => 1, "j" => 2] == a[1, 2] - @test na["j" => 2, "i" => 1] == a[1, 2] - na["j" => 2, "i" => 1] = 12 - @test na[1, 2] == 12 - @test na[j => 1, i => 2] == a[2, 1] - @test na[aj => 1, ai => 2] == a[2, 1] - na[j => 1, i => 2] = 21 - @test na[2, 1] == 21 - na[aj => 1, ai => 2] = 2211 - @test na[2, 1] == 2211 - na′ = align(na, ("j", "i")) - @test a == permutedims(unname(na′), (2, 1)) - na′ = align(na, (j, i)) - @test a == permutedims(unname(na′), (2, 1)) - na′ = align(na, (aj, ai)) - @test a == permutedims(unname(na′), (2, 1)) - end - @testset "Shorthand constructors (eltype=$elt)" for elt in ( - Float32, ComplexF32, Float64, ComplexF64 - ) - i, j = named.((2, 2), ("i", "j")) - value = rand(elt) - for na in (zeros(elt, i, j), zeros(elt, (i, j))) - @test eltype(na) === elt - @test na isa NamedDimsArray - @test dimnames(na) == ("i", "j") - @test iszero(na) - end - for na in (fill(value, i, j), fill(value, (i, j))) - @test eltype(na) === elt - @test na isa NamedDimsArray - @test dimnames(na) == ("i", "j") - @test all(isequal(value), na) - end - for na in (rand(elt, i, j), rand(elt, (i, j))) - @test eltype(na) === elt - @test na isa NamedDimsArray - @test dimnames(na) == ("i", "j") - @test !iszero(na) - @test all(x -> real(x) > 0, na) - end - for na in (randn(elt, i, j), randn(elt, (i, j))) - @test eltype(na) === elt - @test na isa NamedDimsArray - @test dimnames(na) == ("i", "j") - @test !iszero(na) - end - end - @testset "Shorthand constructors (eltype=unspecified)" begin - i, j = named.((2, 2), ("i", "j")) - default_elt = Float64 - for na in (zeros(i, j), zeros((i, j))) - @test eltype(na) === default_elt - @test na isa NamedDimsArray - @test dimnames(na) == ("i", "j") - @test iszero(na) - end - for na in (rand(i, j), rand((i, j))) - @test eltype(na) === default_elt - @test na isa NamedDimsArray - @test dimnames(na) == ("i", "j") - @test !iszero(na) - @test all(x -> real(x) > 0, na) - end - for na in (randn(i, j), randn((i, j))) - @test eltype(na) === default_elt - @test na isa NamedDimsArray - @test dimnames(na) == ("i", "j") - @test !iszero(na) - end - end -end -end diff --git a/NDTensors/src/lib/NamedDimsArrays/test/test_tensoralgebra.jl b/NDTensors/src/lib/NamedDimsArrays/test/test_tensoralgebra.jl deleted file mode 100644 index 464f85510c..0000000000 --- a/NDTensors/src/lib/NamedDimsArrays/test/test_tensoralgebra.jl +++ /dev/null @@ -1,80 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using NDTensors.NamedDimsArrays: dimnames, named, unname, isnamed -@testset "NamedDimsArrays $(@__FILE__) (eltype=$elt)" for elt in ( - Float32, ComplexF32, Float64, ComplexF64 -) - a = randn(elt, 2, 3) - na = named(a, ("i", "j")) - b = randn(elt, 3, 2) - nb = named(b, ("j", "i")) - - nc = similar(na) - @test size(nc) == (2, 3) - @test eltype(nc) == elt - @test dimnames(nc) == ("i", "j") - - nc = similar(na, Float32) - @test size(nc) == (2, 3) - @test eltype(nc) == Float32 - @test dimnames(nc) == ("i", "j") - - c = similar(na, (3, 4)) - @test size(c) == (3, 4) - @test eltype(c) == elt - @test c isa typeof(a) - - c = similar(na, 3, 4) - @test size(c) == (3, 4) - @test eltype(c) == elt - @test c isa typeof(a) - - c = similar(na, Float32, (3, 4)) - @test size(c) == (3, 4) - @test eltype(c) == Float32 - @test !isnamed(c) - - c = similar(na, Float32, 3, 4) - @test size(c) == (3, 4) - @test eltype(c) == Float32 - @test !isnamed(c) - - nc = permutedims(na, (2, 1)) - @test unname(nc) ≈ permutedims(unname(na), (2, 1)) - @test dimnames(nc) == ("j", "i") - @test nc ≈ na - - nc = 2 * na - @test unname(nc) ≈ 2 * a - @test eltype(nc) === elt - - nc = 2 .* na - @test unname(nc) ≈ 2 * a - @test eltype(nc) === elt - - nc = na + nb - @test unname(nc, ("i", "j")) ≈ a + permutedims(b, (2, 1)) - @test eltype(nc) === elt - - nc = na .+ nb - @test unname(nc, ("i", "j")) ≈ a + permutedims(b, (2, 1)) - @test eltype(nc) === elt - - nc = map(+, na, nb) - @test unname(nc, ("i", "j")) ≈ a + permutedims(b, (2, 1)) - @test eltype(nc) === elt - - nc = named(randn(elt, 2, 3), ("i", "j")) - map!(+, nc, na, nb) - @test unname(nc, ("i", "j")) ≈ a + permutedims(b, (2, 1)) - @test eltype(nc) === elt - - nc = na - nb - @test unname(nc, ("i", "j")) ≈ a - permutedims(b, (2, 1)) - @test eltype(nc) === elt - - nc = na .- nb - @test unname(nc, ("i", "j")) ≈ a - permutedims(b, (2, 1)) - @test eltype(nc) === elt -end -end diff --git a/NDTensors/src/lib/NestedPermutedDimsArrays/src/NestedPermutedDimsArrays.jl b/NDTensors/src/lib/NestedPermutedDimsArrays/src/NestedPermutedDimsArrays.jl deleted file mode 100644 index 9234f6aed1..0000000000 --- a/NDTensors/src/lib/NestedPermutedDimsArrays/src/NestedPermutedDimsArrays.jl +++ /dev/null @@ -1,276 +0,0 @@ -# Mostly copied from https://github.com/JuliaLang/julia/blob/master/base/permuteddimsarray.jl -# Like `PermutedDimsArrays` but singly nested, similar to `Adjoint` and `Transpose` -# (though those are fully recursive). -#= -TODO: Investigate replacing this with a `PermutedDimsArray` wrapped around a `MappedArrays.MappedArray`. -There are a few issues with that: -1. Just using a type alias leads to type piracy, for example the constructor is type piracy. -2. `setindex!(::NestedPermutedDimsArray, I...)` fails because no conversion is defined between `Array` -and `PermutedDimsArray`. -3. The type alias is tricky to define, ideally it would have similar type parameters to the current -`NestedPermutedDimsArrays.NestedPermutedDimsArray` definition which matches the type parameters -of `PermutedDimsArrays.PermutedDimsArray` but that seems to be difficult to achieve. -```julia -module NestedPermutedDimsArrays - -using MappedArrays: MultiMappedArray, mappedarray -export NestedPermutedDimsArray - -const NestedPermutedDimsArray{TT,T<:AbstractArray{TT},N,perm,iperm,AA<:AbstractArray{T}} = PermutedDimsArray{ - PermutedDimsArray{TT,N,perm,iperm,T}, - N, - perm, - iperm, - MultiMappedArray{ - PermutedDimsArray{TT,N,perm,iperm,T}, - N, - Tuple{AA}, - Type{PermutedDimsArray{TT,N,perm,iperm,T}}, - Type{PermutedDimsArray{TT,N,iperm,perm,T}}, - }, -} - -function NestedPermutedDimsArray(a::AbstractArray, perm) - iperm = invperm(perm) - f = PermutedDimsArray{eltype(eltype(a)),ndims(a),perm,iperm,eltype(a)} - finv = PermutedDimsArray{eltype(eltype(a)),ndims(a),iperm,perm,eltype(a)} - return PermutedDimsArray(mappedarray(f, finv, a), perm) -end - -end -``` -=# -module NestedPermutedDimsArrays - -import Base: permutedims, permutedims! -export NestedPermutedDimsArray - -# Some day we will want storage-order-aware iteration, so put perm in the parameters -struct NestedPermutedDimsArray{T,N,perm,iperm,AA<:AbstractArray} <: AbstractArray{T,N} - parent::AA - - function NestedPermutedDimsArray{T,N,perm,iperm,AA}( - data::AA - ) where {T,N,perm,iperm,AA<:AbstractArray} - (isa(perm, NTuple{N,Int}) && isa(iperm, NTuple{N,Int})) || - error("perm and iperm must both be NTuple{$N,Int}") - isperm(perm) || - throw(ArgumentError(string(perm, " is not a valid permutation of dimensions 1:", N))) - all(d -> iperm[perm[d]] == d, 1:N) || - throw(ArgumentError(string(perm, " and ", iperm, " must be inverses"))) - return new(data) - end -end - -""" - NestedPermutedDimsArray(A, perm) -> B - -Given an AbstractArray `A`, create a view `B` such that the -dimensions appear to be permuted. Similar to `permutedims`, except -that no copying occurs (`B` shares storage with `A`). - -See also [`permutedims`](@ref), [`invperm`](@ref). - -# Examples -```jldoctest -julia> A = rand(3,5,4); - -julia> B = NestedPermutedDimsArray(A, (3,1,2)); - -julia> size(B) -(4, 3, 5) - -julia> B[3,1,2] == A[1,2,3] -true -``` -""" -Base.@constprop :aggressive function NestedPermutedDimsArray( - data::AbstractArray{T,N}, perm -) where {T,N} - length(perm) == N || - throw(ArgumentError(string(perm, " is not a valid permutation of dimensions 1:", N))) - iperm = invperm(perm) - return NestedPermutedDimsArray{ - PermutedDimsArray{eltype(T),N,(perm...,),(iperm...,),T}, - N, - (perm...,), - (iperm...,), - typeof(data), - }( - data - ) -end - -Base.parent(A::NestedPermutedDimsArray) = A.parent -function Base.size(A::NestedPermutedDimsArray{T,N,perm}) where {T,N,perm} - return genperm(size(parent(A)), perm) -end -function Base.axes(A::NestedPermutedDimsArray{T,N,perm}) where {T,N,perm} - return genperm(axes(parent(A)), perm) -end -Base.has_offset_axes(A::NestedPermutedDimsArray) = Base.has_offset_axes(A.parent) -function Base.similar(A::NestedPermutedDimsArray, T::Type, dims::Base.Dims) - return similar(parent(A), T, dims) -end -function Base.cconvert(::Type{Ptr{T}}, A::NestedPermutedDimsArray{T}) where {T} - return Base.cconvert(Ptr{T}, parent(A)) -end - -# It's OK to return a pointer to the first element, and indeed quite -# useful for wrapping C routines that require a different storage -# order than used by Julia. But for an array with unconventional -# storage order, a linear offset is ambiguous---is it a memory offset -# or a linear index? -function Base.pointer(A::NestedPermutedDimsArray, i::Integer) - throw( - ArgumentError("pointer(A, i) is deliberately unsupported for NestedPermutedDimsArray") - ) -end - -function Base.strides(A::NestedPermutedDimsArray{T,N,perm}) where {T,N,perm} - s = strides(parent(A)) - return ntuple(d -> s[perm[d]], Val(N)) -end -function Base.elsize(::Type{<:NestedPermutedDimsArray{<:Any,<:Any,<:Any,<:Any,P}}) where {P} - return Base.elsize(P) -end - -@inline function Base.getindex( - A::NestedPermutedDimsArray{T,N,perm,iperm}, I::Vararg{Int,N} -) where {T,N,perm,iperm} - @boundscheck checkbounds(A, I...) - @inbounds val = PermutedDimsArray(getindex(A.parent, genperm(I, iperm)...), perm) - return val -end -@inline function Base.setindex!( - A::NestedPermutedDimsArray{T,N,perm,iperm}, val, I::Vararg{Int,N} -) where {T,N,perm,iperm} - @boundscheck checkbounds(A, I...) - @inbounds setindex!(A.parent, PermutedDimsArray(val, iperm), genperm(I, iperm)...) - return val -end - -function Base.isassigned( - A::NestedPermutedDimsArray{T,N,perm,iperm}, I::Vararg{Int,N} -) where {T,N,perm,iperm} - @boundscheck checkbounds(Bool, A, I...) || return false - @inbounds x = isassigned(A.parent, genperm(I, iperm)...) - return x -end - -@inline genperm(I::NTuple{N,Any}, perm::Dims{N}) where {N} = ntuple(d -> I[perm[d]], Val(N)) -@inline genperm(I, perm::AbstractVector{Int}) = genperm(I, (perm...,)) - -function Base.copyto!( - dest::NestedPermutedDimsArray{T,N}, src::AbstractArray{T,N} -) where {T,N} - checkbounds(dest, axes(src)...) - return _copy!(dest, src) -end -Base.copyto!(dest::NestedPermutedDimsArray, src::AbstractArray) = _copy!(dest, src) - -function _copy!(P::NestedPermutedDimsArray{T,N,perm}, src) where {T,N,perm} - # If dest/src are "close to dense," then it pays to be cache-friendly. - # Determine the first permuted dimension - d = 0 # d+1 will hold the first permuted dimension of src - while d < ndims(src) && perm[d + 1] == d + 1 - d += 1 - end - if d == ndims(src) - copyto!(parent(P), src) # it's not permuted - else - R1 = CartesianIndices(axes(src)[1:d]) - d1 = findfirst(isequal(d + 1), perm)::Int # first permuted dim of dest - R2 = CartesianIndices(axes(src)[(d + 2):(d1 - 1)]) - R3 = CartesianIndices(axes(src)[(d1 + 1):end]) - _permutedims!(P, src, R1, R2, R3, d + 1, d1) - end - return P -end - -@noinline function _permutedims!( - P::NestedPermutedDimsArray, src, R1::CartesianIndices{0}, R2, R3, ds, dp -) - ip, is = axes(src, dp), axes(src, ds) - for jo in first(ip):8:last(ip), io in first(is):8:last(is) - for I3 in R3, I2 in R2 - for j in jo:min(jo + 7, last(ip)) - for i in io:min(io + 7, last(is)) - @inbounds P[i, I2, j, I3] = src[i, I2, j, I3] - end - end - end - end - return P -end - -@noinline function _permutedims!(P::NestedPermutedDimsArray, src, R1, R2, R3, ds, dp) - ip, is = axes(src, dp), axes(src, ds) - for jo in first(ip):8:last(ip), io in first(is):8:last(is) - for I3 in R3, I2 in R2 - for j in jo:min(jo + 7, last(ip)) - for i in io:min(io + 7, last(is)) - for I1 in R1 - @inbounds P[I1, i, I2, j, I3] = src[I1, i, I2, j, I3] - end - end - end - end - end - return P -end - -const CommutativeOps = Union{ - typeof(+), - typeof(Base.add_sum), - typeof(min), - typeof(max), - typeof(Base._extrema_rf), - typeof(|), - typeof(&), -} - -function Base._mapreduce_dim( - f, op::CommutativeOps, init::Base._InitialValue, A::NestedPermutedDimsArray, dims::Colon -) - return Base._mapreduce_dim(f, op, init, parent(A), dims) -end -function Base._mapreduce_dim( - f::typeof(identity), - op::Union{typeof(Base.mul_prod),typeof(*)}, - init::Base._InitialValue, - A::NestedPermutedDimsArray{<:Union{Real,Complex}}, - dims::Colon, -) - return Base._mapreduce_dim(f, op, init, parent(A), dims) -end - -function Base.mapreducedim!( - f, op::CommutativeOps, B::AbstractArray{T,N}, A::NestedPermutedDimsArray{S,N,perm,iperm} -) where {T,S,N,perm,iperm} - C = NestedPermutedDimsArray{T,N,iperm,perm,typeof(B)}(B) # make the inverse permutation for the output - Base.mapreducedim!(f, op, C, parent(A)) - return B -end -function Base.mapreducedim!( - f::typeof(identity), - op::Union{typeof(Base.mul_prod),typeof(*)}, - B::AbstractArray{T,N}, - A::NestedPermutedDimsArray{<:Union{Real,Complex},N,perm,iperm}, -) where {T,N,perm,iperm} - C = NestedPermutedDimsArray{T,N,iperm,perm,typeof(B)}(B) # make the inverse permutation for the output - Base.mapreducedim!(f, op, C, parent(A)) - return B -end - -function Base.showarg( - io::IO, A::NestedPermutedDimsArray{T,N,perm}, toplevel -) where {T,N,perm} - print(io, "NestedPermutedDimsArray(") - Base.showarg(io, parent(A), false) - print(io, ", ", perm, ')') - toplevel && print(io, " with eltype ", eltype(A)) - return nothing -end - -end diff --git a/NDTensors/src/lib/NestedPermutedDimsArrays/test/Project.toml b/NDTensors/src/lib/NestedPermutedDimsArrays/test/Project.toml deleted file mode 100644 index 9b1d5ccd25..0000000000 --- a/NDTensors/src/lib/NestedPermutedDimsArrays/test/Project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[deps] -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" diff --git a/NDTensors/src/lib/NestedPermutedDimsArrays/test/runtests.jl b/NDTensors/src/lib/NestedPermutedDimsArrays/test/runtests.jl deleted file mode 100644 index 704297fcc2..0000000000 --- a/NDTensors/src/lib/NestedPermutedDimsArrays/test/runtests.jl +++ /dev/null @@ -1,23 +0,0 @@ -@eval module $(gensym()) -using NDTensors.NestedPermutedDimsArrays: NestedPermutedDimsArray -using Test: @test, @testset -@testset "NestedPermutedDimsArrays" for elt in ( - Float32, Float64, Complex{Float32}, Complex{Float64} -) - a = map(_ -> randn(elt, 2, 3, 4), CartesianIndices((2, 3, 4))) - perm = (3, 1, 2) - p = NestedPermutedDimsArray(a, perm) - T = PermutedDimsArray{elt,3,perm,invperm(perm),eltype(a)} - @test typeof(p) === NestedPermutedDimsArray{T,3,perm,invperm(perm),typeof(a)} - @test size(p) == (4, 2, 3) - @test eltype(p) === T - for I in eachindex(p) - @test size(p[I]) == (4, 2, 3) - @test p[I] == permutedims(a[CartesianIndex(map(i -> Tuple(I)[i], invperm(perm)))], perm) - end - x = randn(elt, 4, 2, 3) - p[3, 1, 2] = x - @test p[3, 1, 2] == x - @test a[1, 2, 3] == permutedims(x, invperm(perm)) -end -end diff --git a/NDTensors/src/lib/SmallVectors/.JuliaFormatter.toml b/NDTensors/src/lib/SmallVectors/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/SmallVectors/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/SmallVectors/README.md b/NDTensors/src/lib/SmallVectors/README.md deleted file mode 100644 index 71ee904af7..0000000000 --- a/NDTensors/src/lib/SmallVectors/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# SmallVectors - -## Introduction - -A module that defines small (mutable and immutable) vectors with a maximum length. Externally they have a dynamic/runtime length, but internally they are backed by a statically sized vector. This makes it so that operations can be performed faster because they can remain on the stack, but it provides some more convenience compared to StaticArrays.jl where the length is encoded in the type. - -## Examples - -For example: -```julia -using NDTensors.SmallVectors - -mv = MSmallVector{10}([1, 2, 3]) # Mutable vector with length 3, maximum length 10 -push!(mv, 4) -mv[2] = 12 -sort!(mv; rev=true) - -v = SmallVector{10}([1, 2, 3]) # Immutable vector with length 3, maximum length 10 -v = SmallVectors.push(v, 4) -v = SmallVectors.setindex(v, 12, 2) -v = SmallVectors.sort(v; rev=true) -``` -This also has the advantage that you can efficiently store collections of `SmallVector`/`MSmallVector` that have different runtime lengths, as long as they have the same maximum length. - -## List of functionality - -`SmallVector` and `MSmallVector` are subtypes of `AbstractVector` and therefore can be used in `Base` `AbstractVector` functions, though `SmallVector` will fail for mutating functions like `setindex!` because it is immutable. - -`MSmallVector` has specialized implementations of `Base` functions that involve resizing such as: -- `resize!` -- `push!` -- `pushfirst!` -- `pop!` -- `popfirst!` -- `append!` -- `prepend!` -- `insert!` -- `deleteat!` -which are guaranteed to not realocate memory, and instead just use the memory buffer that already exists, unlike Base's `Vector` which may have to reallocate memory depending on the operation. However, they will error if they involve operations that resize beyond the maximum length of the `MSmallVector`, which you can access with `SmallVectors.maxlength(v)`. - -In addition, `SmallVector` and `MSmallVector` implement basic non-mutating operations such as: -- `SmallVectors.setindex` -, non-mutating resizing operations: -- `SmallVector.resize` -- `SmallVector.push` -- `SmallVector.pushfirst` -- `SmallVector.pop` -- `SmallVector.popfirst` -- `SmallVector.append` -- `SmallVector.prepend` -- `SmallVector.insert` -- `SmallVector.deleteat` -which output a new vector. In addition, it implements: -- `SmallVectors.circshift` -- `sort` (overloaded from `Base`). - -Finally, it provides some new helpful functions that are not in `Base`: -- `SmallVectors.insertsorted[!]` -- `SmallVectors.insertsortedunique[!]` -- `SmallVectors.mergesorted[!]` -- `SmallVectors.mergesortedunique[!]` - -## TODO - -Add specialized overloads for: -- `splice[!]` -- `union[!]` (`∪`) -- `intersect[!]` (`∩`) -- `setdiff[!]` -- `symdiff[!]` -- `unique[!]` - -Please let us know if there are other operations that would warrant specialized implmentations for `AbstractSmallVector`. diff --git a/NDTensors/src/lib/SmallVectors/src/BaseExt/insertstyle.jl b/NDTensors/src/lib/SmallVectors/src/BaseExt/insertstyle.jl deleted file mode 100644 index c5008fef87..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/BaseExt/insertstyle.jl +++ /dev/null @@ -1,9 +0,0 @@ -# Trait determining the style of inserting into a structure -abstract type InsertStyle end -struct IsInsertable <: InsertStyle end -struct NotInsertable <: InsertStyle end -struct FastCopy <: InsertStyle end - -# Assume is insertable -@inline InsertStyle(::Type) = IsInsertable() -@inline InsertStyle(x) = InsertStyle(typeof(x)) diff --git a/NDTensors/src/lib/SmallVectors/src/BaseExt/sort.jl b/NDTensors/src/lib/SmallVectors/src/BaseExt/sort.jl deleted file mode 100644 index 3c11321da0..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/BaseExt/sort.jl +++ /dev/null @@ -1,23 +0,0 @@ -# Custom version of `sort` (`SmallVectors.sort`) that directly uses an `order::Ordering`. -function sort(v, order::Base.Sort.Ordering; alg::Base.Sort.Algorithm=Base.Sort.defalg(v)) - mv = thaw(v) - SmallVectors.sort!(mv, order; alg) - return freeze(mv) -end - -# Custom version of `sort!` (`SmallVectors.sort!`) that directly uses an `order::Ordering`. -function sort!( - v::AbstractVector{T}, - order::Base.Sort.Ordering; - alg::Base.Sort.Algorithm=Base.Sort.defalg(v), - scratch::Union{Vector{T},Nothing}=nothing, -) where {T} - if VERSION < v"1.9" - Base.sort!(v, alg, order) - else - Base.Sort._sort!( - v, Base.Sort.maybe_apply_initial_optimizations(alg), order, (; scratch) - ) - end - return v -end diff --git a/NDTensors/src/lib/SmallVectors/src/BaseExt/sortedunique.jl b/NDTensors/src/lib/SmallVectors/src/BaseExt/sortedunique.jl deleted file mode 100644 index b8c851a568..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/BaseExt/sortedunique.jl +++ /dev/null @@ -1,241 +0,0 @@ -# Union two unique sorted collections into an -# output buffer, returning a unique sorted collection. - -using Base: Ordering, ord, lt - -function unionsortedunique!( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return unionsortedunique!(itr1, itr2, ord(lt, by, rev, order)) -end - -function unionsortedunique!(itr1, itr2, order::Ordering) - i1 = firstindex(itr1) - i2 = firstindex(itr2) - stop1 = lastindex(itr1) - stop2 = lastindex(itr2) - @inbounds while i1 ≤ stop1 && i2 ≤ stop2 - item1 = itr1[i1] - item2 = itr2[i2] - if lt(order, item1, item2) - i1 += 1 - elseif lt(order, item2, item1) - # TODO: Use `insertat!`? - resize!(itr1, length(itr1) + 1) - for j in length(itr1):-1:(i1 + 1) - itr1[j] = itr1[j - 1] - end - # Replace with the item from the second list - itr1[i1] = item2 - i1 += 1 - i2 += 1 - stop1 += 1 - else # They are equal - i1 += 1 - i2 += 1 - end - end - # TODO: Use `insertat!`? - resize!(itr1, length(itr1) + (stop2 - i2 + 1)) - @inbounds for j2 in i2:stop2 - itr1[i1] = itr2[j2] - i1 += 1 - end - return itr1 -end - -function unionsortedunique( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return unionsortedunique(itr1, itr2, ord(lt, by, rev, order)) -end - -# Union two unique sorted collections into an -# output buffer, returning a unique sorted collection. -function unionsortedunique(itr1, itr2, order::Ordering) - out = thaw_type(itr1)() - i1 = firstindex(itr1) - i2 = firstindex(itr2) - iout = firstindex(out) - stop1 = lastindex(itr1) - stop2 = lastindex(itr2) - stopout = lastindex(out) - @inbounds while i1 ≤ stop1 && i2 ≤ stop2 - iout > stopout && resize!(out, iout) - item1 = itr1[i1] - item2 = itr2[i2] - if lt(order, item1, item2) - out[iout] = item1 - iout += 1 - i1 += 1 - elseif lt(order, item2, item1) - out[iout] = item2 - iout += 1 - i2 += 1 - else # They are equal - out[iout] = item2 - iout += 1 - i1 += 1 - i2 += 1 - end - end - # TODO: Use `insertat!`? - r1 = i1:stop1 - resize!(out, length(out) + length(r1)) - @inbounds for j1 in r1 - out[iout] = itr1[j1] - iout += 1 - end - # TODO: Use `insertat!`? - r2 = i2:stop2 - resize!(out, length(out) + length(r2)) - @inbounds for j2 in r2 - out[iout] = itr2[j2] - iout += 1 - end - return freeze(out) -end - -function setdiffsortedunique!( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return setdiffsortedunique!(itr1, itr2, ord(lt, by, rev, order)) -end - -function setdiffsortedunique!(itr1, itr2, order::Ordering) - i1 = firstindex(itr1) - i2 = firstindex(itr2) - stop1 = lastindex(itr1) - stop2 = lastindex(itr2) - @inbounds while i1 ≤ stop1 && i2 ≤ stop2 - item1 = itr1[i1] - item2 = itr2[i2] - if lt(order, item1, item2) - i1 += 1 - elseif lt(order, item2, item1) - i2 += 1 - else # They are equal - # TODO: Use `deletate!`? - for j1 in i1:(length(itr1) - 1) - itr1[j1] = itr1[j1 + 1] - end - resize!(itr1, length(itr1) - 1) - stop1 = lastindex(itr1) - i2 += 1 - end - end - return itr1 -end - -function setdiffsortedunique( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return setdiffsortedunique(itr1, itr2, ord(lt, by, rev, order)) -end - -function setdiffsortedunique(itr1, itr2, order::Ordering) - out = thaw_type(itr1)() - i1 = firstindex(itr1) - i2 = firstindex(itr2) - iout = firstindex(out) - stop1 = lastindex(itr1) - stop2 = lastindex(itr2) - stopout = lastindex(out) - @inbounds while i1 ≤ stop1 && i2 ≤ stop2 - item1 = itr1[i1] - item2 = itr2[i2] - if lt(order, item1, item2) - iout > stopout && resize!(out, iout) - out[iout] = item1 - iout += 1 - i1 += 1 - elseif lt(order, item2, item1) - i2 += 1 - else # They are equal - i1 += 1 - i2 += 1 - end - end - resize!(out, iout - 1) - return freeze(out) -end - -function intersectsortedunique!( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return intersectsortedunique!(itr1, itr2, ord(lt, by, rev, order)) -end - -function intersectsortedunique!(itr1, itr2, order::Ordering) - return error("Not implemented") -end - -function intersectsortedunique( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return intersectsortedunique(itr1, itr2, ord(lt, by, rev, order)) -end - -function intersectsortedunique(itr1, itr2, order::Ordering) - return error("Not implemented") -end - -function symdiffsortedunique!( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return symdiffsortedunique!(itr1, itr2, ord(lt, by, rev, order)) -end - -function symdiffsortedunique!(itr1, itr2, order::Ordering) - return error("Not implemented") -end - -function symdiffsortedunique( - itr1, - itr2; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return symdiffsortedunique(itr1, itr2, ord(lt, by, rev, order)) -end - -function symdiffsortedunique(itr1, itr2, order::Ordering) - return error("Not implemented") -end diff --git a/NDTensors/src/lib/SmallVectors/src/BaseExt/thawfreeze.jl b/NDTensors/src/lib/SmallVectors/src/BaseExt/thawfreeze.jl deleted file mode 100644 index 7f6cd037a5..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/BaseExt/thawfreeze.jl +++ /dev/null @@ -1,6 +0,0 @@ -thaw(x) = copy(x) -freeze(x) = x - -thaw_type(::Type{<:AbstractArray{<:Any,N}}, ::Type{T}) where {T,N} = Array{T,N} -thaw_type(x::AbstractArray, ::Type{T}) where {T} = thaw_type(typeof(x), T) -thaw_type(x::AbstractArray{T}) where {T} = thaw_type(typeof(x), T) diff --git a/NDTensors/src/lib/SmallVectors/src/SmallVectors.jl b/NDTensors/src/lib/SmallVectors/src/SmallVectors.jl deleted file mode 100644 index e6c6f3330f..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/SmallVectors.jl +++ /dev/null @@ -1,45 +0,0 @@ -module SmallVectors -using StaticArrays - -export AbstractSmallVector, - SmallVector, - MSmallVector, - SubSmallVector, - FastCopy, - InsertStyle, - IsInsertable, - NotInsertable, - insert, - delete, - thaw, - freeze, - maxlength, - unionsortedunique, - unionsortedunique!, - setdiffsortedunique, - setdiffsortedunique!, - intersectsortedunique, - intersectsortedunique!, - symdiffsortedunique, - symdiffsortedunique!, - thaw_type - -struct NotImplemented <: Exception - msg::String -end -NotImplemented() = NotImplemented("Not implemented.") - -include("BaseExt/insertstyle.jl") -include("BaseExt/thawfreeze.jl") -include("BaseExt/sort.jl") -include("BaseExt/sortedunique.jl") -include("abstractarray/insert.jl") -include("abstractsmallvector/abstractsmallvector.jl") -include("abstractsmallvector/deque.jl") -include("msmallvector/msmallvector.jl") -include("smallvector/smallvector.jl") -include("smallvector/insertstyle.jl") -include("msmallvector/thawfreeze.jl") -include("smallvector/thawfreeze.jl") -include("subsmallvector/subsmallvector.jl") -end diff --git a/NDTensors/src/lib/SmallVectors/src/abstractarray/insert.jl b/NDTensors/src/lib/SmallVectors/src/abstractarray/insert.jl deleted file mode 100644 index 3a864aabe6..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/abstractarray/insert.jl +++ /dev/null @@ -1,2 +0,0 @@ -SmallVectors.insert(a::Vector, index::Integer, item) = insert!(copy(a), index, item) -delete(d::AbstractDict, key) = delete!(copy(d), key) diff --git a/NDTensors/src/lib/SmallVectors/src/abstractsmallvector/abstractsmallvector.jl b/NDTensors/src/lib/SmallVectors/src/abstractsmallvector/abstractsmallvector.jl deleted file mode 100644 index 382928489f..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/abstractsmallvector/abstractsmallvector.jl +++ /dev/null @@ -1,34 +0,0 @@ -""" -A vector with a fixed maximum length, backed by a fixed size buffer. -""" -abstract type AbstractSmallVector{T} <: AbstractVector{T} end - -# Required buffer interface -buffer(vec::AbstractSmallVector) = throw(NotImplemented()) - -similar_type(vec::AbstractSmallVector) = typeof(vec) - -# Required buffer interface -maxlength(vec::AbstractSmallVector) = length(buffer(vec)) -maxlength(vectype::Type{<:AbstractSmallVector}) = error("Not implemented") - -function thaw_type(vectype::Type{<:AbstractSmallVector}, ::Type{T}) where {T} - return MSmallVector{maxlength(vectype),T} -end -thaw_type(vectype::Type{<:AbstractSmallVector{T}}) where {T} = thaw_type(vectype, T) - -# Required AbstractArray interface -Base.size(vec::AbstractSmallVector) = throw(NotImplemented()) - -# Derived AbstractArray interface -function Base.getindex(vec::AbstractSmallVector, index::Integer) - return throw(NotImplemented()) -end -function Base.setindex!(vec::AbstractSmallVector, item, index::Integer) - return throw(NotImplemented()) -end -Base.IndexStyle(::Type{<:AbstractSmallVector}) = IndexLinear() - -function Base.convert(::Type{T}, a::AbstractArray) where {T<:AbstractSmallVector} - return a isa T ? a : T(a)::T -end diff --git a/NDTensors/src/lib/SmallVectors/src/abstractsmallvector/deque.jl b/NDTensors/src/lib/SmallVectors/src/abstractsmallvector/deque.jl deleted file mode 100644 index 3002f79f0d..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/abstractsmallvector/deque.jl +++ /dev/null @@ -1,324 +0,0 @@ -# TODO: add -# splice[!] -# union[!] (∪) -# intersect[!] (∩) -# setdiff[!] -# symdiff[!] -# unique[!] - -# unionsorted[!] -# setdiffsorted[!] -# deletesorted[!] (delete all or one?) -# deletesortedfirst[!] (delete all or one?) - -Base.resize!(vec::AbstractSmallVector, len) = throw(NotImplemented()) - -@inline function resize(vec::AbstractSmallVector, len) - mvec = thaw(vec) - resize!(mvec, len) - return convert(similar_type(vec), mvec) -end - -@inline function Base.empty!(vec::AbstractSmallVector) - resize!(vec, 0) - return vec -end - -@inline function empty(vec::AbstractSmallVector) - mvec = thaw(vec) - empty!(mvec) - return convert(similar_type(vec), mvec) -end - -@inline function StaticArrays.setindex(vec::AbstractSmallVector, item, index::Integer) - @boundscheck checkbounds(vec, index) - mvec = thaw(vec) - @inbounds mvec[index] = item - return convert(similar_type(vec), mvec) -end - -@inline function Base.push!(vec::AbstractSmallVector, item) - resize!(vec, length(vec) + 1) - @inbounds vec[length(vec)] = item - return vec -end - -@inline function StaticArrays.push(vec::AbstractSmallVector, item) - mvec = thaw(vec) - push!(mvec, item) - return convert(similar_type(vec), mvec) -end - -@inline function Base.pop!(vec::AbstractSmallVector) - resize!(vec, length(vec) - 1) - return vec -end - -@inline function StaticArrays.pop(vec::AbstractSmallVector) - mvec = thaw(vec) - pop!(mvec) - return convert(similar_type(vec), mvec) -end - -@inline function Base.pushfirst!(vec::AbstractSmallVector, item) - insert!(vec, firstindex(vec), item) - return vec -end - -# Don't `@inline`, makes it slower. -function StaticArrays.pushfirst(vec::AbstractSmallVector, item) - mvec = thaw(vec) - pushfirst!(mvec, item) - return convert(similar_type(vec), mvec) -end - -@inline function Base.popfirst!(vec::AbstractSmallVector) - circshift!(vec, -1) - resize!(vec, length(vec) - 1) - return vec -end - -# Don't `@inline`, makes it slower. -function StaticArrays.popfirst(vec::AbstractSmallVector) - mvec = thaw(vec) - popfirst!(mvec) - return convert(similar_type(vec), mvec) -end - -# This implementation of `midpoint` is performance-optimized but safe -# only if `lo <= hi`. -# TODO: Replace with `Base.midpoint`. -midpoint(lo::T, hi::T) where {T<:Integer} = lo + ((hi - lo) >>> 0x01) -midpoint(lo::Integer, hi::Integer) = midpoint(promote(lo, hi)...) - -@inline function Base.reverse!(vec::AbstractSmallVector) - start, stop = firstindex(vec), lastindex(vec) - r = stop - @inbounds for i in start:midpoint(start, stop - 1) - vec[i], vec[r] = vec[r], vec[i] - r -= 1 - end - return vec -end - -@inline function Base.reverse!( - vec::AbstractSmallVector, start::Integer, stop::Integer=lastindex(v) -) - reverse!(smallview(vec, start, stop)) - return vec -end - -@inline function Base.circshift!(vec::AbstractSmallVector, shift::Integer) - start, stop = firstindex(vec), lastindex(vec) - n = length(vec) - n == 0 && return vec - shift = mod(shift, n) - shift == 0 && return vec - reverse!(smallview(vec, start, stop - shift)) - reverse!(smallview(vec, stop - shift + 1, stop)) - reverse!(smallview(vec, start, stop)) - return vec -end - -@inline function Base.insert!(vec::AbstractSmallVector, index::Integer, item) - resize!(vec, length(vec) + 1) - circshift!(smallview(vec, index, lastindex(vec)), 1) - @inbounds vec[index] = item - return vec -end - -# Don't @inline, makes it slower. -function StaticArrays.insert(vec::AbstractSmallVector, index::Integer, item) - mvec = thaw(vec) - insert!(mvec, index, item) - return convert(similar_type(vec), mvec) -end - -@inline function Base.deleteat!(vec::AbstractSmallVector, index::Integer) - circshift!(smallview(vec, index, lastindex(vec)), -1) - resize!(vec, length(vec) - 1) - return vec -end - -@inline function Base.deleteat!( - vec::AbstractSmallVector, indices::AbstractUnitRange{<:Integer} -) - f = first(indices) - n = length(indices) - circshift!(smallview(vec, f, lastindex(vec)), -n) - resize!(vec, length(vec) - n) - return vec -end - -# Don't @inline, makes it slower. -function StaticArrays.deleteat( - vec::AbstractSmallVector, index::Union{Integer,AbstractUnitRange{<:Integer}} -) - mvec = thaw(vec) - deleteat!(mvec, index) - return convert(similar_type(vec), mvec) -end - -# InsertionSortAlg -# https://github.com/JuliaLang/julia/blob/bed2cd540a11544ed4be381d471bbf590f0b745e/base/sort.jl#L722-L736 -# https://en.wikipedia.org/wiki/Insertion_sort#:~:text=Insertion%20sort%20is%20a%20simple,%2C%20heapsort%2C%20or%20merge%20sort. -# Alternatively could use `TupleTools.jl` or `StaticArrays.jl` for out-of-place sorting. -@inline function sort!(vec::AbstractSmallVector, order::Base.Sort.Ordering) - lo, hi = firstindex(vec), lastindex(vec) - lo_plus_1 = (lo + 1) - @inbounds for i in lo_plus_1:hi - j = i - x = vec[i] - jmax = j - for _ in jmax:-1:lo_plus_1 - y = vec[j - 1] - if !Base.Sort.lt(order, x, y) - break - end - vec[j] = y - j -= 1 - end - vec[j] = x - end - return vec -end - -@inline function Base.sort!( - vec::AbstractSmallVector; lt=isless, by=identity, rev::Bool=false -) - SmallVectors.sort!(vec, Base.Sort.ord(lt, by, rev)) - return vec -end - -# Don't @inline, makes it slower. -function sort(vec::AbstractSmallVector, order::Base.Sort.Ordering) - mvec = thaw(vec) - SmallVectors.sort!(mvec, order) - return convert(similar_type(vec), mvec) -end - -@inline function Base.sort( - vec::AbstractSmallVector; lt=isless, by=identity, rev::Bool=false -) - return SmallVectors.sort(vec, Base.Sort.ord(lt, by, rev)) -end - -@inline function insertsorted!(vec::AbstractSmallVector, item; kwargs...) - insert!(vec, searchsortedfirst(vec, item; kwargs...), item) - return vec -end - -function insertsorted(vec::AbstractSmallVector, item; kwargs...) - mvec = thaw(vec) - insertsorted!(mvec, item; kwargs...) - return convert(similar_type(vec), mvec) -end - -@inline function insertsortedunique!(vec::AbstractSmallVector, item; kwargs...) - r = searchsorted(vec, item; kwargs...) - if length(r) == 0 - insert!(vec, first(r), item) - end - return vec -end - -# Code repeated since inlining doesn't work. -function insertsortedunique(vec::AbstractSmallVector, item; kwargs...) - r = searchsorted(vec, item; kwargs...) - if length(r) == 0 - vec = insert(vec, first(r), item) - end - return vec -end - -@inline function mergesorted!(vec::AbstractSmallVector, item::AbstractVector; kwargs...) - for x in item - insertsorted!(vec, x; kwargs...) - end - return vec -end - -function mergesorted(vec::AbstractSmallVector, item; kwargs...) - mvec = thaw(vec) - mergesorted!(mvec, item; kwargs...) - return convert(similar_type(vec), mvec) -end - -@inline function mergesortedunique!( - vec::AbstractSmallVector, item::AbstractVector; kwargs... -) - for x in item - insertsortedunique!(vec, x; kwargs...) - end - return vec -end - -# Code repeated since inlining doesn't work. -function mergesortedunique(vec::AbstractSmallVector, item; kwargs...) - for x in item - vec = insertsortedunique(vec, x; kwargs...) - end - return vec -end - -Base.@propagate_inbounds function Base.copyto!( - vec::AbstractSmallVector, item::AbstractVector -) - for i in eachindex(item) - vec[i] = item[i] - end - return vec -end - -# Don't @inline, makes it slower. -function Base.circshift(vec::AbstractSmallVector, shift::Integer) - mvec = thaw(vec) - circshift!(mvec, shift) - return convert(similar_type(vec), mvec) -end - -@inline function Base.append!(vec::AbstractSmallVector, item::AbstractVector) - l = length(vec) - r = length(item) - resize!(vec, l + r) - @inbounds copyto!(smallview(vec, l + 1, l + r + 1), item) - return vec -end - -# Missing from `StaticArrays.jl`. -# Don't @inline, makes it slower. -function append(vec::AbstractSmallVector, item::AbstractVector) - mvec = thaw(vec) - append!(mvec, item) - return convert(similar_type(vec), mvec) -end - -@inline function Base.prepend!(vec::AbstractSmallVector, item::AbstractVector) - l = length(vec) - r = length(item) - resize!(vec, l + r) - circshift!(vec, length(item)) - @inbounds copyto!(vec, item) - return vec -end - -# Missing from `StaticArrays.jl`. -# Don't @inline, makes it slower. -function prepend(vec::AbstractSmallVector, item::AbstractVector) - mvec = thaw(vec) - prepend!(mvec, item) - return convert(similar_type(vec), mvec) -end - -# Don't @inline, makes it slower. -function smallvector_vcat(vec1::AbstractSmallVector, vec2::AbstractVector) - mvec1 = thaw(vec1) - append!(mvec1, vec2) - return convert(similar_type(vec1), mvec1) -end - -function Base.vcat(vec1::AbstractSmallVector{<:Number}, vec2::AbstractVector{<:Number}) - return smallvector_vcat(vec1, vec2) -end - -Base.vcat(vec1::AbstractSmallVector, vec2::AbstractVector) = smallvector_vcat(vec1, vec2) diff --git a/NDTensors/src/lib/SmallVectors/src/msmallvector/msmallvector.jl b/NDTensors/src/lib/SmallVectors/src/msmallvector/msmallvector.jl deleted file mode 100644 index 6d45801f93..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/msmallvector/msmallvector.jl +++ /dev/null @@ -1,80 +0,0 @@ -""" -MSmallVector - -TODO: Make `buffer` field `const` (new in Julia 1.8) -""" -mutable struct MSmallVector{S,T} <: AbstractSmallVector{T} - buffer::MVector{S,T} - length::Int -end - -# Constructors -function MSmallVector{S}(buffer::AbstractVector, len::Int) where {S} - return MSmallVector{S,eltype(buffer)}(buffer, len) -end -function MSmallVector(buffer::AbstractVector, len::Int) - return MSmallVector{length(buffer),eltype(buffer)}(buffer, len) -end - -maxlength(::Type{<:MSmallVector{S}}) where {S} = S - -# Empty constructor -(msmallvector_type::Type{MSmallVector{S,T}} where {S,T})() = msmallvector_type(undef, 0) - -""" -`MSmallVector` constructor, uses `MVector` as a buffer. -```julia -MSmallVector{10}([1, 2, 3]) -MSmallVector{10}(SA[1, 2, 3]) -``` -""" -function MSmallVector{S,T}(vec::AbstractVector) where {S,T} - buffer = MVector{S,T}(undef) - copyto!(buffer, vec) - return MSmallVector(buffer, length(vec)) -end - -# Derive the buffer length. -MSmallVector(vec::AbstractSmallVector) = MSmallVector{length(buffer(vec))}(vec) - -function MSmallVector{S}(vec::AbstractVector) where {S} - return MSmallVector{S,eltype(vec)}(vec) -end - -function MSmallVector{S,T}(::UndefInitializer, dims::Tuple{Integer}) where {S,T} - return MSmallVector{S,T}(undef, prod(dims)) -end -function MSmallVector{S,T}(::UndefInitializer, length::Integer) where {S,T} - return MSmallVector{S,T}(MVector{S,T}(undef), length) -end - -# Buffer interface -buffer(vec::MSmallVector) = vec.buffer - -# Accessors -Base.size(vec::MSmallVector) = (vec.length,) - -# Required Base overloads -@inline function Base.getindex(vec::MSmallVector, index::Integer) - @boundscheck checkbounds(vec, index) - return @inbounds buffer(vec)[index] -end - -@inline function Base.setindex!(vec::MSmallVector, item, index::Integer) - @boundscheck checkbounds(vec, index) - @inbounds buffer(vec)[index] = item - return vec -end - -@inline function Base.resize!(vec::MSmallVector, len::Integer) - len < 0 && throw(ArgumentError("New length must be ≥ 0.")) - len > maxlength(vec) && - throw(ArgumentError("New length $len must be ≤ the maximum length $(maxlength(vec)).")) - vec.length = len - return vec -end - -# `similar` creates a `MSmallVector` by default. -function Base.similar(vec::AbstractSmallVector, elt::Type, dims::Dims) - return MSmallVector{length(buffer(vec)),elt}(undef, dims) -end diff --git a/NDTensors/src/lib/SmallVectors/src/msmallvector/thawfreeze.jl b/NDTensors/src/lib/SmallVectors/src/msmallvector/thawfreeze.jl deleted file mode 100644 index 563f20dd18..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/msmallvector/thawfreeze.jl +++ /dev/null @@ -1,2 +0,0 @@ -thaw(vec::MSmallVector) = copy(vec) -freeze(vec::MSmallVector) = SmallVector(vec) diff --git a/NDTensors/src/lib/SmallVectors/src/smallvector/insertstyle.jl b/NDTensors/src/lib/SmallVectors/src/smallvector/insertstyle.jl deleted file mode 100644 index 027d1eb356..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/smallvector/insertstyle.jl +++ /dev/null @@ -1 +0,0 @@ -InsertStyle(::Type{<:SmallVector}) = FastCopy() diff --git a/NDTensors/src/lib/SmallVectors/src/smallvector/smallvector.jl b/NDTensors/src/lib/SmallVectors/src/smallvector/smallvector.jl deleted file mode 100644 index 4b99e76cd6..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/smallvector/smallvector.jl +++ /dev/null @@ -1,82 +0,0 @@ -""" -SmallVector -""" -struct SmallVector{S,T} <: AbstractSmallVector{T} - buffer::SVector{S,T} - length::Int -end - -# Accessors -# TODO: Use `Accessors.jl`. -@inline setbuffer(vec::SmallVector, buffer) = SmallVector(buffer, vec.length) -@inline setlength(vec::SmallVector, length) = SmallVector(vec.buffer, length) - -maxlength(::Type{<:SmallVector{S}}) where {S} = S - -# Constructors -function SmallVector{S}(buffer::AbstractVector, len::Int) where {S} - return SmallVector{S,eltype(buffer)}(buffer, len) -end -function SmallVector(buffer::AbstractVector, len::Int) - return SmallVector{length(buffer),eltype(buffer)}(buffer, len) -end - -""" -`SmallVector` constructor, uses `SVector` as buffer storage. -```julia -SmallVector{10}([1, 2, 3]) -SmallVector{10}(SA[1, 2, 3]) -``` -""" -function SmallVector{S,T}(vec::AbstractVector) where {S,T} - # TODO: This is a bit slower, but simpler. Check if this - # gets faster in newer Julia versions. - # return SmallVector{S,T}(MSmallVector{S,T}(vec)) - length(vec) > S && error("Data is too long for `SmallVector`.") - msvec = MVector{S,T}(undef) - @inbounds for i in eachindex(vec) - msvec[i] = vec[i] - end - svec = SVector(msvec) - return SmallVector{S,T}(svec, length(vec)) -end -# Special optimization codepath for `MSmallVector` -# to avoid a copy. -function SmallVector{S,T}(vec::MSmallVector) where {S,T} - return SmallVector{S,T}(buffer(vec), length(vec)) -end - -function SmallVector{S}(vec::AbstractVector) where {S} - return SmallVector{S,eltype(vec)}(vec) -end - -# Specialized constructor -function MSmallVector{S,T}(vec::SmallVector) where {S,T} - return MSmallVector{S,T}(buffer(vec), length(vec)) -end - -# Derive the buffer length. -SmallVector(vec::AbstractSmallVector) = SmallVector{length(buffer(vec))}(vec) - -# Empty constructor -(smallvector_type::Type{SmallVector{S,T}} where {S,T})() = smallvector_type(undef, 0) -function SmallVector{S,T}(::UndefInitializer, length::Integer) where {S,T} - return SmallVector{S,T}(SVector{S,T}(MVector{S,T}(undef)), length) -end - -# Buffer interface -buffer(vec::SmallVector) = vec.buffer - -# AbstractArray interface -Base.size(vec::SmallVector) = (vec.length,) - -# Base overloads -@inline function Base.getindex(vec::SmallVector, index::Integer) - @boundscheck checkbounds(vec, index) - return @inbounds buffer(vec)[index] -end - -Base.copy(vec::SmallVector) = vec - -# Optimization, default uses `similar`. -Base.copymutable(vec::SmallVector) = MSmallVector(vec) diff --git a/NDTensors/src/lib/SmallVectors/src/smallvector/thawfreeze.jl b/NDTensors/src/lib/SmallVectors/src/smallvector/thawfreeze.jl deleted file mode 100644 index 077e7d539e..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/smallvector/thawfreeze.jl +++ /dev/null @@ -1,2 +0,0 @@ -thaw(vec::SmallVector) = MSmallVector(vec) -freeze(vec::SmallVector) = vec diff --git a/NDTensors/src/lib/SmallVectors/src/subsmallvector/subsmallvector.jl b/NDTensors/src/lib/SmallVectors/src/subsmallvector/subsmallvector.jl deleted file mode 100644 index 922eaa3521..0000000000 --- a/NDTensors/src/lib/SmallVectors/src/subsmallvector/subsmallvector.jl +++ /dev/null @@ -1,80 +0,0 @@ -abstract type AbstractSubSmallVector{T} <: AbstractSmallVector{T} end - -""" -SubSmallVector -""" -struct SubSmallVector{T,P} <: AbstractSubSmallVector{T} - parent::P - start::Int - stop::Int -end - -mutable struct SubMSmallVector{T,P<:AbstractVector{T}} <: AbstractSubSmallVector{T} - parent::P - start::Int - stop::Int -end - -# TODO: Use Accessors.jl -Base.parent(vec::SubSmallVector) = vec.parent -Base.parent(vec::SubMSmallVector) = vec.parent - -# buffer interface -buffer(vec::AbstractSubSmallVector) = buffer(parent(vec)) - -function smallview(vec::SmallVector, start::Integer, stop::Integer) - return SubSmallVector(vec, start, stop) -end -function smallview(vec::MSmallVector, start::Integer, stop::Integer) - return SubMSmallVector(vec, start, stop) -end - -function smallview(vec::SubSmallVector, start::Integer, stop::Integer) - return SubSmallVector(parent(vec), vec.start + start - 1, vec.start + stop - 1) -end -function smallview(vec::SubMSmallVector, start::Integer, stop::Integer) - return SubMSmallVector(parent(vec), vec.start + start - 1, vec.start + stop - 1) -end - -# Constructors -function SubSmallVector(vec::AbstractVector, start::Integer, stop::Integer) - return SubSmallVector{eltype(vec),typeof(vec)}(vec, start, stop) -end -function SubMSmallVector(vec::AbstractVector, start::Integer, stop::Integer) - return SubMSmallVector{eltype(vec),typeof(vec)}(vec, start, stop) -end - -# Accessors -Base.size(vec::AbstractSubSmallVector) = (vec.stop - vec.start + 1,) - -Base.@propagate_inbounds function Base.getindex(vec::AbstractSubSmallVector, index::Integer) - return parent(vec)[index + vec.start - 1] -end - -Base.@propagate_inbounds function Base.setindex!( - vec::AbstractSubSmallVector, item, index::Integer -) - buffer(vec)[index + vec.start - 1] = item - return vec -end - -function SubSmallVector{T,P}(vec::SubMSmallVector) where {T,P} - return SubSmallVector{T,P}(P(parent(vec)), vec.start, vec.stop) -end - -function Base.convert(smalltype::Type{<:SubSmallVector}, vec::SubMSmallVector) - return smalltype(vec) -end - -@inline function Base.resize!(vec::SubMSmallVector, len::Integer) - len < 0 && throw(ArgumentError("New length must be ≥ 0.")) - len > maxlength(vec) - vec.start + 1 && - throw(ArgumentError("New length $len must be ≤ the maximum length $(maxlength(vec)).")) - vec.stop = vec.start + len - 1 - return vec -end - -# Optimization, default uses `similar`. -function Base.copymutable(vec::SubSmallVector) - return SubMSmallVector(Base.copymutable(parent(vec)), vec.start, vec.stop) -end diff --git a/NDTensors/src/lib/SmallVectors/test/runtests.jl b/NDTensors/src/lib/SmallVectors/test/runtests.jl deleted file mode 100644 index 7bf559206f..0000000000 --- a/NDTensors/src/lib/SmallVectors/test/runtests.jl +++ /dev/null @@ -1,158 +0,0 @@ -using NDTensors.SmallVectors -using Test: @inferred, @test, @testset, @test_broken - -using NDTensors.SmallVectors: - setindex, - resize, - push, - pushfirst, - pop, - popfirst, - append, - prepend, - insert, - deleteat, - circshift, - insertsorted, - insertsorted!, - insertsortedunique, - insertsortedunique!, - mergesorted, - mergesorted!, - mergesortedunique, - mergesortedunique! - -function test_smallvectors() - return @testset "SmallVectors" begin - x = SmallVector{10}([1, 3, 5]) - mx = MSmallVector(x) - - @test x isa SmallVector{10,Int} - @test mx isa MSmallVector{10,Int} - @test eltype(x) === Int - @test eltype(mx) === Int - - # TODO: Test construction has zero allocations. - # TODO: Extend construction to arbitrary collections, like tuple. - ## in julia v"1.10" SmallVector(x) does 1 allocation - ## and vcat does 3 allocations (i.e. MSmallVector(x) does 3 allocations) - ## On my mac M1 a single allocation is 96B so allow for up to 3 allocations - alloc_size = 96 - nalloc_limit = 4 * alloc_size - - # conversion - @test @inferred(SmallVector(x)) == x - @test @allocated(SmallVector(x)) < nalloc_limit - @test @inferred(SmallVector(mx)) == x - @test @allocated(SmallVector(mx)) < nalloc_limit - - # length - @test @inferred(length(x)) == 3 - @test @allocated(length(x)) == 0 - @test @inferred(length(SmallVectors.buffer(x))) == 10 - @test @allocated(length(SmallVectors.buffer(x))) < nalloc_limit - - item = 115 - no_broken = (false, false, false, false) - for ( - f!, - f, - ans, - args, - nalloc, - f!_impl_broken, - f!_noalloc_broken, - f_impl_broken, - f_noalloc_broken, - ) in [ - (:push!, :push, [1, 3, 5, item], (item,), nalloc_limit, no_broken...), - (:append!, :append, [1, 3, 5, item], ([item],), nalloc_limit, no_broken...), - (:prepend!, :prepend, [item, 1, 3, 5], ([item],), nalloc_limit, no_broken...), - (:pushfirst!, :pushfirst, [item, 1, 3, 5], (item,), nalloc_limit, no_broken...), - (:setindex!, :setindex, [1, item, 5], (item, 2), nalloc_limit, no_broken...), - (:pop!, :pop, [1, 3], (), nalloc_limit, no_broken...), - (:popfirst!, :popfirst, [3, 5], (), nalloc_limit, no_broken...), - (:insert!, :insert, [1, item, 3, 5], (2, item), nalloc_limit, no_broken...), - (:deleteat!, :deleteat, [1, 5], (2,), nalloc_limit, no_broken...), - (:circshift!, :circshift, [5, 1, 3], (1,), nalloc_limit, no_broken...), - (:sort!, :sort, [1, 3, 5], (), nalloc_limit, no_broken...), - (:insertsorted!, :insertsorted, [1, 2, 3, 5], (2,), nalloc_limit, no_broken...), - (:insertsorted!, :insertsorted, [1, 3, 3, 5], (3,), nalloc_limit, no_broken...), - ( - :insertsortedunique!, - :insertsortedunique, - [1, 2, 3, 5], - (2,), - nalloc_limit, - no_broken..., - ), - ( - :insertsortedunique!, - :insertsortedunique, - [1, 3, 5], - (3,), - nalloc_limit, - no_broken..., - ), - (:mergesorted!, :mergesorted, [1, 2, 3, 3, 5], ([2, 3],), nalloc_limit, no_broken...), - ( - :mergesortedunique!, - :mergesortedunique, - [1, 2, 3, 5], - ([2, 3],), - nalloc_limit, - no_broken..., - ), - ] - mx_tmp = copy(mx) - @eval begin - if VERSION < v"1.7" - # broken kwarg wasn't added to @test yet - if $f!_impl_broken - @test_broken @inferred($f!(copy($mx), $args...)) == $ans - else - @test @inferred($f!(copy($mx), $args...)) == $ans - end - if $f!_noalloc_broken - @test_broken @allocated($f!($mx_tmp, $args...)) ≤ $nalloc - else - @test @allocated($f!($mx_tmp, $args...)) ≤ $nalloc - end - if $f_impl_broken - @test_broken @inferred($f($x, $args...)) == $ans - else - @test @inferred($f($x, $args...)) == $ans - end - if $f_noalloc_broken - @test_broken @allocated($f($x, $args...)) ≤ $nalloc - else - @test @allocated($f($x, $args...)) ≤ $nalloc - end - else - @test @inferred($f!(copy($mx), $args...)) == $ans broken = $f!_impl_broken - @test @allocated($f!($mx_tmp, $args...)) ≤ $nalloc broken = $f!_noalloc_broken - @test @inferred($f($x, $args...)) == $ans broken = $f_impl_broken - @test @allocated($f($x, $args...)) ≤ $nalloc broken = $f_noalloc_broken - end - end - end - - # Separated out since for some reason it breaks the `@inferred` - # check when `kwargs` are interpolated into `@eval`. - ans, kwargs = [5, 3, 1], (; rev=true) - mx_tmp = copy(mx) - @test @inferred(sort!(copy(mx); kwargs...)) == ans - @test @allocated(sort!(mx_tmp; kwargs...)) == 0 - @test @inferred(sort(x; kwargs...)) == ans - @test @allocated(sort(x; kwargs...)) ≤ nalloc_limit - - ans, args = [1, 3, 5, item], ([item],) - @test @inferred(vcat(x, args...)) == ans - @test @allocated(vcat(x, args...)) ≤ nalloc_limit - end -end - -# TODO: switch to: -# @testset "SmallVectors" test_smallvectors() -# (new in Julia 1.9) -test_smallvectors() diff --git a/NDTensors/src/lib/SortedSets/.JuliaFormatter.toml b/NDTensors/src/lib/SortedSets/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/SortedSets/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/SortedSets/src/BaseExt/sorted.jl b/NDTensors/src/lib/SortedSets/src/BaseExt/sorted.jl deleted file mode 100644 index 54a2873765..0000000000 --- a/NDTensors/src/lib/SortedSets/src/BaseExt/sorted.jl +++ /dev/null @@ -1,54 +0,0 @@ -# TODO: -# Add ` -# Version that uses an `Ordering`. -function _insorted( - x, - v::AbstractVector; - lt=isless, - by=identity, - rev::Union{Bool,Nothing}=nothing, - order::Ordering=Forward, -) - return _insorted(x, v, ord(lt, by, rev, order)) -end -_insorted(x, v::AbstractVector, o::Ordering) = !isempty(searchsorted(v, x, o)) - -function alluniquesorted( - vec; lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward -) - return alluniquesorted(vec, ord(lt, by, rev, order)) -end - -function alluniquesorted(vec, order::Ordering) - length(vec) < 2 && return true - iter = eachindex(vec) - I = iterate(iter) - while I !== nothing - i, s = I - J = iterate(iter, s) - isnothing(J) && return true - j, _ = J - !lt(order, @inbounds(vec[i]), @inbounds(vec[j])) && return false - I = J - end - return true -end - -function uniquesorted(vec; lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward) - return uniquesorted(vec, ord(lt, by, rev, order)) -end - -function uniquesorted(vec::AbstractVector, order::Ordering) - mvec = thaw(vec) - i = firstindex(mvec) - stopi = lastindex(mvec) - while i < stopi - if !lt(order, @inbounds(mvec[i]), @inbounds(mvec[i + 1])) - deleteat!(mvec, i) - stopi -= 1 - else - i += 1 - end - end - return freeze(mvec) -end diff --git a/NDTensors/src/lib/SortedSets/src/DictionariesExt/insert.jl b/NDTensors/src/lib/SortedSets/src/DictionariesExt/insert.jl deleted file mode 100644 index 847f312208..0000000000 --- a/NDTensors/src/lib/SortedSets/src/DictionariesExt/insert.jl +++ /dev/null @@ -1,35 +0,0 @@ -SmallVectors.insert(inds::AbstractIndices, i) = insert(InsertStyle(inds), inds, i) - -function SmallVectors.insert(::InsertStyle, inds::AbstractIndices, i) - return error("Not implemented") -end - -function SmallVectors.insert(::IsInsertable, inds::AbstractIndices, i) - inds = copy(inds) - insert!(inds, i) - return inds -end - -function SmallVectors.insert(::FastCopy, inds::AbstractIndices, i) - minds = thaw(inds) - insert!(minds, i) - return freeze(minds) -end - -SmallVectors.delete(inds::AbstractIndices, i) = delete(InsertStyle(inds), inds, i) - -function SmallVectors.delete(::InsertStyle, inds::AbstractIndices, i) - return error("Not implemented") -end - -function SmallVectors.delete(::IsInsertable, inds::AbstractIndices, i) - inds = copy(inds) - delete!(inds, i) - return inds -end - -function SmallVectors.delete(::FastCopy, inds::AbstractIndices, i) - minds = thaw(inds) - delete!(minds, i) - return freeze(minds) -end diff --git a/NDTensors/src/lib/SortedSets/src/DictionariesExt/isinsertable.jl b/NDTensors/src/lib/SortedSets/src/DictionariesExt/isinsertable.jl deleted file mode 100644 index 6c9599ce39..0000000000 --- a/NDTensors/src/lib/SortedSets/src/DictionariesExt/isinsertable.jl +++ /dev/null @@ -1 +0,0 @@ -Dictionaries.isinsertable(::AbstractArray) = true diff --git a/NDTensors/src/lib/SortedSets/src/SmallVectorsDictionariesExt/interface.jl b/NDTensors/src/lib/SortedSets/src/SmallVectorsDictionariesExt/interface.jl deleted file mode 100644 index 20dca8d56f..0000000000 --- a/NDTensors/src/lib/SortedSets/src/SmallVectorsDictionariesExt/interface.jl +++ /dev/null @@ -1,3 +0,0 @@ -Dictionaries.isinsertable(::AbstractSmallVector) = true -Dictionaries.isinsertable(::SmallVector) = false -Dictionaries.empty_type(::Type{SmallVector{S,T}}, ::Type{T}) where {S,T} = MSmallVector{S,T} diff --git a/NDTensors/src/lib/SortedSets/src/SortedSets.jl b/NDTensors/src/lib/SortedSets/src/SortedSets.jl deleted file mode 100644 index 777407f3c5..0000000000 --- a/NDTensors/src/lib/SortedSets/src/SortedSets.jl +++ /dev/null @@ -1,21 +0,0 @@ -module SortedSets -using Compat -using Dictionaries -using Random -using ..SmallVectors - -using Base: @propagate_inbounds -using Base.Order: Ordering, Forward, ord, lt - -export AbstractWrappedSet, SortedSet, SmallSet, MSmallSet - -include("BaseExt/sorted.jl") -include("DictionariesExt/insert.jl") -include("DictionariesExt/isinsertable.jl") -include("abstractset.jl") -include("abstractwrappedset.jl") -include("SmallVectorsDictionariesExt/interface.jl") -include("sortedset.jl") -include("SortedSetsSmallVectorsExt/smallset.jl") - -end diff --git a/NDTensors/src/lib/SortedSets/src/SortedSetsSmallVectorsExt/smallset.jl b/NDTensors/src/lib/SortedSets/src/SortedSetsSmallVectorsExt/smallset.jl deleted file mode 100644 index 8c70f8fe60..0000000000 --- a/NDTensors/src/lib/SortedSets/src/SortedSetsSmallVectorsExt/smallset.jl +++ /dev/null @@ -1,16 +0,0 @@ -const AbstractSmallSet{T} = SortedSet{T,<:AbstractSmallVector{T}} -const SmallSet{S,T} = SortedSet{T,SmallVector{S,T}} -const MSmallSet{S,T} = SortedSet{T,MSmallVector{S,T}} - -# Specialized constructors -@propagate_inbounds SmallSet{S}(; kwargs...) where {S} = SmallSet{S}([]; kwargs...) -@propagate_inbounds SmallSet{S}(iter; kwargs...) where {S} = - SmallSet{S}(collect(iter); kwargs...) -@propagate_inbounds SmallSet{S}(a::AbstractArray{I}; kwargs...) where {S,I} = - SmallSet{S,I}(a; kwargs...) - -@propagate_inbounds MSmallSet{S}(; kwargs...) where {S} = MSmallSet{S}([]; kwargs...) -@propagate_inbounds MSmallSet{S}(iter; kwargs...) where {S} = - MSmallSet{S}(collect(iter); kwargs...) -@propagate_inbounds MSmallSet{S}(a::AbstractArray{I}; kwargs...) where {S,I} = - MSmallSet{S,I}(a; kwargs...) diff --git a/NDTensors/src/lib/SortedSets/src/abstractset.jl b/NDTensors/src/lib/SortedSets/src/abstractset.jl deleted file mode 100644 index 57ccb90619..0000000000 --- a/NDTensors/src/lib/SortedSets/src/abstractset.jl +++ /dev/null @@ -1,88 +0,0 @@ -abstract type AbstractSet{T} <: AbstractIndices{T} end - -# Specialized versions of set operations for `AbstractSet` -# that allow more specialization. - -function Base.union(i::AbstractSet, itr) - return union(InsertStyle(i), i, itr) -end - -function Base.union(::InsertStyle, i::AbstractSet, itr) - return error("Not implemented") -end - -function Base.union(::IsInsertable, i::AbstractSet, itr) - out = copy(i) - union!(out, itr) - return out -end - -function Base.union(::NotInsertable, i::AbstractSet, itr) - out = empty(i) - union!(out, i) - union!(out, itr) - return out -end - -function Base.intersect(i::AbstractSet, itr) - return intersect(InsertStyle(i), i, itr) -end - -function Base.intersect(::InsertStyle, i::AbstractSet, itr) - return error("Not implemented") -end - -function Base.intersect(::IsInsertable, i::AbstractSet, itr) - out = copy(i) - intersect!(out, itr) - return out -end - -function Base.intersect(::NotInsertable, i::AbstractSet, itr) - out = empty(i) - union!(out, i) - intersect!(out, itr) - return out -end - -function Base.setdiff(i::AbstractSet, itr) - return setdiff(InsertStyle(i), i, itr) -end - -function Base.setdiff(::InsertStyle, i::AbstractSet, itr) - return error("Not implemented") -end - -function Base.setdiff(::IsInsertable, i::AbstractSet, itr) - out = copy(i) - setdiff!(out, itr) - return out -end - -function Base.setdiff(::NotInsertable, i::AbstractSet, itr) - out = empty(i) - union!(out, i) - setdiff!(out, itr) - return out -end - -function Base.symdiff(i::AbstractSet, itr) - return symdiff(InsertStyle(i), i, itr) -end - -function Base.symdiff(::InsertStyle, i::AbstractSet, itr) - return error("Not implemented") -end - -function Base.symdiff(::IsInsertable, i::AbstractSet, itr) - out = copy(i) - symdiff!(out, itr) - return out -end - -function Base.symdiff(::NotInsertable, i::AbstractSet, itr) - out = empty(i) - union!(out, i) - symdiff!(out, itr) - return out -end diff --git a/NDTensors/src/lib/SortedSets/src/abstractwrappedset.jl b/NDTensors/src/lib/SortedSets/src/abstractwrappedset.jl deleted file mode 100644 index e1a1094ff8..0000000000 --- a/NDTensors/src/lib/SortedSets/src/abstractwrappedset.jl +++ /dev/null @@ -1,117 +0,0 @@ -# AbstractWrappedSet: a wrapper around an `AbstractIndices` -# with methods automatically forwarded via `parent` -# and rewrapped via `rewrap`. -abstract type AbstractWrappedSet{T,D} <: AbstractIndices{T} end - -# Required interface -Base.parent(set::AbstractWrappedSet) = error("Not implemented") -function Dictionaries.empty_type(::Type{AbstractWrappedSet{I}}, ::Type{I}) where {I} - return error("Not implemented") -end -rewrap(::AbstractWrappedSet, data) = error("Not implemented") - -SmallVectors.thaw(set::AbstractWrappedSet) = rewrap(set, thaw(parent(set))) -SmallVectors.freeze(set::AbstractWrappedSet) = rewrap(set, freeze(parent(set))) - -# Traits -SmallVectors.InsertStyle(::Type{<:AbstractWrappedSet{T,D}}) where {T,D} = InsertStyle(D) - -# AbstractSet interface -@propagate_inbounds function Base.iterate(set::AbstractWrappedSet, state...) - return iterate(parent(set), state...) -end - -# `I` is needed to avoid ambiguity error. -@inline Base.in(item::I, set::AbstractWrappedSet{I}) where {I} = in(item, parent(set)) -@inline Base.IteratorSize(set::AbstractWrappedSet) = Base.IteratorSize(parent(set)) -@inline Base.length(set::AbstractWrappedSet) = length(parent(set)) - -@inline Dictionaries.istokenizable(set::AbstractWrappedSet) = istokenizable(parent(set)) -@inline Dictionaries.tokentype(set::AbstractWrappedSet) = tokentype(parent(set)) -@inline Dictionaries.iteratetoken(set::AbstractWrappedSet, s...) = - iterate(parent(set), s...) -@inline function Dictionaries.iteratetoken_reverse(set::AbstractWrappedSet) - return iteratetoken_reverse(parent(set)) -end -@inline function Dictionaries.iteratetoken_reverse(set::AbstractWrappedSet, t) - return iteratetoken_reverse(parent(set), t) -end - -@inline function Dictionaries.gettoken(set::AbstractWrappedSet, i) - return gettoken(parent(set), i) -end -@propagate_inbounds Dictionaries.gettokenvalue(set::AbstractWrappedSet, x) = - gettokenvalue(parent(set), x) - -@inline Dictionaries.isinsertable(set::AbstractWrappedSet) = isinsertable(parent(set)) - -# Specify `I` to fix ambiguity error. -@inline function Dictionaries.gettoken!( - set::AbstractWrappedSet{I}, i::I, values=() -) where {I} - return gettoken!(parent(set), i, values) -end - -@inline function Dictionaries.deletetoken!(set::AbstractWrappedSet, x, values=()) - deletetoken!(parent(set), x, values) - return set -end - -@inline function Base.empty!(set::AbstractWrappedSet, values=()) - empty!(parent(set)) - return set -end - -# Not defined to be part of the `AbstractIndices` interface, -# but seems to be needed. -@inline function Base.filter!(pred, set::AbstractWrappedSet) - filter!(pred, parent(set)) - return set -end - -# TODO: Maybe require an implementation? -@inline function Base.copy(set::AbstractWrappedSet, eltype::Type) - return typeof(set)(copy(parent(set), eltype)) -end - -# Not required for AbstractIndices interface but -# helps with faster code paths -SmallVectors.insert(set::AbstractWrappedSet, item) = rewrap(set, insert(parent(set), item)) -function Base.insert!(set::AbstractWrappedSet, item) - insert!(parent(set), item) - return set -end - -SmallVectors.delete(set::AbstractWrappedSet, item) = rewrap(set, delete(parent(set), item)) -function Base.delete!(set::AbstractWrappedSet, item) - delete!(parent(set), item) - return set -end - -function Base.union(set1::AbstractWrappedSet, set2::AbstractWrappedSet) - return rewrap(set1, union(parent(set1), parent(set2))) -end -function Base.union(set1::AbstractWrappedSet, set2) - return rewrap(set1, union(parent(set1), set2)) -end - -function Base.intersect(set1::AbstractWrappedSet, set2::AbstractWrappedSet) - return rewrap(set1, intersect(parent(set1), parent(set2))) -end -function Base.intersect(set1::AbstractWrappedSet, set2) - return rewrap(set1, intersect(parent(set1), set2)) -end - -function Base.setdiff(set1::AbstractWrappedSet, set2::AbstractWrappedSet) - return rewrap(set1, setdiff(parent(set1), parent(set2))) -end -function Base.setdiff(set1::AbstractWrappedSet, set2) - return rewrap(set1, setdiff(parent(set1), set2)) -end - -function Base.symdiff(set1::AbstractWrappedSet, set2::AbstractWrappedSet) - return rewrap(set1, symdiff(parent(set1), parent(set2))) -end -function Base.symdiff(set1::AbstractWrappedSet, set2) - return rewrap(set1, symdiff(parent(set1), set2)) -end diff --git a/NDTensors/src/lib/SortedSets/src/sortedset.jl b/NDTensors/src/lib/SortedSets/src/sortedset.jl deleted file mode 100644 index dff1b441a0..0000000000 --- a/NDTensors/src/lib/SortedSets/src/sortedset.jl +++ /dev/null @@ -1,301 +0,0 @@ -""" - SortedSet(iter) - -Construct an `SortedSet <: AbstractSet` from an arbitrary Julia iterable with unique -elements. Lookup uses that they are sorted. - -SortedSet can be faster than ArrayIndices which use naive search that may be optimal for -small collections. Larger collections are better handled by containers like `Indices`. -""" -struct SortedSet{T,Data<:AbstractArray{T},Order<:Ordering} <: AbstractSet{T} - data::Data - order::Order - global @inline _SortedSet( - data::Data, order::Order - ) where {T,Data<:AbstractArray{T},Order<:Ordering} = new{T,Data,Order}(data, order) -end - -@inline Base.parent(set::SortedSet) = getfield(set, :data) -@inline order(set::SortedSet) = getfield(set, :order) - -# Dictionaries.jl interface -const SortedIndices = SortedSet - -# Inner constructor. -# Sorts and makes unique as needed. -function SortedSet{T,Data,Order}( - a::Data, order::Order -) where {T,Data<:AbstractArray{T},Order<:Ordering} - if !issorted(a, order) - a = SmallVectors.sort(a, order) - end - if !alluniquesorted(a, order) - a = uniquesorted(a, order) - end - return _SortedSet(a, order) -end - -@inline function SortedSet{T,Data,Order}( - a::AbstractArray, order::Ordering -) where {T,Data<:AbstractArray{T},Order<:Ordering} - return SortedSet{T,Data,Order}(convert(Data, a), convert(Order, order)) -end - -@inline function SortedSet{T,Data}( - a::AbstractArray, order::Order -) where {T,Data<:AbstractArray{T},Order<:Ordering} - return SortedSet{T,Data,Order}(a, order) -end - -@inline function SortedSet(a::Data, order::Ordering) where {T,Data<:AbstractArray{T}} - return SortedSet{T,Data}(a, order) -end - -# Accept other inputs like `Tuple`. -@inline function SortedSet(itr, order::Ordering) - return SortedSet(collect(itr), order) -end - -@inline function SortedSet{T,Data}( - a::Data; lt=isless, by=identity, rev::Bool=false -) where {T,Data<:AbstractArray{T}} - return SortedSet{T,Data}(a, ord(lt, by, rev)) -end - -# Traits -@inline SmallVectors.InsertStyle(::Type{<:SortedSet{T,Data}}) where {T,Data} = - InsertStyle(Data) -@inline SmallVectors.thaw(set::SortedSet) = SortedSet(thaw(parent(set)), order(set)) -@inline SmallVectors.freeze(set::SortedSet) = SortedSet(freeze(parent(set)), order(set)) - -@propagate_inbounds SortedSet(; kwargs...) = SortedSet{Any}([]; kwargs...) -@propagate_inbounds SortedSet{T}(; kwargs...) where {T} = - SortedSet{T,Vector{T}}(T[]; kwargs...) -@propagate_inbounds SortedSet{T,Data}(; kwargs...) where {T,Data} = - SortedSet{T}(Data(); kwargs...) - -@propagate_inbounds SortedSet(iter; kwargs...) = SortedSet(collect(iter); kwargs...) -@propagate_inbounds SortedSet{T}(iter; kwargs...) where {T} = - SortedSet{T}(collect(T, iter); kwargs...) - -@propagate_inbounds SortedSet(a::AbstractArray{T}; kwargs...) where {T} = - SortedSet{T}(a; kwargs...) -@propagate_inbounds SortedSet{T}(a::AbstractArray{T}; kwargs...) where {T} = - SortedSet{T,typeof(a)}(a; kwargs...) - -@propagate_inbounds SortedSet{T,Data}( - a::AbstractArray; kwargs... -) where {T,Data<:AbstractArray{T}} = SortedSet{T,Data}(Data(a); kwargs...) - -function Base.convert(::Type{AbstractIndices{T}}, set::SortedSet) where {T} - return convert(SortedSet{T}, set) -end -function Base.convert(::Type{SortedSet}, set::AbstractIndices{T}) where {T} - return convert(SortedSet{T}, set) -end -function Base.convert(::Type{SortedSet{T}}, set::AbstractIndices) where {T} - return convert(SortedSet{T,Vector{T}}, set) -end -function Base.convert( - ::Type{SortedSet{T,Data}}, set::AbstractIndices -) where {T,Data<:AbstractArray{T}} - a = convert(Data, collect(T, set)) - return @inbounds SortedSet{T,typeof(a)}(a) -end - -Base.convert(::Type{SortedSet{T}}, set::SortedSet{T}) where {T} = set -function Base.convert( - ::Type{SortedSet{T}}, set::SortedSet{<:Any,Data} -) where {T,Data<:AbstractArray{T}} - return convert(SortedSet{T,Data}, set) -end -function Base.convert( - ::Type{SortedSet{T,Data}}, set::SortedSet{T,Data} -) where {T,Data<:AbstractArray{T}} - return set -end -function Base.convert( - ::Type{SortedSet{T,Data}}, set::SortedSet -) where {T,Data<:AbstractArray{T}} - a = convert(Data, parent(set)) - return @inbounds SortedSet{T,Data}(a) -end - -# Basic interface -@propagate_inbounds function Base.iterate(set::SortedSet{T}, state...) where {T} - return iterate(parent(set), state...) -end - -@inline function Base.in(i::T, set::SortedSet{T}) where {T} - return _insorted(i, parent(set), order(set)) -end -@inline Base.IteratorSize(::SortedSet) = Base.HasLength() -@inline Base.length(set::SortedSet) = length(parent(set)) - -function Base.:(==)(set1::SortedSet, set2::SortedSet) - if length(set1) ≠ length(set2) - return false - end - for (j1, j2) in zip(set1, set2) - if j1 ≠ j2 - return false - end - end - return true -end - -function Base.issetequal(set1::SortedSet, set2::SortedSet) - if length(set1) ≠ length(set2) - return false - end - if order(set1) ≠ order(set2) - # TODO: Make sure this actually sorts! - set2 = SortedSet(parent(set2), order(set1)) - end - for (j1, j2) in zip(set1, set2) - if lt(order(set1), j1, j2) || lt(order(set1), j2, j1) - return false - end - end - return true -end - -@inline Dictionaries.istokenizable(::SortedSet) = true -@inline Dictionaries.tokentype(::SortedSet) = Int -@inline Dictionaries.iteratetoken(set::SortedSet, s...) = - iterate(LinearIndices(parent(set)), s...) -@inline function Dictionaries.iteratetoken_reverse(set::SortedSet) - li = LinearIndices(parent(set)) - if isempty(li) - return nothing - else - t = last(li) - return (t, t) - end -end -@inline function Dictionaries.iteratetoken_reverse(set::SortedSet, t) - li = LinearIndices(parent(set)) - t -= 1 - if t < first(li) - return nothing - else - return (t, t) - end -end - -@inline function Dictionaries.gettoken(set::SortedSet, i) - a = parent(set) - r = searchsorted(a, i, order(set)) - @assert 0 ≤ length(r) ≤ 1 # If > 1, means the elements are not unique - length(r) == 0 && return (false, 0) - return (true, convert(Int, only(r))) -end -@propagate_inbounds Dictionaries.gettokenvalue(set::SortedSet, x::Int) = parent(set)[x] - -@inline Dictionaries.isinsertable(set::SortedSet) = isinsertable(parent(set)) - -@inline function Dictionaries.gettoken!(set::SortedSet{T}, i::T, values=()) where {T} - a = parent(set) - r = searchsorted(a, i, order(set)) - @assert 0 ≤ length(r) ≤ 1 # If > 1, means the elements are not unique - if length(r) == 0 - insert!(a, first(r), i) - foreach(v -> resize!(v, length(v) + 1), values) - return (false, last(LinearIndices(a))) - end - return (true, convert(Int, only(r))) -end - -@inline function Dictionaries.deletetoken!(set::SortedSet, x::Int, values=()) - deleteat!(parent(set), x) - foreach(v -> deleteat!(v, x), values) - return set -end - -@inline function Base.empty!(set::SortedSet, values=()) - empty!(parent(set)) - foreach(empty!, values) - return set -end - -# TODO: Make into `MSmallVector`? -# More generally, make a `thaw(::AbstractArray)` function to return -# a mutable version of an AbstractArray. -@inline Dictionaries.empty_type(::Type{SortedSet{T,D,Order}}, ::Type{T}) where {T,D,Order} = - SortedSet{T,Dictionaries.empty_type(D, T),Order} - -@inline Dictionaries.empty_type(::Type{<:AbstractVector}, ::Type{T}) where {T} = Vector{T} - -function Base.empty(set::SortedSet{T,D}, ::Type{T}) where {T,D} - return Dictionaries.empty_type(typeof(set), T)(D(), order(set)) -end - -@inline function Base.copy(set::SortedSet, ::Type{T}) where {T} - if T === eltype(set) - SortedSet(copy(parent(set)), order(set)) - else - SortedSet(convert(AbstractArray{T}, parent(set)), order(set)) - end -end - -# TODO: Can this take advantage of sorting? -@inline function Base.filter!(pred, set::SortedSet) - filter!(pred, parent(set)) - return set -end - -function Dictionaries.randtoken(rng::Random.AbstractRNG, set::SortedSet) - return rand(rng, keys(parent(set))) -end - -@inline function Base.sort!(set::SortedSet; lt=isless, by=identity, rev::Bool=false) - @assert Base.Sort.ord(lt, by, rev) == order(set) - # No-op, should be sorted already. - return set -end - -# Custom faster operations (not required for interface) -function Base.union!(set::SortedSet, items::SortedSet) - if order(set) ≠ order(items) - # Reorder if the orderings are different. - items = SortedSet(parent(set), order(set)) - end - unionsortedunique!(parent(set), parent(items), order(set)) - return set -end - -function Base.union(set::SortedSet, items::SortedSet) - if order(set) ≠ order(items) - # TODO: Reorder if the orderings are different. - items = SortedSet(parent(set), order(set)) - end - out = unionsortedunique(parent(set), parent(items), order(set)) - return SortedSet(out, order(set)) -end - -function Base.union(set::SortedSet, items) - return union(set, SortedSet(items, order(set))) -end - -function Base.intersect(set::SortedSet, items::SortedSet) - # TODO: Make an `intersectsortedunique`. - return intersect(NotInsertable(), set, items) -end - -function Base.setdiff(set::SortedSet, items) - return setdiff(set, SortedSet(items, order(set))) -end - -function Base.setdiff(set::SortedSet, items::SortedSet) - # TODO: Make an `setdiffsortedunique`. - return setdiff(NotInsertable(), set, items) -end - -function Base.symdiff(set::SortedSet, items) - return symdiff(set, SortedSet(items, order(set))) -end - -function Base.symdiff(set::SortedSet, items::SortedSet) - # TODO: Make an `symdiffsortedunique`. - return symdiff(NotInsertable(), set, items) -end diff --git a/NDTensors/src/lib/SortedSets/test/runtests.jl b/NDTensors/src/lib/SortedSets/test/runtests.jl deleted file mode 100644 index 882fa15e18..0000000000 --- a/NDTensors/src/lib/SortedSets/test/runtests.jl +++ /dev/null @@ -1,42 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using NDTensors.SortedSets -using NDTensors.SmallVectors - -@testset "Test NDTensors.SortedSets" begin - @testset "Basic operations" begin - for V in (Vector, MSmallVector{10}, SmallVector{10}) - for by in (+, -) - s1 = SortedSet(V([1, 5, 3]); by) - s2 = SortedSet(V([2, 3, 6]); by) - - @test thaw(s1) == s1 - @test SmallVectors.insert(s1, 2) isa typeof(s1) - @test SmallVectors.insert(s1, 2) == SortedSet([1, 2, 3, 5]; by) - @test SmallVectors.delete(s1, 3) isa typeof(s1) - @test SmallVectors.delete(s1, 3) == SortedSet([1, 5]; by) - - # Set interface - @test union(s1, s2) == SortedSet([1, 2, 3, 5, 6]; by) - @test union(s1, [3]) == s1 - @test setdiff(s1, s2) == SortedSet([1, 5]; by) - @test symdiff(s1, s2) == SortedSet([1, 2, 5, 6]; by) - @test intersect(s1, s2) == SortedSet([3]; by) - if SmallVectors.InsertStyle(V) isa IsInsertable - @test insert!(copy(s1), 4) == SortedSet([1, 3, 4, 5]; by) - @test delete!(copy(s1), 3) == SortedSet([1, 5]; by) - end - end - end - end - @testset "Replacement behavior" begin - s1 = SortedSet([("a", 3), ("b", 2)]; by=first) - s2 = SortedSet([("a", 5)]; by=first) - s = union(s1, s2) - @test s ≠ s1 - @test issetequal(s, s1) - @test ("a", 5) ∈ parent(s) - @test ("a", 3) ∉ parent(s) - end -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/.JuliaFormatter.toml b/NDTensors/src/lib/SparseArraysBase/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/SparseArraysBase/README.md b/NDTensors/src/lib/SparseArraysBase/README.md deleted file mode 100644 index 629cc07e54..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# SparseArraysBase - -SparseArraysBase is a package that aims to expand on the sparse array functionality that is currently in Julia Base. -While SparseArrays.jl is centered mostly around `SparseMatrixCSC` and the SuiteSparse library, here we wish to broaden the scope a bit, and consider generic sparse arrays. -Abstractly, the mental model can be considered as a storage object that holds the stored values, and a bijection between the array indices and the indices of the storage. -For now, we focus on providing efficient implementations of Dictionary of Key (DOK) type sparse storage formats, but may expand upon this in the future. -As a result, for typical linear algebra routines, we still expect `SparseMatrixCSC` to be the object of choice. - -The design consists of roughly three components: -- `AbstractSparseArray` interface functions -- Overloaded Julia base methods -- `SparseArrayDOK` struct that implements this - -## AbstractSparseArray - -The first part consists of typical functions that are useful in the context of sparse arrays. -The minimal interface, which enables the usage of the rest of this package, consists of the following functions: - -| Signature | Description | Default | -|-----------|-------------|---------| -| `sparse_storage(a::AbstractArray)` | Returns the storage object of the sparse array | `a` | -| `storage_index_to_index(a::AbstractArray, I)` | Converts a storage index to an array index | `I` | -| `index_to_storage_index(a::AbstractArray, I)` | Converts an array index to a storage index | `I` | - -Using these primitives, several convenience functions are defined to facilitate the writing of sparse array algorithms. - -| Signature | Description | Default | -|-----------|-------------|---------| -| `storage_indices(a)` | Returns the indices of the storage | `eachindex(sparse_storage(a))` | -| `stored_indices(a)` | Returns the indices of the stored values | `Iterators.map(Base.Fix1(storage_index_to_index, a), storage_indices(a))` | -| `stored_length(a)` | Returns the number of stored values | `length(storage_indices(a))` | - - - -Interesting to note here is that the design is such that we can define sparse arrays without having to subtype `AbstractSparseArray`. -To achieve this, each function `f` is defined in terms of `sparse_f`, rather than directly overloading `f`. - - -## Overloaded Julia base methods - -The second part consists of overloading Julia base methods to work with sparse arrays. -In particular, specialised implementations exist for the following functions: - -- `sparse_similar` -- `sparse_reduce` -- `sparse_map` -- `sparse_map!` -- `sparse_all` -- `sparse_any` -- `sparse_isequal` -- `sparse_fill!` -- `sparse_zero`, `sparse_zero!`, `sparse_iszero` -- `sparse_one`, `sparse_one!`, `sparse_isone` -- `sparse_reshape`, `sparse_reshape!` -- `sparse_cat`, `sparse_cat!` -- `sparse_copy!`, `sparse_copyto!` -- `sparse_permutedims`, `sparse_permutedims!` -- `sparse_mul!`, `sparse_dot` - -## SparseArrayDOK - -Finally, the `SparseArrayDOK` struct is provided as a concrete implementation of the `AbstractSparseArray` interface. -It is a dictionary of keys (DOK) type sparse array, which stores the values in a `Dictionaries.jl` dictionary, and maps the indices to the keys of the dictionary. -This model is particularly useful for sparse arrays with a small number of non-zero elements, or for arrays that are constructed incrementally, as it boasts fast random accesses and insertions. -The drawback is that sequential iteration is slower than for other sparse array types, leading to slower linear algebra operations. -For the purposes of `SparseArraysBase`, this struct will serve as the canonical example of a sparse array, and will be returned by default when new sparse arrays are created. - -One particular feature of `SparseArrayDOK` is that it can be used in cases where the non-stored entries have to be constructed in a non-trivial way. -Typically, sparse arrays use `zero(eltype(a))` to construct the non-stored entries, but this is not always sufficient. -A concrete example is found in `BlockSparseArrays.jl`, where initialization of the non-stored entries requires the construction of a block of zeros of appropriate size. - - - -## TODO -Still need to implement `Base` functions: -```julia -[x] sparse_zero(a::AbstractArray) = similar(a) -[x] sparse_iszero(a::AbstractArray) = iszero(nonzero_length(a)) # Uses `all`, make `sparse_all`? -[x] sparse_one(a::AbstractArray) = ... -[x] sparse_isreal(a::AbstractArray) = ... # Uses `all`, make `sparse_all`? -[x] sparse_isequal(a1::AbstractArray, a2::AbstractArray) = ... -[x] sparse_conj!(a::AbstractArray) = conj!(nonzeros(a)) -[x] sparse_reshape(a::AbstractArray, dims) = ... -[ ] sparse_all(f, a::AbstractArray) = ... -[ ] sparse_getindex(a::AbstractArray, 1:2, 2:3) = ... # Slicing -``` -`LinearAlgebra` functions: -```julia -[ ] sparse_mul! -[ ] sparse_lmul! -[ ] sparse_ldiv! -[ ] sparse_rdiv! -[ ] sparse_axpby! -[ ] sparse_axpy! -[ ] sparse_norm -[ ] sparse_dot/sparse_inner -[ ] sparse_adoint! -[ ] sparse_transpose! - -# Using conversion to `SparseMatrixCSC`: -[ ] sparse_qr -[ ] sparse_eigen -[ ] sparse_svd -``` -`TensorAlgebra` functions: -```julia -[ ] add! -[ ] contract! -``` diff --git a/NDTensors/src/lib/SparseArraysBase/src/SparseArraysBase.jl b/NDTensors/src/lib/SparseArraysBase/src/SparseArraysBase.jl deleted file mode 100644 index 0a9ff4fe4a..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/SparseArraysBase.jl +++ /dev/null @@ -1,36 +0,0 @@ -module SparseArraysBase -include("sparsearrayinterface/arraylayouts.jl") -include("sparsearrayinterface/densearray.jl") -include("sparsearrayinterface/vectorinterface.jl") -include("sparsearrayinterface/interface.jl") -include("sparsearrayinterface/interface_optional.jl") -include("sparsearrayinterface/indexing.jl") -include("sparsearrayinterface/base.jl") -include("sparsearrayinterface/map.jl") -include("sparsearrayinterface/copyto.jl") -include("sparsearrayinterface/broadcast.jl") -include("sparsearrayinterface/conversion.jl") -include("sparsearrayinterface/wrappers.jl") -include("sparsearrayinterface/zero.jl") -include("sparsearrayinterface/cat.jl") -include("sparsearrayinterface/SparseArraysBaseLinearAlgebraExt.jl") -include("abstractsparsearray/abstractsparsearray.jl") -include("abstractsparsearray/abstractsparsematrix.jl") -include("abstractsparsearray/abstractsparsevector.jl") -include("abstractsparsearray/wrappedabstractsparsearray.jl") -include("abstractsparsearray/arraylayouts.jl") -include("abstractsparsearray/sparsearrayinterface.jl") -include("abstractsparsearray/base.jl") -include("abstractsparsearray/broadcast.jl") -include("abstractsparsearray/map.jl") -include("abstractsparsearray/baseinterface.jl") -include("abstractsparsearray/convert.jl") -include("abstractsparsearray/cat.jl") -include("abstractsparsearray/SparseArraysBaseSparseArraysExt.jl") -include("abstractsparsearray/SparseArraysBaseLinearAlgebraExt.jl") -include("sparsearraydok/defaults.jl") -include("sparsearraydok/sparsearraydok.jl") -include("sparsearraydok/sparsematrixdok.jl") -include("sparsearraydok/sparsevectordok.jl") -include("sparsearraydok/arraylayouts.jl") -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseLinearAlgebraExt.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseLinearAlgebraExt.jl deleted file mode 100644 index b90dfb5f84..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseLinearAlgebraExt.jl +++ /dev/null @@ -1,15 +0,0 @@ -using LinearAlgebra: LinearAlgebra - -LinearAlgebra.norm(a::AbstractSparseArray, p::Real=2) = sparse_norm(a, p) - -# a1 * a2 * α + a_dest * β -function LinearAlgebra.mul!( - a_dest::AbstractMatrix, - a1::AbstractSparseMatrix, - a2::AbstractSparseMatrix, - α::Number=true, - β::Number=false, -) - sparse_mul!(a_dest, a1, a2, α, β) - return a_dest -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseSparseArraysExt.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseSparseArraysExt.jl deleted file mode 100644 index 492a0a37f7..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/SparseArraysBaseSparseArraysExt.jl +++ /dev/null @@ -1,20 +0,0 @@ -using Base: Forward -using SparseArrays: SparseArrays, SparseMatrixCSC, findnz, getcolptr, nonzeros, rowvals -using ..SparseArraysBase: stored_length - -# Julia Base `AbstractSparseArray` interface -SparseArrays.nnz(a::AbstractSparseArray) = stored_length(a) - -sparse_storage(a::SparseMatrixCSC) = nonzeros(a) -function storage_index_to_index(a::SparseMatrixCSC, I) - I1s, I2s = findnz(a) - return CartesianIndex(I1s[I], I2s[I]) -end -function index_to_storage_index(a::SparseMatrixCSC, I::CartesianIndex{2}) - i0, i1 = Tuple(I) - r1 = getcolptr(a)[i1] - r2 = getcolptr(a)[i1 + 1] - 1 - (r1 > r2) && return nothing - r1 = searchsortedfirst(rowvals(a), i0, r1, r2, Forward) - return ((r1 > r2) || (rowvals(a)[r1] != i0)) ? nothing : r1 -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsearray.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsearray.jl deleted file mode 100644 index 8c73f7e035..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsearray.jl +++ /dev/null @@ -1,3 +0,0 @@ -using ArrayLayouts: LayoutArray - -abstract type AbstractSparseArray{T,N} <: LayoutArray{T,N} end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsematrix.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsematrix.jl deleted file mode 100644 index a545c562e6..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsematrix.jl +++ /dev/null @@ -1 +0,0 @@ -const AbstractSparseMatrix{T} = AbstractSparseArray{T,2} diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsevector.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsevector.jl deleted file mode 100644 index 033df09d63..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/abstractsparsevector.jl +++ /dev/null @@ -1 +0,0 @@ -const AbstractSparseVector{T} = AbstractSparseArray{T,1} diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/arraylayouts.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/arraylayouts.jl deleted file mode 100644 index 293d58f3ce..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/arraylayouts.jl +++ /dev/null @@ -1,41 +0,0 @@ -using ArrayLayouts: ArrayLayouts, Dot, DualLayout, MatMulMatAdd, MatMulVecAdd, MulAdd -using LinearAlgebra: Adjoint, Transpose -using ..TypeParameterAccessors: parenttype - -function ArrayLayouts.MemoryLayout(arraytype::Type{<:AnyAbstractSparseArray}) - return SparseLayout() -end - -# TODO: Generalize to `SparseVectorLike`/`AnySparseVector`. -function ArrayLayouts.MemoryLayout(arraytype::Type{<:Adjoint{<:Any,<:AbstractSparseVector}}) - return DualLayout{typeof(MemoryLayout(parenttype(arraytype)))}() -end -# TODO: Generalize to `SparseVectorLike`/`AnySparseVector`. -function ArrayLayouts.MemoryLayout( - arraytype::Type{<:Transpose{<:Any,<:AbstractSparseVector}} -) - return DualLayout{typeof(MemoryLayout(parenttype(arraytype)))}() -end - -function sparse_matmul!(m::MulAdd) - α, a1, a2, β, a_dest = m.α, m.A, m.B, m.β, m.C - sparse_mul!(a_dest, a1, a2, α, β) - return a_dest -end - -function ArrayLayouts.materialize!( - m::MatMulMatAdd{<:AbstractSparseLayout,<:AbstractSparseLayout,<:AbstractSparseLayout} -) - sparse_matmul!(m) - return m.C -end -function ArrayLayouts.materialize!( - m::MatMulVecAdd{<:AbstractSparseLayout,<:AbstractSparseLayout,<:AbstractSparseLayout} -) - sparse_matmul!(m) - return m.C -end - -function Base.copy(d::Dot{<:SparseLayout,<:SparseLayout}) - return sparse_dot(d.A, d.B) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/base.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/base.jl deleted file mode 100644 index 0ea8265ed6..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/base.jl +++ /dev/null @@ -1,16 +0,0 @@ -# Base -function Base.:(==)(a1::AnyAbstractSparseArray, a2::AnyAbstractSparseArray) - return sparse_isequal(a1, a2) -end - -function Base.reshape(a::AnyAbstractSparseArray, dims::Tuple{Vararg{Int}}) - return sparse_reshape(a, dims) -end - -function Base.zero(a::AnyAbstractSparseArray) - return sparse_zero(a) -end - -function Base.one(a::AnyAbstractSparseArray) - return sparse_one(a) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/baseinterface.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/baseinterface.jl deleted file mode 100644 index ba16da704d..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/baseinterface.jl +++ /dev/null @@ -1,33 +0,0 @@ -Base.size(a::AbstractSparseArray) = error("Not implemented") - -function Base.similar(a::AbstractSparseArray, elt::Type, dims::Tuple{Vararg{Int}}) - return error("Not implemented") -end - -function Base.getindex(a::AbstractSparseArray, I...) - return sparse_getindex(a, I...) -end - -# Fixes ambiguity error with `ArrayLayouts`. -function Base.getindex(a::AbstractSparseMatrix, I1::AbstractVector, I2::AbstractVector) - return sparse_getindex(a, I1, I2) -end - -# Fixes ambiguity error with `ArrayLayouts`. -function Base.getindex( - a::AbstractSparseMatrix, I1::AbstractUnitRange, I2::AbstractUnitRange -) - return sparse_getindex(a, I1, I2) -end - -function Base.isassigned(a::AbstractSparseArray, I::Integer...) - return sparse_isassigned(a, I...) -end - -function Base.setindex!(a::AbstractSparseArray, I...) - return sparse_setindex!(a, I...) -end - -function Base.fill!(a::AbstractSparseArray, value) - return sparse_fill!(a, value) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/broadcast.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/broadcast.jl deleted file mode 100644 index 565fccb441..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/broadcast.jl +++ /dev/null @@ -1,4 +0,0 @@ -# Broadcasting -function Broadcast.BroadcastStyle(arraytype::Type{<:AnyAbstractSparseArray}) - return SparseArraysBase.SparseArrayStyle{ndims(arraytype)}() -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/cat.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/cat.jl deleted file mode 100644 index 3d0475159c..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/cat.jl +++ /dev/null @@ -1,4 +0,0 @@ -# TODO: Change to `AnyAbstractSparseArray`. -function Base.cat(as::AnyAbstractSparseArray...; dims) - return sparse_cat(as...; dims) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/convert.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/convert.jl deleted file mode 100644 index 8b532ede73..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/convert.jl +++ /dev/null @@ -1,7 +0,0 @@ -Base.convert(type::Type{<:AbstractSparseArray}, a::AbstractArray) = type(a) - -Base.convert(::Type{T}, a::T) where {T<:AbstractSparseArray} = a - -function (::Type{T})(a::T) where {T<:AbstractSparseArray} - return copy(a) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/map.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/map.jl deleted file mode 100644 index 106cfff579..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/map.jl +++ /dev/null @@ -1,42 +0,0 @@ -using ArrayLayouts: LayoutArray - -# Map -function Base.map!(f, a_dest::AbstractArray, a_srcs::Vararg{AnyAbstractSparseArray}) - SparseArraysBase.sparse_map!(f, a_dest, a_srcs...) - return a_dest -end - -function Base.copy!(a_dest::AbstractArray, a_src::AnyAbstractSparseArray) - SparseArraysBase.sparse_copy!(a_dest, a_src) - return a_dest -end - -function Base.copyto!(a_dest::AbstractArray, a_src::AnyAbstractSparseArray) - SparseArraysBase.sparse_copyto!(a_dest, a_src) - return a_dest -end - -# Fix ambiguity error -function Base.copyto!(a_dest::LayoutArray, a_src::AnyAbstractSparseArray) - SparseArraysBase.sparse_copyto!(a_dest, a_src) - return a_dest -end - -function Base.permutedims!(a_dest::AbstractArray, a_src::AnyAbstractSparseArray, perm) - SparseArraysBase.sparse_permutedims!(a_dest, a_src, perm) - return a_dest -end - -function Base.mapreduce(f, op, as::Vararg{AnyAbstractSparseArray}; kwargs...) - return SparseArraysBase.sparse_mapreduce(f, op, as...; kwargs...) -end - -# TODO: Why isn't this calling `mapreduce` already? -function Base.iszero(a::AnyAbstractSparseArray) - return SparseArraysBase.sparse_iszero(a) -end - -# TODO: Why isn't this calling `mapreduce` already? -function Base.isreal(a::AnyAbstractSparseArray) - return SparseArraysBase.sparse_isreal(a) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/sparsearrayinterface.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/sparsearrayinterface.jl deleted file mode 100644 index 8b86d1be12..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/sparsearrayinterface.jl +++ /dev/null @@ -1,46 +0,0 @@ -using Dictionaries: set! - -sparse_storage(::AbstractSparseArray) = error("Not implemented") - -function index_to_storage_index( - a::AbstractSparseArray{<:Any,N}, I::CartesianIndex{N} -) where {N} - !isassigned(sparse_storage(a), I) && return nothing - return I -end - -function setindex_notstored!( - a::AbstractSparseArray{<:Any,N}, value, I::CartesianIndex{N} -) where {N} - iszero(value) && return a - return error("Setting the specified unstored index is not supported.") -end - -# TODO: Make this into a generic definition of all `AbstractArray`? -# TODO: Check if this is efficient, or determine if this mapping should -# be performed in `storage_index_to_index` and/or `index_to_storage_index`. -function sparse_storage(a::SubArray{<:Any,<:Any,<:AbstractSparseArray}) - parent_storage = sparse_storage(parent(a)) - all_sliced_storage_indices = map(keys(parent_storage)) do I - return map_index(a.indices, I) - end - sliced_storage_indices = filter(!isnothing, all_sliced_storage_indices) - sliced_parent_storage = map(I -> parent_storage[I], keys(sliced_storage_indices)) - return typeof(parent_storage)(sliced_storage_indices, sliced_parent_storage) -end - -# TODO: Make this into a generic definition of all `AbstractArray`? -function stored_indices( - a::AnyPermutedDimsArray{<:Any,<:Any,<:Any,<:Any,<:AbstractSparseArray} -) - return Iterators.map( - I -> CartesianIndex(map(i -> I[i], perm(a))), stored_indices(parent(a)) - ) -end - -# TODO: Make this into a generic definition of all `AbstractArray`? -function sparse_storage( - a::AnyPermutedDimsArray{<:Any,<:Any,<:Any,<:Any,<:AbstractSparseArray} -) - return sparse_storage(parent(a)) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/wrappedabstractsparsearray.jl b/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/wrappedabstractsparsearray.jl deleted file mode 100644 index a4ee4bebe3..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/abstractsparsearray/wrappedabstractsparsearray.jl +++ /dev/null @@ -1,22 +0,0 @@ -using Adapt: WrappedArray -using LinearAlgebra: Adjoint, Transpose - -const WrappedAbstractSparseArray{T,N,A} = WrappedArray{ - T,N,<:AbstractSparseArray,<:AbstractSparseArray{T,N} -} - -const AnyAbstractSparseArray{T,N} = Union{ - <:AbstractSparseArray{T,N},<:WrappedAbstractSparseArray{T,N} -} - -function stored_indices(a::Adjoint) - return Iterators.map(I -> CartesianIndex(reverse(Tuple(I))), stored_indices(parent(a))) -end -stored_length(a::Adjoint) = stored_length(parent(a)) -sparse_storage(a::Adjoint) = Iterators.map(adjoint, sparse_storage(parent(a))) - -function stored_indices(a::Transpose) - return Iterators.map(I -> CartesianIndex(reverse(Tuple(I))), stored_indices(parent(a))) -end -stored_length(a::Transpose) = stored_length(parent(a)) -sparse_storage(a::Transpose) = Iterators.map(transpose, sparse_storage(parent(a))) diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/arraylayouts.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/arraylayouts.jl deleted file mode 100644 index fc2740d377..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/arraylayouts.jl +++ /dev/null @@ -1,13 +0,0 @@ -using ArrayLayouts: ArrayLayouts, MemoryLayout, MulAdd - -ArrayLayouts.MemoryLayout(::Type{<:SparseArrayDOK}) = SparseLayout() - -# Default sparse array type for `AbstractSparseLayout`. -default_sparsearraytype(elt::Type) = SparseArrayDOK{elt} - -# TODO: Preserve GPU memory! Implement `CuSparseArrayLayout`, `MtlSparseLayout`? -function Base.similar( - ::MulAdd{<:AbstractSparseLayout,<:AbstractSparseLayout}, elt::Type, axes -) - return similar(default_sparsearraytype(elt), axes) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/defaults.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/defaults.jl deleted file mode 100644 index 1dc674b8b2..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/defaults.jl +++ /dev/null @@ -1,5 +0,0 @@ -using Dictionaries: Dictionary - -default_zero() = Zero() -default_data(type::Type, ndims::Int) = Dictionary{default_keytype(ndims),type}() -default_keytype(ndims::Int) = CartesianIndex{ndims} diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsearraydok.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsearraydok.jl deleted file mode 100644 index 95a5b14017..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsearraydok.jl +++ /dev/null @@ -1,146 +0,0 @@ -using Accessors: @set -using Dictionaries: Dictionary, set! -using MacroTools: @capture - -# TODO: Parametrize by `data`? -struct SparseArrayDOK{T,N,Zero} <: AbstractSparseArray{T,N} - data::Dictionary{CartesianIndex{N},T} - dims::Ref{NTuple{N,Int}} - zero::Zero - function SparseArrayDOK{T,N,Zero}(data, dims::NTuple{N,Int}, zero) where {T,N,Zero} - return new{T,N,Zero}(data, Ref(dims), zero) - end -end - -# Constructors -function SparseArrayDOK(data, dims::Tuple{Vararg{Int}}, zero) - return SparseArrayDOK{eltype(data),length(dims),typeof(zero)}(data, dims, zero) -end - -function SparseArrayDOK{T,N,Zero}(dims::Tuple{Vararg{Int}}, zero) where {T,N,Zero} - return SparseArrayDOK{T,N,Zero}(default_data(T, N), dims, zero) -end - -function SparseArrayDOK{T,N}(dims::Tuple{Vararg{Int}}, zero) where {T,N} - return SparseArrayDOK{T,N,typeof(zero)}(dims, zero) -end - -function SparseArrayDOK{T,N}(dims::Tuple{Vararg{Int}}) where {T,N} - return SparseArrayDOK{T,N}(dims, default_zero()) -end - -function SparseArrayDOK{T}(dims::Tuple{Vararg{Int}}) where {T} - return SparseArrayDOK{T,length(dims)}(dims) -end - -function SparseArrayDOK{T}(dims::Int...) where {T} - return SparseArrayDOK{T}(dims) -end - -# Specify zero function -function SparseArrayDOK{T}(dims::Tuple{Vararg{Int}}, zero) where {T} - return SparseArrayDOK{T,length(dims)}(dims, zero) -end - -# undef -function SparseArrayDOK{T,N,Zero}( - ::UndefInitializer, dims::Tuple{Vararg{Int}}, zero -) where {T,N,Zero} - return SparseArrayDOK{T,N,Zero}(dims, zero) -end - -function SparseArrayDOK{T,N}(::UndefInitializer, dims::Tuple{Vararg{Int}}, zero) where {T,N} - return SparseArrayDOK{T,N}(dims, zero) -end - -function SparseArrayDOK{T,N}(::UndefInitializer, dims::Tuple{Vararg{Int}}) where {T,N} - return SparseArrayDOK{T,N}(dims) -end - -function SparseArrayDOK{T}(::UndefInitializer, dims::Tuple{Vararg{Int}}) where {T} - return SparseArrayDOK{T}(dims) -end - -# Axes version -function SparseArrayDOK{T}( - ::UndefInitializer, axes::Tuple{Vararg{AbstractUnitRange}} -) where {T} - @assert all(isone, first.(axes)) - return SparseArrayDOK{T}(length.(axes)) -end - -function SparseArrayDOK{T}(::UndefInitializer, dims::Int...) where {T} - return SparseArrayDOK{T}(dims...) -end - -function SparseArrayDOK{T}(::UndefInitializer, dims::Tuple{Vararg{Int}}, zero) where {T} - return SparseArrayDOK{T}(dims, zero) -end - -# Base `AbstractArray` interface -Base.size(a::SparseArrayDOK) = a.dims[] - -getindex_zero_function(a::SparseArrayDOK) = a.zero -function set_getindex_zero_function(a::SparseArrayDOK, f) - return @set a.zero = f -end - -function setindex_notstored!( - a::SparseArrayDOK{<:Any,N}, value, I::CartesianIndex{N} -) where {N} - set!(sparse_storage(a), I, value) - return a -end - -function Base.similar(a::SparseArrayDOK, elt::Type, dims::Tuple{Vararg{Int}}) - return SparseArrayDOK{elt}(undef, dims, getindex_zero_function(a)) -end - -# `SparseArraysBase` interface -sparse_storage(a::SparseArrayDOK) = a.data - -function dropall!(a::SparseArrayDOK) - return empty!(sparse_storage(a)) -end - -SparseArrayDOK(a::AbstractArray) = SparseArrayDOK{eltype(a)}(a) - -SparseArrayDOK{T}(a::AbstractArray) where {T} = SparseArrayDOK{T,ndims(a)}(a) - -function SparseArrayDOK{T,N}(a::AbstractArray) where {T,N} - return sparse_convert(SparseArrayDOK{T,N}, a) -end - -function Base.resize!(a::SparseArrayDOK{<:Any,N}, new_size::NTuple{N,Integer}) where {N} - a.dims[] = new_size - return a -end - -function setindex_maybe_grow!(a::SparseArrayDOK{<:Any,N}, value, I::Vararg{Int,N}) where {N} - if any(I .> size(a)) - resize!(a, max.(I, size(a))) - end - a[I...] = value - return a -end - -function is_setindex!_expr(expr::Expr) - return is_assignment_expr(expr) && is_getindex_expr(first(expr.args)) -end -is_setindex!_expr(x) = false - -is_getindex_expr(expr::Expr) = (expr.head === :ref) -is_getindex_expr(x) = false - -is_assignment_expr(expr::Expr) = (expr.head === :(=)) -is_assignment_expr(expr) = false - -macro maybe_grow(expr) - if !is_setindex!_expr(expr) - error( - "@maybe_grow must be used with setindex! syntax (as @maybe_grow a[i,j,...] = value)" - ) - end - @capture(expr, array_[indices__] = value_) - return :(setindex_maybe_grow!($(esc(array)), $(esc(value)), $(esc.(indices)...))) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsematrixdok.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsematrixdok.jl deleted file mode 100644 index f568760c19..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsematrixdok.jl +++ /dev/null @@ -1 +0,0 @@ -const SparseMatrixDOK{T} = SparseArrayDOK{T,2} diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsevectordok.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsevectordok.jl deleted file mode 100644 index 7cc7df00d6..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearraydok/sparsevectordok.jl +++ /dev/null @@ -1 +0,0 @@ -const SparseVectorDOK{T} = SparseArrayDOK{T,1} diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/SparseArraysBaseLinearAlgebraExt.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/SparseArraysBaseLinearAlgebraExt.jl deleted file mode 100644 index 4e4ed259d0..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/SparseArraysBaseLinearAlgebraExt.jl +++ /dev/null @@ -1,78 +0,0 @@ -using LinearAlgebra: dot, mul!, norm - -sparse_norm(a::AbstractArray, p::Real=2) = norm(sparse_storage(a)) - -function mul_indices(I1::CartesianIndex{2}, I2::CartesianIndex{2}) - if I1[2] ≠ I2[1] - return nothing - end - return CartesianIndex(I1[1], I2[2]) -end - -# TODO: Is this needed? Maybe when multiplying vectors? -function mul_indices(I1::CartesianIndex{1}, I2::CartesianIndex{1}) - if I1 ≠ I2 - return nothing - end - return CartesianIndex(I1) -end - -function default_mul!!( - a_dest::AbstractMatrix, - a1::AbstractMatrix, - a2::AbstractMatrix, - α::Number=true, - β::Number=false, -) - mul!(a_dest, a1, a2, α, β) - return a_dest -end - -function default_mul!!( - a_dest::Number, a1::Number, a2::Number, α::Number=true, β::Number=false -) - return a1 * a2 * α + a_dest * β -end - -# a1 * a2 * α + a_dest * β -function sparse_mul!( - a_dest::AbstractArray, - a1::AbstractArray, - a2::AbstractArray, - α::Number=true, - β::Number=false; - (mul!!)=(default_mul!!), -) - for I1 in stored_indices(a1) - for I2 in stored_indices(a2) - I_dest = mul_indices(I1, I2) - if !isnothing(I_dest) - a_dest[I_dest] = mul!!(a_dest[I_dest], a1[I1], a2[I2], α, β) - end - end - end - return a_dest -end - -function sparse_dot(a1::AbstractArray, a2::AbstractArray) - # This requires that `a1` and `a2` have the same shape. - # TODO: Generalize (Base supports dot products of - # arrays with the same length but different sizes). - size(a1) == size(a2) || - throw(DimensionMismatch("Sizes $(size(a1)) and $(size(a2)) don't match.")) - dot_dest = zero(Base.promote_op(dot, eltype(a1), eltype(a2))) - # TODO: First check if the number of stored elements (`stored_length`, to be renamed - # `stored_length`) is smaller in `a1` or `a2` and use whicheven one is smallar - # as the outer loop. - for I1 in stored_indices(a1) - # TODO: Overload and use `Base.isstored(a, I) = I in stored_indices(a)` instead. - # TODO: This assumes fast lookup of indices, which may not always be the case. - # It could be better to loop over `stored_indices(a2)` and check that - # `I1 == I2` instead (say using `mul_indices(I1, I2)`. We could have a trait - # `HasFastIsStored(a::AbstractArray)` to choose between the two. - if I1 in stored_indices(a2) - dot_dest += dot(a1[I1], a2[I1]) - end - end - return dot_dest -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/arraylayouts.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/arraylayouts.jl deleted file mode 100644 index 4ff6cc148d..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/arraylayouts.jl +++ /dev/null @@ -1,5 +0,0 @@ -using ArrayLayouts: MemoryLayout - -abstract type AbstractSparseLayout <: MemoryLayout end - -struct SparseLayout <: AbstractSparseLayout end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/base.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/base.jl deleted file mode 100644 index 9a6fd24941..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/base.jl +++ /dev/null @@ -1,126 +0,0 @@ -# This is used when a sparse output structure not matching -# the input structure is needed, for example when reshaping -# a DiagonalArray. Overload: -# -# sparse_similar(a::AbstractArray, elt::Type, dims::Tuple{Vararg{Int}}) -# -# as needed. -function sparse_similar(a::AbstractArray, elt::Type) - return similar(a, elt, size(a)) -end - -function sparse_similar(a::AbstractArray, dims::Tuple{Vararg{Int}}) - return sparse_similar(a, eltype(a), dims) -end - -function sparse_similar(a::AbstractArray) - return sparse_similar(a, eltype(a), size(a)) -end - -function sparse_reduce(op, a::AbstractArray; kwargs...) - return sparse_mapreduce(identity, op, a; kwargs...) -end - -function sparse_all(a::AbstractArray) - return sparse_reduce(&, a; init=true) -end - -function sparse_all(f, a::AbstractArray) - return sparse_mapreduce(f, &, a; init=true) -end - -function sparse_iszero(a::AbstractArray) - return sparse_all(iszero, a) -end - -function sparse_isreal(a::AbstractArray) - return sparse_all(isreal, a) -end - -# This is equivalent to: -# -# sparse_map!(Returns(x), a, a) -# -# but we don't use that here since `sparse_fill!` -# is used inside of `sparse_map!`. -function sparse_fill!(a::AbstractArray, x) - if iszero(x) - # This checks that `x` is compatible - # with `eltype(a)`. - x = convert(eltype(a), x) - sparse_zero!(a) - return a - end - for I in eachindex(a) - a[I] = x - end - return a -end - -# This could just call `sparse_fill!` -# but it avoids a zero construction and check. -function sparse_zero!(a::AbstractArray) - dropall!(a) - sparse_zerovector!(a) - return a -end - -function sparse_zero(a::AbstractArray) - # Need to overload `similar` for custom types - a = similar(a) - sparse_zerovector!(a) - return a -end - -# TODO: Is this a good definition? -function sparse_zero(arraytype::Type{<:AbstractArray}, dims::Tuple{Vararg{Int}}) - a = arraytype(undef, dims) - sparse_zerovector!(a) - return a -end - -function sparse_one!(a::AbstractMatrix) - sparse_zero!(a) - m, n = size(a) - @assert m == n - for i in 1:m - a[i, i] = one(eltype(a)) - end - return a -end - -function sparse_one(a::AbstractMatrix) - a = sparse_zero(a) - sparse_one!(a) - return a -end - -# TODO: Use `sparse_mapreduce(==, &, a1, a2)`? -function sparse_isequal(a1::AbstractArray, a2::AbstractArray) - Is = collect(stored_indices(a1)) - intersect!(Is, stored_indices(a2)) - if !(length(Is) == stored_length(a1) == stored_length(a2)) - return false - end - for I in Is - a1[I] == a2[I] || return false - end - return true -end - -function sparse_reshape!(a_dest::AbstractArray, a_src::AbstractArray, dims) - @assert length(a_src) == prod(dims) - sparse_zero!(a_dest) - linear_inds = LinearIndices(a_src) - dest_cartesian_inds = CartesianIndices(dims) - for I in stored_indices(a_src) - a_dest[dest_cartesian_inds[linear_inds[I]]] = a_src[I] - end - return a_dest -end - -function sparse_reshape(a::AbstractArray, dims) - a_reshaped = sparse_similar(a, dims) - sparse_reshape!(a_reshaped, a, dims) - return a_reshaped -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/broadcast.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/broadcast.jl deleted file mode 100644 index d113932d44..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/broadcast.jl +++ /dev/null @@ -1,37 +0,0 @@ -using Base.Broadcast: BroadcastStyle, AbstractArrayStyle, DefaultArrayStyle, Broadcasted -using ..BroadcastMapConversion: map_function, map_args - -struct SparseArrayStyle{N} <: AbstractArrayStyle{N} end - -# Define for new sparse array types. -# function Broadcast.BroadcastStyle(arraytype::Type{<:MySparseArray}) -# return SparseArrayStyle{ndims(arraytype)}() -# end - -SparseArrayStyle(::Val{N}) where {N} = SparseArrayStyle{N}() -SparseArrayStyle{M}(::Val{N}) where {M,N} = SparseArrayStyle{N}() - -Broadcast.BroadcastStyle(a::SparseArrayStyle, ::DefaultArrayStyle{0}) = a -function Broadcast.BroadcastStyle(::SparseArrayStyle{N}, a::DefaultArrayStyle) where {N} - return BroadcastStyle(DefaultArrayStyle{N}(), a) -end -function Broadcast.BroadcastStyle(::SparseArrayStyle{N}, ::Broadcast.Style{Tuple}) where {N} - return DefaultArrayStyle{N}() -end - -# TODO: Use `allocate_output`, share logic with `map`. -function Base.similar(bc::Broadcasted{<:SparseArrayStyle}, elt::Type) - # TODO: Is this a good definition? Probably should check that - # they have consistent axes. - return similar(first(map_args(bc)), elt) -end - -# Broadcasting implementation -function Base.copyto!( - dest::AbstractArray{<:Any,N}, bc::Broadcasted{SparseArrayStyle{N}} -) where {N} - # convert to map - # flatten and only keep the AbstractArray arguments - sparse_map!(map_function(bc), dest, map_args(bc)...) - return dest -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/cat.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/cat.jl deleted file mode 100644 index 9f2b3179a5..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/cat.jl +++ /dev/null @@ -1,64 +0,0 @@ -unval(x) = x -unval(::Val{x}) where {x} = x - -# TODO: Assert that `a1` and `a2` start at one. -axis_cat(a1::AbstractUnitRange, a2::AbstractUnitRange) = Base.OneTo(length(a1) + length(a2)) -function axis_cat( - a1::AbstractUnitRange, a2::AbstractUnitRange, a_rest::AbstractUnitRange... -) - return axis_cat(axis_cat(a1, a2), a_rest...) -end -function cat_axes(as::AbstractArray...; dims) - return ntuple(length(first(axes.(as)))) do dim - return if dim in unval(dims) - axis_cat(map(axes -> axes[dim], axes.(as))...) - else - axes(first(as))[dim] - end - end -end - -function allocate_cat_output(as::AbstractArray...; dims) - eltype_dest = promote_type(eltype.(as)...) - axes_dest = cat_axes(as...; dims) - # TODO: Promote the block types of the inputs rather than using - # just the first input. - # TODO: Make this customizable with `cat_similar`. - # TODO: Base the zero element constructor on those of the inputs, - # for example block sparse arrays. - return similar(first(as), eltype_dest, axes_dest...) -end - -# https://github.com/JuliaLang/julia/blob/v1.11.1/base/abstractarray.jl#L1748-L1857 -# https://docs.julialang.org/en/v1/base/arrays/#Concatenation-and-permutation -# This is very similar to the `Base.cat` implementation but handles zero values better. -function cat_offset!( - a_dest::AbstractArray, offsets, a1::AbstractArray, a_rest::AbstractArray...; dims -) - inds = ntuple(ndims(a_dest)) do dim - dim in unval(dims) ? offsets[dim] .+ axes(a1, dim) : axes(a_dest, dim) - end - a_dest[inds...] = a1 - new_offsets = ntuple(ndims(a_dest)) do dim - dim in unval(dims) ? offsets[dim] + size(a1, dim) : offsets[dim] - end - cat_offset!(a_dest, new_offsets, a_rest...; dims) - return a_dest -end -function cat_offset!(a_dest::AbstractArray, offsets; dims) - return a_dest -end - -# TODO: Define a generic `cat!` function. -function sparse_cat!(a_dest::AbstractArray, as::AbstractArray...; dims) - offsets = ntuple(zero, ndims(a_dest)) - # TODO: Fill `a_dest` with zeros if needed. - cat_offset!(a_dest, offsets, as...; dims) - return a_dest -end - -function sparse_cat(as::AbstractArray...; dims) - a_dest = allocate_cat_output(as...; dims) - sparse_cat!(a_dest, as...; dims) - return a_dest -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/conversion.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/conversion.jl deleted file mode 100644 index 57f1850ba0..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/conversion.jl +++ /dev/null @@ -1,5 +0,0 @@ -function sparse_convert(arraytype::Type{<:AbstractArray}, a::AbstractArray) - a_dest = sparse_zero(arraytype, size(a)) - sparse_copyto!(a_dest, a) - return a_dest -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/copyto.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/copyto.jl deleted file mode 100644 index 218502f3d9..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/copyto.jl +++ /dev/null @@ -1,15 +0,0 @@ -function sparse_copy!(dest::AbstractArray, src::AbstractArray) - @assert axes(dest) == axes(src) - sparse_map!(identity, dest, src) - return dest -end - -function sparse_copyto!(dest::AbstractArray, src::AbstractArray) - sparse_map!(identity, dest, src) - return dest -end - -function sparse_permutedims!(dest::AbstractArray, src::AbstractArray, perm) - sparse_copyto!(dest, PermutedDimsArray(src, perm)) - return dest -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/densearray.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/densearray.jl deleted file mode 100644 index 2f4fd028c7..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/densearray.jl +++ /dev/null @@ -1,12 +0,0 @@ -# Generic functionality for converting to a -# dense array, trying to preserve information -# about the array (such as which device it is on). -# TODO: Maybe call `densecopy`? -# TODO: Make sure this actually preserves the device, -# maybe use `NDTensors.TypeParameterAccessors.unwrap_array_type`. -function densearray(a::AbstractArray) - # TODO: `set_ndims(unwrap_array_type(a), ndims(a))(a)` - # Maybe define `densetype(a) = set_ndims(unwrap_array_type(a), ndims(a))`. - # Or could use `unspecify_parameters(unwrap_array_type(a))(a)`. - return Array(a) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/indexing.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/indexing.jl deleted file mode 100644 index 5f8c1cad7e..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/indexing.jl +++ /dev/null @@ -1,216 +0,0 @@ -using ArrayLayouts: ArrayLayouts - -# An index into the storage of the sparse array. -struct StorageIndex{I} - i::I -end -index(i::StorageIndex) = i.i - -# Indicate if the index into the sparse array is -# stored or not. -abstract type MaybeStoredIndex{I} end - -# An index into a stored value of the sparse array. -# Stores both the index into the outer array -# as well as into the underlying storage. -struct StoredIndex{Iouter,Istorage} <: MaybeStoredIndex{Iouter} - iouter::Iouter - istorage::StorageIndex{Istorage} -end -index(i::StoredIndex) = i.iouter -StorageIndex(i::StoredIndex) = i.istorage - -stored_length(a::AbstractArray) = length(sparse_storage(a)) - -struct NotStoredIndex{Iouter} <: MaybeStoredIndex{Iouter} - iouter::Iouter -end -index(i::NotStoredIndex) = i.iouter - -function MaybeStoredIndex(a::AbstractArray, I) - return MaybeStoredIndex(I, index_to_storage_index(a, I)) -end -MaybeStoredIndex(I, I_storage) = StoredIndex(I, StorageIndex(I_storage)) -MaybeStoredIndex(I, I_storage::Nothing) = NotStoredIndex(I) - -# Convert the index into an index into the storage. -# Return `NotStoredIndex(I)` if it isn't in the storage. -storage_index(a::AbstractArray, I...) = MaybeStoredIndex(a, I...) - -function storage_indices(a::AbstractArray) - return eachindex(sparse_storage(a)) -end - -# Derived -function index_to_storage_index(a::AbstractArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return index_to_storage_index(a, CartesianIndex(I)) -end - -function sparse_getindex(a::AbstractArray, I::NotStoredIndex) - return getindex_notstored(a, index(I)) -end - -function sparse_getindex(a::AbstractArray, I::StoredIndex) - return sparse_getindex(a, StorageIndex(I)) -end - -function sparse_getindex(a::AbstractArray, I::StorageIndex) - return sparse_storage(a)[index(I)] -end - -function sparse_getindex(a::AbstractArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return sparse_getindex(a, CartesianIndex(I)) -end - -function sparse_getindex(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N} - return _sparse_getindex(a, I) -end - -# Ambiguity with linear indexing -function sparse_getindex(a::AbstractArray{<:Any,1}, I::CartesianIndex{1}) - return _sparse_getindex(a, I) -end - -# Implementation of element access -function _sparse_getindex(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N} - @boundscheck checkbounds(a, I) - return sparse_getindex(a, storage_index(a, I)) -end - -# Handle trailing indices or linear indexing -function sparse_getindex(a::AbstractArray, I::Vararg{Int}) - return sparse_getindex(a, CartesianIndex(I)) -end - -# Fix ambiguity error. -function sparse_getindex(a::AbstractArray{<:Any,0}) - return sparse_getindex(a, CartesianIndex()) -end - -# Linear indexing -function sparse_getindex(a::AbstractArray, I::CartesianIndex{1}) - return sparse_getindex(a, CartesianIndices(a)[I]) -end - -# Handle trailing indices -function sparse_getindex(a::AbstractArray, I::CartesianIndex) - t = Tuple(I) - length(t) < ndims(a) && error("Not enough indices passed") - I′ = ntuple(i -> t[i], ndims(a)) - @assert all(i -> isone(I[i]), (ndims(a) + 1):length(I)) - return _sparse_getindex(a, CartesianIndex(I′)) -end - -# Slicing -function sparse_getindex(a::AbstractArray, I::AbstractVector...) - return copy(@view a[I...]) -end - -function ArrayLayouts.sub_materialize(::SparseLayout, a::AbstractArray, axes) - a_dest = similar(a, axes) - a_dest .= a - return a_dest -end - -# Update a nonzero value -function sparse_setindex!(a::AbstractArray, value, I::StorageIndex) - sparse_storage(a)[index(I)] = value - return a -end - -# Implementation of element access -function _sparse_setindex!(a::AbstractArray{<:Any,N}, value, I::CartesianIndex{N}) where {N} - @boundscheck checkbounds(a, I) - sparse_setindex!(a, value, storage_index(a, I)) - return a -end - -# Ambiguity with linear indexing -function sparse_setindex!(a::AbstractArray{<:Any,1}, value, I::CartesianIndex{1}) - _sparse_setindex!(a, value, I) - return a -end - -# Handle trailing indices or linear indexing -function sparse_setindex!(a::AbstractArray, value, I::Vararg{Int}) - sparse_setindex!(a, value, CartesianIndex(I)) - return a -end - -# Fix ambiguity error -function sparse_setindex!(a::AbstractArray, value) - sparse_setindex!(a, value, CartesianIndex()) - return a -end - -# Linear indexing -function sparse_setindex!(a::AbstractArray, value, I::CartesianIndex{1}) - sparse_setindex!(a, value, CartesianIndices(a)[I]) - return a -end - -# Slicing -# TODO: Make this handle more general slicing operations, -# base it off of `ArrayLayouts.sub_materialize`. -function sparse_setindex!(a::AbstractArray, value, I::AbstractUnitRange...) - inds = CartesianIndices(I) - for i in stored_indices(value) - if i in CartesianIndices(inds) - a[inds[i]] = value[i] - end - end - return a -end - -# Handle trailing indices -function sparse_setindex!(a::AbstractArray, value, I::CartesianIndex) - t = Tuple(I) - length(t) < ndims(a) && error("Not enough indices passed") - I′ = ntuple(i -> t[i], ndims(a)) - @assert all(i -> isone(I[i]), (ndims(a) + 1):length(I)) - return _sparse_setindex!(a, value, CartesianIndex(I′)) -end - -function sparse_setindex!(a::AbstractArray, value, I::StoredIndex) - sparse_setindex!(a, value, StorageIndex(I)) - return a -end - -function sparse_setindex!(a::AbstractArray, value, I::NotStoredIndex) - setindex_notstored!(a, value, index(I)) - return a -end - -# isassigned -function sparse_isassigned(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N} - return sparse_isassigned(a, Tuple(I)...) -end -function sparse_isassigned(a::AbstractArray, I::Integer...) - # Check trailing dimensions are one. This is needed in generic - # AbstractArray show when `a isa AbstractVector`. - all(d -> isone(I[d]), (ndims(a) + 1):length(I)) || return false - return all(dim -> I[dim] ∈ axes(a, dim), 1:ndims(a)) -end - -# A set of indices into the storage of the sparse array. -struct StorageIndices{I} - i::I -end -indices(i::StorageIndices) = i.i - -function sparse_getindex(a::AbstractArray, I::StorageIndices{Colon}) - return sparse_storage(a) -end - -function sparse_getindex(a::AbstractArray, I::StorageIndices) - return error("Not implemented") -end - -function sparse_setindex!(a::AbstractArray, value, I::StorageIndices{Colon}) - sparse_storage(a) .= value - return a -end - -function sparse_setindex!(a::AbstractArray, value, I::StorageIndices) - return error("Not implemented") -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface.jl deleted file mode 100644 index ed5f7cb1d8..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface.jl +++ /dev/null @@ -1,18 +0,0 @@ -# Also look into: -# https://juliaarrays.github.io/ArrayInterface.jl/stable/sparsearrays/ - -# Minimal sparse array interface. -# Data structure of the stored (generally nonzero) values. -# By default assume it is dense, so all values are stored. -sparse_storage(a::AbstractArray) = a - -# Minimal sparse array interface. -# Map an index into the stored data to a CartesianIndex of the -# outer array. -storage_index_to_index(a::AbstractArray, I) = I - -# Minimal interface -# Map a `CartesianIndex` to an index/key into the nonzero data structure -# returned by `storage`. -# Return `nothing` if the index corresponds to a structural zero (unstored) value. -index_to_storage_index(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N} = I diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface_optional.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface_optional.jl deleted file mode 100644 index 710cd2570d..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/interface_optional.jl +++ /dev/null @@ -1,44 +0,0 @@ -# Optional interface. - -# Function for computing unstored zero values. -getindex_zero_function(::AbstractArray) = Zero() - -# Change the function for computing unstored values -set_getindex_zero_function(a::AbstractArray, f) = error("Not implemented") - -function getindex_notstored(a::AbstractArray, I) - return getindex_zero_function(a)(a, I) -end - -# Optional interface. -# Insert a new value into a location -# where there is not a stored value. -# Some types (like `Diagonal`) may not support this. -function setindex_notstored!(a::AbstractArray, value, I) - iszero(value) && return a - return throw(ArgumentError("Can't set nonzero values of $(typeof(a)).")) -end - -# Optional interface. -# Iterates over the indices of `a` where there are stored values. -# Can overload for faster iteration when there is more structure, -# for example with DiagonalArrays. -function stored_indices(a::AbstractArray) - return Iterators.map(Inz -> storage_index_to_index(a, Inz), storage_indices(a)) -end - -# Empty the sparse storage if possible. -# Array types should overload `Base.dataids` to opt-in -# to aliasing detection with `Base.mightalias` -# to avoid emptying an input array in the case of `sparse_map!`. -# `dropall!` is used to zero out the output array. -# See also `Base.unalias` and `Base.unaliascopy`. -# Interface is inspired by Base `SparseArrays.droptol!` -# and `SparseArrays.dropzeros!`, and is like -# `dropall!(a) = SparseArrays.droptol!(a, Inf)`. -dropall!(a::AbstractArray) = a - -# Overload -function sparse_similar(a::AbstractArray, elt::Type, dims::Tuple{Vararg{Int}}) - return similar(a, elt, dims) -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/map.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/map.jl deleted file mode 100644 index 0f9d9aad5f..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/map.jl +++ /dev/null @@ -1,120 +0,0 @@ -using Base.Broadcast: BroadcastStyle, combine_styles -using Compat: allequal -using LinearAlgebra: LinearAlgebra - -# Represents a value that isn't stored -# Used to hijack dispatch -struct NotStoredValue{Value} - value::Value -end -value(v::NotStoredValue) = v.value -stored_length(::NotStoredValue) = false -Base.:*(x::Number, y::NotStoredValue) = false -Base.:*(x::NotStoredValue, y::Number) = false -Base.:/(x::NotStoredValue, y::Number) = false -Base.:+(::NotStoredValue, ::NotStoredValue...) = false -Base.:-(::NotStoredValue, ::NotStoredValue...) = false -Base.:+(x::Number, ::NotStoredValue...) = x -Base.iszero(::NotStoredValue) = true -Base.isreal(::NotStoredValue) = true -Base.conj(x::NotStoredValue) = conj(value(x)) -Base.iterate(x::NotStoredValue) = (x, nothing) -Base.mapreduce(f, op, x::NotStoredValue) = f(x) -Base.zero(x::NotStoredValue) = zero(value(x)) -LinearAlgebra.norm(x::NotStoredValue, p::Real=2) = zero(value(x)) - -notstored_index(a::AbstractArray) = NotStoredIndex(first(eachindex(a))) - -# Get some not-stored value -function get_notstored(a::AbstractArray) - return sparse_getindex(a, notstored_index(a)) -end - -function apply_notstored(f, as::Vararg{AbstractArray}) - return apply(f, NotStoredValue.(get_notstored.(as))...) -end - -function apply(f, xs::Vararg{NotStoredValue}) - return f(xs...) - #return try - # return f(xs...) - #catch - # f(value(x)) - #end -end - -# Test if the function preserves zero values and therefore -# preserves the sparsity structure. -function preserves_zero(f, as...) - # return iszero(f(map(get_notstored, as)...)) - return iszero(apply_notstored(f, as...)) -end - -# Map a subset of indices -function sparse_map_indices!(f, a_dest::AbstractArray, indices, as::AbstractArray...) - for I in indices - a_dest[I] = f(map(a -> a[I], as)...) - end - return a_dest -end - -# Overload for custom `stored_indices` types. -function promote_indices(I1, I2) - return union(I1, I2) -end - -function promote_indices(I1, I2, Is...) - return promote_indices(promote_indices(I1, I2), Is...) -end - -# Base case -promote_indices(I) = I - -function promote_stored_indices(as::AbstractArray...) - return promote_indices(stored_indices.(as)...) -end - -function sparse_map_stored!(f, a_dest::AbstractArray, as::AbstractArray...) - # Need to zero out the destination. - sparse_zero!(a_dest) - Is = promote_stored_indices(as...) - sparse_map_indices!(f, a_dest, Is, as...) - return a_dest -end - -# Handle nonzero case, fill all values. -function sparse_map_all!(f, a_dest::AbstractArray, as::AbstractArray...) - Is = eachindex(a_dest) - sparse_map_indices!(f, a_dest, Is, as...) - return a_dest -end - -function sparse_map!(f, a_dest::AbstractArray, as::AbstractArray...) - return sparse_map!(combine_styles(as...), f, a_dest, as...) -end - -function sparse_map!(::BroadcastStyle, f, a_dest::AbstractArray, as::AbstractArray...) - @assert allequal(axes.((a_dest, as...))) - if preserves_zero(f, as...) - # Remove aliases to avoid overwriting inputs. - as = map(a -> Base.unalias(a_dest, a), as) - sparse_map_stored!(f, a_dest, as...) - else - sparse_map_all!(f, a_dest, as...) - end - return a_dest -end - -# `f::typeof(norm)`, `op::typeof(max)` used by `norm`. -function reduce_init(f, op, a) - return f(zero(eltype(a))) -end - -# TODO: Generalize to multiple arguements. -# TODO: Define `sparse_mapreducedim!`. -function sparse_mapreduce(f, op, a::AbstractArray; init=reduce_init(f, op, a), kwargs...) - output = mapreduce(f, op, sparse_storage(a); init, kwargs...) - f_notstored = apply_notstored(f, a) - @assert isequal(op(output, eltype(output)(f_notstored)), output) - return output -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/vectorinterface.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/vectorinterface.jl deleted file mode 100644 index 787ec83019..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/vectorinterface.jl +++ /dev/null @@ -1,28 +0,0 @@ -using VectorInterface: zerovector! - -################################################## -# TODO: Move to `DictionariesVectorInterfaceExt`. -using VectorInterface: VectorInterface, zerovector!, zerovector!! -using Dictionaries: AbstractDictionary - -function VectorInterface.zerovector!(x::AbstractDictionary{<:Number}) - return fill!(x, zero(scalartype(x))) -end -function VectorInterface.zerovector!(x::AbstractDictionary) - T = eltype(x) - for I in eachindex(x) - if isbitstype(T) || isassigned(x, I) - x[I] = zerovector!!(x[I]) - else - x[I] = zero(eltype(x)) - end - end - return x -end -################################################## - -function sparse_zerovector!(a::AbstractArray) - dropall!(a) - zerovector!(sparse_storage(a)) - return a -end diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/wrappers.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/wrappers.jl deleted file mode 100644 index a4fce3bb0c..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/wrappers.jl +++ /dev/null @@ -1,51 +0,0 @@ -using ..NestedPermutedDimsArrays: NestedPermutedDimsArray - -## PermutedDimsArray - -const AnyPermutedDimsArray{T,N,perm,iperm,P} = Union{ - PermutedDimsArray{T,N,perm,iperm,P},NestedPermutedDimsArray{T,N,perm,iperm,P} -} - -# TODO: Use `TypeParameterAccessors`. -perm(::AnyPermutedDimsArray{<:Any,<:Any,Perm}) where {Perm} = Perm -iperm(::AnyPermutedDimsArray{<:Any,<:Any,<:Any,IPerm}) where {IPerm} = IPerm - -# TODO: Use `Base.PermutedDimsArrays.genperm` or -# https://github.com/jipolanco/StaticPermutations.jl? -genperm(v, perm) = map(j -> v[j], perm) -genperm(v::CartesianIndex, perm) = CartesianIndex(map(j -> Tuple(v)[j], perm)) - -function storage_index_to_index(a::AnyPermutedDimsArray, I) - return genperm(storage_index_to_index(parent(a), I), perm(a)) -end - -function index_to_storage_index( - a::AnyPermutedDimsArray{<:Any,N}, I::CartesianIndex{N} -) where {N} - return index_to_storage_index(parent(a), genperm(I, perm(a))) -end - -# TODO: Add `getindex_zero_function` definition? - -## SubArray - -function map_index( - indices::Tuple{Vararg{Any,N}}, cartesian_index::CartesianIndex{N} -) where {N} - index = Tuple(cartesian_index) - new_index = ntuple(length(indices)) do i - findfirst(==(index[i]), indices[i]) - end - any(isnothing, new_index) && return nothing - return CartesianIndex(new_index) -end - -function storage_index_to_index(a::SubArray, I) - return storage_index_to_index(parent(a), I) -end - -function index_to_storage_index(a::SubArray{<:Any,N}, I::CartesianIndex{N}) where {N} - return index_to_storage_index(parent(a), I) -end - -getindex_zero_function(a::SubArray) = getindex_zero_function(parent(a)) diff --git a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/zero.jl b/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/zero.jl deleted file mode 100644 index 72899b4445..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/src/sparsearrayinterface/zero.jl +++ /dev/null @@ -1,5 +0,0 @@ -# Represents a zero value and an index -# TODO: Rename `GetIndexZero`? -struct Zero end -(f::Zero)(a::AbstractArray, I) = f(eltype(a), I) -(::Zero)(type::Type, I) = zero(type) diff --git a/NDTensors/src/lib/SparseArraysBase/test/Project.toml b/NDTensors/src/lib/SparseArraysBase/test/Project.toml deleted file mode 100644 index d674f61e4e..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/Project.toml +++ /dev/null @@ -1,7 +0,0 @@ -[deps] -ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" -Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" -Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/AbstractSparseArrays.jl b/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/AbstractSparseArrays.jl deleted file mode 100644 index 5ae5f5c1ff..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/AbstractSparseArrays.jl +++ /dev/null @@ -1,74 +0,0 @@ -module AbstractSparseArrays -using ArrayLayouts: ArrayLayouts, MatMulMatAdd, MemoryLayout, MulAdd -using NDTensors.SparseArraysBase: SparseArraysBase, AbstractSparseArray, Zero - -struct SparseArray{T,N,Zero} <: AbstractSparseArray{T,N} - data::Vector{T} - dims::Tuple{Vararg{Int,N}} - index_to_dataindex::Dict{CartesianIndex{N},Int} - dataindex_to_index::Vector{CartesianIndex{N}} - zero::Zero -end -function SparseArray{T,N}(dims::Tuple{Vararg{Int,N}}; zero=Zero()) where {T,N} - return SparseArray{T,N,typeof(zero)}( - T[], dims, Dict{CartesianIndex{N},Int}(), Vector{CartesianIndex{N}}(), zero - ) -end -function SparseArray{T,N}(dims::Vararg{Int,N}; kwargs...) where {T,N} - return SparseArray{T,N}(dims; kwargs...) -end -function SparseArray{T}(dims::Tuple{Vararg{Int}}; kwargs...) where {T} - return SparseArray{T,length(dims)}(dims; kwargs...) -end -function SparseArray{T}(::UndefInitializer, dims::Tuple{Vararg{Int}}; kwargs...) where {T} - return SparseArray{T}(dims; kwargs...) -end -SparseArray{T}(dims::Vararg{Int}; kwargs...) where {T} = SparseArray{T}(dims; kwargs...) - -# ArrayLayouts interface -struct SparseLayout <: MemoryLayout end -ArrayLayouts.MemoryLayout(::Type{<:SparseArray}) = SparseLayout() -function Base.similar(::MulAdd{<:SparseLayout,<:SparseLayout}, elt::Type, axes) - return similar(SparseArray{elt}, axes) -end -function ArrayLayouts.materialize!( - m::MatMulMatAdd{<:SparseLayout,<:SparseLayout,<:SparseLayout} -) - α, a1, a2, β, a_dest = m.α, m.A, m.B, m.β, m.C - SparseArraysBase.sparse_mul!(a_dest, a1, a2, α, β) - return a_dest -end - -# AbstractArray interface -Base.size(a::SparseArray) = a.dims -function Base.similar(a::SparseArray, elt::Type, dims::Tuple{Vararg{Int}}) - return SparseArray{elt}(dims) -end - -# Minimal interface -SparseArraysBase.getindex_zero_function(a::SparseArray) = a.zero -SparseArraysBase.sparse_storage(a::SparseArray) = a.data -function SparseArraysBase.index_to_storage_index( - a::SparseArray{<:Any,N}, I::CartesianIndex{N} -) where {N} - return get(a.index_to_dataindex, I, nothing) -end -SparseArraysBase.storage_index_to_index(a::SparseArray, I) = a.dataindex_to_index[I] -function SparseArraysBase.setindex_notstored!( - a::SparseArray{<:Any,N}, value, I::CartesianIndex{N} -) where {N} - push!(a.data, value) - push!(a.dataindex_to_index, I) - a.index_to_dataindex[I] = length(a.data) - return a -end - -# Empty the storage, helps with efficiency in `map!` to drop -# zeros. -function SparseArraysBase.dropall!(a::SparseArray) - empty!(a.data) - empty!(a.index_to_dataindex) - empty!(a.dataindex_to_index) - return a -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/DiagonalArrays.jl b/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/DiagonalArrays.jl deleted file mode 100644 index 394a622694..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/DiagonalArrays.jl +++ /dev/null @@ -1,95 +0,0 @@ -module DiagonalArrays -using NDTensors.SparseArraysBase: SparseArraysBase - -struct DiagonalArray{T,N} <: AbstractArray{T,N} - data::Vector{T} - dims::Tuple{Vararg{Int,N}} -end -function DiagonalArray{T,N}(::UndefInitializer, dims::Tuple{Vararg{Int,N}}) where {T,N} - return DiagonalArray{T,N}(Vector{T}(undef, minimum(dims)), dims) -end -function DiagonalArray{T,N}(::UndefInitializer, dims::Vararg{Int,N}) where {T,N} - return DiagonalArray{T,N}(undef, dims) -end -function DiagonalArray{T}(::UndefInitializer, dims::Tuple{Vararg{Int}}) where {T} - return DiagonalArray{T,length(dims)}(undef, dims) -end -function DiagonalArray{T}(::UndefInitializer, dims::Vararg{Int}) where {T} - return DiagonalArray{T}(undef, dims) -end - -# AbstractArray interface -Base.size(a::DiagonalArray) = a.dims -function Base.getindex(a::DiagonalArray, I...) - return SparseArraysBase.sparse_getindex(a, I...) -end -function Base.setindex!(a::DiagonalArray, I...) - return SparseArraysBase.sparse_setindex!(a, I...) -end -function Base.similar(a::DiagonalArray, elt::Type, dims::Tuple{Vararg{Int}}) - return DiagonalArray{elt}(undef, dims) -end - -# Minimal interface -SparseArraysBase.sparse_storage(a::DiagonalArray) = a.data -function SparseArraysBase.index_to_storage_index( - a::DiagonalArray{<:Any,N}, I::CartesianIndex{N} -) where {N} - !allequal(Tuple(I)) && return nothing - return first(Tuple(I)) -end -function SparseArraysBase.storage_index_to_index(a::DiagonalArray, I) - return CartesianIndex(ntuple(Returns(I), ndims(a))) -end -function SparseArraysBase.sparse_similar( - a::DiagonalArray, elt::Type, dims::Tuple{Vararg{Int}} -) - return Array{elt}(undef, dims) -end -function SparseArraysBase.sparse_similar(a::DiagonalArray, elt::Type, dims::Tuple{Int}) - return similar(a, elt, dims) -end - -# Broadcasting -function Broadcast.BroadcastStyle(arraytype::Type{<:DiagonalArray}) - return SparseArraysBase.SparseArrayStyle{ndims(arraytype)}() -end - -# Base -function Base.iszero(a::DiagonalArray) - return SparseArraysBase.sparse_iszero(a) -end -function Base.isreal(a::DiagonalArray) - return SparseArraysBase.sparse_isreal(a) -end -function Base.zero(a::DiagonalArray) - return SparseArraysBase.sparse_zero(a) -end -function Base.one(a::DiagonalArray) - return SparseArraysBase.sparse_one(a) -end -function Base.:(==)(a1::DiagonalArray, a2::DiagonalArray) - return SparseArraysBase.sparse_isequal(a1, a2) -end -function Base.reshape(a::DiagonalArray, dims::Tuple{Vararg{Int}}) - return SparseArraysBase.sparse_reshape(a, dims) -end - -# Map -function Base.map!(f, dest::AbstractArray, src::DiagonalArray) - SparseArraysBase.sparse_map!(f, dest, src) - return dest -end -function Base.copy!(dest::AbstractArray, src::DiagonalArray) - SparseArraysBase.sparse_copy!(dest, src) - return dest -end -function Base.copyto!(dest::AbstractArray, src::DiagonalArray) - SparseArraysBase.sparse_copyto!(dest, src) - return dest -end -function Base.permutedims!(dest::AbstractArray, src::DiagonalArray, perm) - SparseArraysBase.sparse_permutedims!(dest, src, perm) - return dest -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/Project.toml b/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/Project.toml deleted file mode 100644 index 9b1d5ccd25..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/Project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[deps] -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" diff --git a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArrays.jl b/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArrays.jl deleted file mode 100644 index 082adb173d..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArrays.jl +++ /dev/null @@ -1,166 +0,0 @@ -module SparseArrays -using LinearAlgebra: LinearAlgebra -using NDTensors.SparseArraysBase: SparseArraysBase, Zero - -struct SparseArray{T,N,Zero} <: AbstractArray{T,N} - data::Vector{T} - dims::Tuple{Vararg{Int,N}} - index_to_dataindex::Dict{CartesianIndex{N},Int} - dataindex_to_index::Vector{CartesianIndex{N}} - zero::Zero -end -function SparseArray{T,N}(dims::Tuple{Vararg{Int,N}}; zero=Zero()) where {T,N} - return SparseArray{T,N,typeof(zero)}( - T[], dims, Dict{CartesianIndex{N},Int}(), Vector{CartesianIndex{N}}(), zero - ) -end -function SparseArray{T,N}(dims::Vararg{Int,N}; kwargs...) where {T,N} - return SparseArray{T,N}(dims; kwargs...) -end -function SparseArray{T}(dims::Tuple{Vararg{Int}}; kwargs...) where {T} - return SparseArray{T,length(dims)}(dims; kwargs...) -end -function SparseArray{T}(::UndefInitializer, dims::Tuple{Vararg{Int}}; kwargs...) where {T} - return SparseArray{T}(dims; kwargs...) -end -SparseArray{T}(dims::Vararg{Int}; kwargs...) where {T} = SparseArray{T}(dims; kwargs...) - -# LinearAlgebra interface -function LinearAlgebra.mul!( - a_dest::AbstractMatrix, - a1::SparseArray{<:Any,2}, - a2::SparseArray{<:Any,2}, - α::Number, - β::Number, -) - SparseArraysBase.sparse_mul!(a_dest, a1, a2, α, β) - return a_dest -end - -function LinearAlgebra.dot(a1::SparseArray, a2::SparseArray) - return SparseArraysBase.sparse_dot(a1, a2) -end - -# AbstractArray interface -Base.size(a::SparseArray) = a.dims -function Base.similar(a::SparseArray, elt::Type, dims::Tuple{Vararg{Int}}) - return SparseArray{elt}(dims) -end - -function Base.getindex(a::SparseArray, I...) - return SparseArraysBase.sparse_getindex(a, I...) -end -function Base.setindex!(a::SparseArray, value, I...) - return SparseArraysBase.sparse_setindex!(a, value, I...) -end -function Base.fill!(a::SparseArray, value) - return SparseArraysBase.sparse_fill!(a, value) -end - -# Minimal interface -SparseArraysBase.getindex_zero_function(a::SparseArray) = a.zero -SparseArraysBase.sparse_storage(a::SparseArray) = a.data -function SparseArraysBase.index_to_storage_index( - a::SparseArray{<:Any,N}, I::CartesianIndex{N} -) where {N} - return get(a.index_to_dataindex, I, nothing) -end -SparseArraysBase.storage_index_to_index(a::SparseArray, I) = a.dataindex_to_index[I] -function SparseArraysBase.setindex_notstored!( - a::SparseArray{<:Any,N}, value, I::CartesianIndex{N} -) where {N} - push!(a.data, value) - push!(a.dataindex_to_index, I) - a.index_to_dataindex[I] = length(a.data) - return a -end - -# TODO: Make this into a generic definition of all `AbstractArray`? -using NDTensors.SparseArraysBase: perm, stored_indices -function SparseArraysBase.stored_indices( - a::PermutedDimsArray{<:Any,<:Any,<:Any,<:Any,<:SparseArray} -) - return Iterators.map( - I -> CartesianIndex(map(i -> I[i], perm(a))), stored_indices(parent(a)) - ) -end - -# TODO: Make this into a generic definition of all `AbstractArray`? -using NDTensors.SparseArraysBase: sparse_storage -function SparseArraysBase.sparse_storage( - a::PermutedDimsArray{<:Any,<:Any,<:Any,<:Any,<:SparseArray} -) - return sparse_storage(parent(a)) -end - -# TODO: Make this into a generic definition of all `AbstractArray`? -using NDTensors.NestedPermutedDimsArrays: NestedPermutedDimsArray -function SparseArraysBase.stored_indices( - a::NestedPermutedDimsArray{<:Any,<:Any,<:Any,<:Any,<:SparseArray} -) - return Iterators.map( - I -> CartesianIndex(map(i -> I[i], perm(a))), stored_indices(parent(a)) - ) -end - -# TODO: Make this into a generic definition of all `AbstractArray`? -using NDTensors.NestedPermutedDimsArrays: NestedPermutedDimsArray -using NDTensors.SparseArraysBase: sparse_storage -function SparseArraysBase.sparse_storage( - a::NestedPermutedDimsArray{<:Any,<:Any,<:Any,<:Any,<:SparseArray} -) - return sparse_storage(parent(a)) -end - -# Empty the storage, helps with efficiency in `map!` to drop -# zeros. -function SparseArraysBase.dropall!(a::SparseArray) - empty!(a.data) - empty!(a.index_to_dataindex) - empty!(a.dataindex_to_index) - return a -end - -# Broadcasting -function Broadcast.BroadcastStyle(arraytype::Type{<:SparseArray}) - return SparseArraysBase.SparseArrayStyle{ndims(arraytype)}() -end - -# Map -function Base.map!(f, dest::AbstractArray, src::SparseArray) - SparseArraysBase.sparse_map!(f, dest, src) - return dest -end -function Base.copy!(dest::AbstractArray, src::SparseArray) - SparseArraysBase.sparse_copy!(dest, src) - return dest -end -function Base.copyto!(dest::AbstractArray, src::SparseArray) - SparseArraysBase.sparse_copyto!(dest, src) - return dest -end -function Base.permutedims!(dest::AbstractArray, src::SparseArray, perm) - SparseArraysBase.sparse_permutedims!(dest, src, perm) - return dest -end - -# Base -function Base.:(==)(a1::SparseArray, a2::SparseArray) - return SparseArraysBase.sparse_isequal(a1, a2) -end -function Base.reshape(a::SparseArray, dims::Tuple{Vararg{Int}}) - return SparseArraysBase.sparse_reshape(a, dims) -end -function Base.iszero(a::SparseArray) - return SparseArraysBase.sparse_iszero(a) -end -function Base.isreal(a::SparseArray) - return SparseArraysBase.sparse_isreal(a) -end -function Base.zero(a::SparseArray) - return SparseArraysBase.sparse_zero(a) -end -function Base.one(a::SparseArray) - return SparseArraysBase.sparse_one(a) -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArraysBaseTestUtils.jl b/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArraysBaseTestUtils.jl deleted file mode 100644 index 9067f9df96..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/SparseArraysBaseTestUtils/SparseArraysBaseTestUtils.jl +++ /dev/null @@ -1,5 +0,0 @@ -module SparseArraysBaseTestUtils -include("AbstractSparseArrays.jl") -include("DiagonalArrays.jl") -include("SparseArrays.jl") -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/runtests.jl b/NDTensors/src/lib/SparseArraysBase/test/runtests.jl deleted file mode 100644 index 40340f5eaa..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/runtests.jl +++ /dev/null @@ -1,5 +0,0 @@ -@eval module $(gensym()) -for filename in ["sparsearraydok", "abstractsparsearray", "array", "diagonalarray"] - include("test_$filename.jl") -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/test_abstractsparsearray.jl b/NDTensors/src/lib/SparseArraysBase/test/test_abstractsparsearray.jl deleted file mode 100644 index b64955cb55..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/test_abstractsparsearray.jl +++ /dev/null @@ -1,439 +0,0 @@ -@eval module $(gensym()) -using LinearAlgebra: dot, mul!, norm -using NDTensors.SparseArraysBase: SparseArraysBase -using NDTensors.NestedPermutedDimsArrays: NestedPermutedDimsArray -include("SparseArraysBaseTestUtils/SparseArraysBaseTestUtils.jl") -using .SparseArraysBaseTestUtils.AbstractSparseArrays: AbstractSparseArrays -using .SparseArraysBaseTestUtils.SparseArrays: SparseArrays -using Test: @test, @testset -@testset "AbstractSparseArray (arraytype=$SparseArray, eltype=$elt)" for SparseArray in ( - AbstractSparseArrays.SparseArray, SparseArrays.SparseArray - ), - elt in (Float32, ComplexF32, Float64, ComplexF64) - - a = SparseArray{elt}(2, 3) - @test size(a) == (2, 3) - @test axes(a) == (1:2, 1:3) - @test SparseArraysBase.sparse_storage(a) == elt[] - @test iszero(SparseArraysBase.stored_length(a)) - @test collect(SparseArraysBase.stored_indices(a)) == CartesianIndex{2}[] - @test iszero(a) - @test iszero(norm(a)) - for I in eachindex(a) - @test iszero(a) - end - for I in CartesianIndices(a) - @test isassigned(a, Tuple(I)...) - @test isassigned(a, I) - end - @test !isassigned(a, 0, 1) - @test !isassigned(a, CartesianIndex(0, 1)) - @test !isassigned(a, 1, 4) - @test !isassigned(a, CartesianIndex(1, 4)) - - a = SparseArray{elt}(2, 3) - fill!(a, 0) - @test size(a) == (2, 3) - @test iszero(a) - @test iszero(SparseArraysBase.stored_length(a)) - - a_dense = SparseArraysBase.densearray(a) - @test a_dense == a - @test a_dense isa Array{elt,ndims(a)} - - a = SparseArray{elt}(2, 3) - fill!(a, 2) - @test size(a) == (2, 3) - @test !iszero(a) - @test SparseArraysBase.stored_length(a) == length(a) - for I in eachindex(a) - @test a[I] == 2 - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - @test a[1, 2] == 12 - @test a[3] == 12 # linear indexing - @test size(a) == (2, 3) - @test axes(a) == (1:2, 1:3) - @test a[SparseArraysBase.StorageIndex(1)] == 12 - @test SparseArraysBase.sparse_storage(a) == elt[12] - @test isone(SparseArraysBase.stored_length(a)) - @test collect(SparseArraysBase.stored_indices(a)) == [CartesianIndex(1, 2)] - @test !iszero(a) - @test !iszero(norm(a)) - for I in eachindex(a) - if I == CartesianIndex(1, 2) - @test a[I] == 12 - else - @test iszero(a[I]) - end - end - for I in CartesianIndices(a) - @test isassigned(a, Tuple(I)...) - @test isassigned(a, I) - end - @test !isassigned(a, 0, 1) - @test !isassigned(a, CartesianIndex(0, 1)) - @test !isassigned(a, 1, 4) - @test !isassigned(a, CartesianIndex(1, 4)) - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - a = map(x -> 2x, a) - for I in eachindex(a) - if I == CartesianIndex(1, 2) - @test a[I] == 2 * 12 - else - @test iszero(a[I]) - end - end - - a = SparseArray{elt}(2, 2, 2) - a[1, 2, 2] = 122 - a_r = reshape(a, 2, 4) - @test a_r[1, 4] == a[1, 2, 2] == 122 - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - a = zero(a) - @test size(a) == (2, 3) - @test iszero(SparseArraysBase.stored_length(a)) - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = SparseArray{elt}(2, 3) - b[2, 1] = 21 - @test a == a - @test a ≠ b - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - @test isreal(a) - - a = SparseArray{elt}(2, 3) - a[1, 2] = randn(elt) - b = copy(a) - conj!(b) - for I in eachindex(a) - @test conj(a[I]) == b[I] - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = randn(elt) - b = conj(a) - for I in eachindex(a) - @test conj(a[I]) == b[I] - end - - if !(elt <: Real) - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 + 12im - @test !isreal(a) - end - - a = SparseArray{elt}(2, 2) - a[1, 2] = 12 - a = one(a) - @test size(a) == (2, 2) - @test isone(a[1, 1]) - @test isone(a[2, 2]) - @test iszero(a[1, 2]) - @test iszero(a[2, 1]) - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - a = zero(a) - @test size(a) == (2, 3) - @test iszero(SparseArraysBase.stored_length(a)) - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - a = copy(a) - @test size(a) == (2, 3) - @test axes(a) == (1:2, 1:3) - @test SparseArraysBase.sparse_storage(a) == elt[12] - @test isone(SparseArraysBase.stored_length(a)) - @test SparseArraysBase.storage_indices(a) == 1:1 - @test collect(SparseArraysBase.stored_indices(a)) == [CartesianIndex(1, 2)] - @test !iszero(a) - @test !iszero(norm(a)) - for I in eachindex(a) - if I == CartesianIndex(1, 2) - @test a[I] == 12 - else - @test iszero(a[I]) - end - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - a = 2 * a - @test size(a) == (2, 3) - @test axes(a) == (1:2, 1:3) - @test SparseArraysBase.sparse_storage(a) == elt[24] - @test isone(SparseArraysBase.stored_length(a)) - @test collect(SparseArraysBase.stored_indices(a)) == [CartesianIndex(1, 2)] - @test !iszero(a) - @test !iszero(norm(a)) - for I in eachindex(a) - if I == CartesianIndex(1, 2) - @test a[I] == 24 - else - @test iszero(a[I]) - end - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = SparseArray{elt}(2, 3) - b[2, 1] = 21 - c = a + b - @test size(c) == (2, 3) - @test axes(c) == (1:2, 1:3) - @test SparseArraysBase.sparse_storage(c) == elt[12, 21] - @test SparseArraysBase.stored_length(c) == 2 - @test collect(SparseArraysBase.stored_indices(c)) == - [CartesianIndex(1, 2), CartesianIndex(2, 1)] - @test !iszero(c) - @test !iszero(norm(c)) - for I in eachindex(c) - if I == CartesianIndex(1, 2) - @test c[I] == 12 - elseif I == CartesianIndex(2, 1) - @test c[I] == 21 - else - @test iszero(c[I]) - end - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = permutedims(a, (2, 1)) - @test size(b) == (3, 2) - @test axes(b) == (1:3, 1:2) - @test SparseArraysBase.sparse_storage(b) == elt[12] - @test SparseArraysBase.stored_length(b) == 1 - @test collect(SparseArraysBase.stored_indices(b)) == [CartesianIndex(2, 1)] - @test !iszero(b) - @test !iszero(norm(b)) - for I in eachindex(b) - if I == CartesianIndex(2, 1) - @test b[I] == 12 - else - @test iszero(b[I]) - end - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = PermutedDimsArray(a, (2, 1)) - @test size(b) == (3, 2) - @test axes(b) == (1:3, 1:2) - @test SparseArraysBase.sparse_storage(b) == elt[12] - @test SparseArraysBase.stored_length(b) == 1 - @test collect(SparseArraysBase.stored_indices(b)) == [CartesianIndex(2, 1)] - @test !iszero(b) - @test !iszero(norm(b)) - for I in eachindex(b) - if I == CartesianIndex(2, 1) - @test b[I] == 12 - else - @test iszero(b[I]) - end - end - - a = SparseArray{Matrix{elt}}( - 2, 3; zero=(a, I) -> (z = similar(eltype(a), 2, 3); fill!(z, false); z) - ) - a[1, 2] = randn(elt, 2, 3) - b = NestedPermutedDimsArray(a, (2, 1)) - @test size(b) == (3, 2) - @test axes(b) == (1:3, 1:2) - @test SparseArraysBase.sparse_storage(b) == [a[1, 2]] - @test SparseArraysBase.stored_length(b) == 1 - @test collect(SparseArraysBase.stored_indices(b)) == [CartesianIndex(2, 1)] - @test !iszero(b) - @test !iszero(norm(b)) - for I in eachindex(b) - if I == CartesianIndex(2, 1) - @test b[I] == permutedims(a[1, 2], (2, 1)) - else - @test iszero(b[I]) - end - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = randn(elt, 2, 3) - b .= a - @test a == b - for I in eachindex(a) - @test a[I] == b[I] - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = randn(elt, 2, 3) - b .= 2 .* a - @test 2 * a == b - for I in eachindex(a) - @test 2 * a[I] == b[I] - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = randn(elt, 2, 3) - b .= 2 .+ a - @test 2 .+ a == b - for I in eachindex(a) - @test 2 + a[I] == b[I] - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = randn(elt, 2, 3) - map!(x -> 2x, b, a) - @test 2 * a == b - for I in eachindex(a) - @test 2 * a[I] == b[I] - end - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = zeros(elt, 2, 3) - b[2, 1] = 21 - @test Array(a) == a - @test a + b == Array(a) + b - @test b + a == Array(a) + b - @test b .+ 2 .* a == 2 * Array(a) + b - @test a .+ 2 .* b == Array(a) + 2b - @test a + b isa Matrix{elt} - @test b + a isa Matrix{elt} - @test SparseArraysBase.stored_length(a + b) == length(a) - - a = SparseArray{elt}(2, 3) - a[1, 2] = 12 - b = zeros(elt, 2, 3) - b[2, 1] = 21 - a′ = copy(a) - a′ .+= b - @test a′ == a + b - # TODO: Should this be: - # ```julia - # @test SparseArraysBase.stored_length(a′) == 2 - # ``` - # ? I.e. should it only store the nonzero values? - @test SparseArraysBase.stored_length(a′) == 6 - - # Matrix multiplication - a1 = SparseArray{elt}(2, 3) - a1[1, 2] = 12 - a1[2, 1] = 21 - a2 = SparseArray{elt}(3, 4) - a2[1, 1] = 11 - a2[2, 2] = 22 - a_dest = a1 * a2 - @test Array(a_dest) ≈ Array(a1) * Array(a2) - @test a_dest isa SparseArray{elt} - @test SparseArraysBase.stored_length(a_dest) == 2 - - # Dot product - a1 = SparseArray{elt}(4) - a1[1] = randn() - a1[3] = randn() - a2 = SparseArray{elt}(4) - a2[2] = randn() - a2[3] = randn() - a_dest = a1' * a2 - @test a_dest isa elt - @test a_dest ≈ Array(a1)' * Array(a2) - @test a_dest ≈ dot(a1, a2) - - # In-place matrix multiplication - a1 = SparseArray{elt}(2, 3) - a1[1, 2] = 12 - a1[2, 1] = 21 - a2 = SparseArray{elt}(3, 4) - a2[1, 1] = 11 - a2[2, 2] = 22 - a_dest = SparseArray{elt}(2, 4) - mul!(a_dest, a1, a2) - @test Array(a_dest) ≈ Array(a1) * Array(a2) - @test a_dest isa SparseArray{elt} - @test SparseArraysBase.stored_length(a_dest) == 2 - - # In-place matrix multiplication - a1 = SparseArray{elt}(2, 3) - a1[1, 2] = 12 - a1[2, 1] = 21 - a2 = SparseArray{elt}(3, 4) - a2[1, 1] = 11 - a2[2, 2] = 22 - a_dest = SparseArray{elt}(2, 4) - a_dest[1, 2] = 12 - a_dest[2, 1] = 21 - α = elt(2) - β = elt(3) - a_dest′ = copy(a_dest) - mul!(a_dest, a1, a2, α, β) - @test Array(a_dest) ≈ Array(a1) * Array(a2) * α + Array(a_dest′) * β - @test a_dest isa SparseArray{elt} - @test SparseArraysBase.stored_length(a_dest) == 2 - - # cat - a1 = SparseArray{elt}(2, 3) - a1[1, 2] = 12 - a1[2, 1] = 21 - a2 = SparseArray{elt}(2, 3) - a2[1, 1] = 11 - a2[2, 2] = 22 - - a_dest = cat(a1, a2; dims=1) - @test size(a_dest) == (4, 3) - @test SparseArraysBase.stored_length(a_dest) == 4 - @test a_dest[1, 2] == a1[1, 2] - @test a_dest[2, 1] == a1[2, 1] - @test a_dest[3, 1] == a2[1, 1] - @test a_dest[4, 2] == a2[2, 2] - - a_dest = cat(a1, a2; dims=2) - @test size(a_dest) == (2, 6) - @test SparseArraysBase.stored_length(a_dest) == 4 - @test a_dest[1, 2] == a1[1, 2] - @test a_dest[2, 1] == a1[2, 1] - @test a_dest[1, 4] == a2[1, 1] - @test a_dest[2, 5] == a2[2, 2] - - a_dest = cat(a1, a2; dims=(1, 2)) - @test size(a_dest) == (4, 6) - @test SparseArraysBase.stored_length(a_dest) == 4 - @test a_dest[1, 2] == a1[1, 2] - @test a_dest[2, 1] == a1[2, 1] - @test a_dest[3, 4] == a2[1, 1] - @test a_dest[4, 5] == a2[2, 2] - - ## # Sparse matrix of matrix multiplication - ## TODO: Make this work, seems to require - ## a custom zero constructor. - ## a1 = SparseArray{Matrix{elt}}(2, 3) - ## a1[1, 1] = zeros(elt, (2, 3)) - ## a1[1, 2] = randn(elt, (2, 3)) - ## a1[2, 1] = randn(elt, (2, 3)) - ## a1[2, 2] = zeros(elt, (2, 3)) - ## a2 = SparseArray{Matrix{elt}}(3, 4) - ## a2[1, 1] = randn(elt, (3, 4)) - ## a2[1, 2] = zeros(elt, (3, 4)) - ## a2[2, 2] = randn(elt, (3, 4)) - ## a2[2, 2] = zeros(elt, (3, 4)) - ## a_dest = SparseArray{Matrix{elt}}(2, 4) - ## a_dest[1, 1] = zeros(elt, (3, 4)) - ## a_dest[1, 2] = zeros(elt, (3, 4)) - ## a_dest[2, 2] = zeros(elt, (3, 4)) - ## a_dest[2, 2] = zeros(elt, (3, 4)) - ## mul!(a_dest, a1, a2) - ## @test Array(a_dest) ≈ Array(a1) * Array(a2) - ## @test a_dest isa SparseArray{Matrix{elt}} - ## @test SparseArraysBase.stored_length(a_dest) == 2 -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/test_array.jl b/NDTensors/src/lib/SparseArraysBase/test/test_array.jl deleted file mode 100644 index 0037412edf..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/test_array.jl +++ /dev/null @@ -1,13 +0,0 @@ -@eval module $(gensym()) -using NDTensors.SparseArraysBase: SparseArraysBase -include("SparseArraysBaseTestUtils/SparseArraysBaseTestUtils.jl") -using Test: @test, @testset -@testset "Array (eltype=$elt)" for elt in (Float32, ComplexF32, Float64, ComplexF64) - a = randn(2, 3) - @test SparseArraysBase.sparse_storage(a) == a - @test SparseArraysBase.index_to_storage_index(a, CartesianIndex(1, 2)) == - CartesianIndex(1, 2) - @test SparseArraysBase.storage_index_to_index(a, CartesianIndex(1, 2)) == - CartesianIndex(1, 2) -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/test_diagonalarray.jl b/NDTensors/src/lib/SparseArraysBase/test/test_diagonalarray.jl deleted file mode 100644 index 18075e3d35..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/test_diagonalarray.jl +++ /dev/null @@ -1,76 +0,0 @@ -@eval module $(gensym()) -using LinearAlgebra: norm -using NDTensors.SparseArraysBase: SparseArraysBase -include("SparseArraysBaseTestUtils/SparseArraysBaseTestUtils.jl") -using .SparseArraysBaseTestUtils.DiagonalArrays: DiagonalArray -using Test: @test, @testset, @test_throws -@testset "DiagonalArray (eltype=$elt)" for elt in (Float32, ComplexF32, Float64, ComplexF64) - # TODO: Test `fill!`. - - # Test - a = DiagonalArray{elt}(undef, 2, 3) - @test size(a) == (2, 3) - a[1, 1] = 11 - a[2, 2] = 22 - @test a[1, 1] == 11 - @test a[2, 2] == 22 - @test_throws ArgumentError a[1, 2] = 12 - @test SparseArraysBase.storage_indices(a) == 1:2 - @test collect(SparseArraysBase.stored_indices(a)) == - [CartesianIndex(1, 1), CartesianIndex(2, 2)] - a[1, 2] = 0 - @test a[1, 1] == 11 - @test a[2, 2] == 22 - - a_dense = SparseArraysBase.densearray(a) - @test a_dense == a - @test a_dense isa Array{elt,ndims(a)} - - b = similar(a) - @test b isa DiagonalArray - @test size(b) == (2, 3) - - a = DiagonalArray(elt[1, 2, 3], (3, 3)) - @test size(a) == (3, 3) - @test a[1, 1] == 1 - @test a[2, 2] == 2 - @test a[3, 3] == 3 - @test a[SparseArraysBase.StorageIndex(1)] == 1 - @test a[SparseArraysBase.StorageIndex(2)] == 2 - @test a[SparseArraysBase.StorageIndex(3)] == 3 - @test iszero(a[1, 2]) - - a = DiagonalArray(elt[1, 2, 3], (3, 3)) - a = 2 * a - @test size(a) == (3, 3) - @test a[1, 1] == 2 - @test a[2, 2] == 4 - @test a[3, 3] == 6 - @test iszero(a[1, 2]) - - a = DiagonalArray(elt[1, 2, 3], (3, 3)) - a_r = reshape(a, 9) - @test a_r isa DiagonalArray{elt,1} - for I in LinearIndices(a) - @test a[I] == a_r[I] - end - - # This needs `Base.reshape` with a custom destination - # calling `SparseArraysBase.sparse_reshape!` - # in order to specify an appropriate output - # type to work. - a = DiagonalArray(elt[1, 2], (2, 2, 2)) - a_r = reshape(a, 2, 4) - @test a_r isa Matrix{elt} - for I in LinearIndices(a) - @test a[I] == a_r[I] - end - - # Matrix multiplication! - a1 = DiagonalArray(elt[1, 2], (2, 2)) - a2 = DiagonalArray(elt[2, 3], (2, 2)) - a_dest = a1 * a2 - @test Array(a_dest) ≈ Array(a1) * Array(a2) - @test a_dest isa DiagonalArray{elt} -end -end diff --git a/NDTensors/src/lib/SparseArraysBase/test/test_sparsearraydok.jl b/NDTensors/src/lib/SparseArraysBase/test/test_sparsearraydok.jl deleted file mode 100644 index 92afb068bc..0000000000 --- a/NDTensors/src/lib/SparseArraysBase/test/test_sparsearraydok.jl +++ /dev/null @@ -1,139 +0,0 @@ -@eval module $(gensym()) - -# TODO: Test: -# zero (PermutedDimsArray) -# Custom zero type -# Slicing - -using Dictionaries: Dictionary -using Test: @test, @testset, @test_broken -using NDTensors.SparseArraysBase: - SparseArraysBase, SparseArrayDOK, SparseMatrixDOK, @maybe_grow -using NDTensors.SparseArraysBase: storage_indices, stored_length -using SparseArrays: SparseMatrixCSC, nnz -@testset "SparseArrayDOK (eltype=$elt)" for elt in - (Float32, ComplexF32, Float64, ComplexF64) - @testset "Basics" begin - a = SparseArrayDOK{elt}(3, 4) - @test a == SparseArrayDOK{elt}((3, 4)) - @test a == SparseArrayDOK{elt}(undef, 3, 4) - @test a == SparseArrayDOK{elt}(undef, (3, 4)) - @test iszero(a) - @test iszero(nnz(a)) - @test stored_length(a) == nnz(a) - @test size(a) == (3, 4) - @test eltype(a) == elt - for I in eachindex(a) - @test iszero(a[I]) - @test a[I] isa elt - end - @test isempty(storage_indices(a)) - - x12 = randn(elt) - x23 = randn(elt) - b = copy(a) - @test b isa SparseArrayDOK{elt} - @test iszero(b) - b[1, 2] = x12 - b[2, 3] = x23 - @test iszero(a) - @test !iszero(b) - @test b[1, 2] == x12 - @test b[2, 3] == x23 - @test iszero(stored_length(a)) - @test stored_length(b) == 2 - end - @testset "map/broadcast" begin - a = SparseArrayDOK{elt}(3, 4) - a[1, 1] = 11 - a[3, 4] = 34 - @test stored_length(a) == 2 - b = 2 * a - @test stored_length(b) == 2 - @test b[1, 1] == 2 * 11 - @test b[3, 4] == 2 * 34 - end - @testset "reshape" begin - a = SparseArrayDOK{elt}(2, 2, 2) - a[1, 2, 2] = 122 - b = reshape(a, 2, 4) - @test b[1, 4] == 122 - end - @testset "Matrix multiplication" begin - a1 = SparseArrayDOK{elt}(2, 3) - a1[1, 2] = 12 - a1[2, 1] = 21 - a2 = SparseArrayDOK{elt}(3, 4) - a2[1, 1] = 11 - a2[2, 2] = 22 - a2[3, 3] = 33 - a_dest = a1 * a2 - # TODO: Use `densearray` to make generic to GPU. - @test Array(a_dest) ≈ Array(a1) * Array(a2) - # TODO: Make this work with `ArrayLayouts`. - @test stored_length(a_dest) == 2 - @test a_dest isa SparseMatrixDOK{elt} - - a2 = randn(elt, (3, 4)) - a_dest = a1 * a2 - # TODO: Use `densearray` to make generic to GPU. - @test Array(a_dest) ≈ Array(a1) * Array(a2) - @test stored_length(a_dest) == 8 - @test a_dest isa Matrix{elt} - end - @testset "SparseMatrixCSC" begin - a = SparseArrayDOK{elt}(2, 2) - a[1, 2] = 12 - for (type, a′) in ((SparseMatrixCSC, a), (SparseArrayDOK, SparseMatrixCSC(a))) - b = type(a′) - @test b isa type{elt} - @test b[1, 2] == 12 - @test isone(nnz(b)) - for I in eachindex(b) - if I ≠ CartesianIndex(1, 2) - @test iszero(b[I]) - end - end - end - end - @testset "Maybe Grow Feature" begin - a = SparseArrayDOK{elt,2}((0, 0)) - SparseArraysBase.setindex_maybe_grow!(a, 230, 2, 3) - @test size(a) == (2, 3) - @test a[2, 3] == 230 - # Test @maybe_grow macro - @maybe_grow a[5, 5] = 550 - @test size(a) == (5, 5) - @test a[2, 3] == 230 - @test a[5, 5] == 550 - # Test that size remains same - # if we set at an index smaller than - # the maximum size: - @maybe_grow a[3, 4] = 340 - @test size(a) == (5, 5) - @test a[2, 3] == 230 - @test a[5, 5] == 550 - @test a[3, 4] == 340 - # Test vector case - v = SparseArrayDOK{elt,1}((0,)) - @maybe_grow v[5] = 50 - @test size(v) == (5,) - @test v[5] == 50 - # Test setting from a variable (to test macro escaping) - i = 6 - val = 60 - @maybe_grow v[i] = val - @test v[i] == val - i, j = 1, 2 - val = 120 - @maybe_grow a[i, j] = val - @test a[i, j] == val - end - @testset "Test Lower Level Constructor" begin - d = Dictionary{CartesianIndex{2},elt}() - a = SparseArrayDOK(d, (2, 2), zero(elt)) - a[1, 2] = 12.0 - @test a[1, 2] == 12.0 - end -end -end diff --git a/NDTensors/src/lib/SymmetrySectors/.JuliaFormatter.toml b/NDTensors/src/lib/SymmetrySectors/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/SymmetrySectors/Project.toml b/NDTensors/src/lib/SymmetrySectors/Project.toml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/NDTensors/src/lib/SymmetrySectors/src/SymmetrySectors.jl b/NDTensors/src/lib/SymmetrySectors/src/SymmetrySectors.jl deleted file mode 100644 index 93ecbda986..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/SymmetrySectors.jl +++ /dev/null @@ -1,17 +0,0 @@ -module SymmetrySectors - -include("symmetry_style.jl") -include("abstractsector.jl") -include("sector_definitions/fib.jl") -include("sector_definitions/ising.jl") -include("sector_definitions/o2.jl") -include("sector_definitions/trivial.jl") -include("sector_definitions/su.jl") -include("sector_definitions/su2k.jl") -include("sector_definitions/u1.jl") -include("sector_definitions/zn.jl") - -include("namedtuple_operations.jl") -include("sector_product.jl") - -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/abstractsector.jl b/NDTensors/src/lib/SymmetrySectors/src/abstractsector.jl deleted file mode 100644 index 2257e9fb36..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/abstractsector.jl +++ /dev/null @@ -1,114 +0,0 @@ -# This file defines the abstract type AbstractSector -# all fusion categories (Z{2}, SU2, Ising...) are subtypes of AbstractSector - -using BlockArrays: blocklengths -using ..LabelledNumbers: LabelledInteger, label, label_type, labelled, unlabel, unlabel_type -using ..GradedAxes: GradedAxes, blocklabels, fuse_blocklengths, gradedrange, tensor_product - -abstract type AbstractSector end - -# =================================== Base interface ===================================== -function Base.isless(c1::C, c2::C) where {C<:AbstractSector} - return isless(sector_label(c1), sector_label(c2)) -end - -# ================================= Sectors interface ==================================== -trivial(x) = trivial(typeof(x)) -function trivial(axis_type::Type{<:AbstractUnitRange}) - return gradedrange([trivial(eltype(axis_type))]) # always returns nondual -end -function trivial(la_type::Type{<:LabelledInteger}) - return labelled(one(unlabel_type(la_type)), trivial(label_type(la_type))) -end -function trivial(type::Type) - return error("`trivial` not defined for type $(type).") -end - -istrivial(c::AbstractSector) = (c == trivial(c)) - -function sector_label(c::AbstractSector) - return error("method `sector_label` not defined for type $(typeof(c))") -end - -block_dimensions(g::AbstractUnitRange) = block_dimensions(SymmetryStyle(g), g) -block_dimensions(::AbelianStyle, g) = unlabel.(blocklengths(g)) -function block_dimensions(::NotAbelianStyle, g) - return quantum_dimension.(blocklabels(g)) .* blocklengths(g) -end - -quantum_dimension(x) = quantum_dimension(SymmetryStyle(x), x) - -function quantum_dimension(::NotAbelianStyle, c::AbstractSector) - return error("method `quantum_dimension` not defined for type $(typeof(c))") -end - -quantum_dimension(::AbelianStyle, ::AbstractSector) = 1 -quantum_dimension(::AbelianStyle, g::AbstractUnitRange) = length(g) -quantum_dimension(::NotAbelianStyle, g::AbstractUnitRange) = sum(block_dimensions(g)) - -# =============================== Fusion rule interface ================================== -⊗(c1::AbstractSector, c2::AbstractSector) = fusion_rule(c1, c2) - -function fusion_rule(c1::AbstractSector, c2::AbstractSector) - return fusion_rule(combine_styles(SymmetryStyle(c1), SymmetryStyle(c2)), c1, c2) -end - -function fusion_rule(::NotAbelianStyle, c1::C, c2::C) where {C<:AbstractSector} - sector_degen_pairs = label_fusion_rule(C, sector_label(c1), sector_label(c2)) - return gradedrange(sector_degen_pairs) -end - -# abelian case: return Sector -function fusion_rule(::AbelianStyle, c1::C, c2::C) where {C<:AbstractSector} - return label(only(fusion_rule(NotAbelianStyle(), c1, c2))) -end - -function label_fusion_rule(sector_type::Type{<:AbstractSector}, l1, l2) - return [abelian_label_fusion_rule(sector_type, l1, l2) => 1] -end - -# ================================ GradedAxes interface ================================== -# tensor_product interface -function GradedAxes.fuse_blocklengths( - l1::LabelledInteger{<:Integer,<:AbstractSector}, - l2::LabelledInteger{<:Integer,<:AbstractSector}, -) - return fuse_blocklengths(combine_styles(SymmetryStyle(l1), SymmetryStyle(l2)), l1, l2) -end - -function GradedAxes.fuse_blocklengths( - ::NotAbelianStyle, l1::LabelledInteger, l2::LabelledInteger -) - fused = label(l1) ⊗ label(l2) - v = labelled.(l1 * l2 .* blocklengths(fused), blocklabels(fused)) - return gradedrange(v) -end - -function GradedAxes.fuse_blocklengths( - ::AbelianStyle, l1::LabelledInteger, l2::LabelledInteger -) - fused = label(l1) ⊗ label(l2) - return gradedrange([labelled(l1 * l2, fused)]) -end - -# cast to range -to_gradedrange(c::AbstractSector) = to_gradedrange(labelled(1, c)) -to_gradedrange(l::LabelledInteger) = gradedrange([l]) -to_gradedrange(g::AbstractUnitRange) = g - -# allow to fuse a Sector with a GradedUnitRange -function GradedAxes.tensor_product(c::AbstractSector, g::AbstractUnitRange) - return tensor_product(to_gradedrange(c), g) -end - -function GradedAxes.tensor_product(g::AbstractUnitRange, c::AbstractSector) - return tensor_product(g, to_gradedrange(c)) -end - -function GradedAxes.tensor_product(c1::AbstractSector, c2::AbstractSector) - return to_gradedrange(fusion_rule(c1, c2)) -end - -function GradedAxes.fusion_product(c::AbstractSector) - return to_gradedrange(c) -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/namedtuple_operations.jl b/NDTensors/src/lib/SymmetrySectors/src/namedtuple_operations.jl deleted file mode 100644 index a325dea2b2..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/namedtuple_operations.jl +++ /dev/null @@ -1,16 +0,0 @@ - -@generated function sort_keys(nt::NamedTuple{N}) where {N} - return :(NamedTuple{$(Tuple(sort(collect(N))))}(nt)) -end - -@generated function intersect_keys(nt1::NamedTuple{N1}, nt2::NamedTuple{N2}) where {N1,N2} - return :(NamedTuple{$(Tuple(intersect(N1, N2)))}(merge(nt2, nt1))) -end - -union_keys(ns1::NamedTuple, ns2::NamedTuple) = Base.merge(ns2, ns1) - -setdiff_keys(ns1::NamedTuple, ns2::NamedTuple) = Base.structdiff(ns1, ns2) - -function symdiff_keys(ns1::NamedTuple, ns2::NamedTuple) - return merge(Base.structdiff(ns1, ns2), Base.structdiff(ns2, ns1)) -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/fib.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/fib.jl deleted file mode 100644 index d7fded55f2..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/fib.jl +++ /dev/null @@ -1,45 +0,0 @@ -# -# Fibonacci category -# -# (same fusion rules as subcategory {0,1} of su2{3}) -# -using ..GradedAxes: GradedAxes - -struct Fib <: AbstractSector - l::Int -end - -# TODO: Use `Val` dispatch here? -function Fib(s::AbstractString) - if s == "1" - return Fib(0) - elseif s == "τ" - return Fib(1) - end - return error("Unrecognized input \"$s\" to Fib constructor") -end - -SymmetryStyle(::Type{Fib}) = NotAbelianStyle() - -GradedAxes.dual(f::Fib) = f - -sector_label(f::Fib) = f.l - -trivial(::Type{Fib}) = Fib(0) - -quantum_dimension(::NotAbelianStyle, f::Fib) = istrivial(f) ? 1.0 : ((1 + √5) / 2) - -# Fusion rules identical to su2₃ -function label_fusion_rule(::Type{Fib}, l1, l2) - suk_sectors_degen = label_fusion_rule(su2{3}, l1, l2) - suk_sectors = first.(suk_sectors_degen) - degen = last.(suk_sectors_degen) - sectors = Fib.(sector_label.(suk_sectors)) - return sectors .=> degen -end - -label_to_str(f::Fib) = istrivial(f) ? "1" : "τ" - -function Base.show(io::IO, f::Fib) - return print(io, "Fib(", label_to_str(f), ")") -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/ising.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/ising.jl deleted file mode 100644 index d4a955069e..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/ising.jl +++ /dev/null @@ -1,46 +0,0 @@ -# -# Ising category -# -# (same fusion rules as su2{2}) -# - -using HalfIntegers: Half, twice -using ..GradedAxes: GradedAxes - -struct Ising <: AbstractSector - l::Half{Int} -end - -# TODO: Use `Val` dispatch here? -function Ising(s::AbstractString) - for (a, v) in enumerate(("1", "σ", "ψ")) - (v == s) && return Ising((a - 1)//2) - end - return error("Unrecognized input \"$s\" to Ising constructor") -end - -SymmetryStyle(::Type{Ising}) = NotAbelianStyle() - -GradedAxes.dual(i::Ising) = i - -sector_label(i::Ising) = i.l - -trivial(::Type{Ising}) = Ising(0) - -quantum_dimension(::NotAbelianStyle, i::Ising) = (sector_label(i) == 1//2) ? √2 : 1.0 - -# Fusion rules identical to su2₂ -function label_fusion_rule(::Type{Ising}, l1, l2) - suk_sectors_degen = label_fusion_rule(su2{2}, l1, l2) - suk_sectors = first.(suk_sectors_degen) - degen = last.(suk_sectors_degen) - sectors = Ising.(sector_label.(suk_sectors)) - return sectors .=> degen -end - -# TODO: Use `Val` dispatch here? -label_to_str(i::Ising) = ("1", "σ", "ψ")[twice(sector_label(i)) + 1] - -function Base.show(io::IO, f::Ising) - return print(io, "Ising(", label_to_str(f), ")") -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/o2.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/o2.jl deleted file mode 100644 index 4a0dcf7646..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/o2.jl +++ /dev/null @@ -1,75 +0,0 @@ -# -# Orthogonal group O(2) -# isomorphic to Z_2 ⋉ U(1) -# isomorphic to SU(2) subgroup with Sz conservation + Sz-reversal -# -# O(2) has 3 kinds of irreps: -# - trivial irrep, or "0e", corresponds to Sz=0 and even under Sz-reversal -# - "zero odd", or "0o" irrep, corresponds to Sz=0 and odd under Sz-reversal -# - 2-dimensional Sz=±|m| irrep, with m a half integer -# - -using HalfIntegers: Half, HalfInteger -using ..GradedAxes: GradedAxes - -# here we use only one half-integer as label: -# - l=0 for trivial -# - l=-1 for zero odd -# - l=+|m| for Sz=±|m| -struct O2 <: AbstractSector - l::Half{Int} -end - -SymmetryStyle(::Type{O2}) = NotAbelianStyle() - -sector_label(s::O2) = s.l - -trivial(::Type{O2}) = O2(0) -zero_odd(::Type{O2}) = O2(-1) - -is_zero_even_or_odd(s::O2) = is_zero_even_or_odd(sector_label(s)) -iszero_odd(s::O2) = iszero_odd(sector_label(s)) - -is_zero_even_or_odd(l::HalfInteger) = iszero_even(l) || iszero_odd(l) -iszero_even(l::HalfInteger) = l == sector_label(trivial(O2)) -iszero_odd(l::HalfInteger) = l == sector_label(zero_odd(O2)) - -quantum_dimension(::NotAbelianStyle, s::O2) = 2 - is_zero_even_or_odd(s) - -GradedAxes.dual(s::O2) = s - -function Base.show(io::IO, s::O2) - if iszero_odd(s) - disp = "0o" - elseif istrivial(s) - disp = "0e" - else - disp = "±" * string(sector_label(s)) - end - return print(io, "O(2)[", disp, "]") -end - -function label_fusion_rule(::Type{O2}, l1, l2) - if is_zero_even_or_odd(l1) - degens = [1] - if is_zero_even_or_odd(l2) - labels = l1 == l2 ? [sector_label(trivial(O2))] : [sector_label(zero_odd(O2))] - else - labels = [l2] - end - else - if is_zero_even_or_odd(l2) - degens = [1] - labels = [l1] - else - if l1 == l2 - degens = [1, 1, 1] - labels = [sector_label(zero_odd(O2)), sector_label(trivial(O2)), 2 * l1] - else - degens = [1, 1] - labels = [abs(l1 - l2), l1 + l2] - end - end - end - return O2.(labels) .=> degens -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su.jl deleted file mode 100644 index b44ef4d6eb..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su.jl +++ /dev/null @@ -1,175 +0,0 @@ -# -# Special unitary group SU(N) -# - -using HalfIntegers: HalfInteger, half, twice -using ...GradedAxes: GradedAxes - -struct SU{N,M} <: AbstractSector - # l is the first row of the - # Gelfand-Tsetlin (GT) pattern describing - # an SU(N) irrep - # this first row is identical to the Young tableau of the irrep - l::NTuple{M,Int} - - # M is there to avoid storing a N-Tuple with an extra zero. - # inner constructor enforces M = N - 1 - # It does NOT check for Young Tableau validity (non-increasing positive integers) - function SU{N,M}(t::NTuple{M,Integer}) where {N,M} - return N == M + 1 && M > 0 ? new{N,M}(t) : error("Invalid tuple length") - end -end - -SU{N}(t::Tuple) where {N} = SU{N,length(t)}(t) -SU(t::Tuple) = SU{length(t) + 1}(t) # infer N from tuple length - -SymmetryStyle(::Type{<:SU}) = NotAbelianStyle() - -sector_label(s::SU) = s.l - -groupdim(::SU{N}) where {N} = N - -trivial(::Type{<:SU{N}}) where {N} = SU{N}(ntuple(_ -> 0, Val(N - 1))) - -fundamental(::Type{<:SU{N}}) where {N} = SU{N}(ntuple(i -> i == 1, Val(N - 1))) - -function quantum_dimension(::NotAbelianStyle, s::SU) - N = groupdim(s) - l = (sector_label(s)..., 0) - d = 1 - for k1 in 1:N, k2 in (k1 + 1):N - d *= ((k2 - k1) + (l[k1] - l[k2]))//(k2 - k1) - end - return Int(d) -end - -function GradedAxes.dual(s::SU) - l = sector_label(s) - nl = reverse(cumsum((l[begin:(end - 1)] .- l[(begin + 1):end]..., l[end]))) - return typeof(s)(nl) -end - -function Base.show(io::IO, s::SU) - disp = join([string(l) for l in sector_label(s)], ", ") - return print(io, "SU(", groupdim(s), ")[", disp, "]") -end - -# display SU(N) irrep as a Young tableau with utf8 box char -function Base.show(io::IO, ::MIME"text/plain", s::SU) - if istrivial(s) # singlet = no box - return print(io, "●") - end - - N = groupdim(s) - l = sector_label(s) - println(io, "┌─" * "┬─"^(l[1] - 1) * "┐") - i = 1 - while i < N - 1 && l[i + 1] != 0 - println( - io, - "├─", - "┼─"^(l[i + 1] - 1 + (l[i] > l[i + 1])), - "┴─"^max(0, (l[i] - l[i + 1] - 1)), - "┤"^(l[i] == l[i + 1]), - "┘"^(l[i] > l[i + 1]), - ) - i += 1 - end - - print(io, "└─", "┴─"^max(0, l[i] - 1), "┘") - return nothing -end - -# -# Specializations for the case SU{2} -# - -# optimize implementation -quantum_dimension(s::SU{2}) = sector_label(s)[1] + 1 - -GradedAxes.dual(s::SU{2}) = s - -function label_fusion_rule(::Type{<:SU{2}}, s1, s2) - irreps = [SU{2}((i,)) for i in (abs(s1[1] - s2[1])):2:(s1[1] + s2[1])] - degen = ones(Int, length(irreps)) - return irreps .=> degen -end - -# define angular momentum-like interface using half-integers -SU2(h::Number) = SU{2}((twice(HalfInteger(h)),)) - -# display SU2 using half-integers -function Base.show(io::IO, s::SU{2}) - return print(io, "SU(2)[S=", half(quantum_dimension(s) - 1), "]") -end - -function Base.show(io::IO, ::MIME"text/plain", s::SU{2}) - return print(io, "S = ", half(quantum_dimension(s) - 1)) -end - -# -# Specializations for the case SU{3} -# aimed for testing non-abelian non self-conjugate representations -# TODO replace with generic implementation -# - -function label_fusion_rule(::Type{<:SU{3}}, left, right) - # Compute SU(3) fusion rules using Littlewood-Richardson rule for Young tableaus. - # See e.g. Di Francesco, Mathieu and Sénéchal, section 13.5.3. - if sum(right) > sum(left) # impose more boxes in left Young tableau - return label_fusion_rule(SU{3}, right, left) - end - - if right[1] == 0 # avoid issues with singlet - return [SU{3}(left) => 1] - end - - left_row1 = left[1] - left_row2 = left[2] - right_row1 = right[1] - right_row2 = right[2] - - irreps = [] - - # put a23 boxes on 2nd or 3rd line - a23max1 = 2 * left_row1 # row2a <= row1a - a23max2 = right_row1 # a2 + a3 <= total number of a - a23max = min(a23max1, a23max2) - for a23 in 0:a23max - a3min1 = left_row2 + 2 * a23 - left_row1 - right_row1 - a3min2 = left_row2 - left_row1 + a23 # no a below a: row2a <= row1 - a3min = max(0, a3min1, a3min2) - a3max1 = left_row2 # row3a <= row2a - a3max2 = a23 # a3 <= a2 + a3 - a3max3 = right_row1 - right_row2 # more a than b, right to left: b2 + b3 <= a1 + a2 - a3max = min(a3max1, a3max2, a3max3) - for a3 in a3min:a3max - a2 = a23 - a3 - row1a = left_row1 + right_row1 - a23 - row2a = left_row2 + a23 - a3 - - # cannot put any b on 1st line: row1ab = row1a - b3min1 = row2a + right_row2 - row1a # row2ab <= row1ab = row1a - b3min2 = right_row2 + a23 - right_row1 - b3min = max(0, b3min1, b3min2) - b3max1 = right_row2 # only other.row2 b boxes - b3max2 = (row2a + right_row2 - a3) ÷ 2 # row3ab >= row2ab - b3max3 = right_row1 - a3 # more a than b, right to left: b2 <= a1 - b3max4 = row2a - a3 # no b below b: row2a >= row3ab - b3max = min(b3max1, b3max2, b3max3, b3max4) - for b3 in b3min:b3max - b2 = right_row2 - b3 - row2ab = row2a + b2 - row3ab = a3 + b3 - yt = (row1a - row3ab, row2ab - row3ab) - - push!(irreps, yt) - end - end - end - - unique_labels = sort(unique(irreps)) - degen = [count(==(irr), irreps) for irr in unique_labels] - sectors = SU{3}.(unique_labels) - return sectors .=> degen -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su2k.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su2k.jl deleted file mode 100644 index cdf9bfbb1a..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/su2k.jl +++ /dev/null @@ -1,27 +0,0 @@ -# -# Quantum 'group' su2ₖ -# - -using HalfIntegers: Half -using ...GradedAxes: GradedAxes - -struct su2{k} <: AbstractSector - j::Half{Int} -end - -SymmetryStyle(::Type{<:su2}) = NotAbelianStyle() - -GradedAxes.dual(s::su2) = s - -sector_label(s::su2) = s.j - -level(::su2{k}) where {k} = k - -trivial(::Type{su2{k}}) where {k} = su2{k}(0) - -function label_fusion_rule(::Type{su2{k}}, j1, j2) where {k} - labels = collect(abs(j1 - j2):min(k - j1 - j2, j1 + j2)) - degen = ones(Int, length(labels)) - sectors = su2{k}.(labels) - return sectors .=> degen -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/trivial.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/trivial.jl deleted file mode 100644 index 27b3fec88e..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/trivial.jl +++ /dev/null @@ -1,38 +0,0 @@ -# -# Trivial sector -# acts as a trivial sector for any AbstractSector -# - -using ...GradedAxes: GradedAxes - -# Trivial is special as it does not have a label -struct TrivialSector <: AbstractSector end - -SymmetryStyle(::Type{TrivialSector}) = AbelianStyle() - -trivial(::Type{TrivialSector}) = TrivialSector() - -GradedAxes.dual(::TrivialSector) = TrivialSector() - -# TrivialSector acts as trivial on any AbstractSector -function fusion_rule(::NotAbelianStyle, ::TrivialSector, c::AbstractSector) - return to_gradedrange(c) -end -function fusion_rule(::NotAbelianStyle, c::AbstractSector, ::TrivialSector) - return to_gradedrange(c) -end - -# abelian case: return Sector -fusion_rule(::AbelianStyle, c::AbstractSector, ::TrivialSector) = c -fusion_rule(::AbelianStyle, ::TrivialSector, c::AbstractSector) = c -fusion_rule(::AbelianStyle, ::TrivialSector, ::TrivialSector) = TrivialSector() - -# any trivial sector equals TrivialSector -Base.:(==)(c::AbstractSector, ::TrivialSector) = istrivial(c) -Base.:(==)(::TrivialSector, c::AbstractSector) = istrivial(c) -Base.:(==)(::TrivialSector, ::TrivialSector) = true - -# sorts as trivial for any Sector -Base.isless(c::AbstractSector, ::TrivialSector) = c < trivial(c) -Base.isless(::TrivialSector, c::AbstractSector) = trivial(c) < c -Base.isless(::TrivialSector, ::TrivialSector) = false # bypass default that calls label diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/u1.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/u1.jl deleted file mode 100644 index 2d79796c34..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/u1.jl +++ /dev/null @@ -1,31 +0,0 @@ -# -# U₁ group (circle group, or particle number, total Sz etc.) -# - -using ...GradedAxes: GradedAxes - -# Parametric type to allow both integer label as well as -# HalfInteger for easy conversion to/from SU(2) -struct U1{T} <: AbstractSector - n::T -end - -SymmetryStyle(::Type{<:U1}) = AbelianStyle() -sector_label(u::U1) = u.n - -set_sector_label(s::U1, sector_label) = typeof(s)(sector_label) -GradedAxes.dual(s::U1) = set_sector_label(s, -sector_label(s)) - -trivial(::Type{U1}) = trivial(U1{Int}) -trivial(::Type{U1{T}}) where {T} = U1(zero(T)) - -abelian_label_fusion_rule(sector_type::Type{<:U1}, n1, n2) = sector_type(n1 + n2) - -# hide label type in printing -function Base.show(io::IO, u::U1) - return print(io, "U(1)[", sector_label(u), "]") -end - -# enforce U1(Int32(1)) == U1(1) -Base.:(==)(s1::U1, s2::U1) = sector_label(s1) == sector_label(s2) -Base.isless(s1::U1, s2::U1) = sector_label(s1) < sector_label(s2) diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/zn.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/zn.jl deleted file mode 100644 index 8628288dc3..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_definitions/zn.jl +++ /dev/null @@ -1,25 +0,0 @@ -# -# Cyclic group Zₙ -# - -using ...GradedAxes: GradedAxes - -struct Z{N} <: AbstractSector - m::Int - Z{N}(m) where {N} = new{N}(mod(m, N)) -end - -modulus(::Type{Z{N}}) where {N} = N -modulus(c::Z) = modulus(typeof(c)) - -SymmetryStyle(::Type{<:Z}) = AbelianStyle() -sector_label(c::Z) = c.m - -set_sector_label(s::Z, sector_label) = typeof(s)(sector_label) -GradedAxes.dual(s::Z) = set_sector_label(s, -sector_label(s)) - -trivial(sector_type::Type{<:Z}) = sector_type(0) - -function abelian_label_fusion_rule(sector_type::Type{<:Z}, n1, n2) - return sector_type(n1 + n2) -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_product.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_product.jl deleted file mode 100644 index 12a72d022e..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_product.jl +++ /dev/null @@ -1,238 +0,0 @@ -# This files defines a structure for Cartesian product of 2 or more fusion sectors -# e.g. U(1)×U(1), U(1)×SU2(2)×SU(3) - -using BlockArrays: blocklengths -using ..LabelledNumbers: LabelledInteger, label, labelled, unlabel -using ..GradedAxes: AbstractGradedUnitRange, GradedAxes, dual - -# ===================================== Definition ======================================= -struct SectorProduct{Sectors} <: AbstractSector - arguments::Sectors - global _SectorProduct(l) = new{typeof(l)}(l) -end - -SectorProduct(c::SectorProduct) = _SectorProduct(arguments(c)) - -arguments(s::SectorProduct) = s.arguments - -# ================================= Sectors interface ==================================== -function SymmetryStyle(T::Type{<:SectorProduct}) - return arguments_symmetrystyle(arguments_type(T)) -end - -function quantum_dimension(::NotAbelianStyle, s::SectorProduct) - return mapreduce(quantum_dimension, *, arguments(s)) -end - -# use map instead of broadcast to support both Tuple and NamedTuple -GradedAxes.dual(s::SectorProduct) = SectorProduct(map(dual, arguments(s))) - -function trivial(type::Type{<:SectorProduct}) - return SectorProduct(arguments_trivial(arguments_type(type))) -end - -# =================================== Base interface ===================================== -function Base.:(==)(A::SectorProduct, B::SectorProduct) - return arguments_isequal(arguments(A), arguments(B)) -end - -function Base.show(io::IO, s::SectorProduct) - (length(arguments(s)) < 2) && print(io, "sector") - print(io, "(") - symbol = "" - for p in pairs(arguments(s)) - print(io, symbol) - sector_show(io, p[1], p[2]) - symbol = " × " - end - return print(io, ")") -end - -sector_show(io::IO, ::Int, v) = print(io, v) -sector_show(io::IO, k::Symbol, v) = print(io, "($k=$v,)") - -function Base.isless(s1::SectorProduct, s2::SectorProduct) - return arguments_isless(arguments(s1), arguments(s2)) -end - -# ======================================= shared ========================================= -# there are 2 implementations for SectorProduct -# - ordered-like with a Tuple -# - dictionary-like with a NamedTuple - -arguments_type(::Type{<:SectorProduct{T}}) where {T} = T - -arguments_maybe_insert_unspecified(s1, ::Any) = s1 -function sym_arguments_maybe_insert_unspecified(s1, s2) - return arguments_maybe_insert_unspecified(s1, s2), - arguments_maybe_insert_unspecified(s2, s1) -end - -function make_empty_match(a1, b1) - a2 = isempty(a1) ? empty(b1) : a1 - b2 = isempty(b1) ? empty(a2) : b1 - return a2, b2 -end - -function arguments_isequal(a1, b1) - return ==(sym_arguments_maybe_insert_unspecified(make_empty_match(a1, b1)...)...) -end - -function arguments_product(s1, s2) - isempty(s1) && return s2 - isempty(s2) && return s1 - return throw(ArgumentError("Mixing non-empty storage types is illegal")) -end - -function arguments_isless(a1, b1) - return isless(sym_arguments_maybe_insert_unspecified(make_empty_match(a1, b1)...)...) -end - -# ================================= Cartesian Product ==================================== -×(c1::AbstractSector, c2::AbstractSector) = ×(SectorProduct(c1), SectorProduct(c2)) -function ×(p1::SectorProduct, p2::SectorProduct) - return SectorProduct(arguments_product(arguments(p1), arguments(p2))) -end - -×(a, g::AbstractUnitRange) = ×(to_gradedrange(a), g) -×(g::AbstractUnitRange, b) = ×(g, to_gradedrange(b)) -×(nt1::NamedTuple, nt2::NamedTuple) = ×(SectorProduct(nt1), SectorProduct(nt2)) -×(c1::NamedTuple, c2::AbstractSector) = ×(SectorProduct(c1), SectorProduct(c2)) -×(c1::AbstractSector, c2::NamedTuple) = ×(SectorProduct(c1), SectorProduct(c2)) - -function ×(l1::LabelledInteger, l2::LabelledInteger) - c3 = label(l1) × label(l2) - m3 = unlabel(l1) * unlabel(l2) - return labelled(m3, c3) -end - -function ×(g1::AbstractUnitRange, g2::AbstractUnitRange) - v = map( - ((l1, l2),) -> l1 × l2, - Iterators.flatten((Iterators.product(blocklengths(g1), blocklengths(g2)),),), - ) - return gradedrange(v) -end - -# ==================================== Fusion rules ====================================== -# cast AbstractSector to SectorProduct -function fusion_rule(style::SymmetryStyle, c1::SectorProduct, c2::AbstractSector) - return fusion_rule(style, c1, SectorProduct(c2)) -end -function fusion_rule(style::SymmetryStyle, c1::AbstractSector, c2::SectorProduct) - return fusion_rule(style, SectorProduct(c1), c2) -end - -# generic case: fusion returns a GradedAxes, even for fusion with Empty -function fusion_rule(::NotAbelianStyle, s1::SectorProduct, s2::SectorProduct) - return to_gradedrange(arguments_fusion_rule(arguments(s1), arguments(s2))) -end - -# Abelian case: fusion returns SectorProduct -function fusion_rule(::AbelianStyle, s1::SectorProduct, s2::SectorProduct) - return label(only(fusion_rule(NotAbelianStyle(), s1, s2))) -end - -# lift ambiguities for TrivialSector -fusion_rule(::AbelianStyle, c::SectorProduct, ::TrivialSector) = c -fusion_rule(::AbelianStyle, ::TrivialSector, c::SectorProduct) = c -fusion_rule(::NotAbelianStyle, c::SectorProduct, ::TrivialSector) = to_gradedrange(c) -fusion_rule(::NotAbelianStyle, ::TrivialSector, c::SectorProduct) = to_gradedrange(c) - -function arguments_fusion_rule(sects1, sects2) - isempty(sects1) && return SectorProduct(sects2) - isempty(sects2) && return SectorProduct(sects1) - shared_sect = shared_arguments_fusion_rule(arguments_common(sects1, sects2)...) - diff_sect = SectorProduct(arguments_diff(sects1, sects2)) - return shared_sect × diff_sect -end - -# =============================== Ordered implementation ================================= -SectorProduct(t::Tuple) = _SectorProduct(t) -SectorProduct(sects::AbstractSector...) = SectorProduct(sects) - -function arguments_symmetrystyle(T::Type{<:Tuple}) - return mapreduce(SymmetryStyle, combine_styles, fieldtypes(T); init=AbelianStyle()) -end - -arguments_product(l1::Tuple, l2::Tuple) = (l1..., l2...) - -arguments_trivial(T::Type{<:Tuple}) = trivial.(fieldtypes(T)) - -function arguments_common(t1::Tuple, t2::Tuple) - n = min(length(t1), length(t2)) - return t1[begin:n], t2[begin:n] -end - -function arguments_diff(t1::Tuple, t2::Tuple) - n1 = length(t1) - n2 = length(t2) - return n1 < n2 ? t2[(n1 + 1):end] : t1[(n2 + 1):end] -end - -function shared_arguments_fusion_rule(shared1::T, shared2::T) where {T<:Tuple} - return mapreduce( - to_gradedrange ∘ fusion_rule, - ×, - shared1, - shared2; - init=to_gradedrange(SectorProduct(())), - ) -end - -function arguments_maybe_insert_unspecified(t1::Tuple, t2::Tuple) - n1 = length(t1) - return (t1..., trivial.(t2[(n1 + 1):end])...) -end - -# =========================== Dictionary-like implementation ============================= -function SectorProduct(nt::NamedTuple) - arguments = sort_keys(nt) - return _SectorProduct(arguments) -end - -SectorProduct(; kws...) = SectorProduct((; kws...)) - -function SectorProduct(pairs::Pair...) - keys = Symbol.(first.(pairs)) - vals = last.(pairs) - return SectorProduct(NamedTuple{keys}(vals)) -end - -function arguments_symmetrystyle(NT::Type{<:NamedTuple}) - return mapreduce(SymmetryStyle, combine_styles, fieldtypes(NT); init=AbelianStyle()) -end - -function arguments_maybe_insert_unspecified(nt1::NamedTuple, nt2::NamedTuple) - diff1 = arguments_trivial(typeof(setdiff_keys(nt2, nt1))) - return sort_keys(union_keys(nt1, diff1)) -end - -function arguments_product(l1::NamedTuple, l2::NamedTuple) - if length(intersect_keys(l1, l2)) > 0 - throw(ArgumentError("Cannot define product of shared keys")) - end - return union_keys(l1, l2) -end - -function arguments_trivial(NT::Type{<:NamedTuple{Keys}}) where {Keys} - return NamedTuple{Keys}(trivial.(fieldtypes(NT))) -end - -function arguments_common(nt1::NamedTuple, nt2::NamedTuple) - # SectorProduct(nt::NamedTuple) sorts keys at init - @assert issorted(keys(nt1)) - @assert issorted(keys(nt2)) - return intersect_keys(nt1, nt2), intersect_keys(nt2, nt1) -end - -arguments_diff(nt1::NamedTuple, nt2::NamedTuple) = symdiff_keys(nt1, nt2) - -function map_blocklabels(f, r::AbstractUnitRange) - return gradedrange(labelled.(unlabel.(blocklengths(r)), f.(blocklabels(r)))) -end - -function shared_arguments_fusion_rule(shared1::NT, shared2::NT) where {NT<:NamedTuple} - tuple_fused = shared_arguments_fusion_rule(values(shared1), values(shared2)) - return map_blocklabels(SectorProduct ∘ NT ∘ arguments ∘ SectorProduct, tuple_fused) -end diff --git a/NDTensors/src/lib/SymmetrySectors/src/symmetry_style.jl b/NDTensors/src/lib/SymmetrySectors/src/symmetry_style.jl deleted file mode 100644 index f3e443dce0..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/src/symmetry_style.jl +++ /dev/null @@ -1,17 +0,0 @@ -# This file defines SymmetryStyle, a trait to distinguish abelian groups, non-abelian groups -# and non-group fusion categories. - -using ..LabelledNumbers: LabelledInteger, label_type - -abstract type SymmetryStyle end - -struct AbelianStyle <: SymmetryStyle end -struct NotAbelianStyle <: SymmetryStyle end - -SymmetryStyle(x) = SymmetryStyle(typeof(x)) -SymmetryStyle(T::Type) = error("method `SymmetryStyle` not defined for type $(T)") -SymmetryStyle(L::Type{<:LabelledInteger}) = SymmetryStyle(label_type(L)) -SymmetryStyle(G::Type{<:AbstractUnitRange}) = SymmetryStyle(eltype(G)) - -combine_styles(::AbelianStyle, ::AbelianStyle) = AbelianStyle() -combine_styles(::SymmetryStyle, ::SymmetryStyle) = NotAbelianStyle() diff --git a/NDTensors/src/lib/SymmetrySectors/test/runtests.jl b/NDTensors/src/lib/SymmetrySectors/test/runtests.jl deleted file mode 100644 index 5bf73eb20f..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/test/runtests.jl +++ /dev/null @@ -1,12 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -@testset "$(@__DIR__)" begin - filenames = filter(readdir(@__DIR__)) do f - startswith("test_")(f) && endswith(".jl")(f) - end - @testset "Test $(@__DIR__)/$filename" for filename in filenames - println("Running $(@__DIR__)/$filename") - @time include(filename) - end -end -end diff --git a/NDTensors/src/lib/SymmetrySectors/test/test_fusion_rules.jl b/NDTensors/src/lib/SymmetrySectors/test/test_fusion_rules.jl deleted file mode 100644 index bd00abef86..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/test/test_fusion_rules.jl +++ /dev/null @@ -1,287 +0,0 @@ -@eval module $(gensym()) -using NDTensors.GradedAxes: - dual, fusion_product, space_isequal, gradedrange, flip, tensor_product -using NDTensors.SymmetrySectors: - ⊗, - Fib, - Ising, - O2, - SU, - SU2, - TrivialSector, - U1, - Z, - block_dimensions, - quantum_dimension, - trivial -using Test: @inferred, @test, @testset, @test_throws - -@testset "Simple SymmetrySector fusion rules" begin - @testset "Z{2} fusion rules" begin - z0 = Z{2}(0) - z1 = Z{2}(1) - - @test z0 ⊗ z0 == z0 - @test z0 ⊗ z1 == z1 - @test z1 ⊗ z1 == z0 - @test (@inferred z0 ⊗ z0) == z0 # no better way, see Julia PR 23426 - - q = TrivialSector() - @test (@inferred q ⊗ q) == q - @test (@inferred q ⊗ z0) == z0 - @test (@inferred z1 ⊗ q) == z1 - - # using GradedAxes interface - @test space_isequal(fusion_product(z0, z0), gradedrange([z0 => 1])) - @test space_isequal(fusion_product(z0, z1), gradedrange([z1 => 1])) - - # test different input number - @test space_isequal(fusion_product(z0), gradedrange([z0 => 1])) - @test space_isequal(fusion_product(z0, z0, z0), gradedrange([z0 => 1])) - @test space_isequal(fusion_product(z0, z0, z0, z0), gradedrange([z0 => 1])) - @test (@inferred block_dimensions(gradedrange([z1 => 1]))) == [1] - end - @testset "U(1) fusion rules" begin - q1 = U1(1) - q2 = U1(2) - q3 = U1(3) - - @test q1 ⊗ q1 == U1(2) - @test q1 ⊗ q2 == U1(3) - @test q2 ⊗ q1 == U1(3) - @test (@inferred q1 ⊗ q2) == q3 # no better way, see Julia PR 23426 - end - - @testset "O2 fusion rules" begin - s0e = O2(0) - s0o = O2(-1) - s12 = O2(1//2) - s1 = O2(1) - - q = TrivialSector() - @test space_isequal((@inferred s0e ⊗ q), gradedrange([s0e => 1])) - @test space_isequal((@inferred q ⊗ s0o), gradedrange([s0o => 1])) - - @test space_isequal((@inferred s0e ⊗ s0e), gradedrange([s0e => 1])) - @test space_isequal((@inferred s0o ⊗ s0e), gradedrange([s0o => 1])) - @test space_isequal((@inferred s0o ⊗ s0e), gradedrange([s0o => 1])) - @test space_isequal((@inferred s0o ⊗ s0o), gradedrange([s0e => 1])) - - @test space_isequal((@inferred s0e ⊗ s12), gradedrange([s12 => 1])) - @test space_isequal((@inferred s0o ⊗ s12), gradedrange([s12 => 1])) - @test space_isequal((@inferred s12 ⊗ s0e), gradedrange([s12 => 1])) - @test space_isequal((@inferred s12 ⊗ s0o), gradedrange([s12 => 1])) - @test space_isequal((@inferred s12 ⊗ s1), gradedrange([s12 => 1, O2(3//2) => 1])) - @test space_isequal((@inferred s12 ⊗ s12), gradedrange([s0o => 1, s0e => 1, s1 => 1])) - - @test (@inferred quantum_dimension(s0o ⊗ s1)) == 2 - @test (@inferred block_dimensions(s0o ⊗ s1)) == [2] - end - - @testset "SU2 fusion rules" begin - j1 = SU2(0) - j2 = SU2(1//2) - j3 = SU2(1) - j4 = SU2(3//2) - j5 = SU2(2) - - @test space_isequal(j1 ⊗ j2, gradedrange([j2 => 1])) - @test space_isequal(j2 ⊗ j2, gradedrange([j1 => 1, j3 => 1])) - @test space_isequal(j2 ⊗ j3, gradedrange([j2 => 1, j4 => 1])) - @test space_isequal(j3 ⊗ j3, gradedrange([j1 => 1, j3 => 1, j5 => 1])) - @test space_isequal((@inferred j1 ⊗ j2), gradedrange([j2 => 1])) - @test (@inferred quantum_dimension(j1 ⊗ j2)) == 2 - @test (@inferred block_dimensions(j1 ⊗ j2)) == [2] - - @test space_isequal(fusion_product(j2), gradedrange([j2 => 1])) - @test space_isequal(fusion_product(j2, j1), gradedrange([j2 => 1])) - @test space_isequal(fusion_product(j2, j1, j1), gradedrange([j2 => 1])) - end - - @testset "Fibonacci fusion rules" begin - ı = Fib("1") - τ = Fib("τ") - - @test space_isequal(ı ⊗ ı, gradedrange([ı => 1])) - @test space_isequal(ı ⊗ τ, gradedrange([τ => 1])) - @test space_isequal(τ ⊗ ı, gradedrange([τ => 1])) - @test space_isequal((@inferred τ ⊗ τ), gradedrange([ı => 1, τ => 1])) - @test (@inferred quantum_dimension(gradedrange([ı => 1, ı => 1]))) == 2.0 - end - - @testset "Ising fusion rules" begin - ı = Ising("1") - σ = Ising("σ") - ψ = Ising("ψ") - - @test space_isequal(ı ⊗ ı, gradedrange([ı => 1])) - @test space_isequal(ı ⊗ σ, gradedrange([σ => 1])) - @test space_isequal(σ ⊗ ı, gradedrange([σ => 1])) - @test space_isequal(ı ⊗ ψ, gradedrange([ψ => 1])) - @test space_isequal(ψ ⊗ ı, gradedrange([ψ => 1])) - @test space_isequal(σ ⊗ σ, gradedrange([ı => 1, ψ => 1])) - @test space_isequal(σ ⊗ ψ, gradedrange([σ => 1])) - @test space_isequal(ψ ⊗ σ, gradedrange([σ => 1])) - @test space_isequal(ψ ⊗ ψ, gradedrange([ı => 1])) - @test space_isequal((@inferred ψ ⊗ ψ), gradedrange([ı => 1])) - @test (@inferred quantum_dimension(σ ⊗ σ)) == 2.0 - end -end -@testset "Gradedrange fusion rules" begin - @testset "Trivial GradedUnitRange" begin - g1 = gradedrange([U1(0) => 1]) - g2 = gradedrange([SU2(0) => 1]) - @test space_isequal(trivial(g1), g1) - @test space_isequal(trivial(dual(g1)), g1) # trivial returns nondual - @test space_isequal(trivial(typeof(g2)), g2) - end - @testset "GradedUnitRange abelian tensor/fusion product" begin - g1 = gradedrange([U1(-1) => 1, U1(0) => 1, U1(1) => 2]) - g2 = gradedrange([U1(-2) => 2, U1(0) => 1, U1(1) => 2]) - - @test space_isequal(flip(dual(g1)), gradedrange([U1(1) => 1, U1(0) => 1, U1(-1) => 2])) - @test (@inferred block_dimensions(g1)) == [1, 1, 2] - - gt = gradedrange([ - U1(-3) => 2, - U1(-2) => 2, - U1(-1) => 4, - U1(-1) => 1, - U1(0) => 1, - U1(1) => 2, - U1(0) => 2, - U1(1) => 2, - U1(2) => 4, - ]) - gf = gradedrange([ - U1(-3) => 2, U1(-2) => 2, U1(-1) => 5, U1(0) => 3, U1(1) => 4, U1(2) => 4 - ]) - @test space_isequal((@inferred tensor_product(g1, g2)), gt) - @test space_isequal((@inferred fusion_product(g1, g2)), gf) - - gtd1 = gradedrange([ - U1(-1) => 2, - U1(-2) => 2, - U1(-3) => 4, - U1(1) => 1, - U1(0) => 1, - U1(-1) => 2, - U1(2) => 2, - U1(1) => 2, - U1(0) => 4, - ]) - gfd1 = gradedrange([ - U1(-3) => 4, U1(-2) => 2, U1(-1) => 4, U1(0) => 5, U1(1) => 3, U1(2) => 2 - ]) - @test space_isequal((@inferred tensor_product(dual(g1), g2)), gtd1) - @test space_isequal((@inferred fusion_product(dual(g1), g2)), gfd1) - - gtd2 = gradedrange([ - U1(1) => 2, - U1(2) => 2, - U1(3) => 4, - U1(-1) => 1, - U1(0) => 1, - U1(1) => 2, - U1(-2) => 2, - U1(-1) => 2, - U1(0) => 4, - ]) - gfd2 = gradedrange([ - U1(-2) => 2, U1(-1) => 3, U1(0) => 5, U1(1) => 4, U1(2) => 2, U1(3) => 4 - ]) - @test space_isequal((@inferred tensor_product(g1, dual(g2))), gtd2) - @test space_isequal((@inferred fusion_product(g1, dual(g2))), gfd2) - - gtd = gradedrange([ - U1(3) => 2, - U1(2) => 2, - U1(1) => 4, - U1(1) => 1, - U1(0) => 1, - U1(-1) => 2, - U1(0) => 2, - U1(-1) => 2, - U1(-2) => 4, - ]) - gfd = gradedrange([ - U1(-2) => 4, U1(-1) => 4, U1(0) => 3, U1(1) => 5, U1(2) => 2, U1(3) => 2 - ]) - @test space_isequal((@inferred tensor_product(dual(g1), dual(g2))), gtd) - @test space_isequal((@inferred fusion_product(dual(g1), dual(g2))), gfd) - - # test different (non-product) sectors cannot be fused - @test_throws MethodError fusion_product(gradedrange([Z{2}(0) => 1]), g1) - @test_throws MethodError tensor_product(gradedrange([Z{2}(0) => 1]), g2) - end - - @testset "GradedUnitRange non-abelian fusion rules" begin - g3 = gradedrange([SU2(0) => 1, SU2(1//2) => 2, SU2(1) => 1]) - g4 = gradedrange([SU2(1//2) => 1, SU2(1) => 2]) - g34 = gradedrange([ - SU2(1//2) => 1, - SU2(0) => 2, - SU2(1) => 2, - SU2(1//2) => 1, - SU2(3//2) => 1, - SU2(1) => 2, - SU2(1//2) => 4, - SU2(3//2) => 4, - SU2(0) => 2, - SU2(1) => 2, - SU2(2) => 2, - ]) - - @test space_isequal(tensor_product(g3, g4), g34) - - @test space_isequal(dual(flip(g3)), g3) # trivial for SU(2) - @test space_isequal( - (@inferred fusion_product(g3, g4)), - gradedrange([SU2(0) => 4, SU2(1//2) => 6, SU2(1) => 6, SU2(3//2) => 5, SU2(2) => 2]), - ) - @test (@inferred block_dimensions(g3)) == [1, 4, 3] - - # test dual on non self-conjugate non-abelian representations - s1 = SU{3}((0, 0)) - f3 = SU{3}((1, 0)) - c3 = SU{3}((1, 1)) - ad8 = SU{3}((2, 1)) - - g5 = gradedrange([s1 => 1, f3 => 1]) - g6 = gradedrange([s1 => 1, c3 => 1]) - @test space_isequal(dual(flip(g5)), g6) - @test space_isequal( - fusion_product(g5, g6), gradedrange([s1 => 2, f3 => 1, c3 => 1, ad8 => 1]) - ) - @test space_isequal( - fusion_product(dual(g5), g6), - gradedrange([s1 => 1, f3 => 1, c3 => 2, SU{3}((2, 2)) => 1]), - ) - @test space_isequal( - fusion_product(g5, dual(g6)), - gradedrange([s1 => 1, f3 => 2, c3 => 1, SU{3}((2, 0)) => 1]), - ) - @test space_isequal( - fusion_product(dual(g5), dual(g6)), gradedrange([s1 => 2, f3 => 1, c3 => 1, ad8 => 1]) - ) - end - - @testset "Mixed GradedUnitRange - Sector fusion rules" begin - g1 = gradedrange([U1(1) => 1, U1(2) => 2]) - g2 = gradedrange([U1(2) => 1, U1(3) => 2]) - @test space_isequal((@inferred fusion_product(g1, U1(1))), g2) - @test space_isequal((@inferred fusion_product(U1(1), g1)), g2) - - g3 = gradedrange([SU2(0) => 1, SU2(1//2) => 2]) - g4 = gradedrange([SU2(0) => 2, SU2(1//2) => 1, SU2(1) => 2]) - @test space_isequal((@inferred fusion_product(g3, SU2(1//2))), g4) - @test space_isequal((@inferred fusion_product(SU2(1//2), g3)), g4) - - # test different simple sectors cannot be fused - @test_throws MethodError Z{2}(0) ⊗ U1(1) - @test_throws MethodError SU2(1) ⊗ U1(1) - @test_throws MethodError fusion_product(g1, SU2(1)) - @test_throws MethodError fusion_product(U1(1), g3) - end -end -end diff --git a/NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl b/NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl deleted file mode 100644 index de046fc307..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl +++ /dev/null @@ -1,622 +0,0 @@ -@eval module $(gensym()) -using NDTensors.SymmetrySectors: - ×, - ⊗, - Fib, - Ising, - SectorProduct, - SU, - SU2, - TrivialSector, - U1, - Z, - block_dimensions, - quantum_dimension, - arguments, - trivial -using NDTensors.GradedAxes: dual, fusion_product, space_isequal, gradedrange -using Test: @inferred, @test, @testset, @test_throws - -@testset "Test Ordered Products" begin - @testset "Ordered Constructor" begin - s = SectorProduct(U1(1)) - @test length(arguments(s)) == 1 - @test (@inferred quantum_dimension(s)) == 1 - @test (@inferred dual(s)) == SectorProduct(U1(-1)) - @test arguments(s)[1] == U1(1) - @test (@inferred trivial(s)) == SectorProduct(U1(0)) - - s = SectorProduct(U1(1), U1(2)) - @test length(arguments(s)) == 2 - @test (@inferred quantum_dimension(s)) == 1 - @test (@inferred dual(s)) == SectorProduct(U1(-1), U1(-2)) - @test arguments(s)[1] == U1(1) - @test arguments(s)[2] == U1(2) - @test (@inferred trivial(s)) == SectorProduct(U1(0), U1(0)) - - s = U1(1) × SU2(1//2) × U1(3) - @test length(arguments(s)) == 3 - @test (@inferred quantum_dimension(s)) == 2 - @test (@inferred dual(s)) == U1(-1) × SU2(1//2) × U1(-3) - @test arguments(s)[1] == U1(1) - @test arguments(s)[2] == SU2(1//2) - @test arguments(s)[3] == U1(3) - @test (@inferred trivial(s)) == SectorProduct(U1(0), SU2(0), U1(0)) - - s = U1(3) × SU2(1//2) × Fib("τ") - @test length(arguments(s)) == 3 - @test (@inferred quantum_dimension(s)) == 1.0 + √5 - @test dual(s) == U1(-3) × SU2(1//2) × Fib("τ") - @test arguments(s)[1] == U1(3) - @test arguments(s)[2] == SU2(1//2) - @test arguments(s)[3] == Fib("τ") - @test (@inferred trivial(s)) == SectorProduct(U1(0), SU2(0), Fib("1")) - - s = TrivialSector() × U1(3) × SU2(1 / 2) - @test length(arguments(s)) == 3 - @test (@inferred quantum_dimension(s)) == 2 - @test dual(s) == TrivialSector() × U1(-3) × SU2(1//2) - @test (@inferred trivial(s)) == SectorProduct(TrivialSector(), U1(0), SU2(0)) - @test s > trivial(s) - end - - @testset "Ordered comparisons" begin - # convention: missing arguments are filled with singlets - @test SectorProduct(U1(1), SU2(1)) == SectorProduct(U1(1), SU2(1)) - @test SectorProduct(U1(1), SU2(0)) != SectorProduct(U1(1), SU2(1)) - @test SectorProduct(U1(0), SU2(1)) != SectorProduct(U1(1), SU2(1)) - @test SectorProduct(U1(1)) != U1(1) - @test SectorProduct(U1(1)) == SectorProduct(U1(1), U1(0)) - @test SectorProduct(U1(1)) != SectorProduct(U1(1), U1(1)) - @test SectorProduct(U1(0), SU2(0)) == TrivialSector() - @test SectorProduct(U1(0), SU2(0)) == SectorProduct(TrivialSector(), SU2(0)) - @test SectorProduct(U1(0), SU2(0)) == SectorProduct(U1(0), TrivialSector()) - @test SectorProduct(U1(0), SU2(0)) == SectorProduct(TrivialSector(), TrivialSector()) - - @test SectorProduct(U1(0)) < SectorProduct((U1(1))) - @test SectorProduct(U1(0), U1(2)) < SectorProduct((U1(1)), U1(0)) - @test SectorProduct(U1(0)) < SectorProduct(U1(0), U1(1)) - @test SectorProduct(U1(0)) > SectorProduct(U1(0), U1(-1)) - end - - @testset "Quantum dimension and GradedUnitRange" begin - g = gradedrange([(U1(0) × Z{2}(0)) => 1, (U1(1) × Z{2}(0)) => 2]) # abelian - @test (@inferred quantum_dimension(g)) == 3 - - g = gradedrange([ # non-abelian - (SU2(0) × SU2(0)) => 1, - (SU2(1) × SU2(0)) => 1, - (SU2(0) × SU2(1)) => 1, - (SU2(1) × SU2(1)) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 16 - @test (@inferred block_dimensions(g)) == [1, 3, 3, 9] - - # mixed group - g = gradedrange([(U1(2) × SU2(0) × Z{2}(0)) => 1, (U1(2) × SU2(1) × Z{2}(0)) => 1]) - @test (@inferred quantum_dimension(g)) == 4 - @test (@inferred block_dimensions(g)) == [1, 3] - g = gradedrange([(SU2(0) × U1(0) × SU2(1//2)) => 1, (SU2(0) × U1(1) × SU2(1//2)) => 1]) - @test (@inferred quantum_dimension(g)) == 4 - @test (@inferred block_dimensions(g)) == [2, 2] - - # NonGroupCategory - g_fib = gradedrange([(Fib("1") × Fib("1")) => 1]) - g_ising = gradedrange([(Ising("1") × Ising("1")) => 1]) - @test (@inferred quantum_dimension((Fib("1") × Fib("1")))) == 1.0 - @test (@inferred quantum_dimension(g_fib)) == 1.0 - @test (@inferred quantum_dimension(g_ising)) == 1.0 - @test (@inferred quantum_dimension((Ising("1") × Ising("1")))) == 1.0 - @test (@inferred block_dimensions(g_fib)) == [1.0] - @test (@inferred block_dimensions(g_ising)) == [1.0] - - @test (@inferred quantum_dimension(U1(1) × Fib("1"))) == 1.0 - @test (@inferred quantum_dimension(gradedrange([U1(1) × Fib("1") => 1]))) == 1.0 - - # mixed product Abelian / NonAbelian / NonGroup - g = gradedrange([ - (U1(2) × SU2(0) × Ising(1)) => 1, - (U1(2) × SU2(1) × Ising(1)) => 1, - (U1(2) × SU2(0) × Ising("ψ")) => 1, - (U1(2) × SU2(1) × Ising("ψ")) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 8.0 - @test (@inferred block_dimensions(g)) == [1.0, 3.0, 1.0, 3.0] - - ϕ = (1 + √5) / 2 - g = gradedrange([ - (Fib("1") × SU2(0) × U1(2)) => 1, - (Fib("1") × SU2(1) × U1(2)) => 1, - (Fib("τ") × SU2(0) × U1(2)) => 1, - (Fib("τ") × SU2(1) × U1(2)) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 4.0 + 4.0ϕ - @test (@inferred block_dimensions(g)) == [1.0, 3.0, 1.0ϕ, 3.0ϕ] - end - - @testset "Fusion of Abelian products" begin - p1 = SectorProduct(U1(1)) - p2 = SectorProduct(U1(2)) - @test (@inferred p1 ⊗ TrivialSector()) == p1 - @test (@inferred TrivialSector() ⊗ p2) == p2 - @test (@inferred p1 ⊗ p2) == SectorProduct(U1(3)) - - p11 = U1(1) × U1(1) - @test p11 ⊗ p11 == U1(2) × U1(2) - - p123 = U1(1) × U1(2) × U1(3) - @test p123 ⊗ p123 == U1(2) × U1(4) × U1(6) - - s1 = SectorProduct(U1(1), Z{2}(1)) - s2 = SectorProduct(U1(0), Z{2}(0)) - @test s1 ⊗ s2 == U1(1) × Z{2}(1) - end - - @testset "Fusion of NonAbelian products" begin - p0 = SectorProduct(SU2(0)) - ph = SectorProduct(SU2(1//2)) - @test space_isequal( - (@inferred p0 ⊗ TrivialSector()), gradedrange([SectorProduct(SU2(0)) => 1]) - ) - @test space_isequal( - (@inferred TrivialSector() ⊗ ph), gradedrange([SectorProduct(SU2(1//2)) => 1]) - ) - - phh = SU2(1//2) × SU2(1//2) - @test space_isequal( - phh ⊗ phh, - gradedrange([ - (SU2(0) × SU2(0)) => 1, - (SU2(1) × SU2(0)) => 1, - (SU2(0) × SU2(1)) => 1, - (SU2(1) × SU2(1)) => 1, - ]), - ) - @test space_isequal( - phh ⊗ phh, - gradedrange([ - (SU2(0) × SU2(0)) => 1, - (SU2(1) × SU2(0)) => 1, - (SU2(0) × SU2(1)) => 1, - (SU2(1) × SU2(1)) => 1, - ]), - ) - end - - @testset "Fusion of NonGroupCategory products" begin - ı = Fib("1") - τ = Fib("τ") - s = ı × ı - @test space_isequal(s ⊗ s, gradedrange([s => 1])) - - s = τ × τ - @test space_isequal( - s ⊗ s, gradedrange([(ı × ı) => 1, (τ × ı) => 1, (ı × τ) => 1, (τ × τ) => 1]) - ) - - σ = Ising("σ") - ψ = Ising("ψ") - s = τ × σ - g = gradedrange([ - (ı × Ising("1")) => 1, (τ × Ising("1")) => 1, (ı × ψ) => 1, (τ × ψ) => 1 - ]) - @test space_isequal(s ⊗ s, g) - end - - @testset "Fusion of mixed Abelian and NonAbelian products" begin - p2h = U1(2) × SU2(1//2) - p1h = U1(1) × SU2(1//2) - @test space_isequal( - p2h ⊗ p1h, gradedrange([(U1(3) × SU2(0)) => 1, (U1(3) × SU2(1)) => 1]) - ) - - p1h1 = U1(1) × SU2(1//2) × Z{2}(1) - @test space_isequal( - p1h1 ⊗ p1h1, - gradedrange([(U1(2) × SU2(0) × Z{2}(0)) => 1, (U1(2) × SU2(1) × Z{2}(0)) => 1]), - ) - end - - @testset "Fusion of fully mixed products" begin - s = U1(1) × SU2(1//2) × Ising("σ") - @test space_isequal( - s ⊗ s, - gradedrange([ - (U1(2) × SU2(0) × Ising("1")) => 1, - (U1(2) × SU2(1) × Ising("1")) => 1, - (U1(2) × SU2(0) × Ising("ψ")) => 1, - (U1(2) × SU2(1) × Ising("ψ")) => 1, - ]), - ) - - ı = Fib("1") - τ = Fib("τ") - s = SU2(1//2) × U1(1) × τ - @test space_isequal( - s ⊗ s, - gradedrange([ - (SU2(0) × U1(2) × ı) => 1, - (SU2(1) × U1(2) × ı) => 1, - (SU2(0) × U1(2) × τ) => 1, - (SU2(1) × U1(2) × τ) => 1, - ]), - ) - - s = U1(1) × ı × τ - @test space_isequal(s ⊗ s, gradedrange([(U1(2) × ı × ı) => 1, (U1(2) × ı × τ) => 1])) - end - - @testset "Fusion of different length Categories" begin - @test SectorProduct(U1(1) × U1(0)) ⊗ SectorProduct(U1(1)) == - SectorProduct(U1(2) × U1(0)) - @test space_isequal( - (@inferred SectorProduct(SU2(0) × SU2(0)) ⊗ SectorProduct(SU2(1))), - gradedrange([SectorProduct(SU2(1) × SU2(0)) => 1]), - ) - - @test space_isequal( - (@inferred SectorProduct(SU2(1) × U1(1)) ⊗ SectorProduct(SU2(0))), - gradedrange([SectorProduct(SU2(1) × U1(1)) => 1]), - ) - @test space_isequal( - (@inferred SectorProduct(U1(1) × SU2(1)) ⊗ SectorProduct(U1(2))), - gradedrange([SectorProduct(U1(3) × SU2(1)) => 1]), - ) - - # check incompatible sectors - p12 = Z{2}(1) × U1(2) - z12 = Z{2}(1) × Z{2}(1) - @test_throws MethodError p12 ⊗ z12 - end - - @testset "GradedUnitRange fusion rules" begin - s1 = U1(1) × SU2(1//2) × Ising("σ") - s2 = U1(0) × SU2(1//2) × Ising("1") - g1 = gradedrange([s1 => 2]) - g2 = gradedrange([s2 => 1]) - @test space_isequal( - fusion_product(g1, g2), - gradedrange([U1(1) × SU2(0) × Ising("σ") => 2, U1(1) × SU2(1) × Ising("σ") => 2]), - ) - end -end - -@testset "Test Named Sector Products" begin - @testset "Construct from × of NamedTuples" begin - s = (A=U1(1),) × (B=Z{2}(0),) - @test length(arguments(s)) == 2 - @test arguments(s)[:A] == U1(1) - @test arguments(s)[:B] == Z{2}(0) - @test (@inferred quantum_dimension(s)) == 1 - @test (@inferred dual(s)) == (A=U1(-1),) × (B=Z{2}(0),) - @test (@inferred trivial(s)) == (A=U1(0),) × (B=Z{2}(0),) - - s = (A=U1(1),) × (B=SU2(2),) - @test length(arguments(s)) == 2 - @test arguments(s)[:A] == U1(1) - @test arguments(s)[:B] == SU2(2) - @test (@inferred quantum_dimension(s)) == 5 - @test (@inferred dual(s)) == (A=U1(-1),) × (B=SU2(2),) - @test (@inferred trivial(s)) == (A=U1(0),) × (B=SU2(0),) - @test s == (B=SU2(2),) × (A=U1(1),) - - s = s × (C=Ising("ψ"),) - @test length(arguments(s)) == 3 - @test arguments(s)[:C] == Ising("ψ") - @test (@inferred quantum_dimension(s)) == 5.0 - @test (@inferred dual(s)) == (A=U1(-1),) × (B=SU2(2),) × (C=Ising("ψ"),) - - s1 = (A=U1(1),) × (B=Z{2}(0),) - s2 = (A=U1(1),) × (C=Z{2}(0),) - @test_throws ArgumentError s1 × s2 - end - - @testset "Construct from Pairs" begin - s = SectorProduct("A" => U1(2)) - @test length(arguments(s)) == 1 - @test arguments(s)[:A] == U1(2) - @test s == SectorProduct(; A=U1(2)) - @test (@inferred quantum_dimension(s)) == 1 - @test (@inferred dual(s)) == SectorProduct("A" => U1(-2)) - @test (@inferred trivial(s)) == SectorProduct(; A=U1(0)) - - s = SectorProduct("B" => Ising("ψ"), :C => Z{2}(1)) - @test length(arguments(s)) == 2 - @test arguments(s)[:B] == Ising("ψ") - @test arguments(s)[:C] == Z{2}(1) - @test (@inferred quantum_dimension(s)) == 1.0 - end - - @testset "Comparisons with unspecified labels" begin - # convention: arguments evaluate as equal if unmatched labels are trivial - # this is different from ordered tuple convention - q2 = SectorProduct(; N=U1(2)) - q20 = (N=U1(2),) × (J=SU2(0),) - @test q20 == q2 - @test !(q20 < q2) - @test !(q2 < q20) - - q21 = (N=U1(2),) × (J=SU2(1),) - @test q21 != q2 - @test q20 < q21 - @test q2 < q21 - - a = (A=U1(0),) × (B=U1(2),) - b = (B=U1(2),) × (C=U1(0),) - @test a == b - c = (B=U1(2),) × (C=U1(1),) - @test a != c - end - - @testset "Quantum dimension and GradedUnitRange" begin - g = gradedrange([ - SectorProduct(; A=U1(0), B=Z{2}(0)) => 1, SectorProduct(; A=U1(1), B=Z{2}(0)) => 2 - ]) # abelian - @test (@inferred quantum_dimension(g)) == 3 - - g = gradedrange([ # non-abelian - SectorProduct(; A=SU2(0), B=SU2(0)) => 1, - SectorProduct(; A=SU2(1), B=SU2(0)) => 1, - SectorProduct(; A=SU2(0), B=SU2(1)) => 1, - SectorProduct(; A=SU2(1), B=SU2(1)) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 16 - - # mixed group - g = gradedrange([ - SectorProduct(; A=U1(2), B=SU2(0), C=Z{2}(0)) => 1, - SectorProduct(; A=U1(2), B=SU2(1), C=Z{2}(0)) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 4 - g = gradedrange([ - SectorProduct(; A=SU2(0), B=Z{2}(0), C=SU2(1//2)) => 1, - SectorProduct(; A=SU2(0), B=Z{2}(1), C=SU2(1//2)) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 4 - - # non group sectors - g_fib = gradedrange([SectorProduct(; A=Fib("1"), B=Fib("1")) => 1]) - g_ising = gradedrange([SectorProduct(; A=Ising("1"), B=Ising("1")) => 1]) - @test (@inferred quantum_dimension(g_fib)) == 1.0 - @test (@inferred quantum_dimension(g_ising)) == 1.0 - - # mixed product Abelian / NonAbelian / NonGroup - g = gradedrange([ - SectorProduct(; A=U1(2), B=SU2(0), C=Ising(1)) => 1, - SectorProduct(; A=U1(2), B=SU2(1), C=Ising(1)) => 1, - SectorProduct(; A=U1(2), B=SU2(0), C=Ising("ψ")) => 1, - SectorProduct(; A=U1(2), B=SU2(1), C=Ising("ψ")) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 8.0 - - g = gradedrange([ - SectorProduct(; A=Fib("1"), B=SU2(0), C=U1(2)) => 1, - SectorProduct(; A=Fib("1"), B=SU2(1), C=U1(2)) => 1, - SectorProduct(; A=Fib("τ"), B=SU2(0), C=U1(2)) => 1, - SectorProduct(; A=Fib("τ"), B=SU2(1), C=U1(2)) => 1, - ]) - @test (@inferred quantum_dimension(g)) == 4.0 + 4.0quantum_dimension(Fib("τ")) - end - - @testset "Fusion of Abelian products" begin - q00 = SectorProduct(;) - q10 = SectorProduct(; A=U1(1)) - q01 = SectorProduct(; B=U1(1)) - q11 = SectorProduct(; A=U1(1), B=U1(1)) - - @test (@inferred q10 ⊗ q10) == SectorProduct(; A=U1(2)) - @test (@inferred q01 ⊗ q00) == q01 - @test (@inferred q00 ⊗ q01) == q01 - @test (@inferred q10 ⊗ q01) == q11 - @test q11 ⊗ q11 == SectorProduct(; A=U1(2), B=U1(2)) - - s11 = SectorProduct(; A=U1(1), B=Z{2}(1)) - s10 = SectorProduct(; A=U1(1)) - s01 = SectorProduct(; B=Z{2}(1)) - @test (@inferred s01 ⊗ q00) == s01 - @test (@inferred q00 ⊗ s01) == s01 - @test (@inferred s10 ⊗ s01) == s11 - @test s11 ⊗ s11 == SectorProduct(; A=U1(2), B=Z{2}(0)) - end - - @testset "Fusion of NonAbelian products" begin - p0 = SectorProduct(;) - pha = SectorProduct(; A=SU2(1//2)) - phb = SectorProduct(; B=SU2(1//2)) - phab = SectorProduct(; A=SU2(1//2), B=SU2(1//2)) - - @test space_isequal( - (@inferred pha ⊗ pha), - gradedrange([SectorProduct(; A=SU2(0)) => 1, SectorProduct(; A=SU2(1)) => 1]), - ) - @test space_isequal((@inferred pha ⊗ p0), gradedrange([pha => 1])) - @test space_isequal((@inferred p0 ⊗ phb), gradedrange([phb => 1])) - @test space_isequal((@inferred pha ⊗ phb), gradedrange([phab => 1])) - - @test space_isequal( - phab ⊗ phab, - gradedrange([ - SectorProduct(; A=SU2(0), B=SU2(0)) => 1, - SectorProduct(; A=SU2(1), B=SU2(0)) => 1, - SectorProduct(; A=SU2(0), B=SU2(1)) => 1, - SectorProduct(; A=SU2(1), B=SU2(1)) => 1, - ]), - ) - end - - @testset "Fusion of NonGroupCategory products" begin - ı = Fib("1") - τ = Fib("τ") - s = SectorProduct(; A=ı, B=ı) - @test space_isequal(s ⊗ s, gradedrange([s => 1])) - - s = SectorProduct(; A=τ, B=τ) - @test space_isequal( - s ⊗ s, - gradedrange([ - SectorProduct(; A=ı, B=ı) => 1, - SectorProduct(; A=τ, B=ı) => 1, - SectorProduct(; A=ı, B=τ) => 1, - SectorProduct(; A=τ, B=τ) => 1, - ]), - ) - - σ = Ising("σ") - ψ = Ising("ψ") - s = SectorProduct(; A=τ, B=σ) - g = gradedrange([ - SectorProduct(; A=ı, B=Ising("1")) => 1, - SectorProduct(; A=τ, B=Ising("1")) => 1, - SectorProduct(; A=ı, B=ψ) => 1, - SectorProduct(; A=τ, B=ψ) => 1, - ]) - @test space_isequal(s ⊗ s, g) - end - - @testset "Fusion of mixed Abelian and NonAbelian products" begin - q0h = SectorProduct(; J=SU2(1//2)) - q10 = (N=U1(1),) × (J=SU2(0),) - # Put names in reverse order sometimes: - q1h = (J=SU2(1//2),) × (N=U1(1),) - q11 = (N=U1(1),) × (J=SU2(1),) - q20 = (N=U1(2),) × (J=SU2(0),) # julia 1.6 does not accept gradedrange without J - q2h = (N=U1(2),) × (J=SU2(1//2),) - q21 = (N=U1(2),) × (J=SU2(1),) - q22 = (N=U1(2),) × (J=SU2(2),) - - @test space_isequal(q1h ⊗ q1h, gradedrange([q20 => 1, q21 => 1])) - @test space_isequal(q10 ⊗ q1h, gradedrange([q2h => 1])) - @test space_isequal((@inferred q0h ⊗ q1h), gradedrange([q10 => 1, q11 => 1])) - @test space_isequal(q11 ⊗ q11, gradedrange([q20 => 1, q21 => 1, q22 => 1])) - end - - @testset "Fusion of fully mixed products" begin - s = SectorProduct(; A=U1(1), B=SU2(1//2), C=Ising("σ")) - @test space_isequal( - s ⊗ s, - gradedrange([ - SectorProduct(; A=U1(2), B=SU2(0), C=Ising("1")) => 1, - SectorProduct(; A=U1(2), B=SU2(1), C=Ising("1")) => 1, - SectorProduct(; A=U1(2), B=SU2(0), C=Ising("ψ")) => 1, - SectorProduct(; A=U1(2), B=SU2(1), C=Ising("ψ")) => 1, - ]), - ) - - ı = Fib("1") - τ = Fib("τ") - s = SectorProduct(; A=SU2(1//2), B=U1(1), C=τ) - @test space_isequal( - s ⊗ s, - gradedrange([ - SectorProduct(; A=SU2(0), B=U1(2), C=ı) => 1, - SectorProduct(; A=SU2(1), B=U1(2), C=ı) => 1, - SectorProduct(; A=SU2(0), B=U1(2), C=τ) => 1, - SectorProduct(; A=SU2(1), B=U1(2), C=τ) => 1, - ]), - ) - - s = SectorProduct(; A=τ, B=U1(1), C=ı) - @test space_isequal( - s ⊗ s, - gradedrange([ - SectorProduct(; B=U1(2), A=ı, C=ı) => 1, SectorProduct(; B=U1(2), A=τ, C=ı) => 1 - ]), - ) - end - @testset "GradedUnitRange fusion rules" begin - s1 = SectorProduct(; A=U1(1), B=SU2(1//2), C=Ising("σ")) - s2 = SectorProduct(; A=U1(0), B=SU2(1//2), C=Ising("1")) - g1 = gradedrange([s1 => 2]) - g2 = gradedrange([s2 => 1]) - s3 = SectorProduct(; A=U1(1), B=SU2(0), C=Ising("σ")) - s4 = SectorProduct(; A=U1(1), B=SU2(1), C=Ising("σ")) - @test space_isequal(fusion_product(g1, g2), gradedrange([s3 => 2, s4 => 2])) - - sA = SectorProduct(; A=U1(1)) - sB = SectorProduct(; B=SU2(1//2)) - sAB = SectorProduct(; A=U1(1), B=SU2(1//2)) - gA = gradedrange([sA => 2]) - gB = gradedrange([sB => 1]) - @test space_isequal(fusion_product(gA, gB), gradedrange([sAB => 2])) - end -end - -@testset "Mixing implementations" begin - st1 = SectorProduct(U1(1)) - sA1 = SectorProduct(; A=U1(1)) - - @test sA1 != st1 - @test_throws MethodError sA1 < st1 - @test_throws MethodError st1 < sA1 - @test_throws MethodError st1 ⊗ sA1 - @test_throws MethodError sA1 ⊗ st1 - @test_throws ArgumentError st1 × sA1 - @test_throws ArgumentError sA1 × st1 -end - -@testset "Empty SymmetrySector" begin - st1 = SectorProduct(U1(1)) - sA1 = SectorProduct(; A=U1(1)) - - for s in (SectorProduct(()), SectorProduct((;))) - @test s == TrivialSector() - @test s == SectorProduct(()) - @test s == SectorProduct((;)) - - @test !(s < SectorProduct()) - @test !(s < SectorProduct(;)) - - @test (@inferred s × SectorProduct(())) == s - @test (@inferred s × SectorProduct((;))) == s - @test (@inferred s ⊗ SectorProduct(())) == s - @test (@inferred s ⊗ SectorProduct((;))) == s - - @test (@inferred dual(s)) == s - @test (@inferred trivial(s)) == s - @test (@inferred quantum_dimension(s)) == 1 - - g0 = gradedrange([s => 2]) - @test space_isequal((@inferred fusion_product(g0, g0)), gradedrange([s => 4])) - - @test (@inferred s × U1(1)) == st1 - @test (@inferred U1(1) × s) == st1 - @test (@inferred s × st1) == st1 - @test (@inferred st1 × s) == st1 - @test (@inferred s × sA1) == sA1 - @test (@inferred sA1 × s) == sA1 - - @test (@inferred U1(1) ⊗ s) == st1 - @test (@inferred s ⊗ U1(1)) == st1 - @test (@inferred SU2(0) ⊗ s) == gradedrange([SectorProduct(SU2(0)) => 1]) - @test (@inferred s ⊗ SU2(0)) == gradedrange([SectorProduct(SU2(0)) => 1]) - @test (@inferred Fib("τ") ⊗ s) == gradedrange([SectorProduct(Fib("τ")) => 1]) - @test (@inferred s ⊗ Fib("τ")) == gradedrange([SectorProduct(Fib("τ")) => 1]) - - @test (@inferred st1 ⊗ s) == st1 - @test (@inferred SectorProduct(SU2(0)) ⊗ s) == gradedrange([SectorProduct(SU2(0)) => 1]) - @test (@inferred SectorProduct(Fib("τ"), SU2(1), U1(2)) ⊗ s) == - gradedrange([SectorProduct(Fib("τ"), SU2(1), U1(2)) => 1]) - - @test (@inferred sA1 ⊗ s) == sA1 - @test (@inferred SectorProduct(; A=SU2(0)) ⊗ s) == - gradedrange([SectorProduct(; A=SU2(0)) => 1]) - @test (@inferred SectorProduct(; A=Fib("τ"), B=SU2(1), C=U1(2)) ⊗ s) == - gradedrange([SectorProduct(; A=Fib("τ"), B=SU2(1), C=U1(2)) => 1]) - - # Empty behaves as empty NamedTuple - @test s != U1(0) - @test s == SectorProduct(U1(0)) - @test s == SectorProduct(; A=U1(0)) - @test SectorProduct(; A=U1(0)) == s - @test s != sA1 - @test s != st1 - - @test s < st1 - @test SectorProduct(U1(-1)) < s - @test s < sA1 - @test s > SectorProduct(; A=U1(-1)) - @test !(s < SectorProduct(; A=U1(0))) - @test !(s > SectorProduct(; A=U1(0))) - end -end -end diff --git a/NDTensors/src/lib/SymmetrySectors/test/test_simple_sectors.jl b/NDTensors/src/lib/SymmetrySectors/test/test_simple_sectors.jl deleted file mode 100644 index a2b243c725..0000000000 --- a/NDTensors/src/lib/SymmetrySectors/test/test_simple_sectors.jl +++ /dev/null @@ -1,215 +0,0 @@ -@eval module $(gensym()) -using NDTensors.GradedAxes: dual -using NDTensors.SymmetrySectors: - Fib, - Ising, - O2, - SU, - SU2, - TrivialSector, - U1, - Z, - quantum_dimension, - fundamental, - istrivial, - trivial -using Test: @inferred, @test, @testset, @test_throws -@testset "Test SymmetrySectors Types" begin - @testset "TrivialSector" begin - q = TrivialSector() - - @test (@inferred quantum_dimension(q)) == 1 - @test q == q - @test trivial(q) == q - @test istrivial(q) - - @test dual(q) == q - @test !isless(q, q) - end - - @testset "U(1)" begin - q1 = U1(1) - q2 = U1(2) - q3 = U1(3) - - @test quantum_dimension(q1) == 1 - @test quantum_dimension(q2) == 1 - @test (@inferred quantum_dimension(q1)) == 1 - - @test trivial(q1) == U1(0) - @test trivial(U1) == U1(0) - @test istrivial(U1(0)) - - @test dual(U1(2)) == U1(-2) - @test isless(U1(1), U1(2)) - @test !isless(U1(2), U1(1)) - @test U1(Int8(1)) == U1(1) - @test U1(UInt32(1)) == U1(1) - - @test U1(0) == TrivialSector() - @test TrivialSector() == U1(0) - @test U1(-1) < TrivialSector() - @test TrivialSector() < U1(1) - @test U1(Int8(1)) < U1(Int32(2)) - end - - @testset "Z₂" begin - z0 = Z{2}(0) - z1 = Z{2}(1) - - @test trivial(Z{2}) == Z{2}(0) - @test istrivial(Z{2}(0)) - - @test quantum_dimension(z0) == 1 - @test quantum_dimension(z1) == 1 - @test (@inferred quantum_dimension(z0)) == 1 - - @test dual(z0) == z0 - @test dual(z1) == z1 - - @test dual(Z{2}(1)) == Z{2}(1) - @test isless(Z{2}(0), Z{2}(1)) - @test !isless(Z{2}(1), Z{2}(0)) - @test Z{2}(0) == z0 - @test Z{2}(-3) == z1 - - @test Z{2}(0) == TrivialSector() - @test TrivialSector() < Z{2}(1) - @test_throws MethodError U1(0) < Z{2}(1) - @test Z{2}(0) != Z{2}(1) - @test Z{2}(0) != Z{3}(0) - @test Z{2}(0) != U1(0) - end - - @testset "O(2)" begin - s0e = O2(0) - s0o = O2(-1) - s12 = O2(1//2) - s1 = O2(1) - - @test trivial(O2) == s0e - @test istrivial(s0e) - - @test (@inferred quantum_dimension(s0e)) == 1 - @test (@inferred quantum_dimension(s0o)) == 1 - @test (@inferred quantum_dimension(s12)) == 2 - @test (@inferred quantum_dimension(s1)) == 2 - - @test (@inferred dual(s0e)) == s0e - @test (@inferred dual(s0o)) == s0o - @test (@inferred dual(s12)) == s12 - @test (@inferred dual(s1)) == s1 - - @test s0o < s0e < s12 < s1 - @test s0e == TrivialSector() - @test s0o < TrivialSector() - @test TrivialSector() < s12 - end - - @testset "SU(2)" begin - j1 = SU2(0) - j2 = SU2(1//2) # Rational will be cast to HalfInteger - j3 = SU2(1) - j4 = SU2(3//2) - - # alternative constructors - @test j2 == SU{2}((1,)) # tuple SU(N)-like constructor - @test j2 == SU{2,1}((1,)) # tuple constructor with explicit {N,N-1} - @test j2 == SU((1,)) # infer N from tuple length - @test j2 == SU{2}((Int8(1),)) # any Integer type accepted - @test j2 == SU{2}((UInt32(1),)) # any Integer type accepted - @test j2 == SU2(1 / 2) # Float will be cast to HalfInteger - @test_throws MethodError SU2((1,)) # avoid confusion between tuple and half-integer interfaces - @test_throws MethodError SU{2,1}(1) # avoid confusion - - @test trivial(SU{2}) == SU2(0) - @test istrivial(SU2(0)) - @test fundamental(SU{2}) == SU2(1//2) - - @test quantum_dimension(j1) == 1 - @test quantum_dimension(j2) == 2 - @test quantum_dimension(j3) == 3 - @test quantum_dimension(j4) == 4 - @test (@inferred quantum_dimension(j1)) == 1 - - @test dual(j1) == j1 - @test dual(j2) == j2 - @test dual(j3) == j3 - @test dual(j4) == j4 - - @test j1 < j2 < j3 < j4 - @test SU2(0) == TrivialSector() - @test !(j2 < TrivialSector()) - @test TrivialSector() < j2 - end - - @testset "SU(N)" begin - f3 = SU{3}((1, 0)) - f4 = SU{4}((1, 0, 0)) - ad3 = SU{3}((2, 1)) - ad4 = SU{4}((2, 1, 1)) - - @test trivial(SU{3}) == SU{3}((0, 0)) - @test istrivial(SU{3}((0, 0))) - @test trivial(SU{4}) == SU{4}((0, 0, 0)) - @test istrivial(SU{4}((0, 0, 0))) - @test SU{3}((0, 0)) == TrivialSector() - @test SU{4}((0, 0, 0)) == TrivialSector() - - @test fundamental(SU{3}) == f3 - @test fundamental(SU{4}) == f4 - - @test dual(f3) == SU{3}((1, 1)) - @test dual(f4) == SU{4}((1, 1, 1)) - @test dual(ad3) == ad3 - @test dual(ad4) == ad4 - - @test quantum_dimension(f3) == 3 - @test quantum_dimension(f4) == 4 - @test quantum_dimension(ad3) == 8 - @test quantum_dimension(ad4) == 15 - @test quantum_dimension(SU{3}((4, 2))) == 27 - @test quantum_dimension(SU{3}((3, 3))) == 10 - @test quantum_dimension(SU{3}((3, 0))) == 10 - @test quantum_dimension(SU{3}((0, 0))) == 1 - @test (@inferred quantum_dimension(f3)) == 3 - end - - @testset "Fibonacci" begin - ı = Fib("1") - τ = Fib("τ") - - @test trivial(Fib) == ı - @test istrivial(ı) - @test ı == TrivialSector() - - @test dual(ı) == ı - @test dual(τ) == τ - - @test (@inferred quantum_dimension(ı)) == 1.0 - @test (@inferred quantum_dimension(τ)) == ((1 + √5) / 2) - - @test ı < τ - end - - @testset "Ising" begin - ı = Ising("1") - σ = Ising("σ") - ψ = Ising("ψ") - - @test trivial(Ising) == ı - @test istrivial(ı) - @test ı == TrivialSector() - - @test dual(ı) == ı - @test dual(σ) == σ - @test dual(ψ) == ψ - - @test (@inferred quantum_dimension(ı)) == 1.0 - @test (@inferred quantum_dimension(σ)) == √2 - @test (@inferred quantum_dimension(ψ)) == 1.0 - - @test ı < σ < ψ - end -end -end diff --git a/NDTensors/src/lib/TagSets/.JuliaFormatter.toml b/NDTensors/src/lib/TagSets/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/TagSets/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/TagSets/README.md b/NDTensors/src/lib/TagSets/README.md deleted file mode 100644 index 346026463b..0000000000 --- a/NDTensors/src/lib/TagSets/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# TagSets.jl - -A sorted collection of unique tags of type `T`. - -# TODO - -- Add `skipchars` (see `skipmissing`) and `delim` for delimiter. -- https://docs.julialang.org/en/v1/base/strings/#Base.strip -- https://docs.julialang.org/en/v1/stdlib/DelimitedFiles/#Delimited-Files -- Add a `Bool` param for bounds checking/ignoring overflow/spillover? -- Make `S` a first argument, hardcode `SmallVector` storage? -- https://juliacollections.github.io/DataStructures.jl/v0.9/sorted_containers.html -- https://github.com/JeffreySarnoff/SortingNetworks.jl -- https://github.com/vvjn/MergeSorted.jl -- https://bkamins.github.io/julialang/2023/08/25/infiltrate.html -- https://github.com/Jutho/TensorKit.jl/blob/master/src/auxiliary/dicts.jl -- https://github.com/tpapp/SortedVectors.jl -- https://discourse.julialang.org/t/special-purpose-subtypes-of-arrays/20327 -- https://discourse.julialang.org/t/all-the-ways-to-group-reduce-sorted-vectors-ideas/45239 -- https://discourse.julialang.org/t/sorting-a-vector-of-fixed-size/71766 diff --git a/NDTensors/src/lib/TagSets/examples/benchmark.jl b/NDTensors/src/lib/TagSets/examples/benchmark.jl deleted file mode 100644 index 98a40e5f46..0000000000 --- a/NDTensors/src/lib/TagSets/examples/benchmark.jl +++ /dev/null @@ -1,47 +0,0 @@ -using NDTensors.TagSets -using NDTensors.InlineStrings -using NDTensors.SmallVectors -using NDTensors.SortedSets -using NDTensors.TagSets - -using BenchmarkTools -using Cthulhu -using Profile -using PProf - -function main(; profile=false) - TS = SmallTagSet{10,String31} - ts1 = TS(["a", "b"]) - ts2 = TS(["b", "c", "d"]) - - @btime $TS($("x,y")) - - @show union(ts1, ts2) - @show intersect(ts1, ts2) - @show setdiff(ts1, ts2) - @show symdiff(ts1, ts2) - - @btime union($ts1, $ts2) - @btime intersect($ts1, $ts2) - @btime setdiff($ts1, $ts2) - @btime symdiff($ts1, $ts2) - - @show addtags(ts1, ts2) - @show commontags(ts1, ts2) - @show removetags(ts1, ts2) - @show noncommontags(ts1, ts2) - @show replacetags(ts1, ["b"], ["c", "d"]) - - @btime addtags($ts1, $ts2) - @btime commontags($ts1, $ts2) - @btime removetags($ts1, $ts2) - @btime noncommontags($ts1, $ts2) - @btime replacetags($ts1, $(["b"]), $(["c", "d"])) - - if profile - Profile.clear() - @profile foreach(_ -> TagSet("x,y"; data_type=set_type), 1:1_000_000) - return pprof() - end - return nothing -end diff --git a/NDTensors/src/lib/TagSets/src/TagSets.jl b/NDTensors/src/lib/TagSets/src/TagSets.jl deleted file mode 100644 index c4d9f1013f..0000000000 --- a/NDTensors/src/lib/TagSets/src/TagSets.jl +++ /dev/null @@ -1,89 +0,0 @@ -module TagSets -using Dictionaries -using ..SmallVectors -using ..SortedSets - -using Base: @propagate_inbounds - -export TagSet, - SmallTagSet, MSmallTagSet, addtags, removetags, replacetags, commontags, noncommontags - -# A sorted collection of unique tags of type `T`. -struct TagSet{T,D<:AbstractIndices{T}} <: AbstractWrappedSet{T,D} - data::D -end - -TagSet{T}(data::D) where {T,D<:AbstractIndices{T}} = TagSet{T,D}(data) - -TagSet{T,D}(vec::AbstractVector) where {T,D<:AbstractIndices{T}} = TagSet{T,D}(D(vec)) -TagSet{T,D}() where {T,D<:AbstractIndices{T}} = TagSet{T,D}(D()) - -# Defaults to Indices if unspecified. -default_data_type() = Indices{String} -TagSet(vec::AbstractVector) = TagSet(default_data_type()(vec)) - -# Constructor from string -default_delim() = ',' -@inline function TagSet(str::AbstractString; delim=default_delim()) - return TagSet(default_data_type(), str) -end -@inline function TagSet( - ::Type{D}, str::AbstractString; delim=default_delim() -) where {T,D<:AbstractIndices{T}} - return TagSet{T,D}(str) -end -@inline function TagSet{T,D}( - str::AbstractString; delim=default_delim() -) where {T,D<:AbstractIndices{T}} - return TagSet{T,D}(split(str, delim)) -end - -for (SetTyp, TagSetTyp) in ((:SmallSet, :SmallTagSet), (:MSmallSet, :MSmallTagSet)) - @eval begin - const $TagSetTyp{S,T,Order} = TagSet{T,$SetTyp{S,T,Order}} - @propagate_inbounds function $TagSetTyp{S,I}(a::AbstractArray; kwargs...) where {S,I} - return TagSet($SetTyp{S,I}(a; kwargs...)) - end - @propagate_inbounds $TagSetTyp{S}(; kwargs...) where {S} = $TagSetTyp{S}([]; kwargs...) - @propagate_inbounds $TagSetTyp{S}(iter; kwargs...) where {S} = - $TagSetTyp{S}(collect(iter); kwargs...) - @propagate_inbounds $TagSetTyp{S}(a::AbstractArray{I}; kwargs...) where {S,I} = - $TagSetTyp{S,I}(a; kwargs...) - # Strings get split by a deliminator. - function $TagSetTyp{S}(str::T; kwargs...) where {S,T<:AbstractString} - return $TagSetTyp{S,T}(str, kwargs...) - end - # Strings get split by a deliminator. - function $TagSetTyp{S,T}( - str::AbstractString; delim=default_delim(), kwargs... - ) where {S,T} - # TODO: Optimize for `SmallSet`. - return $TagSetTyp{S,T}(split(str, delim); kwargs...) - end - end -end - -# Field accessors -Base.parent(set::TagSet) = getfield(set, :data) - -# AbstractWrappedSet interface. -# Specialized version when they are the same data type is faster. -@inline SortedSets.rewrap(::TagSet{T,D}, data::D) where {T,D<:AbstractIndices{T}} = - TagSet{T,D}(data) -@inline SortedSets.rewrap(::TagSet, data) = TagSet(data) - -# TagSet interface -addtags(set::TagSet, items) = union(set, items) -removetags(set::TagSet, items) = setdiff(set, items) -commontags(set::TagSet, items) = intersect(set, items) -noncommontags(set::TagSet, items) = symdiff(set, items) -function replacetags(set::TagSet, rem, add) - remtags = setdiff(set, rem) - if length(set) ≠ length(remtags) + length(rem) - # Not all are removed, no replacement - return set - end - return union(remtags, add) -end - -end diff --git a/NDTensors/src/lib/TagSets/test/runtests.jl b/NDTensors/src/lib/TagSets/test/runtests.jl deleted file mode 100644 index ee5c72a199..0000000000 --- a/NDTensors/src/lib/TagSets/test/runtests.jl +++ /dev/null @@ -1,35 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @testset -using NDTensors.TagSets -using NDTensors.SortedSets -using NDTensors.SmallVectors -using NDTensors.InlineStrings -using NDTensors.Dictionaries - -@testset "Test NDTensors.TagSets" begin - for data_type in (Vector,) # SmallVector{10}) - d1 = data_type{String31}(["1", "3", "5"]) - d2 = data_type{String31}(["2", "3", "6"]) - for set_type in (Indices, SortedSet) - s1 = TagSet(set_type(d1)) - s2 = TagSet(set_type(d2)) - - @test issetequal(union(s1, s2), ["1", "2", "3", "5", "6"]) - @test issetequal(setdiff(s1, s2), ["1", "5"]) - @test issetequal(symdiff(s1, s2), ["1", "2", "5", "6"]) - @test issetequal(intersect(s1, s2), ["3"]) - - # TagSet interface - @test issetequal(addtags(s1, ["4"]), ["1", "3", "4", "5"]) - @test issetequal(removetags(s1, ["3"]), ["1", "5"]) - @test issetequal(replacetags(s1, ["3"], ["6", "7"]), ["1", "5", "6", "7"]) - @test issetequal(replacetags(s1, ["3", "4"], ["6, 7"]), ["1", "3", "5"]) - - # Only test if `isinsertable`. Make sure that is false - # for `SmallVector`. - ## @test issetequal(insert!(copy(s1), "4"), ["1", "3", "4", "5"]) - ## @test issetequal(delete!(copy(s1), "3"), ["1", "5"]) - end - end -end -end diff --git a/NDTensors/src/lib/TensorAlgebra/.JuliaFormatter.toml b/NDTensors/src/lib/TensorAlgebra/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/TensorAlgebra/Project.toml b/NDTensors/src/lib/TensorAlgebra/Project.toml deleted file mode 100644 index 659e1f0606..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/Project.toml b/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/Project.toml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/src/TensorAlgebraGradedAxesExt.jl b/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/src/TensorAlgebraGradedAxesExt.jl deleted file mode 100644 index 2b66b688cb..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/src/TensorAlgebraGradedAxesExt.jl +++ /dev/null @@ -1,8 +0,0 @@ -module TensorAlgebraGradedAxesExt -using ...GradedAxes: GradedUnitRange, tensor_product -using ..TensorAlgebra: TensorAlgebra - -function TensorAlgebra.:⊗(a1::GradedUnitRange, a2::GradedUnitRange) - return tensor_product(a1, a2) -end -end diff --git a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/Project.toml b/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/Project.toml deleted file mode 100644 index c959701978..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/Project.toml +++ /dev/null @@ -1,7 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/runtests.jl b/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/runtests.jl deleted file mode 100644 index b8b27153b2..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/runtests.jl +++ /dev/null @@ -1,7 +0,0 @@ -@eval module $(gensym()) -using Test: @testset -@testset "TensorAlgebraGradedAxesExt" begin - include("test_basics.jl") - include("test_contract.jl") -end -end diff --git a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_basics.jl b/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_basics.jl deleted file mode 100644 index 1ee0a45fbe..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_basics.jl +++ /dev/null @@ -1,30 +0,0 @@ -@eval module $(gensym()) -using BlockArrays: Block -using NDTensors.TensorAlgebra: ⊗ -using NDTensors.GradedAxes: GradedAxes, gradedrange, label -using Test: @test, @testset - -struct U1 - dim::Int -end -Base.isless(l1::U1, l2::U1) = isless(l1.dim, l2.dim) -GradedAxes.fuse_labels(l1::U1, l2::U1) = U1(l1.dim + l2.dim) - -## TODO: This should need to get implemented, but `dual` -## isn't being used right now in `GradedAxes`. -## GradedAxes.dual(l::U1) = U1(-l.dim) - -@testset "TensorAlgebraGradedAxesExt" begin - a1 = gradedrange([U1(0) => 2, U1(1) => 3]) - a2 = gradedrange([U1(2) => 3, U1(3) => 4]) - a = a1 ⊗ a2 - @test label(a[Block(1)]) == U1(2) - @test label(a[Block(2)]) == U1(3) - @test label(a[Block(3)]) == U1(3) - @test label(a[Block(4)]) == U1(4) - @test a[Block(1)] == 1:6 - @test a[Block(2)] == 7:15 - @test a[Block(3)] == 16:23 - @test a[Block(4)] == 24:35 -end -end diff --git a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_contract.jl b/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_contract.jl deleted file mode 100644 index 636900303c..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/ext/TensorAlgebraGradedAxesExt/test/test_contract.jl +++ /dev/null @@ -1,34 +0,0 @@ -@eval module $(gensym()) -using BlockArrays: Block, blocksize -using Compat: Returns -using NDTensors.BlockSparseArrays: BlockSparseArray -using NDTensors.GradedAxes: gradedrange -using NDTensors.SparseArraysBase: densearray -using NDTensors.SymmetrySectors: U1 -using NDTensors.TensorAlgebra: contract -using Random: randn! -using Test: @test, @testset - -function randn_blockdiagonal(elt::Type, axes::Tuple) - a = BlockSparseArray{elt}(axes) - blockdiaglength = minimum(blocksize(a)) - for i in 1:blockdiaglength - b = Block(ntuple(Returns(i), ndims(a))) - a[b] = randn!(a[b]) - end - return a -end - -const elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) -@testset "`contract` `BlockSparseArray` (eltype=$elt)" for elt in elts - d = gradedrange([U1(0) => 2, U1(1) => 3]) - a1 = randn_blockdiagonal(elt, (d, d, d)) - a2 = randn_blockdiagonal(elt, (d, d, d)) - a_dest, dimnames_dest = contract(a1, (-1, 1, -2), a2, (-1, -2, 2)) - a1_dense = densearray(a1) - a2_dense = densearray(a2) - a_dest_dense, dimnames_dest_dense = contract(a1_dense, (-1, 1, -2), a2_dense, (-1, -2, 2)) - @test dimnames_dest == dimnames_dest_dense - @test a_dest ≈ a_dest_dense -end -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/BaseExtensions.jl b/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/BaseExtensions.jl deleted file mode 100644 index c994fd81cd..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/BaseExtensions.jl +++ /dev/null @@ -1,4 +0,0 @@ -module BaseExtensions -include("indexin.jl") -include("permutedims.jl") -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/indexin.jl b/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/indexin.jl deleted file mode 100644 index 80a6f58eaf..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/indexin.jl +++ /dev/null @@ -1,5 +0,0 @@ -# `Base.indexin` doesn't handle tuples -indexin(x, y) = Base.indexin(x, y) -indexin(x, y::Tuple) = Base.indexin(x, collect(y)) -indexin(x::Tuple, y) = Tuple{Vararg{Any,length(x)}}(Base.indexin(x, y)) -indexin(x::Tuple, y::Tuple) = Tuple{Vararg{Any,length(x)}}(Base.indexin(x, collect(y))) diff --git a/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/permutedims.jl b/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/permutedims.jl deleted file mode 100644 index c80e07db1e..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/BaseExtensions/permutedims.jl +++ /dev/null @@ -1,20 +0,0 @@ -# Workaround for https://github.com/JuliaLang/julia/issues/52615. -# Fixed by https://github.com/JuliaLang/julia/pull/52623. -function _permutedims!( - a_dest::AbstractArray{<:Any,N}, a_src::AbstractArray{<:Any,N}, perm::Tuple{Vararg{Int,N}} -) where {N} - permutedims!(a_dest, a_src, perm) - return a_dest -end -function _permutedims!( - a_dest::AbstractArray{<:Any,0}, a_src::AbstractArray{<:Any,0}, perm::Tuple{} -) - a_dest[] = a_src[] - return a_dest -end -function _permutedims(a::AbstractArray{<:Any,N}, perm::Tuple{Vararg{Int,N}}) where {N} - return permutedims(a, perm) -end -function _permutedims(a::AbstractArray{<:Any,0}, perm::Tuple{}) - return copy(a) -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/LinearAlgebraExtensions.jl b/NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/LinearAlgebraExtensions.jl deleted file mode 100644 index 471f2bd30a..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/LinearAlgebraExtensions.jl +++ /dev/null @@ -1,3 +0,0 @@ -module LinearAlgebraExtensions -include("qr.jl") -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/qr.jl b/NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/qr.jl deleted file mode 100644 index 7c0d3f0ebb..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/LinearAlgebraExtensions/qr.jl +++ /dev/null @@ -1,68 +0,0 @@ -using ArrayLayouts: LayoutMatrix -using LinearAlgebra: LinearAlgebra, qr -using ..TensorAlgebra: - TensorAlgebra, - BlockedPermutation, - blockedperm, - blockedperm_indexin, - blockpermute, - fusedims, - splitdims - -# TODO: Define as `tensor_qr`. -# TODO: This look generic but doesn't work for `BlockSparseArrays`. -function _qr(a::AbstractArray, biperm::BlockedPermutation{2}) - a_matricized = fusedims(a, biperm) - - # TODO: Make this more generic, allow choosing thin or full, - # make sure this works on GPU. - q_matricized, r_matricized = qr(a_matricized) - q_matricized_thin = typeof(a_matricized)(q_matricized) - - axes_codomain, axes_domain = blockpermute(axes(a), biperm) - axes_q = (axes_codomain..., axes(q_matricized_thin, 2)) - # TODO: Use `tuple_oneto(n) = ntuple(identity, n)`, currently in `BlockSparseArrays`. - biperm_q = blockedperm( - ntuple(identity, length(axes_codomain)), (length(axes_codomain) + 1,) - ) - axes_r = (axes(r_matricized, 1), axes_domain...) - biperm_r = blockedperm((1,), ntuple(identity, length(axes_domain)) .+ 1) - q = splitdims(q_matricized_thin, axes_q) - r = splitdims(r_matricized, axes_r) - return q, r -end - -function LinearAlgebra.qr(a::AbstractArray, biperm::BlockedPermutation{2}) - return _qr(a, biperm) -end - -# Fix ambiguity error with `LinearAlgebra`. -function LinearAlgebra.qr(a::AbstractMatrix, biperm::BlockedPermutation{2}) - return _qr(a, biperm) -end - -# Fix ambiguity error with `ArrayLayouts`. -function LinearAlgebra.qr(a::LayoutMatrix, biperm::BlockedPermutation{2}) - return _qr(a, biperm) -end - -# TODO: Define in terms of an inner function `_qr` or `tensor_qr`. -function LinearAlgebra.qr( - a::AbstractArray, labels_a::Tuple, labels_q::Tuple, labels_r::Tuple -) - return qr(a, blockedperm_indexin(labels_a, labels_q, labels_r)) -end - -# Fix ambiguity error with `LinearAlgebra`. -function LinearAlgebra.qr( - a::AbstractMatrix, labels_a::Tuple, labels_q::Tuple, labels_r::Tuple -) - return qr(a, blockedperm_indexin(labels_a, labels_q, labels_r)) -end - -# Fix ambiguity error with `ArrayLayouts`. -function LinearAlgebra.qr( - a::LayoutMatrix, labels_a::Tuple, labels_q::Tuple, labels_r::Tuple -) - return qr(a, blockedperm_indexin(labels_a, labels_q, labels_r)) -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/TensorAlgebra.jl b/NDTensors/src/lib/TensorAlgebra/src/TensorAlgebra.jl deleted file mode 100644 index f0b5f07568..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/TensorAlgebra.jl +++ /dev/null @@ -1,14 +0,0 @@ -module TensorAlgebra -include("blockedpermutation.jl") -include("BaseExtensions/BaseExtensions.jl") -include("fusedims.jl") -include("splitdims.jl") -include("contract/contract.jl") -include("contract/output_labels.jl") -include("contract/blockedperms.jl") -include("contract/allocate_output.jl") -include("contract/contract_matricize/contract.jl") -# TODO: Rename to `TensorAlgebraLinearAlgebraExt`. -include("LinearAlgebraExtensions/LinearAlgebraExtensions.jl") -include("../ext/TensorAlgebraGradedAxesExt/src/TensorAlgebraGradedAxesExt.jl") -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/blockedpermutation.jl b/NDTensors/src/lib/TensorAlgebra/src/blockedpermutation.jl deleted file mode 100644 index c13b68a642..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/blockedpermutation.jl +++ /dev/null @@ -1,192 +0,0 @@ -using BlockArrays: - BlockArrays, Block, blockfirsts, blocklasts, blocklength, blocklengths, blocks -using EllipsisNotation: Ellipsis, var".." -using TupleTools: TupleTools - -value(::Val{N}) where {N} = N - -_flatten_tuples(t::Tuple) = t -function _flatten_tuples(t1::Tuple, t2::Tuple, trest::Tuple...) - return _flatten_tuples((t1..., t2...), trest...) -end -_flatten_tuples() = () -flatten_tuples(ts::Tuple) = _flatten_tuples(ts...) - -_blocklength(blocklengths::Tuple{Vararg{Int}}) = length(blocklengths) -function _blockfirsts(blocklengths::Tuple{Vararg{Int}}) - return ntuple(_blocklength(blocklengths)) do i - prev_blocklast = - isone(i) ? zero(eltype(blocklengths)) : _blocklasts(blocklengths)[i - 1] - return prev_blocklast + 1 - end -end -_blocklasts(blocklengths::Tuple{Vararg{Int}}) = cumsum(blocklengths) - -collect_tuple(x) = (x,) -collect_tuple(x::Ellipsis) = x -collect_tuple(t::Tuple) = t - -const TupleOfTuples{N} = Tuple{Vararg{Tuple{Vararg{Int}},N}} - -abstract type AbstractBlockedPermutation{BlockLength,Length} end - -BlockArrays.blocks(blockedperm::AbstractBlockedPermutation) = error("Not implemented") - -function Base.Tuple(blockedperm::AbstractBlockedPermutation) - return flatten_tuples(blocks(blockedperm)) -end - -function BlockArrays.blocklengths(blockedperm::AbstractBlockedPermutation) - return length.(blocks(blockedperm)) -end - -function BlockArrays.blockfirsts(blockedperm::AbstractBlockedPermutation) - return _blockfirsts(blocklengths(blockedperm)) -end - -function BlockArrays.blocklasts(blockedperm::AbstractBlockedPermutation) - return _blocklasts(blocklengths(blockedperm)) -end - -Base.iterate(permblocks::AbstractBlockedPermutation) = iterate(Tuple(permblocks)) -function Base.iterate(permblocks::AbstractBlockedPermutation, state) - return iterate(Tuple(permblocks), state) -end - -# Block a permutation based on the specified lengths. -# blockperm((4, 3, 2, 1), (2, 2)) == blockedperm((4, 3), (2, 1)) -# TODO: Optimize with StaticNumbers.jl or generated functions, see: -# https://discourse.julialang.org/t/avoiding-type-instability-when-slicing-a-tuple/38567 -function blockperm(perm::Tuple{Vararg{Int}}, blocklengths::Tuple{Vararg{Int}}) - starts = _blockfirsts(blocklengths) - stops = _blocklasts(blocklengths) - return blockedperm(ntuple(i -> perm[starts[i]:stops[i]], length(blocklengths))...) -end - -function Base.invperm(blockedperm::AbstractBlockedPermutation) - return blockperm(invperm(Tuple(blockedperm)), blocklengths(blockedperm)) -end - -Base.length(blockedperm::AbstractBlockedPermutation) = length(Tuple(blockedperm)) -function BlockArrays.blocklength(blockedperm::AbstractBlockedPermutation) - return length(blocks(blockedperm)) -end - -function Base.getindex(blockedperm::AbstractBlockedPermutation, i::Int) - return Tuple(blockedperm)[i] -end - -function Base.getindex(blockedperm::AbstractBlockedPermutation, I::AbstractUnitRange) - perm = Tuple(blockedperm) - return [perm[i] for i in I] -end - -function Base.getindex(blockedperm::AbstractBlockedPermutation, b::Block) - return blocks(blockedperm)[Int(b)] -end - -# Like `BlockRange`. -function blockeachindex(blockedperm::AbstractBlockedPermutation) - return ntuple(i -> Block(i), blocklength(blockedperm)) -end - -# -# Constructors -# - -# Bipartition a vector according to the -# bipartitioned permutation. -# Like `Base.permute!` block out-of-place and blocked. -function blockpermute(v, blockedperm::AbstractBlockedPermutation) - return map(blockperm -> map(i -> v[i], blockperm), blocks(blockedperm)) -end - -# blockedperm((4, 3), (2, 1)) -function blockedperm(permblocks::Tuple{Vararg{Int}}...; length::Union{Val,Nothing}=nothing) - return blockedperm(length, permblocks...) -end - -function blockedperm(length::Nothing, permblocks::Tuple{Vararg{Int}}...) - return blockedperm(Val(sum(Base.length, permblocks; init=zero(Bool))), permblocks...) -end - -# blockedperm((3, 2), 1) == blockedperm((3, 2), (1,)) -function blockedperm(permblocks::Union{Tuple{Vararg{Int}},Int}...; kwargs...) - return blockedperm(collect_tuple.(permblocks)...; kwargs...) -end - -function blockedperm(permblocks::Union{Tuple{Vararg{Int}},Int,Ellipsis}...; kwargs...) - return blockedperm(collect_tuple.(permblocks)...; kwargs...) -end - -function _blockedperm_length(::Nothing, specified_perm::Tuple{Vararg{Int}}) - return maximum(specified_perm) -end - -function _blockedperm_length(vallength::Val, specified_perm::Tuple{Vararg{Int}}) - return value(vallength) -end - -# blockedperm((4, 3), .., 1) == blockedperm((4, 3), 2, 1) -# blockedperm((4, 3), .., 1; length=Val(5)) == blockedperm((4, 3), 2, 5, 1) -function blockedperm( - permblocks::Union{Tuple{Vararg{Int}},Ellipsis}...; length::Union{Val,Nothing}=nothing -) - # Check there is only one `Ellipsis`. - @assert isone(count(x -> x isa Ellipsis, permblocks)) - specified_permblocks = filter(x -> !(x isa Ellipsis), permblocks) - unspecified_dim = findfirst(x -> x isa Ellipsis, permblocks) - specified_perm = flatten_tuples(specified_permblocks) - len = _blockedperm_length(length, specified_perm) - unspecified_dims = Tuple(setdiff(Base.OneTo(len), flatten_tuples(specified_permblocks))) - permblocks_specified = TupleTools.insertat(permblocks, unspecified_dim, unspecified_dims) - return blockedperm(permblocks_specified...) -end - -# Version of `indexin` that outputs a `blockedperm`. -function blockedperm_indexin(collection, subs...) - return blockedperm(map(sub -> BaseExtensions.indexin(sub, collection), subs)...) -end - -struct BlockedPermutation{BlockLength,Length,Blocks<:TupleOfTuples{BlockLength}} <: - AbstractBlockedPermutation{BlockLength,Length} - blocks::Blocks - global function _BlockedPermutation(blocks::TupleOfTuples) - len = sum(length, blocks; init=zero(Bool)) - blocklength = length(blocks) - return new{blocklength,len,typeof(blocks)}(blocks) - end -end - -BlockArrays.blocks(blockedperm::BlockedPermutation) = getfield(blockedperm, :blocks) - -function blockedperm(length::Val, permblocks::Tuple{Vararg{Int}}...) - @assert value(length) == sum(Base.length, permblocks; init=zero(Bool)) - blockedperm = _BlockedPermutation(permblocks) - @assert isperm(blockedperm) - return blockedperm -end - -trivialperm(length::Union{Integer,Val}) = ntuple(identity, length) - -struct BlockedTrivialPermutation{BlockLength,Length,Blocks<:TupleOfTuples{BlockLength}} <: - AbstractBlockedPermutation{BlockLength,Length} - blocks::Blocks - global function _BlockedTrivialPermutation(blocklengths::Tuple{Vararg{Int}}) - len = sum(blocklengths; init=zero(Bool)) - blocklength = length(blocklengths) - permblocks = blocks(blockperm(trivialperm(len), blocklengths)) - return new{blocklength,len,typeof(permblocks)}(permblocks) - end -end - -BlockArrays.blocks(blockedperm::BlockedTrivialPermutation) = getfield(blockedperm, :blocks) - -function blockedtrivialperm(blocklengths::Tuple{Vararg{Int}}) - return _BlockedTrivialPermutation(blocklengths) -end - -function trivialperm(blockedperm::AbstractBlockedPermutation) - return blockedtrivialperm(blocklengths(blockedperm)) -end -Base.invperm(blockedperm::BlockedTrivialPermutation) = blockedperm diff --git a/NDTensors/src/lib/TensorAlgebra/src/contract/allocate_output.jl b/NDTensors/src/lib/TensorAlgebra/src/contract/allocate_output.jl deleted file mode 100644 index 2beff4c5bc..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/contract/allocate_output.jl +++ /dev/null @@ -1,83 +0,0 @@ -using Base.PermutedDimsArrays: genperm - -# TODO: Use `ArrayLayouts`-like `MulAdd` object, -# i.e. `ContractAdd`? -function output_axes( - ::typeof(contract), - biperm_dest::BlockedPermutation{2}, - a1::AbstractArray, - biperm1::BlockedPermutation{2}, - a2::AbstractArray, - biperm2::BlockedPermutation{2}, - α::Number=true, -) - axes_codomain, axes_contracted = blockpermute(axes(a1), biperm1) - axes_contracted2, axes_domain = blockpermute(axes(a2), biperm2) - @assert axes_contracted == axes_contracted2 - return genperm((axes_codomain..., axes_domain...), invperm(Tuple(biperm_dest))) -end - -# Inner-product contraction. -# TODO: Use `ArrayLayouts`-like `MulAdd` object, -# i.e. `ContractAdd`? -function output_axes( - ::typeof(contract), - perm_dest::BlockedPermutation{0}, - a1::AbstractArray, - perm1::BlockedPermutation{1}, - a2::AbstractArray, - perm2::BlockedPermutation{1}, - α::Number=true, -) - axes_contracted = blockpermute(axes(a1), perm1) - axes_contracted′ = blockpermute(axes(a2), perm2) - @assert axes_contracted == axes_contracted′ - return () -end - -# Vec-mat. -function output_axes( - ::typeof(contract), - perm_dest::BlockedPermutation{1}, - a1::AbstractArray, - perm1::BlockedPermutation{1}, - a2::AbstractArray, - biperm2::BlockedPermutation{2}, - α::Number=true, -) - (axes_contracted,) = blockpermute(axes(a1), perm1) - axes_contracted′, axes_dest = blockpermute(axes(a2), biperm2) - @assert axes_contracted == axes_contracted′ - return genperm((axes_dest...,), invperm(Tuple(perm_dest))) -end - -# Mat-vec. -function output_axes( - ::typeof(contract), - perm_dest::BlockedPermutation{1}, - a1::AbstractArray, - perm1::BlockedPermutation{2}, - a2::AbstractArray, - biperm2::BlockedPermutation{1}, - α::Number=true, -) - axes_dest, axes_contracted = blockpermute(axes(a1), perm1) - (axes_contracted′,) = blockpermute(axes(a2), biperm2) - @assert axes_contracted == axes_contracted′ - return genperm((axes_dest...,), invperm(Tuple(perm_dest))) -end - -# TODO: Use `ArrayLayouts`-like `MulAdd` object, -# i.e. `ContractAdd`? -function allocate_output( - ::typeof(contract), - biperm_dest::BlockedPermutation, - a1::AbstractArray, - biperm1::BlockedPermutation, - a2::AbstractArray, - biperm2::BlockedPermutation, - α::Number=true, -) - axes_dest = output_axes(contract, biperm_dest, a1, biperm1, a2, biperm2, α) - return similar(a1, promote_type(eltype(a1), eltype(a2), typeof(α)), axes_dest) -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/contract/blockedperms.jl b/NDTensors/src/lib/TensorAlgebra/src/contract/blockedperms.jl deleted file mode 100644 index 60009de9ef..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/contract/blockedperms.jl +++ /dev/null @@ -1,32 +0,0 @@ -using ..BackendSelection: Algorithm -using .BaseExtensions: BaseExtensions - -function blockedperms( - f::typeof(contract), alg::Algorithm, dimnames_dest, dimnames1, dimnames2 -) - return blockedperms(f, dimnames_dest, dimnames1, dimnames2) -end - -# codomain <-- domain -function blockedperms(::typeof(contract), dimnames_dest, dimnames1, dimnames2) - codomain = Tuple(setdiff(dimnames1, dimnames2)) - contracted = Tuple(intersect(dimnames1, dimnames2)) - domain = Tuple(setdiff(dimnames2, dimnames1)) - - perm_codomain_dest = BaseExtensions.indexin(codomain, dimnames_dest) - perm_domain_dest = BaseExtensions.indexin(domain, dimnames_dest) - - perm_codomain1 = BaseExtensions.indexin(codomain, dimnames1) - perm_domain1 = BaseExtensions.indexin(contracted, dimnames1) - - perm_codomain2 = BaseExtensions.indexin(contracted, dimnames2) - perm_domain2 = BaseExtensions.indexin(domain, dimnames2) - - permblocks_dest = (perm_codomain_dest, perm_domain_dest) - biperm_dest = blockedperm(filter(!isempty, permblocks_dest)...) - permblocks1 = (perm_codomain1, perm_domain1) - biperm1 = blockedperm(filter(!isempty, permblocks1)...) - permblocks2 = (perm_codomain2, perm_domain2) - biperm2 = blockedperm(filter(!isempty, permblocks2)...) - return biperm_dest, biperm1, biperm2 -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/contract/contract.jl b/NDTensors/src/lib/TensorAlgebra/src/contract/contract.jl deleted file mode 100644 index 328be79387..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/contract/contract.jl +++ /dev/null @@ -1,120 +0,0 @@ -using ..BackendSelection: Algorithm, @Algorithm_str - -# TODO: Add `contract!!` definitions as pass-throughs to `contract!`. - -default_contract_alg() = Algorithm"matricize"() - -# Required interface if not using -# matricized contraction. -function contract!( - alg::Algorithm, - a_dest::AbstractArray, - biperm_dest::BlockedPermutation, - a1::AbstractArray, - biperm1::BlockedPermutation, - a2::AbstractArray, - biperm2::BlockedPermutation, - α::Number, - β::Number, -) - return error("Not implemented") -end - -function contract( - a1::AbstractArray, - labels1::Tuple, - a2::AbstractArray, - labels2::Tuple, - α::Number=true; - alg=default_contract_alg(), - kwargs..., -) - return contract(Algorithm(alg), a1, labels1, a2, labels2, α; kwargs...) -end - -function contract( - alg::Algorithm, - a1::AbstractArray, - labels1::Tuple, - a2::AbstractArray, - labels2::Tuple, - α::Number=true; - kwargs..., -) - labels_dest = output_labels(contract, alg, a1, labels1, a2, labels2, α; kwargs...) - return contract(alg, labels_dest, a1, labels1, a2, labels2, α; kwargs...), labels_dest -end - -function contract( - labels_dest::Tuple, - a1::AbstractArray, - labels1::Tuple, - a2::AbstractArray, - labels2::Tuple, - α::Number=true; - alg=default_contract_alg(), - kwargs..., -) - return contract(Algorithm(alg), labels_dest, a1, labels1, a2, labels2, α; kwargs...) -end - -function contract!( - a_dest::AbstractArray, - labels_dest::Tuple, - a1::AbstractArray, - labels1::Tuple, - a2::AbstractArray, - labels2::Tuple, - α::Number=true, - β::Number=false; - alg=default_contract_alg(), - kwargs..., -) - contract!(Algorithm(alg), a_dest, labels_dest, a1, labels1, a2, labels2, α, β; kwargs...) - return a_dest -end - -function contract( - alg::Algorithm, - labels_dest::Tuple, - a1::AbstractArray, - labels1::Tuple, - a2::AbstractArray, - labels2::Tuple, - α::Number=true; - kwargs..., -) - biperm_dest, biperm1, biperm2 = blockedperms(contract, labels_dest, labels1, labels2) - return contract(alg, biperm_dest, a1, biperm1, a2, biperm2, α; kwargs...) -end - -function contract!( - alg::Algorithm, - a_dest::AbstractArray, - labels_dest::Tuple, - a1::AbstractArray, - labels1::Tuple, - a2::AbstractArray, - labels2::Tuple, - α::Number, - β::Number; - kwargs..., -) - biperm_dest, biperm1, biperm2 = blockedperms(contract, labels_dest, labels1, labels2) - return contract!(alg, a_dest, biperm_dest, a1, biperm1, a2, biperm2, α, β; kwargs...) -end - -function contract( - alg::Algorithm, - biperm_dest::BlockedPermutation, - a1::AbstractArray, - biperm1::BlockedPermutation, - a2::AbstractArray, - biperm2::BlockedPermutation, - α::Number; - kwargs..., -) - a_dest = allocate_output(contract, biperm_dest, a1, biperm1, a2, biperm2, α) - contract!(alg, a_dest, biperm_dest, a1, biperm1, a2, biperm2, α, false; kwargs...) - return a_dest -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/contract/contract_matricize/contract.jl b/NDTensors/src/lib/TensorAlgebra/src/contract/contract_matricize/contract.jl deleted file mode 100644 index beb70104bb..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/contract/contract_matricize/contract.jl +++ /dev/null @@ -1,57 +0,0 @@ -using ..BackendSelection: @Algorithm_str -using LinearAlgebra: mul! - -function contract!( - alg::Algorithm"matricize", - a_dest::AbstractArray, - biperm_dest::BlockedPermutation, - a1::AbstractArray, - biperm1::BlockedPermutation, - a2::AbstractArray, - biperm2::BlockedPermutation, - α::Number, - β::Number, -) - a_dest_mat = fusedims(a_dest, biperm_dest) - a1_mat = fusedims(a1, biperm1) - a2_mat = fusedims(a2, biperm2) - _mul!(a_dest_mat, a1_mat, a2_mat, α, β) - splitdims!(a_dest, a_dest_mat, biperm_dest) - return a_dest -end - -# Matrix multiplication. -function _mul!( - a_dest::AbstractMatrix, a1::AbstractMatrix, a2::AbstractMatrix, α::Number, β::Number -) - mul!(a_dest, a1, a2, α, β) - return a_dest -end - -# Inner product. -function _mul!( - a_dest::AbstractArray{<:Any,0}, - a1::AbstractVector, - a2::AbstractVector, - α::Number, - β::Number, -) - a_dest[] = transpose(a1) * a2 * α + a_dest[] * β - return a_dest -end - -# Vec-mat. -function _mul!( - a_dest::AbstractVector, a1::AbstractVector, a2::AbstractMatrix, α::Number, β::Number -) - mul!(transpose(a_dest), transpose(a1), a2, α, β) - return a_dest -end - -# Mat-vec. -function _mul!( - a_dest::AbstractVector, a1::AbstractMatrix, a2::AbstractVector, α::Number, β::Number -) - mul!(a_dest, a1, a2, α, β) - return a_dest -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/contract/output_labels.jl b/NDTensors/src/lib/TensorAlgebra/src/contract/output_labels.jl deleted file mode 100644 index 1de28dd765..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/contract/output_labels.jl +++ /dev/null @@ -1,21 +0,0 @@ -using ..BackendSelection: Algorithm - -function output_labels( - f::typeof(contract), - alg::Algorithm, - a1::AbstractArray, - labels1, - a2::AbstractArray, - labels2, - α, -) - return output_labels(f, alg, labels1, labels2) -end - -function output_labels(f::typeof(contract), alg::Algorithm, labels1, labels2) - return output_labels(f, labels1, labels2) -end - -function output_labels(::typeof(contract), labels1, labels2) - return Tuple(symdiff(labels1, labels2)) -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/fusedims.jl b/NDTensors/src/lib/TensorAlgebra/src/fusedims.jl deleted file mode 100644 index c118dc6ab2..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/fusedims.jl +++ /dev/null @@ -1,69 +0,0 @@ -using .BaseExtensions: _permutedims, _permutedims! - -abstract type FusionStyle end - -struct ReshapeFusion <: FusionStyle end -struct BlockReshapeFusion <: FusionStyle end -struct SectorFusion <: FusionStyle end - -# Defaults to a simple reshape -combine_fusion_styles(style1::Style, style2::Style) where {Style<:FusionStyle} = Style() -combine_fusion_styles(style1::FusionStyle, style2::FusionStyle) = ReshapeFusion() -combine_fusion_styles(styles::FusionStyle...) = foldl(combine_fusion_styles, styles) -FusionStyle(axis::AbstractUnitRange) = ReshapeFusion() -function FusionStyle(axes::Tuple{Vararg{AbstractUnitRange}}) - return combine_fusion_styles(FusionStyle.(axes)...) -end -FusionStyle(a::AbstractArray) = FusionStyle(axes(a)) - -# Overload this version for most arrays -function fusedims(::ReshapeFusion, a::AbstractArray, axes::AbstractUnitRange...) - return reshape(a, axes) -end - -⊗(a::AbstractUnitRange) = a -function ⊗(a1::AbstractUnitRange, a2::AbstractUnitRange, as::AbstractUnitRange...) - return ⊗(a1, ⊗(a2, as...)) -end -⊗(a1::AbstractUnitRange, a2::AbstractUnitRange) = Base.OneTo(length(a1) * length(a2)) -⊗() = Base.OneTo(1) - -# Overload this version for most arrays -function fusedims(a::AbstractArray, axes::AbstractUnitRange...) - return fusedims(FusionStyle(a), a, axes...) -end - -# Overload this version for fusion tensors, array maps, etc. -function fusedims(a::AbstractArray, axesblocks::Tuple{Vararg{AbstractUnitRange}}...) - return fusedims(a, flatten_tuples(axesblocks)...) -end - -# Fix ambiguity issue -fusedims(a::AbstractArray{<:Any,0}, ::Vararg{Tuple{}}) = a - -# TODO: Is this needed? Maybe delete. -function fusedims(a::AbstractArray, permblocks...) - return fusedims(a, blockedperm(permblocks...; length=Val(ndims(a)))) -end - -function fuseaxes( - axes::Tuple{Vararg{AbstractUnitRange}}, blockedperm::AbstractBlockedPermutation -) - axesblocks = blockpermute(axes, blockedperm) - return map(block -> ⊗(block...), axesblocks) -end - -function fuseaxes(a::AbstractArray, blockedperm::AbstractBlockedPermutation) - return fuseaxes(axes(a), blockedperm) -end - -# Fuse adjacent dimensions -function fusedims(a::AbstractArray, blockedperm::BlockedTrivialPermutation) - axes_fused = fuseaxes(a, blockedperm) - return fusedims(a, axes_fused) -end - -function fusedims(a::AbstractArray, blockedperm::BlockedPermutation) - a_perm = _permutedims(a, Tuple(blockedperm)) - return fusedims(a_perm, trivialperm(blockedperm)) -end diff --git a/NDTensors/src/lib/TensorAlgebra/src/splitdims.jl b/NDTensors/src/lib/TensorAlgebra/src/splitdims.jl deleted file mode 100644 index 0554c613ba..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/src/splitdims.jl +++ /dev/null @@ -1,68 +0,0 @@ -using .BaseExtensions: _permutedims, _permutedims! - -to_axis(a::AbstractUnitRange) = a -to_axis(n::Integer) = Base.OneTo(n) - -function blockedaxes(a::AbstractArray, sizeblocks::Pair...) - axes_a = axes(a) - axes_split = tuple.(axes(a)) - for (dim, sizeblock) in sizeblocks - # TODO: Handle conversion from length to range! - axes_split = Base.setindex(axes_split, to_axis.(sizeblock), dim) - end - return axes_split -end - -# splitdims(randn(4, 4), 1:2, 1:2, 1:2, 1:2) -function splitdims(::ReshapeFusion, a::AbstractArray, axes::AbstractUnitRange...) - # TODO: Add `uncanonicalizedims`. - # TODO: Need `length` since `reshape` doesn't accept `axes`, - # maybe make a `reshape_axes` function. - return reshape(a, length.(axes)...) -end - -# splitdims(randn(4, 4), 1:2, 1:2, 1:2, 1:2) -function splitdims(a::AbstractArray, axes::AbstractUnitRange...) - return splitdims(FusionStyle(a), a, axes...) -end - -# splitdims(randn(4, 4), (1:2, 1:2), (1:2, 1:2)) -function splitdims(a::AbstractArray, axesblocks::Tuple{Vararg{AbstractUnitRange}}...) - # TODO: Add `uncanonicalizedims`. - return splitdims(a, flatten_tuples(axesblocks)...) -end - -# Fix ambiguity issue -splitdims(a::AbstractArray) = a - -# splitdims(randn(4, 4), (2, 2), (2, 2)) -function splitdims(a::AbstractArray, sizeblocks::Tuple{Vararg{Integer}}...) - return splitdims(a, map(x -> Base.OneTo.(x), sizeblocks)...) -end - -# splitdims(randn(4, 4), 2 => (1:2, 1:2)) -function splitdims(a::AbstractArray, sizeblocks::Pair...) - return splitdims(a, blockedaxes(a, sizeblocks...)...) -end - -# TODO: Is this needed? -function splitdims( - a::AbstractArray, - axes_dest::Tuple{Vararg{AbstractUnitRange}}, - blockedperm::BlockedPermutation, -) - # TODO: Pass grouped axes. - a_dest_perm = splitdims(a, axes_dest...) - a_dest = _permutedims(a_dest_perm, invperm(Tuple(blockedperm))) - return a_dest -end - -function splitdims!( - a_dest::AbstractArray, a::AbstractArray, blockedperm::BlockedPermutation -) - axes_dest = map(i -> axes(a_dest, i), Tuple(blockedperm)) - # TODO: Pass grouped axes. - a_dest_perm = splitdims(a, axes_dest...) - _permutedims!(a_dest, a_dest_perm, invperm(Tuple(blockedperm))) - return a_dest -end diff --git a/NDTensors/src/lib/TensorAlgebra/test/Project.toml b/NDTensors/src/lib/TensorAlgebra/test/Project.toml deleted file mode 100644 index 661098f08c..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/test/Project.toml +++ /dev/null @@ -1,9 +0,0 @@ -[deps] -BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" -EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -TensorOperations = "6aa20fa7-93e2-5fca-9bc0-fbd0db3c71a2" - -[compat] -TensorOperations = "4.1.1" \ No newline at end of file diff --git a/NDTensors/src/lib/TensorAlgebra/test/runtests.jl b/NDTensors/src/lib/TensorAlgebra/test/runtests.jl deleted file mode 100644 index c26bbcdc4b..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/test/runtests.jl +++ /dev/null @@ -1,4 +0,0 @@ -@eval module $(gensym()) -include("test_basics.jl") -include("../ext/TensorAlgebraGradedAxesExt/test/runtests.jl") -end diff --git a/NDTensors/src/lib/TensorAlgebra/test/test_basics.jl b/NDTensors/src/lib/TensorAlgebra/test/test_basics.jl deleted file mode 100644 index 95576a8bf5..0000000000 --- a/NDTensors/src/lib/TensorAlgebra/test/test_basics.jl +++ /dev/null @@ -1,199 +0,0 @@ -@eval module $(gensym()) -using BlockArrays: blockfirsts, blocklasts, blocklength, blocklengths, blocks -using Combinatorics: permutations -using EllipsisNotation: var".." -using LinearAlgebra: norm, qr -using NDTensors.TensorAlgebra: - TensorAlgebra, blockedperm, blockedperm_indexin, fusedims, splitdims -using NDTensors: NDTensors -include(joinpath(pkgdir(NDTensors), "test", "NDTensorsTestUtils", "NDTensorsTestUtils.jl")) -using .NDTensorsTestUtils: default_rtol -using Test: @test, @test_broken, @testset -const elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) -@testset "BlockedPermutation" begin - p = blockedperm((3, 4, 5), (2, 1)) - @test Tuple(p) === (3, 4, 5, 2, 1) - @test isperm(p) - @test length(p) == 5 - @test blocks(p) == ((3, 4, 5), (2, 1)) - @test blocklength(p) == 2 - @test blocklengths(p) == (3, 2) - @test blockfirsts(p) == (1, 4) - @test blocklasts(p) == (3, 5) - @test invperm(p) == blockedperm((5, 4, 1), (2, 3)) - - # Empty block. - p = blockedperm((3, 2), (), (1,)) - @test Tuple(p) === (3, 2, 1) - @test isperm(p) - @test length(p) == 3 - @test blocks(p) == ((3, 2), (), (1,)) - @test blocklength(p) == 3 - @test blocklengths(p) == (2, 0, 1) - @test blockfirsts(p) == (1, 3, 3) - @test blocklasts(p) == (2, 2, 3) - @test invperm(p) == blockedperm((3, 2), (), (1,)) - - # Split collection into `BlockedPermutation`. - p = blockedperm_indexin(("a", "b", "c", "d"), ("c", "a"), ("b", "d")) - @test p == blockedperm((3, 1), (2, 4)) - - # Singleton dimensions. - p = blockedperm((2, 3), 1) - @test p == blockedperm((2, 3), (1,)) - - # First dimensions are unspecified. - p = blockedperm(.., (4, 3)) - @test p == blockedperm(1, 2, (4, 3)) - # Specify length - p = blockedperm(.., (4, 3); length=Val(6)) - @test p == blockedperm(1, 2, 5, 6, (4, 3)) - - # Last dimensions are unspecified. - p = blockedperm((4, 3), ..) - @test p == blockedperm((4, 3), 1, 2) - # Specify length - p = blockedperm((4, 3), ..; length=Val(6)) - @test p == blockedperm((4, 3), 1, 2, 5, 6) - - # Middle dimensions are unspecified. - p = blockedperm((4, 3), .., 1) - @test p == blockedperm((4, 3), 2, 1) - # Specify length - p = blockedperm((4, 3), .., 1; length=Val(6)) - @test p == blockedperm((4, 3), 2, 5, 6, 1) - - # No dimensions are unspecified. - p = blockedperm((3, 2), .., 1) - @test p == blockedperm((3, 2), 1) -end -@testset "TensorAlgebra" begin - @testset "fusedims (eltype=$elt)" for elt in elts - a = randn(elt, 2, 3, 4, 5) - a_fused = fusedims(a, (1, 2), (3, 4)) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(a, 6, 20) - a_fused = fusedims(a, (3, 1), (2, 4)) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(permutedims(a, (3, 1, 2, 4)), (8, 15)) - a_fused = fusedims(a, (3, 1, 2), 4) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(permutedims(a, (3, 1, 2, 4)), (24, 5)) - a_fused = fusedims(a, .., (3, 1)) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(permutedims(a, (2, 4, 3, 1)), (3, 5, 8)) - a_fused = fusedims(a, (3, 1), ..) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(permutedims(a, (3, 1, 2, 4)), (8, 3, 5)) - a_fused = fusedims(a, .., (3, 1), 2) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(permutedims(a, (4, 3, 1, 2)), (5, 8, 3)) - a_fused = fusedims(a, (3, 1), .., 2) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(permutedims(a, (3, 1, 4, 2)), (8, 5, 3)) - a_fused = fusedims(a, (3, 1), ..) - @test eltype(a_fused) === elt - @test a_fused ≈ reshape(permutedims(a, (3, 1, 2, 4)), (8, 3, 5)) - end - @testset "splitdims (eltype=$elt)" for elt in elts - a = randn(elt, 6, 20) - a_split = splitdims(a, (2, 3), (5, 4)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (2, 3, 5, 4)) - a_split = splitdims(a, (1:2, 1:3), (1:5, 1:4)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (2, 3, 5, 4)) - a_split = splitdims(a, 2 => (5, 4), 1 => (2, 3)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (2, 3, 5, 4)) - a_split = splitdims(a, 2 => (1:5, 1:4), 1 => (1:2, 1:3)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (2, 3, 5, 4)) - a_split = splitdims(a, 2 => (5, 4)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (6, 5, 4)) - a_split = splitdims(a, 2 => (1:5, 1:4)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (6, 5, 4)) - a_split = splitdims(a, 1 => (2, 3)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (2, 3, 20)) - a_split = splitdims(a, 1 => (1:2, 1:3)) - @test eltype(a_split) === elt - @test a_split ≈ reshape(a, (2, 3, 20)) - end - using TensorOperations: TensorOperations - @testset "contract (eltype1=$elt1, eltype2=$elt2)" for elt1 in elts, elt2 in elts - dims = (2, 3, 4, 5, 6, 7, 8, 9, 10) - labels = (:a, :b, :c, :d, :e, :f, :g, :h, :i) - for (d1s, d2s, d_dests) in ( - ((1, 2), (1, 2), ()), - ((1, 2), (2, 1), ()), - ((1, 2), (2, 1, 3), (3,)), - ((1, 2, 3), (2, 1), (3,)), - ((1, 2), (2, 3), (1, 3)), - ((1, 2), (2, 3), (3, 1)), - ((2, 1), (2, 3), (3, 1)), - ((1, 2, 3), (2, 3, 4), (1, 4)), - ((1, 2, 3), (2, 3, 4), (4, 1)), - ((3, 2, 1), (4, 2, 3), (4, 1)), - ((1, 2, 3), (3, 4), (1, 2, 4)), - ((1, 2, 3), (3, 4), (4, 1, 2)), - ((1, 2, 3), (3, 4), (2, 4, 1)), - ((3, 1, 2), (3, 4), (2, 4, 1)), - ((3, 2, 1), (4, 3), (2, 4, 1)), - ((1, 2, 3, 4, 5, 6), (4, 5, 6, 7, 8, 9), (1, 2, 3, 7, 8, 9)), - ((2, 4, 5, 1, 6, 3), (6, 4, 9, 8, 5, 7), (1, 7, 2, 8, 3, 9)), - ) - a1 = randn(elt1, map(i -> dims[i], d1s)) - labels1 = map(i -> labels[i], d1s) - a2 = randn(elt2, map(i -> dims[i], d2s)) - labels2 = map(i -> labels[i], d2s) - labels_dest = map(i -> labels[i], d_dests) - - # Don't specify destination labels - a_dest, labels_dest′ = TensorAlgebra.contract(a1, labels1, a2, labels2) - a_dest_tensoroperations = TensorOperations.tensorcontract( - labels_dest′, a1, labels1, a2, labels2 - ) - @test a_dest ≈ a_dest_tensoroperations - - # Specify destination labels - a_dest = TensorAlgebra.contract(labels_dest, a1, labels1, a2, labels2) - a_dest_tensoroperations = TensorOperations.tensorcontract( - labels_dest, a1, labels1, a2, labels2 - ) - @test a_dest ≈ a_dest_tensoroperations - - # Specify α and β - elt_dest = promote_type(elt1, elt2) - # TODO: Using random `α`, `β` causing - # random test failures, investigate why. - α = elt_dest(1.2) # randn(elt_dest) - β = elt_dest(2.4) # randn(elt_dest) - a_dest_init = randn(elt_dest, map(i -> dims[i], d_dests)) - a_dest = copy(a_dest_init) - TensorAlgebra.contract!(a_dest, labels_dest, a1, labels1, a2, labels2, α, β) - a_dest_tensoroperations = TensorOperations.tensorcontract( - labels_dest, a1, labels1, a2, labels2 - ) - ## Here we loosened the tolerance because of some floating point roundoff issue. - ## with Float32 numbers - @test a_dest ≈ α * a_dest_tensoroperations + β * a_dest_init rtol = - 50 * default_rtol(elt_dest) - end - end -end -@testset "qr (eltype=$elt)" for elt in elts - a = randn(elt, 5, 4, 3, 2) - labels_a = (:a, :b, :c, :d) - labels_q = (:b, :a) - labels_r = (:d, :c) - q, r = qr(a, labels_a, labels_q, labels_r) - label_qr = :qr - a′ = TensorAlgebra.contract( - labels_a, q, (labels_q..., label_qr), r, (label_qr, labels_r...) - ) - @test a ≈ a′ -end -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/.JuliaFormatter.toml b/NDTensors/src/lib/TypeParameterAccessors/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl b/NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl deleted file mode 100644 index 3333cd417b..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl +++ /dev/null @@ -1,21 +0,0 @@ -module TypeParameterAccessors -include("interface.jl") -include("to_unionall.jl") -include("parameters.jl") -include("abstractposition.jl") -include("abstracttypeparameter.jl") -include("type_parameters.jl") -include("position.jl") -include("parameter.jl") -include("is_parameter_specified.jl") -include("unspecify_parameters.jl") -include("set_parameters.jl") -include("specify_parameters.jl") -include("default_parameters.jl") -include("ndims.jl") -include("base/abstractarray.jl") -include("base/similartype.jl") -include("base/array.jl") -include("base/linearalgebra.jl") -include("base/stridedviews.jl") -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/abstractposition.jl b/NDTensors/src/lib/TypeParameterAccessors/src/abstractposition.jl deleted file mode 100644 index 4508c180ae..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/abstractposition.jl +++ /dev/null @@ -1,3 +0,0 @@ -struct Position{Pos} end -Position(pos) = Position{pos}() -Base.Int(pos::Position) = Int(parameter(typeof(pos))) diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/abstracttypeparameter.jl b/NDTensors/src/lib/TypeParameterAccessors/src/abstracttypeparameter.jl deleted file mode 100644 index 65f07c9cff..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/abstracttypeparameter.jl +++ /dev/null @@ -1,12 +0,0 @@ -abstract type AbstractTypeParameter end -AbstractTypeParameter(param::AbstractTypeParameter) = param -wrapped_type_parameter(param) = AbstractTypeParameter(param) -wrapped_type_parameter(type::Type, pos) = AbstractTypeParameter(parameter(type, pos)) - -struct TypeParameter{Param} <: AbstractTypeParameter end -TypeParameter(param) = TypeParameter{param}() -TypeParameter(param::TypeParameter) = param -AbstractTypeParameter(param) = TypeParameter(param) - -struct UnspecifiedTypeParameter <: AbstractTypeParameter end -AbstractTypeParameter(param::TypeVar) = UnspecifiedTypeParameter() diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/base/abstractarray.jl b/NDTensors/src/lib/TypeParameterAccessors/src/base/abstractarray.jl deleted file mode 100644 index 89e38d3b2f..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/base/abstractarray.jl +++ /dev/null @@ -1,95 +0,0 @@ -struct Self end - -parameter(type::Type, pos::Self) = type -function set_type_parameter(type::Type, pos::Self, param) - return error("Can't set the parent type of an unwrapped array type.") -end - -function set_eltype(array::AbstractArray, param) - return convert(set_eltype(typeof(array), param), array) -end - -## This will fail if position of `ndims` is not defined for `type` -function set_ndims(type::Type{<:AbstractArray}, param) - return set_type_parameter(type, ndims, param) -end -function set_ndims(type::Type{<:AbstractArray}, param::NDims) - return set_type_parameter(type, ndims, ndims(param)) -end - -using SimpleTraits: SimpleTraits, @traitdef, @traitimpl - -# Trait indicating if the AbstractArray type is an array wrapper. -# Assumes that it implements `NDTensors.parenttype`. -@traitdef IsWrappedArray{ArrayType} - -#! format: off -@traitimpl IsWrappedArray{ArrayType} <- is_wrapped_array(ArrayType) -#! format: on - -parenttype(type::Type{<:AbstractArray}) = parameter(type, parenttype) -parenttype(object::AbstractArray) = parenttype(typeof(object)) -position(::Type{<:AbstractArray}, ::typeof(parenttype)) = Self() - -is_wrapped_array(arraytype::Type{<:AbstractArray}) = (parenttype(arraytype) ≠ arraytype) -@inline is_wrapped_array(array::AbstractArray) = is_wrapped_array(typeof(array)) -@inline is_wrapped_array(object) = false - -using SimpleTraits: Not, @traitfn - -@traitfn function unwrap_array_type( - arraytype::Type{ArrayType} -) where {ArrayType; IsWrappedArray{ArrayType}} - return unwrap_array_type(parenttype(arraytype)) -end - -@traitfn function unwrap_array_type( - arraytype::Type{ArrayType} -) where {ArrayType; !IsWrappedArray{ArrayType}} - return arraytype -end - -# For working with instances. -unwrap_array_type(array::AbstractArray) = unwrap_array_type(typeof(array)) - -function set_parenttype(t::Type, param) - return set_type_parameter(t, parenttype, param) -end - -@traitfn function set_eltype( - type::Type{ArrayType}, param -) where {ArrayType <: AbstractArray; IsWrappedArray{ArrayType}} - new_parenttype = set_eltype(parenttype(type), param) - # Need to set both in one `set_type_parameters` call to avoid - # conflicts in type parameter constraints of certain wrapper types. - return set_type_parameters(type, (eltype, parenttype), (param, new_parenttype)) -end - -@traitfn function set_eltype( - type::Type{ArrayType}, param -) where {ArrayType <: AbstractArray; !IsWrappedArray{ArrayType}} - return set_type_parameter(type, eltype, param) -end - -# These are generic fallback definitions. By convention, -# this is very commonly true of `AbstractArray` subtypes -# but it may not be correct, but it is very convenient -# to define this to make more operations "just work" -# on most AbstractArrays. -position(type::Type{<:AbstractArray}, ::typeof(eltype)) = Position(1) -position(type::Type{<:AbstractArray}, ::typeof(ndims)) = Position(2) - -default_type_parameters(::Type{<:AbstractArray}) = (Float64, 1) - -for wrapper in [:PermutedDimsArray, :(Base.ReshapedArray), :SubArray] - @eval begin - position(type::Type{<:$wrapper}, ::typeof(eltype)) = Position(1) - position(type::Type{<:$wrapper}, ::typeof(ndims)) = Position(2) - end -end -for wrapper in [:(Base.ReshapedArray), :SubArray] - @eval position(type::Type{<:$wrapper}, ::typeof(parenttype)) = Position(3) -end -for wrapper in [:PermutedDimsArray] - @eval position(type::Type{<:$wrapper}, ::typeof(parenttype)) = Position(5) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/base/array.jl b/NDTensors/src/lib/TypeParameterAccessors/src/base/array.jl deleted file mode 100644 index 247c73ba1f..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/base/array.jl +++ /dev/null @@ -1,2 +0,0 @@ -position(::Type{<:Array}, ::typeof(eltype)) = Position(1) -position(::Type{<:Array}, ::typeof(ndims)) = Position(2) diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/base/linearalgebra.jl b/NDTensors/src/lib/TypeParameterAccessors/src/base/linearalgebra.jl deleted file mode 100644 index 3d818cab16..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/base/linearalgebra.jl +++ /dev/null @@ -1,25 +0,0 @@ -using LinearAlgebra: - Adjoint, - Diagonal, - Hermitian, - LowerTriangular, - Symmetric, - Transpose, - UnitLowerTriangular, - UnitUpperTriangular, - UpperTriangular - -for wrapper in [ - :Transpose, - :Adjoint, - :Symmetric, - :Hermitian, - :UpperTriangular, - :LowerTriangular, - :UnitUpperTriangular, - :UnitLowerTriangular, - :Diagonal, -] - @eval position(::Type{<:$wrapper}, ::typeof(eltype)) = Position(1) - @eval position(::Type{<:$wrapper}, ::typeof(parenttype)) = Position(2) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/base/similartype.jl b/NDTensors/src/lib/TypeParameterAccessors/src/base/similartype.jl deleted file mode 100644 index f6fed09885..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/base/similartype.jl +++ /dev/null @@ -1,88 +0,0 @@ -""" -`set_indstype` should be overloaded for -types with structured dimensions, -like `OffsetArrays` or named indices -(such as ITensors). -""" -function set_indstype(arraytype::Type{<:AbstractArray}, dims::Tuple) - return set_ndims(arraytype, NDims(length(dims))) -end - -function similartype(arraytype::Type{<:AbstractArray}, eltype::Type, ndims::NDims) - return similartype(similartype(arraytype, eltype), ndims) -end - -function similartype(arraytype::Type{<:AbstractArray}, eltype::Type, dims::Tuple) - return similartype(similartype(arraytype, eltype), dims) -end - -@traitfn function similartype( - arraytype::Type{ArrayT} -) where {ArrayT; !IsWrappedArray{ArrayT}} - return arraytype -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, eltype::Type -) where {ArrayT; !IsWrappedArray{ArrayT}} - return set_eltype(arraytype, eltype) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, dims::Tuple -) where {ArrayT; !IsWrappedArray{ArrayT}} - return set_indstype(arraytype, dims) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, ndims::NDims -) where {ArrayT; !IsWrappedArray{ArrayT}} - return set_ndims(arraytype, ndims) -end - -function similartype( - arraytype::Type{<:AbstractArray}, dim1::Base.DimOrInd, dim_rest::Base.DimOrInd... -) - return similartype(arraytype, (dim1, dim_rest...)) -end - -## Wrapped arrays -@traitfn function similartype( - arraytype::Type{ArrayT} -) where {ArrayT; IsWrappedArray{ArrayT}} - return similartype(unwrap_array_type(arraytype), NDims(arraytype)) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, eltype::Type -) where {ArrayT; IsWrappedArray{ArrayT}} - return similartype(unwrap_array_type(arraytype), eltype, NDims(arraytype)) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, dims::Tuple -) where {ArrayT; IsWrappedArray{ArrayT}} - return similartype(unwrap_array_type(arraytype), dims) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, ndims::NDims -) where {ArrayT; IsWrappedArray{ArrayT}} - return similartype(unwrap_array_type(arraytype), ndims) -end - -# This is for uniform `Diag` storage which uses -# a Number as the data type. -# TODO: Delete this when we change to using a -# `FillArray` instead. This is a stand-in -# to make things work with the current design. -function similartype(numbertype::Type{<:Number}) - return numbertype -end - -# Instances -function similartype(array::AbstractArray, eltype::Type, dims...) - return similartype(typeof(array), eltype, dims...) -end -similartype(array::AbstractArray, eltype::Type) = similartype(typeof(array), eltype) -similartype(array::AbstractArray, dims...) = similartype(typeof(array), dims...) diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/base/stridedviews.jl b/NDTensors/src/lib/TypeParameterAccessors/src/base/stridedviews.jl deleted file mode 100644 index f74ae5c465..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/base/stridedviews.jl +++ /dev/null @@ -1,3 +0,0 @@ -using StridedViews: StridedView - -@eval position(type::Type{<:StridedView}, ::typeof(parenttype)) = Position(3) diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/default_parameters.jl b/NDTensors/src/lib/TypeParameterAccessors/src/default_parameters.jl deleted file mode 100644 index 79f7a96dfe..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/default_parameters.jl +++ /dev/null @@ -1,62 +0,0 @@ -default_type_parameters(type::Type) = error("Not implemented") -function default_type_parameters(type::Type, positions::Tuple) - return default_type_parameter.(type, positions) -end -default_type_parameters(object) = default_type_parameters(typeof(object)) -function default_type_parameters(object, positions::Tuple) - return default_type_parameters(typeof(object), positions) -end -function default_type_parameter(type::Type, pos::Position) - return default_type_parameters(type)[Int(pos)] -end -function default_type_parameter(type::Type, pos) - return default_type_parameter(type, position(type, pos)) -end -function default_type_parameter(object, pos) - return default_type_parameter(typeof(object), pos) -end - -# Wrapping type parameters to improve type stability. -function wrapped_default_type_parameters(type::Type) - return wrapped_type_parameter.(default_type_parameters(type)) -end -function wrapped_default_type_parameters(type::Type, positions::Tuple) - return wrapped_default_type_parameter.(type, positions) -end -wrapped_default_type_parameters(object) = wrapped_default_type_parameters(typeof(object)) -function wrapped_default_type_parameters(object, positions::Tuple) - return wrapped_default_type_parameters(typeof(object), positions) -end -function wrapped_default_type_parameter(type::Type, pos::Position) - return wrapped_default_type_parameters(type)[Int(pos)] -end -function wrapped_default_type_parameter(type::Type, pos) - return wrapped_default_type_parameter(type, position(type, pos)) -end -function wrapped_default_type_parameter(object, pos) - return wrapped_default_type_parameter(typeof(object), pos) -end - -function set_default_type_parameter(type::Type, pos) - return set_type_parameter(type, pos, wrapped_default_type_parameter(type, pos)) -end -function set_default_type_parameters(type::Type) - return set_type_parameters(type, wrapped_default_type_parameters(type)) -end -function set_default_type_parameters(type::Type, positions::Tuple) - return set_type_parameters( - type, positions, wrapped_default_type_parameters(type, positions) - ) -end - -function specify_default_type_parameter(type::Type, pos) - return specify_type_parameter(type, pos, wrapped_default_type_parameter(type, pos)) -end -function specify_default_type_parameters(type::Type) - return specify_type_parameters(type, wrapped_default_type_parameters(type)) -end -function specify_default_type_parameters(type::Type, positions::Tuple) - return specify_type_parameters( - type, positions, wrapped_default_type_parameters(type, positions) - ) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/interface.jl b/NDTensors/src/lib/TypeParameterAccessors/src/interface.jl deleted file mode 100644 index 7eaa1391f1..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/interface.jl +++ /dev/null @@ -1,22 +0,0 @@ -""" - position(type::Type, position_name)::Position - -An optional interface function. Defining this allows accessing a parameter -at the defined position using the `position_name`. - -For example, defining `TypeParameterAccessors.position(::Type{<:MyType}, ::typeof(eltype)) = Position(1)` -allows accessing the first type parameter with `type_parameter(MyType(...), eltype)`, -in addition to the standard `type_parameter(MyType(...), 1)` or `type_parameter(MyType(...), Position(1))`. -""" -function position end - -""" - default_parameters(type::Type)::Tuple - -An optional interface function. Defining this allows filling type parameters -of the specified type with default values. - -This function should output a Tuple of the default values, with exactly -one for each type parameter slot of the type. -""" -function default_type_parameters end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/is_parameter_specified.jl b/NDTensors/src/lib/TypeParameterAccessors/src/is_parameter_specified.jl deleted file mode 100644 index 014e5089eb..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/is_parameter_specified.jl +++ /dev/null @@ -1,5 +0,0 @@ -is_specified_parameter(param::TypeParameter) = true -is_specified_parameter(param::UnspecifiedTypeParameter) = false -function is_parameter_specified(type::Type, pos) - return is_specified_parameter(wrapped_type_parameter(type, pos)) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/ndims.jl b/NDTensors/src/lib/TypeParameterAccessors/src/ndims.jl deleted file mode 100644 index f640763583..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/ndims.jl +++ /dev/null @@ -1,6 +0,0 @@ -struct NDims{ndims} end -Base.ndims(::NDims{ndims}) where {ndims} = ndims - -NDims(ndims::Integer) = NDims{ndims}() -NDims(arraytype::Type{<:AbstractArray}) = NDims(ndims(arraytype)) -NDims(array::AbstractArray) = NDims(typeof(array)) diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/parameter.jl b/NDTensors/src/lib/TypeParameterAccessors/src/parameter.jl deleted file mode 100644 index 5b3554fcf7..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/parameter.jl +++ /dev/null @@ -1,3 +0,0 @@ -parameter(type::Type, pos) = parameter(type, position(type, pos)) -parameter(type::Type, pos::Position) = parameters(type)[Int(pos)] -parameter(type::Type) = only(parameters(type)) diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/parameters.jl b/NDTensors/src/lib/TypeParameterAccessors/src/parameters.jl deleted file mode 100644 index f6059fdf02..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/parameters.jl +++ /dev/null @@ -1,18 +0,0 @@ -# JULIA_INTERNALS: Warning! This code relies on undocumented -# internal details of the Julia language. -# It could break from version to version of Julia. - -# The signature `parameters(::Type{type}) where {type}` -# doesn't work if `type` is a `DataType` with `TypeVar`s. -function _parameters(type::Type) - return Tuple(Base.unwrap_unionall(type).parameters) -end -@generated function parameters(type_type::Type) - type = only(type_type.parameters) - return _parameters(type) -end -parameters(object) = parameters(typeof(object)) - -nparameters(type_or_object) = length(parameters(type_or_object)) - -eachposition(type_or_object) = ntuple(Position, Val(nparameters(type_or_object))) diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/position.jl b/NDTensors/src/lib/TypeParameterAccessors/src/position.jl deleted file mode 100644 index aff80a8197..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/position.jl +++ /dev/null @@ -1,11 +0,0 @@ -# These definitions help with generic code, where -# we don't know what kind of position will be passed -# but we want to canonicalize to `Position` positions. -position(type::Type, pos::Position) = pos -position(type::Type, pos::Int) = Position(pos) -# Used for named positions. -function position(type::Type, pos) - return error( - "Type parameter position not defined for type `$(type)` and position name `$(pos)`." - ) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/set_parameters.jl b/NDTensors/src/lib/TypeParameterAccessors/src/set_parameters.jl deleted file mode 100644 index 6ab25d2d9d..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/set_parameters.jl +++ /dev/null @@ -1,46 +0,0 @@ -function _set_type_parameter(type::Type, pos::Int, param) - params = Base.setindex(parameters(type), param, pos) - return new_parameters(type, params) -end -@generated function set_type_parameter( - type_type::Type, pos_type::Position, param_type::TypeParameter -) - type = parameter(type_type) - pos = parameter(pos_type) - param = parameter(param_type) - return _set_type_parameter(type, pos, param) -end -function set_type_parameter(type::Type, pos, param) - return set_type_parameter(type, position(type, pos), param) -end -function set_type_parameter(type::Type, pos::Position, param) - return set_type_parameter(type, pos, TypeParameter(param)) -end -function set_type_parameter(type::Type, pos::Position, param::UnspecifiedTypeParameter) - return unspecify_type_parameter(type, pos) -end - -function _set_type_parameters(type::Type, positions::Tuple{Vararg{Int}}, params::Tuple) - @assert length(positions) == length(params) - new_params = parameters(type) - for i in 1:length(positions) - new_params = Base.setindex(new_params, params[i], positions[i]) - end - return new_parameters(type, new_params) -end -@generated function set_type_parameters( - type_type::Type, - positions_type::Tuple{Vararg{Position}}, - params_type::Tuple{Vararg{TypeParameter}}, -) - type = parameter(type_type) - positions = parameter.(parameters(positions_type)) - params = parameter.(parameters(params_type)) - return _set_type_parameters(type, positions, params) -end -function set_type_parameters(type::Type, positions::Tuple, params::Tuple) - return set_type_parameters(type, position.(type, positions), TypeParameter.(params)) -end -function set_type_parameters(type::Type, params::Tuple) - return set_type_parameters(type, eachposition(type), params) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/specify_parameters.jl b/NDTensors/src/lib/TypeParameterAccessors/src/specify_parameters.jl deleted file mode 100644 index 8c424c286e..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/specify_parameters.jl +++ /dev/null @@ -1,30 +0,0 @@ -function specify_type_parameter(type::Type, pos, param) - is_parameter_specified(type, pos) && return type - return set_type_parameter(type, pos, param) -end - -function _specify_type_parameters(type::Type, positions::Tuple{Vararg{Int}}, params::Tuple) - new_params = parameters(type) - for i in 1:length(positions) - if !is_parameter_specified(type, positions[i]) - new_params = Base.setindex(new_params, params[i], positions[i]) - end - end - return new_parameters(type, new_params) -end -@generated function specify_type_parameters( - type_type::Type, - positions_type::Tuple{Vararg{Position}}, - params_type::Tuple{Vararg{TypeParameter}}, -) - type = parameter(type_type) - positions = parameter.(parameters(positions_type)) - params = parameter.(parameters(params_type)) - return _specify_type_parameters(type, positions, params) -end -function specify_type_parameters(type::Type, positions::Tuple, params::Tuple) - return specify_type_parameters(type, position.(type, positions), TypeParameter.(params)) -end -function specify_type_parameters(type::Type, params::Tuple) - return specify_type_parameters(type, eachposition(type), params) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/to_unionall.jl b/NDTensors/src/lib/TypeParameterAccessors/src/to_unionall.jl deleted file mode 100644 index 449715ef8e..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/to_unionall.jl +++ /dev/null @@ -1,17 +0,0 @@ -# JULIA_INTERNALS: Warning! This code relies on undocumented -# internal details of the Julia language. -# It could break from version to version of Julia. - -# Similar to `Base.rewrap_unionall` but handles -# more general cases of `TypeVar` parameters. -@generated function to_unionall(type_type::Type) - type = only(type_type.parameters) - params = Base.unwrap_unionall(type).parameters - for i in reverse(eachindex(params)) - param = params[i] - if param isa TypeVar - type = UnionAll(param, type) - end - end - return type -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/type_parameters.jl b/NDTensors/src/lib/TypeParameterAccessors/src/type_parameters.jl deleted file mode 100644 index bbdb7375d1..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/type_parameters.jl +++ /dev/null @@ -1,17 +0,0 @@ -type_parameter(param::TypeParameter) = parameter(typeof(param)) -function type_parameter(param::UnspecifiedTypeParameter) - return error("The requested type parameter isn't specified.") -end -function type_parameter(type::Type, pos) - return type_parameter(wrapped_type_parameter(type, pos)) -end -function type_parameter(object, pos) - return type_parameter(typeof(object), pos) -end -function type_parameter(type_or_object) - return only(type_parameters(type_or_object)) -end - -function type_parameters(type_or_object, positions=eachposition(type_or_object)) - return map(pos -> type_parameter(type_or_object, pos), positions) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/unspecify_parameters.jl b/NDTensors/src/lib/TypeParameterAccessors/src/unspecify_parameters.jl deleted file mode 100644 index be0851db86..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/src/unspecify_parameters.jl +++ /dev/null @@ -1,45 +0,0 @@ -function _unspecify_type_parameters(type::Type) - return Base.typename(type).wrapper -end -@generated function unspecify_type_parameters(type_type::Type) - type = parameter(type_type) - return _unspecify_type_parameters(type) -end - -# Like `set_parameters` but less strict, i.e. it allows -# setting with `TypeVar` while `set_parameters` would error. -function new_parameters(type::Type, params) - return to_unionall(unspecify_type_parameters(type){params...}) -end - -function _unspecify_type_parameter(type::Type, pos::Int) - !is_parameter_specified(type, pos) && return type - unspecified_param = parameter(unspecify_type_parameters(type), pos) - params = Base.setindex(parameters(type), unspecified_param, pos) - return new_parameters(type, params) -end -@generated function unspecify_type_parameter(type_type::Type, pos_type::Position) - type = parameter(type_type) - pos = parameter(pos_type) - return _unspecify_type_parameter(type, pos) -end -function unspecify_type_parameter(type::Type, pos) - return unspecify_type_parameter(type, position(type, pos)) -end - -function _unspecify_type_parameters(type::Type, positions::Tuple{Vararg{Int}}) - for pos in positions - type = unspecify_type_parameter(type, pos) - end - return type -end -@generated function unspecify_type_parameters( - type_type::Type, positions_type::Tuple{Vararg{Position}} -) - type = parameter(type_type) - positions = parameter.(parameters(positions_type)) - return _unspecify_type_parameters(type, positions) -end -function unspecify_type_parameters(type::Type, positions::Tuple) - return unspecify_type_parameters(type, position.(type, positions)) -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/Project.toml b/NDTensors/src/lib/TypeParameterAccessors/test/Project.toml deleted file mode 100644 index 372840c75d..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -StridedViews = "4db3bf67-4bd7-4b4e-b153-31dc3fb37143" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl b/NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl deleted file mode 100644 index 7c5ffc416d..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl +++ /dev/null @@ -1,10 +0,0 @@ -@eval module $(gensym()) -using Test: @testset -@testset "TypeParameterAccessors.jl" begin - include("test_basics.jl") - include("test_defaults.jl") - include("test_custom_types.jl") - include("test_wrappers.jl") - include("test_similartype.jl") -end -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/test_basics.jl b/NDTensors/src/lib/TypeParameterAccessors/test/test_basics.jl deleted file mode 100644 index 7df288f3dd..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/test_basics.jl +++ /dev/null @@ -1,85 +0,0 @@ -@eval module $(gensym()) -using Test: @test_throws, @testset -using NDTensors.TypeParameterAccessors: - TypeParameterAccessors, - Position, - TypeParameter, - set_type_parameter, - set_type_parameters, - specify_type_parameter, - specify_type_parameters, - type_parameter, - type_parameters, - unspecify_type_parameter, - unspecify_type_parameters -include("utils/test_inferred.jl") -@testset "TypeParameterAccessors basics" begin - @testset "Get parameters" begin - @test_inferred type_parameter(AbstractArray{Float64}, 1) == Float64 wrapped = true - @test_inferred type_parameter(AbstractArray{Float64}, Position(1)) == Float64 - @test_inferred type_parameter(AbstractArray{Float64}, eltype) == Float64 - @test_inferred type_parameter(AbstractMatrix{Float64}, ndims) == 2 - - @test_inferred type_parameter(Array{Float64}, 1) == Float64 wrapped = true - @test_inferred type_parameter(Array{Float64}, Position(1)) == Float64 - @test_inferred type_parameter(Val{3}) == 3 - @test_throws ErrorException type_parameter(Array, 1) - @test_inferred type_parameter(Array{Float64}, eltype) == Float64 - @test_inferred type_parameter(Matrix{Float64}, ndims) == 2 - @test_throws ErrorException type_parameter(Array{Float64}, ndims) == 2 - @test_inferred type_parameters(Matrix{Float64}, (2, eltype)) == (2, Float64) wrapped = - true - @test_inferred type_parameters(Matrix{Float64}, (Position(2), eltype)) == (2, Float64) - end - @testset "Set parameters" begin - @test_inferred set_type_parameter(Array, 1, Float64) == Array{Float64} wrapped = true - @test_inferred set_type_parameter(Array, Position(1), Float64) == Array{Float64} - @test_inferred set_type_parameter(Array, 2, 2) == Matrix wrapped = true - @test_inferred set_type_parameter(Array, eltype, Float32) == Array{Float32} - @test_inferred set_type_parameters( - Array, (eltype, Position(2)), (TypeParameter(Float32), TypeParameter(3)) - ) == Array{Float32,3} - @test_inferred set_type_parameters(Array, (eltype, 2), (Float32, 3)) == Array{Float32,3} wrapped = - true - - # TODO: This should infer without wrapping but doesn't. - @test_inferred set_type_parameters( - Array, (eltype, Position(2)), (Float32, TypeParameter(3)) - ) == Array{Float32,3} wrapped = true - end - @testset "Specify parameters" begin - @test_inferred specify_type_parameter(Array, 1, Float64) == Array{Float64} wrapped = - true - @test_inferred specify_type_parameter(Array, Position(1), Float64) == Array{Float64} - @test_inferred specify_type_parameters(Matrix, (2, 1), (4, Float32)) == Matrix{Float32} wrapped = - true - @test_inferred specify_type_parameters(Array, (Float64, 2)) == Matrix{Float64} wrapped = - true - @test_inferred specify_type_parameter(Array, eltype, Float32) == Array{Float32} - @test_inferred specify_type_parameters(Array, (eltype, 2), (Float32, 3)) == - Array{Float32,3} wrapped = true - end - @testset "Unspecify parameters" begin - @test_inferred unspecify_type_parameter(Vector, 2) == Array wrapped = true - @test_inferred unspecify_type_parameter(Vector, Position(2)) == Array - @test_inferred unspecify_type_parameter(Vector{Float64}, eltype) == Vector - @test_inferred unspecify_type_parameters(Vector{Float64}) == Array - @test_inferred unspecify_type_parameters(Vector{Float64}, (eltype, 2)) == Array wrapped = - true - @test_inferred unspecify_type_parameters(Vector{Float64}, (eltype, Position(2))) == - Array - end - @testset "On objects" begin - @test_inferred type_parameter(Val{3}()) == 3 - @test_inferred type_parameter(Val{Float32}()) == Float32 - a = randn(Float32, (2, 2, 2)) - @test_inferred type_parameter(a, 1) == Float32 wrapped = true - @test_inferred type_parameter(a, eltype) == Float32 - @test_inferred type_parameter(a, Position(1)) == Float32 - @test_inferred type_parameter(a, 2) == 3 wrapped = true - @test_inferred type_parameter(a, ndims) == 3 - @test_inferred type_parameters(a) == (Float32, 3) - @test_inferred type_parameters(a, (2, eltype)) == (3, Float32) wrapped = true - end -end -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/test_custom_types.jl b/NDTensors/src/lib/TypeParameterAccessors/test/test_custom_types.jl deleted file mode 100644 index 86d99cd7d1..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/test_custom_types.jl +++ /dev/null @@ -1,78 +0,0 @@ -@eval module $(gensym()) -using Test: @testset -@testset "TypeParameterAccessors custom types" begin - @eval module $(gensym()) - using Test: @testset - using NDTensors.TypeParameterAccessors: - TypeParameterAccessors, - Position, - default_type_parameter, - default_type_parameters, - set_default_type_parameter, - set_default_type_parameters, - set_type_parameter, - set_type_parameters, - specify_default_type_parameter, - specify_default_type_parameters, - specify_type_parameter, - specify_type_parameters, - type_parameter, - type_parameters, - unspecify_type_parameter, - unspecify_type_parameters - include("utils/test_inferred.jl") - @testset "TypeParameterAccessors, named positions and defaults" begin - struct MyType{P1,P2} end - TypeParameterAccessors.default_type_parameters(::Type{<:MyType}) = (:P1, :P2) - - @test_inferred default_type_parameter(MyType, 1) == :P1 wrapped = true - @test_inferred default_type_parameter(MyType, Position(1)) == :P1 - @test_inferred default_type_parameter(MyType, 2) == :P2 wrapped = true - @test_inferred default_type_parameter(MyType, Position(2)) == :P2 - @test_inferred default_type_parameter(MyType{<:Any,2}, Position(1)) == :P1 - @test_inferred default_type_parameter(MyType{<:Any,2}, Position(2)) == :P2 - @test_inferred default_type_parameters(MyType{<:Any,2}) == (:P1, :P2) - @test_inferred default_type_parameters(MyType) == (:P1, :P2) - # TODO: These don't infer, need to investigate. - @test_inferred default_type_parameter(MyType{<:Any,2}, 1) == :P1 inferred = false - @test_inferred default_type_parameter(MyType{<:Any,2}, 2) == :P2 inferred = false - - @test_inferred set_default_type_parameter(MyType{1,2}, 1) == MyType{:P1,2} wrapped = - true - @test_inferred set_default_type_parameter(MyType{1,2}, Position(1)) == MyType{:P1,2} - @test_inferred set_default_type_parameter(MyType{<:Any,2}, Position(1)) == - MyType{:P1,2} - @test_inferred set_default_type_parameter(MyType{<:Any,2}, Position(2)) == - MyType{<:Any,:P2} - @test_inferred set_default_type_parameters(MyType{<:Any,2}) == MyType{:P1,:P2} - # TODO: These don't infer, need to investigate. - @test_inferred set_default_type_parameter(MyType{<:Any,2}, 1) == MyType{:P1,2} inferred = - false - @test_inferred set_default_type_parameter(MyType{<:Any,2}, 2) == MyType{<:Any,:P2} inferred = - false - - @test_inferred specify_default_type_parameter(MyType{<:Any,2}, Position(1)) == - MyType{:P1,2} - @test_inferred specify_default_type_parameters(MyType{<:Any,2}) == MyType{:P1,2} - @test_inferred specify_default_type_parameter(MyType{<:Any,2}, Position(2)) == - MyType{<:Any,2} - @test_inferred specify_default_type_parameters(MyType) == MyType{:P1,:P2} - # TODO: These don't infer, need to investigate. - @test_inferred specify_default_type_parameter(MyType{<:Any,2}, 2) == MyType{<:Any,2} inferred = - false - - # Named positions - function p1 end - function p2 end - ## TODO remove TypeParameterAccessors when SetParameters is removed - TypeParameterAccessors.position(::Type{<:MyType}, ::typeof(p1)) = Position(1) - TypeParameterAccessors.position(::Type{<:MyType}, ::typeof(p2)) = Position(2) - - @test_inferred type_parameter(MyType{:p1}, p1) == :p1 - @test_inferred type_parameter(MyType{<:Any,:p2}, p2) == :p2 - @test_inferred default_type_parameter(MyType, p1) == :P1 - @test_inferred default_type_parameter(MyType, p2) == :P2 - end - end -end -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/test_defaults.jl b/NDTensors/src/lib/TypeParameterAccessors/test/test_defaults.jl deleted file mode 100644 index c10d360762..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/test_defaults.jl +++ /dev/null @@ -1,75 +0,0 @@ -@eval module $(gensym()) -using Test: @test_throws, @testset -using NDTensors.TypeParameterAccessors: - TypeParameterAccessors, - Position, - default_type_parameter, - default_type_parameters, - set_default_type_parameter, - set_default_type_parameters, - specify_default_type_parameter, - specify_default_type_parameters -include("utils/test_inferred.jl") -@testset "TypeParameterAccessors defaults" begin - @testset "Erroneously requires wrapping to infer" begin end - @testset "Get defaults" begin - @test_inferred default_type_parameter(Array, 1) == Float64 wrapped = true - @test_inferred default_type_parameter(Array, Position(1)) == Float64 - @test_inferred default_type_parameter(Array, 2) == 1 wrapped = true - @test_inferred default_type_parameter(Array, Position(2)) == 1 - @test_inferred default_type_parameters(Array) == (Float64, 1) - @test_inferred default_type_parameters(Array, (2, 1)) == (1, Float64) wrapped = true - @test_inferred default_type_parameters(Array, (Position(2), Position(1))) == - (1, Float64) - @test_inferred default_type_parameters(Array, (ndims, eltype)) == (1, Float64) - end - @testset "Set defaults" begin - @test_inferred set_default_type_parameter(Array{Float32}, 1) == Array{Float64} wrapped = - true - @test_inferred set_default_type_parameter(Array{Float32}, Position(1)) == Array{Float64} - @test_inferred set_default_type_parameter(Array{Float32}, eltype) == Array{Float64} - @test_inferred set_default_type_parameters(Array{Float32}) == Vector{Float64} - @test_inferred set_default_type_parameters(Array{Float32}, (1, 2)) == Vector{Float64} wrapped = - true - @test_inferred set_default_type_parameters( - Array{Float32}, (Position(1), Position(2)) - ) == Vector{Float64} - @test_inferred set_default_type_parameters(Array{Float32}, (eltype, ndims)) == - Vector{Float64} - @test_inferred set_default_type_parameters(Array) == Vector{Float64} wrapped = true - @test_inferred set_default_type_parameters(Array, (Position(1),)) == Array{Float64} - @test_inferred set_default_type_parameters(Array, (Position(1), Position(2))) == - Vector{Float64} - end - @testset "Specify defaults" begin - @test_inferred specify_default_type_parameter(Array, 1) == Array{Float64} wrapped = true - @test_inferred specify_default_type_parameter(Array, Position(1)) == Array{Float64} - @test_inferred specify_default_type_parameter(Array, eltype) == Array{Float64} - @test_inferred specify_default_type_parameter(Array, 2) == Vector wrapped = true - @test_inferred specify_default_type_parameter(Array, Position(2)) == Vector - @test_inferred specify_default_type_parameter(Array, ndims) == Vector - @test_inferred specify_default_type_parameters(Array) == Vector{Float64} - @test_inferred specify_default_type_parameters(Array, (1,)) == Array{Float64} wrapped = - true - @test_inferred specify_default_type_parameters(Array, (Position(1),)) == Array{Float64} - @test_inferred specify_default_type_parameters(Array, (eltype,)) == Array{Float64} - @test_inferred specify_default_type_parameters(Array, (2,)) == Vector wrapped = true - @test_inferred specify_default_type_parameters(Array, (Position(2),)) == Vector - @test_inferred specify_default_type_parameters(Array, (ndims,)) == Vector - @test_inferred specify_default_type_parameters(Array, (1, 2)) == Vector{Float64} wrapped = - true - @test_inferred specify_default_type_parameters(Array, (Position(1), Position(2))) == - Vector{Float64} - @test_inferred specify_default_type_parameters(Array, (eltype, ndims)) == - Vector{Float64} - end - @testset "On objects" begin - a = randn(Float32, (2, 2, 2)) - @test_inferred default_type_parameter(a, 1) == Float64 wrapped = true - @test_inferred default_type_parameter(a, eltype) == Float64 - @test_inferred default_type_parameter(a, 2) == 1 wrapped = true - @test_inferred default_type_parameter(a, ndims) == 1 - @test_inferred default_type_parameters(a) == (Float64, 1) - end -end -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/test_similartype.jl b/NDTensors/src/lib/TypeParameterAccessors/test/test_similartype.jl deleted file mode 100644 index 0813fc917b..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/test_similartype.jl +++ /dev/null @@ -1,26 +0,0 @@ -@eval module $(gensym()) -using Test: @test, @test_broken, @testset -using LinearAlgebra: Adjoint, Diagonal -using NDTensors.TypeParameterAccessors: NDims, similartype -@testset "TypeParameterAccessors similartype" begin - @test similartype(Array, Float64, (2, 2)) == Matrix{Float64} - @test similartype(Array) == Array - @test similartype(Array, Float64) == Array{Float64} - @test similartype(Array, (2, 2)) == Matrix - @test similartype(Array, NDims(2)) == Matrix - @test similartype(Array, Float64, (2, 2)) == Matrix{Float64} - @test similartype(Array, Float64, NDims(2)) == Matrix{Float64} - @test similartype(Adjoint{Float32,Matrix{Float32}}, Float64, (2, 2, 2)) == - Array{Float64,3} - @test similartype(Adjoint{Float32,Matrix{Float32}}, Float64, NDims(3)) == Array{Float64,3} - @test similartype(Adjoint{Float32,Matrix{Float32}}, Float64) == Matrix{Float64} - @test similartype(Diagonal{Float32,Vector{Float32}}) == Matrix{Float32} - @test similartype(Diagonal{Float32,Vector{Float32}}, Float64) == Matrix{Float64} - @test similartype(Diagonal{Float32,Vector{Float32}}, (2, 2, 2)) == Array{Float32,3} - @test similartype(Diagonal{Float32,Vector{Float32}}, NDims(3)) == Array{Float32,3} - @test similartype(Diagonal{Float32,Vector{Float32}}, Float64, (2, 2, 2)) == - Array{Float64,3} - @test similartype(Diagonal{Float32,Vector{Float32}}, Float64, NDims(3)) == - Array{Float64,3} -end -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/test_wrappers.jl b/NDTensors/src/lib/TypeParameterAccessors/test/test_wrappers.jl deleted file mode 100644 index ed8e223922..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/test_wrappers.jl +++ /dev/null @@ -1,121 +0,0 @@ -@eval module $(gensym()) -using Test: @test_broken, @testset -using LinearAlgebra: - Adjoint, - Diagonal, - Hermitian, - LowerTriangular, - Symmetric, - Transpose, - UnitLowerTriangular, - UnitUpperTriangular, - UpperTriangular -using NDTensors.TypeParameterAccessors: - NDims, - TypeParameter, - is_wrapped_array, - parenttype, - set_eltype, - set_ndims, - set_parenttype, - type_parameter, - unspecify_type_parameters, - unwrap_array_type -using StridedViews: StridedView -include("utils/test_inferred.jl") -@testset "TypeParameterAccessors wrapper types" begin - @testset "Array" begin - array = randn(2, 2) - array_type = typeof(array) - @test_inferred parenttype(Matrix) == Matrix - @test_inferred is_wrapped_array(array) == false - @test_inferred parenttype(array) == array_type - @test_inferred set_eltype(array, Float32) isa Matrix{Float32} - @test_inferred set_eltype(array, Float32) ≈ array - @test_inferred set_eltype(Array{<:Any,2}, Float64) == Matrix{Float64} - @test_inferred set_ndims(Array{Float64}, 2) == Matrix{Float64} wrapped = true - @test_inferred set_ndims(Array{Float64}, NDims(2)) == Matrix{Float64} wrapped = true - @test_inferred set_ndims(Array{Float64}, TypeParameter(2)) == Matrix{Float64} - @test_inferred unwrap_array_type(array_type) == array_type - end - @testset "Base AbstractArray wrappers" begin - array = randn(2, 2) - for wrapped_array in ( - Base.ReshapedArray(array, (2, 2), ()), - SubArray(randn(2, 2), (:, :)), - PermutedDimsArray(randn(2, 2), (1, 2)), - ) - wrapped_array_type = typeof(wrapped_array) - @test_inferred parenttype(wrapped_array) == Matrix{Float64} - @test_inferred type_parameter(wrapped_array, eltype) == Float64 - @test_inferred is_wrapped_array(wrapped_array) == true - @test_inferred unwrap_array_type(wrapped_array_type) == Matrix{Float64} - @test_inferred set_eltype(wrapped_array_type, Float32) <: - unspecify_type_parameters(wrapped_array_type){Float32} - # Julia doesn't have the necessary conversions defined for this to work. - @test_broken set_eltype(wrapped_array, Float32) isa - unspecify_type_parameters(wrapped_array_type){Float32} - end - end - @testset "LinearAlgebra wrappers" begin - for wrapper in ( - Transpose, - Adjoint, - Symmetric, - Hermitian, - UpperTriangular, - LowerTriangular, - UnitUpperTriangular, - UnitLowerTriangular, - ) - array = randn(2, 2) - wrapped_array = wrapper(array) - wrapped_array_type = typeof(wrapped_array) - @test_inferred is_wrapped_array(wrapped_array) == true - @test_inferred parenttype(wrapped_array) == Matrix{Float64} - @test_inferred unwrap_array_type(wrapped_array_type) == Matrix{Float64} - @test_inferred set_parenttype(wrapped_array_type, wrapped_array_type) == - wrapper{eltype(wrapped_array_type),wrapped_array_type} - @test_inferred set_eltype(wrapped_array_type, Float32) == - wrapper{Float32,Matrix{Float32}} - if wrapper ∉ (UnitUpperTriangular, UnitLowerTriangular) - @test_inferred set_eltype(wrapped_array, Float32) isa - wrapper{Float32,Matrix{Float32}} - end - end - end - @testset "LinearAlgebra Diagonal wrapper" begin - array = randn(2, 2) - wrapped_array = Diagonal(array) - wrapped_array_type = typeof(wrapped_array) - @test_inferred is_wrapped_array(wrapped_array) == true - @test_inferred parenttype(wrapped_array) == Vector{Float64} - @test_inferred unwrap_array_type(wrapped_array_type) == Vector{Float64} - @test_inferred set_eltype(wrapped_array_type, Float32) == - Diagonal{Float32,Vector{Float32}} - if VERSION ≥ v"1.8" - # `Diagonal{T,Vector{T}}(diag::Diagonal)` not define in Julia 1.7 - # and below. - @test_inferred set_eltype(wrapped_array, Float32) isa - Diagonal{Float32,Vector{Float32}} - end - end - @testset "LinearAlgebra nested wrappers" begin - array = randn(2, 2) - wrapped_array = view(reshape(transpose(array), 4), 1:2) - wrapped_array_type = typeof(wrapped_array) - @test_inferred is_wrapped_array(wrapped_array) == true - @test_inferred parenttype(wrapped_array) <: - Base.ReshapedArray{Float64,1,Transpose{Float64,Matrix{Float64}}} - @test_inferred unwrap_array_type(array) == Matrix{Float64} - end - @testset "StridedView" begin - array = randn(2, 2) - wrapped_array = StridedView(randn(2, 2)) - wrapped_array_type = typeof(wrapped_array) - @test_inferred is_wrapped_array(wrapped_array) == true - @test_inferred parenttype(wrapped_array) == Matrix{Float64} - @test_inferred unwrap_array_type(wrapped_array_type) == Matrix{Float64} - end -end -end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/utils/test_inferred.jl b/NDTensors/src/lib/TypeParameterAccessors/test/utils/test_inferred.jl deleted file mode 100644 index 755c31eb98..0000000000 --- a/NDTensors/src/lib/TypeParameterAccessors/test/utils/test_inferred.jl +++ /dev/null @@ -1,28 +0,0 @@ -using Test: @inferred, @test - -macro test_inferred(ex, kws...) - @assert ex.head in [:call, :(<:)] - first_arg = ex.head === :(<:) ? 1 : 2 - @assert length(ex.args[first_arg:end]) == 2 - # Collect the broken/skip keywords and remove them from the rest of keywords - @assert all(kw -> kw.head === :(=), kws) - inferreds = [kw.args[2] for kw in kws if kw.args[1] === :inferred] - inferred = isempty(inferreds) ? true : only(inferreds) - wrappeds = [kw.args[2] for kw in kws if kw.args[1] === :wrapped] - wrapped = isempty(wrappeds) ? false : only(wrappeds) - kws = filter(kw -> kw.args[1] ∉ (:inferred, :wrapped), kws) - arg1 = ex.args[first_arg] - arg1 = quote - if $inferred - if $wrapped - @inferred((() -> $arg1)()) - else - @inferred($arg1) - end - else - $arg1 - end - end - ex.args[first_arg] = arg1 - return Expr(:macrocall, Symbol("@test"), :(), esc(ex), kws...) -end diff --git a/NDTensors/src/lib/UnallocatedArrays/.JuliaFormatter.toml b/NDTensors/src/lib/UnallocatedArrays/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/UnallocatedArrays/README.md b/NDTensors/src/lib/UnallocatedArrays/README.md deleted file mode 100644 index 360efad10c..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# UnallocatedArrays - -A module defining a set of unallocated immutable lazy arrays which will be used to quickly construct -tensors and allocating as little data as possible. diff --git a/NDTensors/src/lib/UnallocatedArrays/src/UnallocatedArrays.jl b/NDTensors/src/lib/UnallocatedArrays/src/UnallocatedArrays.jl deleted file mode 100644 index fb95f4ec21..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/src/UnallocatedArrays.jl +++ /dev/null @@ -1,11 +0,0 @@ -module UnallocatedArrays -include("abstractfill/abstractfill.jl") - -include("unallocatedfill.jl") -include("unallocatedzeros.jl") -include("broadcast.jl") -include("abstractunallocatedarray.jl") -include("set_types.jl") - -export UnallocatedFill, UnallocatedZeros, alloctype, set_alloctype, allocate -end diff --git a/NDTensors/src/lib/UnallocatedArrays/src/abstractfill/abstractfill.jl b/NDTensors/src/lib/UnallocatedArrays/src/abstractfill/abstractfill.jl deleted file mode 100644 index 6356478641..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/src/abstractfill/abstractfill.jl +++ /dev/null @@ -1,22 +0,0 @@ -using FillArrays: AbstractFill -using NDTensors.TypeParameterAccessors: TypeParameterAccessors, Position, type_parameter -## Here are functions specifically defined for UnallocatedArrays -## not implemented by FillArrays -## TODO this might need a more generic name maybe like compute unit -function alloctype(A::AbstractFill) - return A.alloc -end - -## TODO this fails if the parameter is a type -function alloctype(Atype::Type{<:AbstractFill}) - return type_parameter(Atype, alloctype) -end - -axestype(T::Type{<:AbstractArray}) = type_parameter(axestype) -set_axestype(T::Type{<:AbstractFill}, ax::Type) = s(T, axestype, ax) - -TypeParameterAccessors.position(::Type{<:AbstractFill}, ::typeof(alloctype)) = Position(4) -TypeParameterAccessors.position(::Type{<:AbstractFill}, ::typeof(axestype)) = Position(3) -function TypeParameterAccessors.default_type_parameters(::Type{<:AbstractFill}) - return (Float64, 0, Tuple{}) -end diff --git a/NDTensors/src/lib/UnallocatedArrays/src/abstractunallocatedarray.jl b/NDTensors/src/lib/UnallocatedArrays/src/abstractunallocatedarray.jl deleted file mode 100644 index 7b07cc27ff..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/src/abstractunallocatedarray.jl +++ /dev/null @@ -1,62 +0,0 @@ -using FillArrays: FillArrays, getindex_value -using NDTensors.TypeParameterAccessors: set_eltype, set_ndims -using Adapt: adapt - -const UnallocatedArray{ElT,N,AxesT,AllocT} = Union{ - UnallocatedFill{ElT,N,AxesT,AllocT},UnallocatedZeros{ElT,N,AxesT,AllocT} -} - -@inline Base.axes(A::UnallocatedArray) = axes(parent(A)) -Base.size(A::UnallocatedArray) = size(parent(A)) -function FillArrays.getindex_value(A::UnallocatedArray) - return getindex_value(parent(A)) -end - -function Base.complex(A::UnallocatedArray) - return complex(eltype(A)).(A) -end - -function Base.transpose(a::UnallocatedArray) - return set_alloctype(transpose(parent(a)), alloctype(a)) -end - -function Base.adjoint(a::UnallocatedArray) - return set_alloctype(adjoint(parent(a)), alloctype(a)) -end - -using NDTensors.TypeParameterAccessors: set_type_parameter -function set_alloctype(T::Type{<:UnallocatedArray}, alloc::Type{<:AbstractArray}) - return set_type_parameter(T, alloctype, alloc) -end - -## This overloads the definition defined in `FillArrays.jl` -for STYPE in (:AbstractArray, :AbstractFill) - @eval begin - @inline $STYPE{T}(F::UnallocatedArray{T}) where {T} = F - @inline $STYPE{T,N}(F::UnallocatedArray{T,N}) where {T,N} = F - end -end - -function allocate(f::UnallocatedArray) - a = similar(f) - fill!(a, getindex_value(f)) - return a -end - -function allocate(arraytype::Type{<:AbstractArray}, elt::Type, axes) - ArrayT = set_ndims(set_eltype(arraytype, elt), length(axes)) - return similar(ArrayT, axes) -end - -function Base.similar(f::UnallocatedArray, elt::Type, axes::Tuple{Int64,Vararg{Int64}}) - return allocate(alloctype(f), elt, axes) -end - -## TODO fix this because reshape loses alloctype -#FillArrays.reshape(a::Union{<:UnallocatedFill, <:UnallocatedZeros}, dims) = set_alloctype(reshape(parent(a), dims), allocate(a)) - -# function Adapt.adapt_storage(to::Type{<:AbstractArray}, x::Union{<:UnallocatedFill, <:UnallocatedZeros}) -# return set_alloctype(parent(x), to) -# end - -# function Adapt.adapt_storage(to::Type{<:Number}, x::) diff --git a/NDTensors/src/lib/UnallocatedArrays/src/broadcast.jl b/NDTensors/src/lib/UnallocatedArrays/src/broadcast.jl deleted file mode 100644 index c5e98e71d4..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/src/broadcast.jl +++ /dev/null @@ -1,28 +0,0 @@ -using FillArrays: broadcasted_fill, broadcasted_zeros, getindex_value - -abstract type ZeroPreserving end -struct IsZeroPreserving <: ZeroPreserving end -struct NotZeroPreserving <: ZeroPreserving end - -# Assume operations don't preserve zeros for safety -ZeroPreserving(x) = NotZeroPreserving() -ZeroPreserving(::typeof(Complex)) = IsZeroPreserving() -ZeroPreserving(::typeof(Real)) = IsZeroPreserving() - -function Broadcast.broadcasted(style::Broadcast.DefaultArrayStyle, f, a::UnallocatedZeros) - return _broadcasted(style, f, ZeroPreserving(f), a) -end - -function _broadcasted( - style::Broadcast.DefaultArrayStyle, f, ::IsZeroPreserving, a::UnallocatedZeros -) - z = f.(parent(a)) - return broadcasted_zeros(f, a, eltype(z), axes(z)) -end - -function _broadcasted( - style::Broadcast.DefaultArrayStyle, f, ::NotZeroPreserving, a::UnallocatedZeros -) - z = f.(parent(a)) - return broadcasted_fill(f, a, getindex_value(z), axes(z)) -end diff --git a/NDTensors/src/lib/UnallocatedArrays/src/set_types.jl b/NDTensors/src/lib/UnallocatedArrays/src/set_types.jl deleted file mode 100644 index 4d169c5511..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/src/set_types.jl +++ /dev/null @@ -1,14 +0,0 @@ -using .TypeParameterAccessors: TypeParameterAccessors -using NDTensors.UnspecifiedTypes: UnspecifiedArray, UnspecifiedNumber, UnspecifiedZero - -function TypeParameterAccessors.default_type_parameters(::Type{<:UnallocatedArray}) - return ( - UnspecifiedNumber{UnspecifiedZero}, - 0, - Tuple{}, - UnspecifiedArray{UnspecifiedNumber{UnspecifiedZero},0}, - ) -end - -unspecify_parameters(::Type{<:UnallocatedFill}) = UnallocatedFill -unspecify_parameters(::Type{<:UnallocatedZeros}) = UnallocatedZeros diff --git a/NDTensors/src/lib/UnallocatedArrays/src/unallocatedfill.jl b/NDTensors/src/lib/UnallocatedArrays/src/unallocatedfill.jl deleted file mode 100644 index c84d2e0d7e..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/src/unallocatedfill.jl +++ /dev/null @@ -1,67 +0,0 @@ -using FillArrays: - FillArrays, AbstractFill, Fill, broadcasted_fill, getindex_value, kron_fill, mult_fill - -struct UnallocatedFill{ElT,N,Axes,Alloc} <: AbstractFill{ElT,N,Axes} - f::Fill{ElT,N,Axes} - alloc::Alloc -end - -function UnallocatedFill{ElT,N,Axes}(f::Fill, alloc::Type) where {ElT,N,Axes} - return UnallocatedFill{ElT,N,Axes,Type{alloc}}(f, alloc) -end - -function UnallocatedFill{ElT,N}(f::Fill, alloc) where {ElT,N} - return UnallocatedFill{ElT,N,typeof(axes(f))}(f, alloc) -end - -function UnallocatedFill{ElT}(f::Fill, alloc) where {ElT} - return UnallocatedFill{ElT,ndims(f)}(f, alloc) -end - -set_alloctype(f::Fill, alloc::Type) = UnallocatedFill(f, alloc) - -Base.parent(F::UnallocatedFill) = F.f - -Base.convert(::Type{<:UnallocatedFill}, A::UnallocatedFill) = A - -############################################# -# Arithmatic - -# mult_fill(a, b, val, ax) = Fill(val, ax) -function FillArrays.mult_fill(a::UnallocatedFill, b, val, ax) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end -FillArrays.mult_fill(a, b::UnallocatedFill, val, ax) = mult_fill(b, a, val, ax) -function FillArrays.mult_fill(a::UnallocatedFill, b::UnallocatedFill, val, ax) - @assert alloctype(a) == alloctype(b) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end - -function FillArrays.broadcasted_fill(f, a::UnallocatedFill, val, ax) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end -function FillArrays.broadcasted_fill(f, a::UnallocatedFill, b::UnallocatedFill, val, ax) - @assert alloctype(a) == alloctype(b) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end - -function FillArrays.broadcasted_fill(f, a::UnallocatedFill, b, val, ax) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end -function FillArrays.broadcasted_fill(f, a, b::UnallocatedFill, val, ax) - return broadcasted_fill(f, b, a, val, ax) -end - -function FillArrays.kron_fill(a::UnallocatedFill, b::UnallocatedFill, val, ax) - @assert alloctype(a) == alloctype(b) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end - -Base.:+(A::UnallocatedFill, B::UnallocatedFill) = A .+ B - -function Base.Broadcast.broadcasted( - ::Base.Broadcast.DefaultArrayStyle, op, r::UnallocatedFill -) - f = op.(parent(r)) - return broadcasted_fill(op, r, getindex_value(f), axes(f)) -end diff --git a/NDTensors/src/lib/UnallocatedArrays/src/unallocatedzeros.jl b/NDTensors/src/lib/UnallocatedArrays/src/unallocatedzeros.jl deleted file mode 100644 index 39752e206e..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/src/unallocatedzeros.jl +++ /dev/null @@ -1,88 +0,0 @@ -using FillArrays: - FillArrays, - AbstractZeros, - Fill, - Zeros, - broadcasted_fill, - broadcasted_zeros, - kron_fill, - kron_zeros, - mult_zeros - -## TODO Should Alloc also be of ElT and N or should there be -## More freedom there? -struct UnallocatedZeros{ElT,N,Axes,Alloc} <: AbstractZeros{ElT,N,Axes} - z::Zeros{ElT,N,Axes} - alloc::Alloc -end - -function UnallocatedZeros{ElT,N,Axes}(z::Zeros, alloc::Type) where {ElT,N,Axes} - return UnallocatedZeros{ElT,N,Axes,Type{alloc}}(z, alloc) -end - -function UnallocatedZeros{ElT,N}(z::Zeros, alloc) where {ElT,N} - return UnallocatedZeros{ElT,N,typeof(axes(z))}(z, alloc) -end - -function UnallocatedZeros{ElT}(z::Zeros, alloc) where {ElT} - return UnallocatedZeros{ElT,ndims(z)}(z, alloc) -end - -set_alloctype(f::Zeros, alloc::Type) = UnallocatedZeros(f, alloc) - -Base.parent(Z::UnallocatedZeros) = Z.z - -Base.convert(::Type{<:UnallocatedZeros}, A::UnallocatedZeros) = A - -############################################# -# Arithmatic - -function FillArrays.mult_zeros(a::UnallocatedZeros, b, elt, ax) - return UnallocatedZeros(Zeros{elt}(ax), alloctype(a)) -end -FillArrays.mult_zeros(a, b::UnallocatedZeros, elt, ax) = mult_zeros(b, a, elt, ax) -function FillArrays.mult_zeros(a::UnallocatedZeros, b::UnallocatedZeros, elt, ax) - @assert alloctype(a) == alloctype(b) - return UnallocatedZeros(Zeros{elt}(ax), alloctype(a)) -end - -function FillArrays.broadcasted_zeros(f, a::UnallocatedZeros, elt, ax) - return UnallocatedZeros(Zeros{elt}(ax), alloctype(a)) -end -function FillArrays.broadcasted_zeros(f, a::UnallocatedZeros, b::UnallocatedZeros, elt, ax) - @assert alloctype(a) == alloctype(b) - return UnallocatedZeros(Zeros{elt}(ax), alloctype(a)) -end - -function FillArrays.broadcasted_zeros(f, a::UnallocatedZeros, b, elt, ax) - return UnallocatedZeros(Zeros{elt}(ax), alloctype(a)) -end -function FillArrays.broadcasted_zeros(f, a, b::UnallocatedZeros, elt, ax) - return broadcasted_zeros(f, b, a, elt, ax) -end - -function FillArrays.broadcasted_fill(f, a::UnallocatedZeros, val, ax) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end -function FillArrays.broadcasted_fill(f, a::UnallocatedZeros, b, val, ax) - return UnallocatedFill(Fill(val, ax), alloctype(a)) -end - -function FillArrays.broadcasted_fill(f, a, b::UnallocatedZeros, val, ax) - return broadcasted_fill(f, b, a, val, ax) -end - -function FillArrays.kron_zeros(a::UnallocatedZeros, b::UnallocatedZeros, elt, ax) - @assert alloctype(a) == alloctype(b) - return UnallocatedZeros(Zeros{elt}(ax), alloctype(a)) -end - -function FillArrays.kron_fill(a::UnallocatedZeros, b::UnallocatedFill, val, ax) - @assert alloctype(a) == alloctype(b) - elt = typeof(val) - return UnallocatedZeros(Zeros{elt}(ax), alloctype(a)) -end - -function FillArrays.kron_fill(a::UnallocatedFill, b::UnallocatedZeros, val, ax) - return kron_fill(b, a, val, ax) -end diff --git a/NDTensors/src/lib/UnallocatedArrays/test/Project.toml b/NDTensors/src/lib/UnallocatedArrays/test/Project.toml deleted file mode 100644 index 88851e5c59..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/test/Project.toml +++ /dev/null @@ -1,5 +0,0 @@ -[deps] -FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/NDTensors/src/lib/UnallocatedArrays/test/runtests.jl b/NDTensors/src/lib/UnallocatedArrays/test/runtests.jl deleted file mode 100644 index 4dd8b8b521..0000000000 --- a/NDTensors/src/lib/UnallocatedArrays/test/runtests.jl +++ /dev/null @@ -1,326 +0,0 @@ -@eval module $(gensym()) -using FillArrays: FillArrays, AbstractFill, Fill, Zeros -using NDTensors: NDTensors -using NDTensors.UnallocatedArrays: - UnallocatedFill, UnallocatedZeros, allocate, alloctype, set_alloctype -using LinearAlgebra: norm -using Test: @test, @test_broken, @testset - -include(joinpath(pkgdir(NDTensors), "test", "NDTensorsTestUtils", "NDTensorsTestUtils.jl")) -using .NDTensorsTestUtils: devices_list - -@testset "Testing UnallocatedArrays on $dev with eltype $elt" for dev in devices_list(ARGS), - elt in (Float64, Float32, ComplexF64, ComplexF32) - - @testset "Basic funcitonality" begin - z = Zeros{elt}((2, 3)) - Z = UnallocatedZeros(z, dev(Matrix{elt})) - - @test Z isa AbstractFill - @test size(Z) == (2, 3) - @test length(Z) == 6 - @test iszero(sum(Z)) - @test iszero(norm(Z)) - @test iszero(Z[2, 3]) - @test allocate(Z) isa dev(Matrix{elt}) - Zp = UnallocatedZeros{elt}(Zeros(2, 3), dev(Matrix{elt})) - @test Zp == Z - Zp = set_alloctype(z, dev(Matrix{elt})) - @test Zp == Z - Zc = copy(Z) - @test Zc == Z - Zc = complex(Z) - @test eltype(Zc) == complex(eltype(z)) - @test iszero(Zc[1, 2]) - @test Zc isa UnallocatedZeros - @test alloctype(Zc) == alloctype(Z) - - Zs = similar(Z) - @test Zs isa alloctype(Z) - - Z = UnallocatedZeros(z, dev(Array)) - Za = allocate(Z) - @test Za isa dev(Array{elt,2}) - @test Za[1, 3] == zero(elt) - - ######################################### - # UnallocatedFill - f = Fill{elt}(3, (2, 3, 4)) - F = UnallocatedFill(f, Array{elt,ndims(f)}) - - @test F isa AbstractFill - @test size(F) == (2, 3, 4) - @test length(F) == 24 - @test sum(F) ≈ elt(3) * 24 - @test norm(F) ≈ sqrt(elt(3)^2 * 24) - @test F[2, 3, 1] == elt(3) - @test allocate(F) isa Array{elt,3} - Fp = UnallocatedFill{elt}(Fill(3, (2, 3, 4)), Array{elt,ndims(f)}) - @test Fp == F - Fp = allocate(F) - @test norm(Fp) ≈ norm(F) - Fs = similar(F) - @test Fs isa alloctype(F) - @test length(Fs) == 2 * 3 * 4 - Fs[1, 1, 1] = elt(10) - @test Fs[1, 1, 1] == elt(10) - - Fp = set_alloctype(f, dev(Array{elt,ndims(f)})) - @test allocate(Fp) isa dev(Array{elt,ndims(f)}) - @test Fp == F - Fc = copy(F) - @test Fc == F - Fc = allocate(complex(F)) - @test eltype(Fc) == complex(eltype(F)) - ## Here we no longer require the eltype of the alloctype to - ## Be the same as the eltype of the `UnallocatedArray`. It will be - ## replaced when the array is allocated - # @test_broken typeof(Fc) == alloctype(complex(F)) - Fc[2, 3, 4] = elt(0) - @test iszero(Fc[2, 3, 4]) - - F = UnallocatedFill(f, dev(Array)) - Fa = allocate(F) - @test Fa isa dev(Array{elt,3}) - @test Fa[2, 1, 4] == elt(3) - - F = UnallocatedFill(f, dev(Vector)) - Fa = allocate(F) - @test ndims(Fa) == 3 - @test Fa isa dev(Array) - end - - @testset "Multiplication" begin - z = Zeros{elt}((2, 3)) - Z = UnallocatedZeros(z, dev(Matrix{elt})) - - R = Z * Z' - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - @test size(R) == (2, 2) - M = rand(elt, (3, 4)) - R = Z * M - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - @test size(R) == (2, 4) - R = M' * Z' - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - @test size(R) == (4, 2) - R = transpose(M) * transpose(Z) - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - @test size(R) == (4, 2) - - ################################### - ## UnallocatedFill - f = Fill{elt}(3, (2, 12)) - F = UnallocatedFill(f, dev(Matrix{elt})) - p = Fill{elt}(4, (12, 5)) - P = UnallocatedFill(p, dev(Array{elt,ndims(p)})) - R = F * P - @test F isa UnallocatedFill - @test R[1, 1] == elt(144) - @test alloctype(R) == alloctype(F) - @test size(R) == (2, 5) - - R = F * F' - @test R isa UnallocatedFill - @test R[1, 2] == elt(108) - @test alloctype(R) == alloctype(F) - @test size(R) == (2, 2) - - R = transpose(F) * F - @test R isa UnallocatedFill - @test R[12, 3] == elt(18) - @test alloctype(R) == alloctype(F) - @test size(R) == (12, 12) - - R = transpose(Z) * F - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - @test size(R) == (3, 12) - end - - @testset "Broadcast" begin - z = Zeros{elt}((2, 3)) - Z = UnallocatedZeros(z, dev(Matrix{elt})) - R = elt(2) .* Z - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - R = Z .* elt(2) - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - - R = Z .* Z - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - - Z = UnallocatedZeros(Zeros{elt}((2, 3)), dev(Matrix{elt})) - R = Z + Z - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(Z) - - R = Z .+ elt(2) - @test R isa UnallocatedFill - @test alloctype(R) == alloctype(Z) - - R = (x -> x .+ 1).(Z) - @test R isa UnallocatedFill - @test alloctype(R) == alloctype(Z) - @test R[1, 1] == elt(1) - - Z .*= 1.0 - @test Z isa UnallocatedZeros - @test alloctype(R) == dev(Matrix{elt}) - @test Z[2, 1] == zero(elt) - ######################## - # UnallocatedFill - f = Fill(elt(3), (2, 3, 4)) - F = UnallocatedFill(f, Array{elt,ndims(f)}) - F2 = F .* 2 - @test F2 isa UnallocatedFill - @test F2[1, 1, 1] == elt(6) - @test alloctype(F2) == alloctype(F) - - F2 = F2 .+ elt(2) - @test F2 isa UnallocatedFill - @test F2[1, 1, 1] == elt(8) - @test alloctype(F2) == alloctype(F) - - F = UnallocatedFill(Fill(elt(2), (2, 3)), dev(Matrix{elt})) - R = Z + F - @test R isa UnallocatedFill - @test alloctype(R) == alloctype(Z) - - R = F + Z - @test R isa UnallocatedFill - @test alloctype(R) == alloctype(Z) - - F = UnallocatedFill(Fill(elt(3), (2, 12)), dev(Matrix{elt})) - R = F .* F - @test R isa UnallocatedFill - @test R[2, 9] == elt(9) - @test alloctype(R) == alloctype(F) - @test size(R) == (2, 12) - - P = UnallocatedFill(Fill(elt(4), (2, 3)), dev(Matrix{elt})) - R = Z .* P - @test R isa UnallocatedZeros - @test alloctype(R) == alloctype(P) - @test size(R) == (2, 3) - - F = UnallocatedFill(Fill(elt(2), (2, 3)), dev(Matrix{elt})) - R = F + F - @test R isa UnallocatedFill - @test R[1, 3] == elt(4) - - R = (x -> x .+ 1).(F) - @test R isa UnallocatedFill - @test R[2, 1] == elt(3) - @test alloctype(R) == alloctype(F) - end - - ## TODO make other kron tests - @testset "Kron" begin - A = UnallocatedZeros(Zeros{elt}(2), dev(Vector{elt})) - B = UnallocatedZeros(Zeros{elt}(2), dev(Vector{elt})) - C = kron(A, B) - @test C isa UnallocatedZeros - @test alloctype(C) == alloctype(B) - - B = UnallocatedFill(Fill(elt(2), (2)), dev(Vector{elt})) - C = kron(A, B) - @test C isa UnallocatedZeros - @test alloctype(C) == alloctype(B) - - C = kron(B, A) - @test C isa UnallocatedZeros - @test alloctype(C) == alloctype(B) - - A = UnallocatedFill(Fill(elt(3), (2)), dev(Vector{elt})) - C = kron(A, B) - @test C isa UnallocatedFill - @test alloctype(C) == alloctype(B) - @test C[1] == elt(6) - end -end -end - -using FillArrays: Fill, Zeros -using NDTensors.UnallocatedArrays: UnallocatedFill, UnallocatedZeros -using NDTensors.TypeParameterAccessors: - Position, default_type_parameter, nparameters, set_type_parameter, type_parameter -using Test: @test, @testset - -@testset "SetParameters" begin - @testset "Tetsing $typ" for (typ) in (:Fill, :Zeros) - @eval begin - t1 = default_type_parameter($typ, Position{1}()) - t2 = default_type_parameter($typ, Position{2}()) - t3 = default_type_parameter($typ, Position{3}()) - t4 = Any - ft1 = $typ{t1} - ft2 = $typ{t1,t2} - ft3 = $typ{t1,t2,t3} - - ## check 1 parameter specified - ftn1 = set_type_parameter(ft1, Position{1}(), t4) - ftn2 = set_type_parameter(ft1, Position{2}(), t4) - ftn3 = set_type_parameter(ft1, Position{3}(), t4) - @test ftn1 == $typ{t4} - @test ftn2 == $typ{t1,t4} - @test ftn3 == $typ{t1,<:Any,t4} - - ## check 2 parameters specified - ftn1 = set_type_parameter(ft2, Position{1}(), t4) - ftn2 = set_type_parameter(ft2, Position{2}(), t4) - ftn3 = set_type_parameter(ft2, Position{3}(), t4) - @test ftn1 == $typ{t4,t2} - @test ftn2 == $typ{t1,t4} - @test ftn3 == $typ{t1,t2,t4} - - ## check 3 parameters specified - ftn1 = set_type_parameter(ft3, Position{1}(), t4) - ftn2 = set_type_parameter(ft3, Position{2}(), t4) - ftn3 = set_type_parameter(ft3, Position{3}(), t4) - @test ftn1 == $typ{t4,t2,t3} - @test ftn2 == $typ{t1,t4,t3} - @test ftn3 == $typ{t1,t2,t4} - - @test type_parameter(ft3, Position{1}()) == t1 - @test type_parameter(ft3, Position{2}()) == t2 - @test type_parameter(ft3, Position{3}()) == t3 - - @test nparameters(ft3) == 3 - end - end - - @testset "Tetsing $typ" for (typ) in (:UnallocatedFill, :UnallocatedZeros) - @eval begin - t1 = default_type_parameter($typ, Position{1}()) - t2 = default_type_parameter($typ, Position{2}()) - t3 = default_type_parameter($typ, Position{3}()) - t4 = default_type_parameter($typ, Position{4}()) - t5 = Any - ft = $typ{t1,t2,t3,t4} - - ## check 4 parameters specified - ftn1 = set_type_parameter(ft, Position{1}(), t5) - ftn2 = set_type_parameter(ft, Position{2}(), t5) - ftn3 = set_type_parameter(ft, Position{3}(), t5) - ftn4 = set_type_parameter(ft, Position{4}(), t5) - @test ftn1 == $typ{t5,t2,t3,t4} - @test ftn2 == $typ{t1,t5,t3,t4} - @test ftn3 == $typ{t1,t2,t5,t4} - @test ftn4 == $typ{t1,t2,t3,t5} - - @test type_parameter(ft, Position{1}()) == t1 - @test type_parameter(ft, Position{2}()) == t2 - @test type_parameter(ft, Position{3}()) == t3 - @test type_parameter(ft, Position{4}()) == t4 - - @test nparameters(ft) == 4 - end - end -end diff --git a/NDTensors/src/lib/UnspecifiedTypes/.JuliaFormatter.toml b/NDTensors/src/lib/UnspecifiedTypes/.JuliaFormatter.toml deleted file mode 100644 index 08f664cdb9..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "blue" -indent = 2 diff --git a/NDTensors/src/lib/UnspecifiedTypes/README.md b/NDTensors/src/lib/UnspecifiedTypes/README.md deleted file mode 100644 index 15ad85367d..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# UnspecifiedTypes - -A module defining a set of basic types which are place holders for allocated bit-wise representable types. diff --git a/NDTensors/src/lib/UnspecifiedTypes/TODO.md b/NDTensors/src/lib/UnspecifiedTypes/TODO.md deleted file mode 100644 index 06955df78d..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/TODO.md +++ /dev/null @@ -1,6 +0,0 @@ -## TODO -Currently this code is relatively unimplemented things we need to do are -1. Fully implement all of the types -2. Make sure these types work properly with infrastructure like `UnallocatedArrays`... -3. Make sure type promotion works as expected for each `UnallocatedType` -4. Make a test suite for the module \ No newline at end of file diff --git a/NDTensors/src/lib/UnspecifiedTypes/src/UnspecifiedTypes.jl b/NDTensors/src/lib/UnspecifiedTypes/src/UnspecifiedTypes.jl deleted file mode 100644 index f94a63a14c..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/src/UnspecifiedTypes.jl +++ /dev/null @@ -1,11 +0,0 @@ -module UnspecifiedTypes - -using LinearAlgebra - -include("unspecifiednumber.jl") -include("unspecifiedzero.jl") - -include("unspecifiedarray.jl") - -export UnspecifiedArray, UnspecifiedNumber, UnspecifiedZero -end diff --git a/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedarray.jl b/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedarray.jl deleted file mode 100644 index e47e9832e5..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedarray.jl +++ /dev/null @@ -1 +0,0 @@ -struct UnspecifiedArray{ElT,N} <: AbstractArray{ElT,N} end diff --git a/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiednumber.jl b/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiednumber.jl deleted file mode 100644 index c44587b376..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiednumber.jl +++ /dev/null @@ -1,5 +0,0 @@ -abstract type AbstractUnspecifiedNumber <: Number end - -struct UnspecifiedNumber{T} <: AbstractUnspecifiedNumber - value::T -end diff --git a/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedzero.jl b/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedzero.jl deleted file mode 100644 index 4ca1858218..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/src/unspecifiedzero.jl +++ /dev/null @@ -1,39 +0,0 @@ -struct UnspecifiedZero <: AbstractUnspecifiedNumber end - -# Base.Complex{UnspecifiedZero}() = complex(UnspecifiedZero()) -# function Base.Complex{UnspecifiedZero}(z::Real) -# return (iszero(z) ? complex(UnspecifiedZero()) : throw(ErrorException)) -# end - -zero(::Type{UnspecifiedZero}) = UnspecifiedZero() -zero(n::UnspecifiedZero) = zero(typeof(n)) - -# This helps handle a lot of basic algebra, like: -# UnspecifiedZero() + 2.3 == 2.3 -convert(::Type{T}, x::UnspecifiedZero) where {T<:Number} = T(zero(T)) - -#convert(::Type{Complex{UnspecifiedZero}}, x::UnspecifiedZero) = complex(x) - -# TODO: Should this be implemented? -#Complex(x::Real, ::UnspecifiedZero) = x - -# This is to help define `float(::UnspecifiedZero) = 0.0`. -# This helps with defining `norm` of `UnallocatedZeros{UnspecifiedZero}`. -AbstractFloat(::UnspecifiedZero) = zero(AbstractFloat) - -# Basic arithmetic -(::UnspecifiedZero + ::UnspecifiedZero) = UnspecifiedZero() -(::UnspecifiedZero - ::UnspecifiedZero) = UnspecifiedZero() -(::Number * ::UnspecifiedZero) = UnspecifiedZero() -(::UnspecifiedZero * ::Number) = UnspecifiedZero() -(::UnspecifiedZero * ::UnspecifiedZero) = UnspecifiedZero() -(::UnspecifiedZero / ::Number) = UnspecifiedZero() -(::Number / ::UnspecifiedZero) = throw(DivideError()) -(::UnspecifiedZero / ::UnspecifiedZero) = throw(DivideError()) --(::UnspecifiedZero) = UnspecifiedZero() - -Base.promote_type(z::Type{<:UnspecifiedZero}, ElT::Type) = Base.promote_type(ElT, z) - -Base.promote_type(ElT::Type, ::Type{<:UnspecifiedZero}) = ElT -Base.promote_type(::Type{<:UnspecifiedZero}, ::Type{<:UnspecifiedZero}) = UnspecifiedZero -Base.promote_type(ElT::Type, ::Type{<:Complex{<:UnspecifiedZero}}) = Complex{real(ElT)} diff --git a/NDTensors/src/lib/UnspecifiedTypes/test/runtests.jl b/NDTensors/src/lib/UnspecifiedTypes/test/runtests.jl deleted file mode 100644 index e9649c3c50..0000000000 --- a/NDTensors/src/lib/UnspecifiedTypes/test/runtests.jl +++ /dev/null @@ -1,6 +0,0 @@ -@eval module $(gensym()) -using NDTensors.UnspecifiedTypes -using Test: @test, @testset - -@testset "Testing UnspecifiedTypes" begin end -end