diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..700707c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..a3f35c8 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,40 @@ +name: CI +on: + push: + branches: + - 'main' + - 'release-' + tags: '*' + paths-ignore: + - 'docs/**' + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Cancel intermediate builds: only if it is a pull request build. + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + tests: + name: "Tests" + strategy: + fail-fast: false + matrix: + version: + - 'lts' # minimal supported version + - '1' # latest released Julia version + group: + - 'core' + - 'optional' + os: + - ubuntu-latest + - macOS-latest + - windows-latest + uses: "ITensor/JuliaActions/.github/workflows/tests.yml@main" + with: + group: "${{ matrix.group }}" + julia-version: "${{ matrix.version }}" + os: "${{ matrix.os }}" + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml new file mode 100644 index 0000000..cba9134 --- /dev/null +++ b/.github/workflows/CompatHelper.yml @@ -0,0 +1,16 @@ +name: CompatHelper +on: + schedule: + - cron: 0 0 * * * + workflow_dispatch: +jobs: + CompatHelper: + runs-on: ubuntu-latest + steps: + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} + run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml new file mode 100644 index 0000000..4d70962 --- /dev/null +++ b/.github/workflows/Documentation.yml @@ -0,0 +1,20 @@ +name: "Documentation" + +on: + push: + branches: + - main + tags: '*' + pull_request: + schedule: + - cron: '1 4 * * 4' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref_name != github.event.repository.default_branch || github.ref != 'refs/tags/v*' }} + +jobs: + build-and-deploy-docs: + name: "Documentation" + uses: "ITensor/JuliaActions/.github/workflows/Documentation.yml@main" + secrets: "inherit" diff --git a/.github/workflows/Formatter.yml b/.github/workflows/Formatter.yml new file mode 100644 index 0000000..351e488 --- /dev/null +++ b/.github/workflows/Formatter.yml @@ -0,0 +1,13 @@ +name: "Format Check" + +on: + push: + branches: + - 'main' + tags: '*' + pull_request: + +jobs: + format-check: + name: "Format Check" + uses: "ITensor/JuliaActions/.github/workflows/FormatCheck.yml@main" diff --git a/.github/workflows/Register.yml b/.github/workflows/Register.yml new file mode 100644 index 0000000..5b7cd3b --- /dev/null +++ b/.github/workflows/Register.yml @@ -0,0 +1,16 @@ +name: Register Package +on: + workflow_dispatch: + inputs: + version: + description: Version to register or component to bump + required: true +jobs: + register: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: julia-actions/RegisterAction@latest + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml new file mode 100644 index 0000000..0cd3114 --- /dev/null +++ b/.github/workflows/TagBot.yml @@ -0,0 +1,31 @@ +name: TagBot +on: + issue_comment: + types: + - created + workflow_dispatch: + inputs: + lookback: + default: "3" +permissions: + actions: read + checks: read + contents: write + deployments: read + issues: read + discussions: read + packages: read + pages: read + pull-requests: read + repository-projects: read + security-events: read + statuses: read +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ssh: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fbdec0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.jl.*.cov +*.jl.cov +*.jl.mem +*.o +*.swp +.DS_Store +.benchmarkci +.tmp +.vscode/ +/docs/Manifest.toml +/docs/build/ +Manifest.toml +benchmark/*.json +docs/build/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7f5c8c6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 ITensor developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..a8e2ee9 --- /dev/null +++ b/Project.toml @@ -0,0 +1,18 @@ +name = "BroadcastMapConversion" +uuid = "7726166c-068e-4473-bed7-0e8eb0255830" +authors = ["ITensor developers"] +version = "0.1.0" + +[compat] +Aqua = "0.8.9" +SafeTestsets = "0.1" +Test = "1.10" +julia = "1.10" + +[extras] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Aqua", "Test", "SafeTestsets"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..3156661 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +docs / src / index.md diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..7abaf86 --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,6 @@ +[deps] +BroadcastMapConversion = "7726166c-068e-4473-bed7-0e8eb0255830" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" + +[compat] +julia = "1.10" diff --git a/docs/makedocs.jl b/docs/makedocs.jl new file mode 100644 index 0000000..5cf0489 --- /dev/null +++ b/docs/makedocs.jl @@ -0,0 +1,23 @@ +using Pkg: Pkg +Pkg.develop(; path=joinpath(@__DIR__, "..")) + +using BroadcastMapConversion +using Documenter + +DocMeta.setdocmeta!( + BroadcastMapConversion, :DocTestSetup, :(using BroadcastMapConversion); recursive=true +) + +makedocs(; + modules=[BroadcastMapConversion], + authors="ITensor developers", + sitename="BroadcastMapConversion.jl", + format=Documenter.HTML(; + canonical="https://ITensor.github.io/BroadcastMapConversion.jl", + edit_link="main", + assets=String[], + ), + pages=["Home" => "index.md", "Lib" => "lib.md"], +) + +deploydocs(; repo="github.com/ITensor/BroadcastMapConversion.jl", devbranch="main") diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..6231971 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,43 @@ +# BroadcastMapConversion + +[![Docs][docs-img]][docs-url] +[![Build Status][ci-img]][ci-url] +[![Coverage][codecov-img]][codecov-url] +[![Code Style][style-img]][style-url] +[![Aqua][aqua-img]][aqua-url] + +[docs-img]: https://img.shields.io/badge/docs-latest%20release-blue.svg +[docs-url]: https://ITensor.github.io/BroadcastMapConversion.jl/stable/ + +[ci-img]: https://github.com/ITensor/BroadcastMapConversion.jl/actions/workflows/CI.yml/badge.svg?branch=main +[ci-url]: https://github.com/ITensor/BroadcastMapConversion.jl/actions/workflows/CI.yml?query=branch%3Amain + +[codecov-img]: https://codecov.io/gh/ITensor/BroadcastMapConversion.jl/branch/main/graph/badge.svg +[codecov-url]: https://codecov.io/gh/ITensor/BroadcastMapConversion.jl + +[style-img]: https://img.shields.io/badge/code%20style-blue-4495d1.svg +[style-url]: https://github.com/invenia/BlueStyle + +[aqua-img]: https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg +[aqua-url]: https://github.com/JuliaTesting/Aqua.jl + +This is a small package that provides a way to convert a `Broadcasted` object into a call to `map`. +It contains a slightly generalized version of the logic used in [Strided.jl](https://github.com/Jutho/Strided.jl), as can be seen [here](https://github.com/Jutho/Strided.jl/blob/v2.0.4/src/broadcast.jl). + +The core idea is to capture non-`AbstractArray` objects, such as `Number`s, as these have to be repeated across the dimensions of the `Broadcasted` object. +In `Strided.jl`, the logic is only used to capture non-`StridedView` objects, while here it is generalized to non-`AbstractArray` types. + +## Installation + +The package can be installed with the Julia package manager via its GitHub link. +From the Julia REPL, you can run: + +````julia +using Pkg: Pkg +Pkg.add("https://github.com/ITensor/BroadcastMapConversion.jl") +```` + +--- + +*This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).* + diff --git a/docs/src/lib.md b/docs/src/lib.md new file mode 100644 index 0000000..2ea410c --- /dev/null +++ b/docs/src/lib.md @@ -0,0 +1,8 @@ +## Lib + +```@index +``` + +```@autodocs +Modules = [BroadcastMapConversion] +``` diff --git a/examples/Project.toml b/examples/Project.toml new file mode 100644 index 0000000..105005a --- /dev/null +++ b/examples/Project.toml @@ -0,0 +1,6 @@ +[deps] +Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" + +[compat] +Literate = "2.9" +julia = "1.10" diff --git a/examples/README.jl b/examples/README.jl new file mode 100644 index 0000000..4377447 --- /dev/null +++ b/examples/README.jl @@ -0,0 +1,38 @@ +md""" +# BroadcastMapConversion + +[![Docs][docs-img]][docs-url] +[![Build Status][ci-img]][ci-url] +[![Coverage][codecov-img]][codecov-url] +[![Code Style][style-img]][style-url] +[![Aqua][aqua-img]][aqua-url] + +[docs-img]: https://img.shields.io/badge/docs-latest%20release-blue.svg +[docs-url]: https://ITensor.github.io/BroadcastMapConversion.jl/stable/ + +[ci-img]: https://github.com/ITensor/BroadcastMapConversion.jl/actions/workflows/CI.yml/badge.svg?branch=main +[ci-url]: https://github.com/ITensor/BroadcastMapConversion.jl/actions/workflows/CI.yml?query=branch%3Amain + +[codecov-img]: https://codecov.io/gh/ITensor/BroadcastMapConversion.jl/branch/main/graph/badge.svg +[codecov-url]: https://codecov.io/gh/ITensor/BroadcastMapConversion.jl + +[style-img]: https://img.shields.io/badge/code%20style-blue-4495d1.svg +[style-url]: https://github.com/invenia/BlueStyle + +[aqua-img]: https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg +[aqua-url]: https://github.com/JuliaTesting/Aqua.jl + +This is a small package that provides a way to convert a `Broadcasted` object into a call to `map`. +It contains a slightly generalized version of the logic used in [Strided.jl](https://github.com/Jutho/Strided.jl), as can be seen [here](https://github.com/Jutho/Strided.jl/blob/v2.0.4/src/broadcast.jl). + +The core idea is to capture non-`AbstractArray` objects, such as `Number`s, as these have to be repeated across the dimensions of the `Broadcasted` object. +In `Strided.jl`, the logic is only used to capture non-`StridedView` objects, while here it is generalized to non-`AbstractArray` types. + +## Installation + +The package can be installed with the Julia package manager via its GitHub link. +From the Julia REPL, you can run: +""" + +using Pkg: Pkg +Pkg.add("https://github.com/ITensor/BroadcastMapConversion.jl") diff --git a/examples/makereadme.jl b/examples/makereadme.jl new file mode 100644 index 0000000..9f9f672 --- /dev/null +++ b/examples/makereadme.jl @@ -0,0 +1,8 @@ +using Literate + +# Generate the README +input_readme = joinpath(@__DIR__, "README.jl") +output_dir = joinpath(@__DIR__, "..", "docs", "src") +Literate.markdown( + input_readme, output_dir; flavor=Literate.CommonMarkFlavor(), mdstrings=true, name="index" +) diff --git a/src/BroadcastMapConversion.jl b/src/BroadcastMapConversion.jl index 6edf0ae..9ef2dbd 100644 --- a/src/BroadcastMapConversion.jl +++ b/src/BroadcastMapConversion.jl @@ -25,6 +25,7 @@ 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[] @@ -45,4 +46,5 @@ function apply_tuple(t::Tuple, args) ttail, newargs = apply_tuple(Base.tail(t), newargs1) return (t1, ttail...), newargs end + end diff --git a/test/runtests.jl b/test/runtests.jl index 92e5d6a..e74a3dd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,10 @@ -@eval module $(gensym()) -using Test: @test, @testset -using NDTensors.BroadcastMapConversion: map_function, map_args -@testset "BroadcastMapConversion" begin +using SafeTestsets: @safetestset + +@time @safetestset "BroadcastMapConversion" begin + using Test: @test, @testset + using BroadcastMapConversion: map_function, map_args using Base.Broadcast: Broadcasted + c = 2.2 a = randn(2, 3) b = randn(2, 3) @@ -11,4 +13,9 @@ using NDTensors.BroadcastMapConversion: map_function, map_args bc = Broadcasted(+, (a, b)) @test copy(bc) ≈ a + b ≈ map(map_function(bc), map_args(bc)...) end + +@time @safetestset "Aqua tests" begin + using Aqua: Aqua + using BroadcastMapConversion: BroadcastMapConversion + Aqua.test_all(BroadcastMapConversion) end