diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md new file mode 100644 index 0000000..47f6f79 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -0,0 +1,62 @@ +--- +name: ITensorVisualizationBase.jl bug report +about: Create a bug report to help us improve ITensorVisualizationBase.jl +title: "[BUG] YOUR SHORT DESCRIPTION OF THE BUG HERE" +labels: ["bug"] +assignees: '' + +--- + +**Description of bug** + +Please give a brief description of the bug or unexpected behavior here. + +**Minimal code demonstrating the bug or unexpected behavior** + +If applicable, provide a minimal code that can be run to demonstrate the bug or unexpected behavior. + +If you are unable to construct a minimal code that demonstrates the bug or unexpected behavior, provide detailed steps for how to reproduce the behavior you are seeing. + +
Minimal runnable code

+ +```julia +[YOUR MINIMAL RUNNABLE CODE HERE] +``` + +

+ + +**Expected output or behavior** + +Describe what you expected to happen. + +If you provided a minimal code that can be run to demonstrate the bug or unexpected behavior, describe what you expected the output would be. + + +**Actual output or behavior** + +Describe what actually happened. + +If you provided a minimal code that demonstrates the bug or unexpected behavior, provide the output you get from that code. If the code leads to an error or warning, include the full error or warning below. + +
Output of minimal runnable code

+ +```julia +[OUTPUT OF YOUR MINIMAL RUNNABLE CODE HERE] +``` + +

+ + +**Version information** + + - Output from `versioninfo()`: +```julia +julia> versioninfo() +[YOUR OUTPUT HERE] +``` + - Output from `using Pkg; Pkg.status("ITensorVisualizationBase")`: +```julia +julia> using Pkg; Pkg.status("ITensorVisualizationBase") +[YOUR OUTPUT HERE] +``` diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 0000000..910ff1b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,24 @@ +--- +name: ITensorVisualizationBase.jl feature request +about: Suggest an idea for ITensorVisualizationBase.jl +title: "[ENHANCEMENT] YOUR SHORT DESCRIPTION OF THE FEATURE REQUEST HERE" +labels: ["enhancement"] +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** + +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** + +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** + +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** + +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..a3c5d5b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,42 @@ +# Description + +Please include a summary of the change and which issue is fixed (if applicable). Please also include relevant motivation and context. List any dependencies that are required for this change. + +Fixes #(issue) + +If practical and applicable, please include a minimal demonstration of the previous behavior and new behavior below. + +
Minimal demonstration of previous behavior

+ +```julia +[YOUR MINIMAL DEMONSTRATION OF PREVIOUS BEHAVIOR] +``` + +

+ +
Minimal demonstration of new behavior

+ +```julia +[YOUR MINIMAL DEMONSTRATION OF NEW BEHAVIOR] +``` + +

+ +# How Has This Been Tested? + +Please add tests that verify your changes to a file in the `test` directory. + +Please give a summary of the tests that you added to verify your changes. + +- [ ] Test A +- [ ] Test B + +# Checklist: + +- [ ] My code follows the style guidelines of this project. Please run the [ITensorFormatter](https://github.com/ITensor/ITensorFormatter.jl) in the base directory of the repository (`~/.julia/dev/ITensorVisualizationBase`) to format your code according to our style guidelines. +- [ ] I have performed a self-review of my own code. +- [ ] I have commented my code, particularly in hard-to-understand areas. +- [ ] I have added tests that verify the behavior of the changes I made. +- [ ] I have made corresponding changes to the documentation. +- [ ] My changes generate no new warnings. +- [ ] Any dependent changes have been merged and published in downstream modules. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 700707c..5ace460 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,6 @@ -# 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 + directory: "/" schedule: interval: "weekly" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml deleted file mode 100644 index d8890e0..0000000 --- a/.github/workflows/CI.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: CI -on: - push: - branches: - - main - tags: ['*'] - pull_request: - workflow_dispatch: -concurrency: - # Skip intermediate builds: always. - # Cancel intermediate builds: only if it is a pull request build. - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} -jobs: - test: - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created - actions: write - contents: read - strategy: - fail-fast: false - matrix: - version: - - 'lts' - - '1' - os: - - ubuntu-latest - - macOS-latest - - windows-latest - arch: - - x64 - steps: - - uses: actions/checkout@v6 - - uses: julia-actions/setup-julia@v2 - with: - version: ${{ matrix.version }} - arch: ${{ matrix.arch }} - - uses: julia-actions/cache@v3 - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-runtest@v1 - - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v5 - with: - files: lcov.info - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: false - docs: - name: Documentation - runs-on: ubuntu-latest - permissions: - actions: write # needed to allow julia-actions/cache to proactively delete old caches that it has created - contents: write - statuses: write - steps: - - uses: actions/checkout@v6 - - uses: julia-actions/setup-julia@v2 - with: - version: '1' - - uses: julia-actions/cache@v3 - - name: Configure doc environment - shell: julia --project=docs --color=yes {0} - run: | - using Pkg - Pkg.develop(PackageSpec(path=pwd())) - Pkg.instantiate() - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-docdeploy@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} - - name: Run doctests - shell: julia --project=docs --color=yes {0} - run: | - using Documenter: DocMeta, doctest - using ITensorVisualizationBase - DocMeta.setdocmeta!(ITensorVisualizationBase, :DocTestSetup, :(using ITensorVisualizationBase); recursive=true) - doctest(ITensorVisualizationBase) diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml new file mode 100644 index 0000000..c3b11ec --- /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/ITensorActions/.github/workflows/Documentation.yml@main" + with: + localregistry: "https://github.com/ITensor/ITensorRegistry.git" + secrets: + CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml new file mode 100644 index 0000000..3c290ea --- /dev/null +++ b/.github/workflows/FormatCheck.yml @@ -0,0 +1,16 @@ +name: "Format Check" +on: + pull_request_target: + types: + - "opened" + - "synchronize" + - "reopened" + - "ready_for_review" +permissions: + contents: "read" + actions: "write" + pull-requests: "write" +jobs: + format-check: + name: "Format Check" + uses: "ITensor/ITensorActions/.github/workflows/FormatCheck.yml@main" diff --git a/.github/workflows/FormatPullRequest.yml b/.github/workflows/FormatPullRequest.yml new file mode 100644 index 0000000..5a8b627 --- /dev/null +++ b/.github/workflows/FormatPullRequest.yml @@ -0,0 +1,16 @@ +name: "Format Pull Request" +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: ~ + issue_comment: + types: + - "created" +permissions: + contents: "write" + pull-requests: "write" +jobs: + format-pull-request: + name: "Format Pull Request" + uses: "ITensor/ITensorActions/.github/workflows/FormatPullRequest.yml@main" + secrets: "inherit" diff --git a/.github/workflows/IntegrationTest.yml b/.github/workflows/IntegrationTest.yml new file mode 100644 index 0000000..3531704 --- /dev/null +++ b/.github/workflows/IntegrationTest.yml @@ -0,0 +1,39 @@ +name: "IntegrationTest" +on: + push: + branches: + - "main" + tags: "*" + paths: + - "Project.toml" + pull_request: + types: + - "opened" + - "synchronize" + - "reopened" + - "ready_for_review" + - "converted_to_draft" + paths: + - "Project.toml" +jobs: + integration-test: + name: "IntegrationTest" + strategy: + matrix: + pkg: + - "__none__" + uses: "ITensor/ITensorActions/.github/workflows/IntegrationTest.yml@main" + with: + localregistry: "https://github.com/ITensor/ITensorRegistry.git" + pkg: "${{ matrix.pkg }}" + integration-gate: + name: "IntegrationTest" + needs: "integration-test" + if: "${{ always() && needs.integration-test.result != 'skipped' }}" + runs-on: "ubuntu-latest" + steps: + - name: "Fail if any downstream integration test failed" + run: | + echo "integration-test.result = ${{ needs.integration-test.result }}" + test "${{ needs.integration-test.result }}" = "success" + diff --git a/.github/workflows/IntegrationTestRequest.yml b/.github/workflows/IntegrationTestRequest.yml new file mode 100644 index 0000000..6f58e45 --- /dev/null +++ b/.github/workflows/IntegrationTestRequest.yml @@ -0,0 +1,14 @@ +name: "Integration Test Request" +on: + issue_comment: + types: + - "created" +jobs: + integrationrequest: + if: | + github.event.issue.pull_request && + contains(fromJSON('["OWNER", "COLLABORATOR", "MEMBER"]'), github.event.comment.author_association) + + uses: "ITensor/ITensorActions/.github/workflows/IntegrationTestRequest.yml@main" + with: + localregistry: "https://github.com/ITensor/ITensorRegistry.git" diff --git a/.github/workflows/Register.yml b/.github/workflows/Register.yml deleted file mode 100644 index 5b7cd3b..0000000 --- a/.github/workflows/Register.yml +++ /dev/null @@ -1,16 +0,0 @@ -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/Registrator.yml b/.github/workflows/Registrator.yml new file mode 100644 index 0000000..97dc033 --- /dev/null +++ b/.github/workflows/Registrator.yml @@ -0,0 +1,22 @@ +name: "Register Package" +on: + workflow_dispatch: ~ + push: + branches: + - "master" + - "main" + paths: + - "Project.toml" + issue_comment: + types: + - "created" +permissions: + contents: "write" + pull-requests: "write" + issues: "write" +jobs: + Register: + uses: "ITensor/ITensorActions/.github/workflows/Registrator.yml@main" + with: + localregistry: "ITensor/ITensorRegistry" + secrets: "inherit" diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index 0cd3114..f535119 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -1,31 +1,11 @@ -name: TagBot +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 + - "created" + workflow_dispatch: ~ 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 }} + if: "github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'" + uses: "ITensor/ITensorActions/.github/workflows/TagBot.yml@main" + secrets: "inherit" diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml new file mode 100644 index 0000000..70f6c8d --- /dev/null +++ b/.github/workflows/Tests.yml @@ -0,0 +1,53 @@ +name: "Tests" +on: + push: + branches: + - "master" + - "main" + - "release-" + tags: "*" + paths-ignore: + - "docs/**" + pull_request: + types: + - "opened" + - "synchronize" + - "reopened" + - "ready_for_review" + - "converted_to_draft" + workflow_dispatch: ~ +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: "${{ startsWith(github.ref, 'refs/pull/') }}" +jobs: + tests: + name: "Tests" + strategy: + fail-fast: false + matrix: + version: + - "lts" + - "1" + os: + - "ubuntu-latest" + - "macOS-latest" + - "windows-latest" + uses: "ITensor/ITensorActions/.github/workflows/Tests.yml@main" + with: + group: "${{ matrix.group }}" + julia-version: "${{ matrix.version }}" + os: "${{ matrix.os }}" + localregistry: "https://github.com/ITensor/ITensorRegistry.git" + secrets: + CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" + tests-gate: + name: "Tests" + needs: "tests" + if: "${{ always() && needs.tests.result != 'skipped' }}" + runs-on: "ubuntu-latest" + steps: + - name: "Fail if any matrix leg failed" + run: | + echo "tests.result = ${{ needs.tests.result }}" + test "${{ needs.tests.result }}" = "success" + diff --git a/.github/workflows/VersionCheck.yml b/.github/workflows/VersionCheck.yml new file mode 100644 index 0000000..bb0df88 --- /dev/null +++ b/.github/workflows/VersionCheck.yml @@ -0,0 +1,9 @@ +name: "Version Check" +on: + pull_request: ~ +jobs: + version-check: + name: "Version Check" + uses: "ITensor/ITensorActions/.github/workflows/VersionCheck.yml@main" + with: + localregistry: "https://github.com/ITensor/ITensorRegistry.git" diff --git a/.gitignore b/.gitignore index faa7bfd..d5d9e4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,14 @@ -Manifest.toml -.*.swp +*.cov +*.mem +*.o +*.swp +.DS_Store +.benchmarkci +.tmp +.vscode/ +LocalPreferences.toml +Manifest*.toml +benchmark/*.json +dev/ +docs/build/ +docs/src/index.md diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d5593c0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +ci: + skip: + - "itensor-formatter" +repos: + - repo: "https://github.com/pre-commit/pre-commit-hooks" + rev: "v6.0.0" + hooks: + - id: "check-merge-conflict" + - id: "check-toml" + - id: "check-yaml" + - id: "end-of-file-fixer" + exclude_types: + - "markdown" + - repo: "https://github.com/ITensor/itensorformatter-pre-commit" + rev: "v1.0.0" + hooks: + - id: "itensor-formatter" diff --git a/Project.toml b/Project.toml index 65abd68..3c35ea1 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ITensorVisualizationBase" uuid = "cd2553d2-8bef-4d93-8a38-c62f17d5ad23" +version = "0.1.15" authors = ["Matthew Fishman and contributors"] -version = "0.1.14" [workspace] projects = ["benchmark", "dev", "docs", "examples", "test"] @@ -21,12 +21,14 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" [compat] AbstractTrees = "0.4" -Compat = "3.40.0, 4" +Compat = "3.40, 4" GeometryBasics = "0.4.1, 0.5" Graphs = "1.4.1" ITensorMPS = "0.3" ITensors = "0.7, 0.8, 0.9" +LinearAlgebra = "1.10" MetaGraphs = "0.7.1, 0.8, 0.9" NetworkLayout = "0.4.3" +SparseArrays = "1.10" Statistics = "1.10" julia = "1.10" diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl new file mode 100644 index 0000000..45b79f4 --- /dev/null +++ b/benchmark/benchmarks.jl @@ -0,0 +1,7 @@ +using BenchmarkTools +using ITensorVisualizationBase + +SUITE = BenchmarkGroup() +SUITE["rand"] = @benchmarkable rand(10) + +# Write your benchmarks here. diff --git a/docs/Project.toml b/docs/Project.toml index 1814eb3..1b4c563 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,12 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +ITensorFormatter = "b6bf39f1-c9d3-4bad-aad8-593d802f65fd" +ITensorVisualizationBase = "cd2553d2-8bef-4d93-8a38-c62f17d5ad23" + +[sources.ITensorVisualizationBase] +path = ".." [compat] Documenter = "1" +ITensorFormatter = "0.2.27" +ITensorVisualizationBase = "0.1" diff --git a/docs/make.jl b/docs/make.jl index 7508ce6..b9e70b9 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,20 +1,27 @@ -using ITensorVisualizationBase -using Documenter +using Documenter: Documenter, DocMeta, deploydocs, makedocs +using ITensorFormatter: ITensorFormatter +using ITensorVisualizationBase: ITensorVisualizationBase DocMeta.setdocmeta!( - ITensorVisualizationBase, :DocTestSetup, :(using ITensorVisualizationBase); recursive=true + ITensorVisualizationBase, :DocTestSetup, :(using ITensorVisualizationBase); + recursive = true ) +ITensorFormatter.make_index!(pkgdir(ITensorVisualizationBase)) + makedocs(; - modules=[ITensorVisualizationBase], - authors="ITensor developers", - sitename="ITensorVisualizationBase.jl", - format=Documenter.HTML(; - canonical="https://ITensor.github.io/ITensorVisualizationBase.jl", - edit_link="main", - assets=String[], - ), - pages=["Home" => "index.md"], + modules = [ITensorVisualizationBase], + authors = "ITensor developers and contributors", + sitename = "ITensorVisualizationBase.jl", + format = Documenter.HTML(; + canonical = "https://itensor.github.io/ITensorVisualizationBase.jl", + edit_link = "main", + assets = ["assets/favicon.ico", "assets/extras.css"] + ), + pages = ["Home" => "index.md", "Reference" => "reference.md"] ) -deploydocs(; repo="github.com/ITensor/ITensorVisualizationBase.jl", devbranch="main") +deploydocs(; + repo = "github.com/ITensor/ITensorVisualizationBase.jl", devbranch = "main", + push_preview = true +) diff --git a/docs/src/assets/CCQ-dark.png b/docs/src/assets/CCQ-dark.png new file mode 100644 index 0000000..fbaef52 Binary files /dev/null and b/docs/src/assets/CCQ-dark.png differ diff --git a/docs/src/assets/CCQ.png b/docs/src/assets/CCQ.png new file mode 100644 index 0000000..e13f908 Binary files /dev/null and b/docs/src/assets/CCQ.png differ diff --git a/docs/src/assets/extras.css b/docs/src/assets/extras.css new file mode 100644 index 0000000..aaab0f8 --- /dev/null +++ b/docs/src/assets/extras.css @@ -0,0 +1,15 @@ +.display-light-only { + display: block; +} + +.display-dark-only { + display: none; +} + +.theme--documenter-dark .display-light-only { + display: none; +} + +.theme--documenter-dark .display-dark-only { + display: block; +} diff --git a/docs/src/assets/favicon.ico b/docs/src/assets/favicon.ico new file mode 100644 index 0000000..0b06780 Binary files /dev/null and b/docs/src/assets/favicon.ico differ diff --git a/docs/src/assets/logo-dark.png b/docs/src/assets/logo-dark.png new file mode 100644 index 0000000..7450635 Binary files /dev/null and b/docs/src/assets/logo-dark.png differ diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png new file mode 100644 index 0000000..2682e14 Binary files /dev/null and b/docs/src/assets/logo.png differ diff --git a/docs/src/reference.md b/docs/src/reference.md new file mode 100644 index 0000000..8d30075 --- /dev/null +++ b/docs/src/reference.md @@ -0,0 +1,5 @@ +# Reference + +```@autodocs +Modules = [ITensorVisualizationBase] +``` diff --git a/examples/Project.toml b/examples/Project.toml index e10076a..6d84b76 100644 --- a/examples/Project.toml +++ b/examples/Project.toml @@ -1,17 +1,8 @@ [deps] -GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" -ITensorMPS = "0d1a4710-d33b-49a5-8f18-73bdf49b47e2" ITensorVisualizationBase = "cd2553d2-8bef-4d93-8a38-c62f17d5ad23" -ITensors = "9136182c-28ba-11e9-034c-db9fb085ebd5" -LayeredLayouts = "f4a74d36-062a-4d48-97cd-1356bad1de4e" -NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a" + +[sources.ITensorVisualizationBase] +path = ".." [compat] -GeometryBasics = "0.4.1, 0.5" -Graphs = "1.4.1" -ITensorMPS = "0.3" ITensorVisualizationBase = "0.1" -ITensors = "0.7, 0.8, 0.9" -LayeredLayouts = "0.2" -NetworkLayout = "0.4.3" diff --git a/examples/ex_2d_tensor_network_layered.jl b/examples/ex_2d_tensor_network_layered.jl index 8a652b8..733021f 100644 --- a/examples/ex_2d_tensor_network_layered.jl +++ b/examples/ex_2d_tensor_network_layered.jl @@ -1,9 +1,9 @@ -using ITensors +using Graphs using ITensorVisualizationBase +using ITensors using LayeredLayouts -using Graphs -tn = itensornetwork(grid((4, 4)); linkspaces=3) +tn = itensornetwork(grid((4, 4)); linkspaces = 3) layout(g) = layered_layout(solve_positions(Zarate(), g)) @visualize fig tn arrow_show = true layout = layout diff --git a/examples/ex_dmrg.jl b/examples/ex_dmrg.jl index b4c3778..b80151f 100644 --- a/examples/ex_dmrg.jl +++ b/examples/ex_dmrg.jl @@ -1,17 +1,17 @@ -using ITensors using ITensorVisualizationBase +using ITensors N = 10 -sites(n) = Index([QN("Sz", 0) => 1, QN("Sz", 1) => 1]; tags="S=1/2,Site,n=$n") -l(n) = Index([QN("Sz", 0) => 10, QN("Sz", 1) => 10]; tags="Link,l=$n") -h(n) = Index([QN("Sz", 0) => 5, QN("Sz", 1) => 5]; tags="ham,Link,l=$n") +sites(n) = Index([QN("Sz", 0) => 1, QN("Sz", 1) => 1]; tags = "S=1/2,Site,n=$n") +l(n) = Index([QN("Sz", 0) => 10, QN("Sz", 1) => 10]; tags = "Link,l=$n") +h(n) = Index([QN("Sz", 0) => 5, QN("Sz", 1) => 5]; tags = "ham,Link,l=$n") s⃗ = [sites(n) for n in 1:N] l⃗ = [l(n) for n in 1:(N - 1)] h⃗ = [h(n) for n in 1:(N - 1)] # Add some more indices between two of the tensors -x = Index([QN("Sz", 0) => 2]; tags="X") -y = Index([QN("Sz", 0) => 2]; tags="Y") +x = Index([QN("Sz", 0) => 2]; tags = "X") +y = Index([QN("Sz", 0) => 2]; tags = "Y") n = 2 ψn1n2 = random_itensor(l⃗[n - 1], s⃗[n], s⃗[n + 1], l⃗[n + 1], dag(x), dag(y)) @@ -20,10 +20,10 @@ hn2 = random_itensor(dag(h⃗[n]), s⃗[n + 1]', dag(s⃗[n + 1]), h⃗[n + 1]) ELn0 = random_itensor(l⃗[n - 1]', h⃗[n - 1], dag(l⃗[n - 1])) ERn2 = random_itensor(l⃗[n + 1]', dag(h⃗[n + 1]), dag(l⃗[n + 1])) -edge_labels = (; plevs=true) +edge_labels = (; plevs = true) R = @visualize fig1 ELn0 * ψn1n2 * hn1 * hn2 * ERn2 edge_labels = edge_labels vertex_size = - 50 + 50 @show R ≈ ELn0 * ψn1n2 * hn1 * hn2 * ERn2 # Split it up into multiple contractions diff --git a/examples/ex_grid_layout.jl b/examples/ex_grid_layout.jl index 9795c23..6244a12 100644 --- a/examples/ex_grid_layout.jl +++ b/examples/ex_grid_layout.jl @@ -1,12 +1,12 @@ -using ITensors -using ITensorVisualizationBase using GeometryBasics using Graphs +using ITensorVisualizationBase +using ITensors using NetworkLayout N = 10 g = grid((N,)) -tn = itensornetwork(g; linkspaces=10, sitespaces=2) -@visualize fig tn siteinds_direction = Point(1, -0.5) layout = SquareGrid(; cols=1) width = - 20 height = 50 +tn = itensornetwork(g; linkspaces = 10, sitespaces = 2) +@visualize fig tn siteinds_direction = Point(1, -0.5) layout = SquareGrid(; cols = 1) width = + 20 height = 50 fig diff --git a/examples/ex_itensor_graph_makie.jl b/examples/ex_itensor_graph_makie.jl index 802d0ef..3db9568 100644 --- a/examples/ex_itensor_graph_makie.jl +++ b/examples/ex_itensor_graph_makie.jl @@ -1,9 +1,9 @@ -using ITensors -using ITensorVisualizationBase using Graphs +using ITensorVisualizationBase +using ITensors g = grid((5,)) -tn = itensornetwork(g; linkspaces=10, sitespaces=2) +tn = itensornetwork(g; linkspaces = 10, sitespaces = 2) @visualize fig tn fig diff --git a/examples/ex_itensor_graph_unicode.jl b/examples/ex_itensor_graph_unicode.jl index 802d0ef..3db9568 100644 --- a/examples/ex_itensor_graph_unicode.jl +++ b/examples/ex_itensor_graph_unicode.jl @@ -1,9 +1,9 @@ -using ITensors -using ITensorVisualizationBase using Graphs +using ITensorVisualizationBase +using ITensors g = grid((5,)) -tn = itensornetwork(g; linkspaces=10, sitespaces=2) +tn = itensornetwork(g; linkspaces = 10, sitespaces = 2) @visualize fig tn fig diff --git a/examples/ex_qn_mps.jl b/examples/ex_qn_mps.jl index 583ba34..20d8e7a 100644 --- a/examples/ex_qn_mps.jl +++ b/examples/ex_qn_mps.jl @@ -1,14 +1,14 @@ -using ITensors using ITensorMPS using ITensorVisualizationBase +using ITensors -s = siteinds("S=1/2", 5; conserve_qns=true) -ψ = random_mps(s, n -> isodd(n) ? "↑" : "↓"; linkdims=2) +s = siteinds("S=1/2", 5; conserve_qns = true) +ψ = random_mps(s, n -> isodd(n) ? "↑" : "↓"; linkdims = 2) orthogonalize!(ψ, 2) ψdag = prime(linkinds, dag(ψ)) tn = [ψ..., ψdag...] -edge_labels = (; plevs=true, qns=true) +edge_labels = (; plevs = true, qns = true) @visualize fig tn edge_labels = edge_labels edge_textsize = 20 fig diff --git a/examples/ex_quantum_circuit.jl b/examples/ex_quantum_circuit.jl index 8e121df..25893a7 100644 --- a/examples/ex_quantum_circuit.jl +++ b/examples/ex_quantum_circuit.jl @@ -1,8 +1,8 @@ -using ITensors +using Graphs using ITensorMPS using ITensorVisualizationBase +using ITensors using LayeredLayouts -using Graphs N = 10 layers = 10 @@ -14,11 +14,11 @@ layer(N) = append!(layer(N, 1), layer(N, 2)) layer_N = layer(N) gates = [] for _ in 1:layers - append!(gates, layer_N) + append!(gates, layer_N) end for _ in 1:ndelete - deleteat!(gates, rand(eachindex(gates))) + deleteat!(gates, rand(eachindex(gates))) end U, s̃ = circuit_network(gates, s) @@ -26,7 +26,7 @@ U, s̃ = circuit_network(gates, s) ψ̃ = prod(MPS(s̃)) tn = [ψ, U..., ψ̃] -edge_labels = (; plevs=true) +edge_labels = (; plevs = true) layout(g) = layered_layout(solve_positions(Zarate(), g)) @visualize fig tn arrow_show = true edge_labels = edge_labels layout = layout diff --git a/examples/ex_visualize_3d.jl b/examples/ex_visualize_3d.jl index de61049..e2e5573 100644 --- a/examples/ex_visualize_3d.jl +++ b/examples/ex_visualize_3d.jl @@ -1,9 +1,9 @@ -using ITensors -using ITensorVisualizationBase using Graphs +using ITensorVisualizationBase +using ITensors tn = itensornetwork(grid((3, 3, 3))) -edge_labels = (; dims=false) +edge_labels = (; dims = false) @visualize fig tn ndims = 3 edge_labels = edge_labels vertex_size = 400 fig diff --git a/src/ITensorVisualizationBase.jl b/src/ITensorVisualizationBase.jl index 46c5325..2f9403c 100644 --- a/src/ITensorVisualizationBase.jl +++ b/src/ITensorVisualizationBase.jl @@ -1,49 +1,31 @@ module ITensorVisualizationBase +import ITensors.ITensorVisualizationCore: visualize, visualize!, visualize_sequence using AbstractTrees using Compat using GeometryBasics using Graphs +using Graphs: Graphs, AbstractEdge, AbstractGraph, SimpleDiGraph, SimpleGraph, add_edge!, + add_vertex!, all_neighbors, dst, edges, ne, neighbors, nv, src, vertices using ITensors using ITensors.ITensorVisualizationCore +using ITensors: QNIndex, data using LinearAlgebra using MetaGraphs using NetworkLayout using SparseArrays using Statistics -# Avoid conflict between `Graphs.contract` and `ITensors.contract` -using Graphs: - Graphs, - AbstractEdge, - AbstractGraph, - SimpleGraph, - SimpleDiGraph, - add_edge!, - add_vertex!, - all_neighbors, - dst, - edges, - ne, - neighbors, - nv, - src, - vertices - -using ITensors: data, QNIndex - -import ITensors.ITensorVisualizationCore: visualize, visualize!, visualize_sequence - export @visualize, - @visualize!, - @visualize_noeval, - @visualize_noeval!, - @visualize_sequence, - @visualize_sequence_noeval, - circuit_network, - itensornetwork, - layered_layout, - IndexLabels + @visualize!, + @visualize_noeval, + @visualize_noeval!, + @visualize_sequence, + @visualize_sequence_noeval, + circuit_network, + itensornetwork, + layered_layout, + IndexLabels # Some general graph functionality include("graphs.jl") diff --git a/src/backends_interface.jl b/src/backends_interface.jl index 9d2476d..8e5d83e 100644 --- a/src/backends_interface.jl +++ b/src/backends_interface.jl @@ -8,35 +8,35 @@ backend(::Backend{N}) where {N} = N Backend() = Backend{Symbol()}() macro Backend_str(s) - return Backend{Symbol(s)} + return Backend{Symbol(s)} end -const current_backend = Ref{Union{Nothing,Backend}}(nothing) +const current_backend = Ref{Union{Nothing, Backend}}(nothing) visualize(::Backend{nothing}, args...; kwargs...) = nothing set_backend!(::Nothing) = (current_backend[] = nothing) function set_backend!(backend::Backend) - original_backend = current_backend[] - current_backend[] = backend - return original_backend + original_backend = current_backend[] + current_backend[] = backend + return original_backend end -set_backend!(backend::Union{Symbol,String}) = set_backend!(Backend(backend)) +set_backend!(backend::Union{Symbol, String}) = set_backend!(Backend(backend)) get_backend() = isnothing(current_backend[]) ? default_backend() : current_backend[] function plot(::Backend{T}, args...; kwargs...) where {T} - return error("plot not implemented for backend type $T.") + return error("plot not implemented for backend type $T.") end function draw_edge!(::Backend{T}, args...; kwargs...) where {T} - return error("draw_edge! not implemented for backend type $T.") + return error("draw_edge! not implemented for backend type $T.") end function annotate!(::Backend{T}, args...; kwargs...) where {T} - return error("annotate! not implemented for backend type $T.") + return error("annotate! not implemented for backend type $T.") end function translate_color(::Backend{T}, color) where {T} - return error("translate_color not implemented for backend type $T and color $color") + return error("translate_color not implemented for backend type $T and color $color") end point_to_line(v1, v2) = ([v1[1], v2[1]], [v1[2], v2[2]]) diff --git a/src/defaults.jl b/src/defaults.jl index a43d72b..9e309cb 100644 --- a/src/defaults.jl +++ b/src/defaults.jl @@ -9,25 +9,25 @@ default_backend() = Backend(nothing) # function subscript_char(n::Integer) - @assert 0 ≤ n ≤ 9 - return Char(0x2080 + n) + @assert 0 ≤ n ≤ 9 + return Char(0x2080 + n) end function subscript(n::Integer) - ss = prod(Iterators.reverse((subscript_char(d) for d in digits(abs(n))))) - if n < 0 - ss = "₋" * ss - end - return ss + ss = prod(Iterators.reverse((subscript_char(d) for d in digits(abs(n))))) + if n < 0 + ss = "₋" * ss + end + return ss end subscript(n) = string(n) default_vertex_labels_prefix(b::Backend, g) = "T" function default_vertex_labels( - b::Backend, g::AbstractGraph, vertex_labels_prefix=default_vertex_labels_prefix(b) -) - return [string(vertex_labels_prefix, subscript(v)) for v in vertices(g)] + b::Backend, g::AbstractGraph, vertex_labels_prefix = default_vertex_labels_prefix(b) + ) + return [string(vertex_labels_prefix, subscript(v)) for v in vertices(g)] end default_vertex_size(b::Backend, g) = 60 @@ -44,11 +44,11 @@ default_vertex_textsize(b::Backend, g) = 20 default_edge_textsize(b::Backend) = 30 function default_edge_labels(b::Backend, g::AbstractGraph) - return fill("", ne(g)) + return fill("", ne(g)) end function default_edge_labels(b::Backend, g::AbstractMetaGraph) - return IndexLabels(b) + return IndexLabels(b) end default_dims(b::Backend) = true @@ -63,59 +63,59 @@ abstract type AbstractEdgeLabels end (l::AbstractEdgeLabels)(g::AbstractGraph) = edge_labels(l, g) struct IndexLabels <: AbstractEdgeLabels - dims::Bool - tags::Bool - ids::Bool - plevs::Bool - qns::Bool - newlines::Bool + dims::Bool + tags::Bool + ids::Bool + plevs::Bool + qns::Bool + newlines::Bool end IndexLabels(; kwargs...) = IndexLabels(Backend(); kwargs...) IndexLabels(backend; kwargs...) = IndexLabels(Backend(backend); kwargs...) function IndexLabels( - b::Backend; - dims=default_dims(b), - tags=default_tags(b), - ids=default_ids(b), - plevs=default_plevs(b), - qns=default_qns(b), - newlines=default_newlines(b), -) - return IndexLabels(dims, tags, ids, plevs, qns, newlines) + b::Backend; + dims = default_dims(b), + tags = default_tags(b), + ids = default_ids(b), + plevs = default_plevs(b), + qns = default_qns(b), + newlines = default_newlines(b) + ) + return IndexLabels(dims, tags, ids, plevs, qns, newlines) end edge_labels(b::Backend, l::Vector{String}, g::AbstractGraph) = l function edge_labels(b::Backend, l::IndexLabels, g::AbstractGraph) - return edge_labels(l, g) + return edge_labels(l, g) end function edge_labels(l::IndexLabels, g::AbstractGraph) - return String[edge_label(l, g, e) for e in edges(g)] + return String[edge_label(l, g, e) for e in edges(g)] end function edge_labels(b::Backend, params::NamedTuple, g::AbstractGraph) - return IndexLabels(b; params...)(g) + return IndexLabels(b; params...)(g) end function edge_label(l::IndexLabels, g::AbstractMetaGraph, e) - indsₑ = get_prop(g, e, :inds) - return label_string( - indsₑ; - is_self_loop=is_self_loop(e), - dims=l.dims, - tags=l.tags, - ids=l.ids, - plevs=l.plevs, - qns=l.qns, - newlines=l.newlines, - ) + indsₑ = get_prop(g, e, :inds) + return label_string( + indsₑ; + is_self_loop = is_self_loop(e), + dims = l.dims, + tags = l.tags, + ids = l.ids, + plevs = l.plevs, + qns = l.qns, + newlines = l.newlines + ) end function _edge_label(l, g::AbstractGraph, e) - return string(e) + return string(e) end edge_label(l::IndexLabels, g::AbstractGraph, e) = _edge_label(l, g, e) @@ -130,68 +130,75 @@ idstring(i::Index) = string(id(i) % 1000) tagsstring(i::Index) = string(tags(i)) qnstring(i::Index) = "" function qnstring(i::QNIndex) - str = "[" - for (n, qnblock) in pairs(space(i)) - str *= "$qnblock" - if n ≠ lastindex(space(i)) - str *= ", " + str = "[" + for (n, qnblock) in pairs(space(i)) + str *= "$qnblock" + if n ≠ lastindex(space(i)) + str *= ", " + end + end + str *= "]" + if dir(i) == ITensors.In + str *= "†" end - end - str *= "]" - if dir(i) == ITensors.In - str *= "†" - end - return str + return str end function label_string(i::Index; dims, tags, plevs, ids, qns) - showing_plev = plevs && (plev(i) > 0) - - str = "" - if any((tags, showing_plev, ids, qns)) - str *= "(" - end - if dims - str *= string(dim(i)) - end - if ids + showing_plev = plevs && (plev(i) > 0) + + str = "" + if any((tags, showing_plev, ids, qns)) + str *= "(" + end if dims - str *= "|" + str *= string(dim(i)) + end + if ids + if dims + str *= "|" + end + str *= idstring(i) + end + if tags + if any((dims, ids)) + str *= "|" + end + str *= tagsstring(i) + end + if any((tags, showing_plev, ids, qns)) + str *= ")" + end + if plevs + str *= plevstring(i) end - str *= idstring(i) - end - if tags - if any((dims, ids)) - str *= "|" + if qns + str *= qnstring(i) end - str *= tagsstring(i) - end - if any((tags, showing_plev, ids, qns)) - str *= ")" - end - if plevs - str *= plevstring(i) - end - if qns - str *= qnstring(i) - end - return str -end - -function label_string(is; is_self_loop=false, dims, tags, plevs, ids, qns, newlines) - str = "" - for n in eachindex(is) - str *= label_string(is[n]; dims=dims, tags=tags, plevs=plevs, ids=ids, qns=qns) - if n ≠ lastindex(is) - if any((dims, tags, ids, qns)) - str *= "⊗" - end - if newlines && any((tags, ids, qns)) - str *= "\n" - end + return str +end + +function label_string(is; is_self_loop = false, dims, tags, plevs, ids, qns, newlines) + str = "" + for n in eachindex(is) + str *= label_string( + is[n]; + dims = dims, + tags = tags, + plevs = plevs, + ids = ids, + qns = qns + ) + if n ≠ lastindex(is) + if any((dims, tags, ids, qns)) + str *= "⊗" + end + if newlines && any((tags, ids, qns)) + str *= "\n" + end + end end - end - return str + return str end ############################################################################# @@ -199,15 +206,15 @@ end # function width(inds) - return log2(dim(inds)) + 1 + return log2(dim(inds)) + 1 end function default_edge_widths(b::Backend, g::AbstractMetaGraph) - return Float64[width(get_prop(g, e, :inds)) for e in edges(g)] + return Float64[width(get_prop(g, e, :inds)) for e in edges(g)] end function default_edge_widths(b::Backend, g::AbstractGraph) - return fill(one(Float64), ne(g)) + return fill(one(Float64), ne(g)) end ############################################################################# @@ -219,14 +226,14 @@ default_arrow_size(b::Backend, g) = 30 _hasqns(tn::Vector{ITensor}) = any(hasqns, tn) function _hasqns(g::AbstractMetaGraph) - if iszero(ne(g)) - if has_prop(g, first(vertices(g)), :inds) - return hasqns(get_prop(g, first(vertices(g)), :inds)) - else - return hasqns(()) + if iszero(ne(g)) + if has_prop(g, first(vertices(g)), :inds) + return hasqns(get_prop(g, first(vertices(g)), :inds)) + else + return hasqns(()) + end end - end - return hasqns(get_prop(g, first(edges(g)), :inds)) + return hasqns(get_prop(g, first(edges(g)), :inds)) end _hasqns(g::AbstractGraph) = false diff --git a/src/experimental/spanning_trees/mst.jl b/src/experimental/spanning_trees/mst.jl index fa3e278..4d1858d 100644 --- a/src/experimental/spanning_trees/mst.jl +++ b/src/experimental/spanning_trees/mst.jl @@ -1,12 +1,14 @@ -using Graphs, SimpleWeightedGraphs -using GraphRecipes, Plots +using GraphRecipes +using Graphs +using Plots +using SimpleWeightedGraphs #spanning_tree_method = "mst" spanning_tree_method = "bfs" nx, ny = 7, 7 n = nx * ny -g = Graphs.grid((nx, ny); periodic=false) +g = Graphs.grid((nx, ny); periodic = false) nx_middle = nx ÷ 2 + 1 ny_middle = ny ÷ 2 + 1 @@ -20,52 +22,52 @@ names = dist wg = SimpleWeightedGraph(nv(g)) for e in edges(g) - dw = mean([dist[src(e)], dist[dst(e)]]) - w = 1 / dw^2 + eps() * randn() - add_edge!(wg, src(e), dst(e), w) + dw = mean([dist[src(e)], dist[dst(e)]]) + w = 1 / dw^2 + eps() * randn() + add_edge!(wg, src(e), dst(e), w) end g_st = if spanning_tree_method == "mst" - # mst_function = boruvka_mst - mst_function = kruskal_mst - mst_weight = mst_function(wg; minimize=false) - mst = mst_function == boruvka_mst ? mst_weight.mst : mst_weight - g_mst = SimpleWeightedGraph(nv(wg)) - for ew in mst - add_edge!(g_mst, src(ew), dst(ew), weight(ew)) - end - g_mst + # mst_function = boruvka_mst + mst_function = kruskal_mst + mst_weight = mst_function(wg; minimize = false) + mst = mst_function == boruvka_mst ? mst_weight.mst : mst_weight + g_mst = SimpleWeightedGraph(nv(wg)) + for ew in mst + add_edge!(g_mst, src(ew), dst(ew), weight(ew)) + end + g_mst elseif spanning_tree_method == "bfs" - # Weights are set to 1 - SimpleWeightedGraph(dfs_tree(wg, n_middle)) + # Weights are set to 1 + SimpleWeightedGraph(dfs_tree(wg, n_middle)) end -edgelabel_dict = Dict{Tuple{Int,Int},String}() +edgelabel_dict = Dict{Tuple{Int, Int}, String}() for ew in edges(wg) - edgelabel_dict[(src(ew), dst(ew))] = string(round(weight(ew); digits=2)) + edgelabel_dict[(src(ew), dst(ew))] = string(round(weight(ew); digits = 2)) end edgecolor_dict = Dict() for ew in edges(wg) - color = ew ∈ edges(g_st) ? :black : :red - edgecolor_dict[(src(ew), dst(ew))] = color + color = ew ∈ edges(g_st) ? :black : :red + edgecolor_dict[(src(ew), dst(ew))] = color end edgelabel_dict_mst = Dict() for i in vertices(g_st), j in vertices(g_st) - edgelabel_dict_mst[(i, j)] = string(round(get_weight(g_st, i, j); digits=2)) + edgelabel_dict_mst[(i, j)] = string(round(get_weight(g_st, i, j); digits = 2)) end plt = graphplot( - wg; - markersize=0.3, - names=names, - edgelabel=edgelabel_dict, - curves=false, - edgecolor=edgecolor_dict, - linewidth=20, - fontsize=20, - size=(3000, 3000), + wg; + markersize = 0.3, + names = names, + edgelabel = edgelabel_dict, + curves = false, + edgecolor = edgecolor_dict, + linewidth = 20, + fontsize = 20, + size = (3000, 3000) ) plt diff --git a/src/experimental/spanning_trees/shortest_path_tree.jl b/src/experimental/spanning_trees/shortest_path_tree.jl index 0cfb3a7..802aade 100644 --- a/src/experimental/spanning_trees/shortest_path_tree.jl +++ b/src/experimental/spanning_trees/shortest_path_tree.jl @@ -4,18 +4,18 @@ using Random Random.seed!(1234) function dijkstra_spt(g, v_src_initial) - out = dijkstra_shortest_paths(g, [v_src_initial]; allpaths=true, trackvertices=true) - paths = out.predecessors - edges = Edge{Int}[] - for v_dst_final in eachindex(paths) - v_src = v_src_initial - p = paths[v_dst_final] - @show v_src_initial, p, v_dst_final - for v_src in p - push!(edges, Edge(v_src => v_dst_final)) + out = dijkstra_shortest_paths(g, [v_src_initial]; allpaths = true, trackvertices = true) + paths = out.predecessors + edges = Edge{Int}[] + for v_dst_final in eachindex(paths) + v_src = v_src_initial + p = paths[v_dst_final] + @show v_src_initial, p, v_dst_final + for v_src in p + push!(edges, Edge(v_src => v_dst_final)) + end end - end - return edges + return edges end g = Graph(6, 10) diff --git a/src/experimental/spanning_trees/spanning_tree.jl b/src/experimental/spanning_trees/spanning_tree.jl index 1efc971..cae42b0 100644 --- a/src/experimental/spanning_trees/spanning_tree.jl +++ b/src/experimental/spanning_trees/spanning_tree.jl @@ -1,12 +1,14 @@ -using Graphs, SimpleWeightedGraphs -using GraphRecipes, Plots +using GraphRecipes +using Graphs +using Plots +using SimpleWeightedGraphs #spanning_tree_method = "mst" spanning_tree_method = "bfs" nx, ny = 7, 7 n = nx * ny -g = Graphs.grid((nx, ny); periodic=false) +g = Graphs.grid((nx, ny); periodic = false) nx_middle = 1 #nx ÷ 2 + 1 ny_middle = 1 #ny ÷ 2 + 1 @@ -20,52 +22,52 @@ names = dist wg = SimpleWeightedGraph(nv(g)) for e in edges(g) - dw = mean([dist[src(e)], dist[dst(e)]]) - w = 1 / dw^2 + eps() * randn() - add_edge!(wg, src(e), dst(e), w) + dw = mean([dist[src(e)], dist[dst(e)]]) + w = 1 / dw^2 + eps() * randn() + add_edge!(wg, src(e), dst(e), w) end g_st = if spanning_tree_method == "mst" - # mst_function = boruvka_mst - mst_function = kruskal_mst - mst_weight = mst_function(wg; minimize=false) - mst = mst_function == boruvka_mst ? mst_weight.mst : mst_weight - g_mst = SimpleWeightedGraph(nv(wg)) - for ew in mst - add_edge!(g_mst, src(ew), dst(ew), weight(ew)) - end - g_mst + # mst_function = boruvka_mst + mst_function = kruskal_mst + mst_weight = mst_function(wg; minimize = false) + mst = mst_function == boruvka_mst ? mst_weight.mst : mst_weight + g_mst = SimpleWeightedGraph(nv(wg)) + for ew in mst + add_edge!(g_mst, src(ew), dst(ew), weight(ew)) + end + g_mst elseif spanning_tree_method == "bfs" - # Weights are set to 1 - SimpleWeightedGraph(bfs_tree(wg, n_middle)) + # Weights are set to 1 + SimpleWeightedGraph(bfs_tree(wg, n_middle)) end -edgelabel_dict = Dict{Tuple{Int,Int},String}() +edgelabel_dict = Dict{Tuple{Int, Int}, String}() for ew in edges(wg) - edgelabel_dict[(src(ew), dst(ew))] = string(round(weight(ew); digits=2)) + edgelabel_dict[(src(ew), dst(ew))] = string(round(weight(ew); digits = 2)) end edgecolor_dict = Dict() for ew in edges(wg) - color = ew ∈ edges(g_st) ? :black : :red - edgecolor_dict[(src(ew), dst(ew))] = color + color = ew ∈ edges(g_st) ? :black : :red + edgecolor_dict[(src(ew), dst(ew))] = color end edgelabel_dict_mst = Dict() for i in vertices(g_st), j in vertices(g_st) - edgelabel_dict_mst[(i, j)] = string(round(get_weight(g_st, i, j); digits=2)) + edgelabel_dict_mst[(i, j)] = string(round(get_weight(g_st, i, j); digits = 2)) end plt = graphplot( - wg; - markersize=0.3, - names=names, - edgelabel=edgelabel_dict, - curves=false, - edgecolor=edgecolor_dict, - linewidth=20, - fontsize=20, - size=(3000, 3000), + wg; + markersize = 0.3, + names = names, + edgelabel = edgelabel_dict, + curves = false, + edgecolor = edgecolor_dict, + linewidth = 20, + fontsize = 20, + size = (3000, 3000) ) plt diff --git a/src/itensor_graph.jl b/src/itensor_graph.jl index e23fd0d..8ad2aeb 100644 --- a/src/itensor_graph.jl +++ b/src/itensor_graph.jl @@ -7,55 +7,55 @@ using ITensors.SiteTypes: op hasuniqueinds(args...; kwargs...) = !isempty(uniqueinds(args...; kwargs...)) function graph_dir(inds) - dirs = dir.(inds) - if length(dirs) == 1 - return only(dirs) - end - if all(==(dirs[1]), dirs) - return dirs[1] - end - return ITensors.Out + dirs = dir.(inds) + if length(dirs) == 1 + return only(dirs) + end + if all(==(dirs[1]), dirs) + return dirs[1] + end + return ITensors.Out end # TODO: rename graph, dispatch on QNs to DiGraph function Graphs.SimpleDiGraph(tn::Vector{ITensor}) - nv = length(tn) - g = SimpleDiGraph(nv) - for v1 in 1:nv, v2 in (v1 + 1):nv - indsᵛ¹ᵛ² = commoninds(tn[v1], tn[v2]) - if !isempty(commoninds(tn[v1], tn[v2])) - e = v1 => v2 - if graph_dir(indsᵛ¹ᵛ²) == ITensors.In - e = reverse(e) - end - add_edge!(g, e) + nv = length(tn) + g = SimpleDiGraph(nv) + for v1 in 1:nv, v2 in (v1 + 1):nv + indsᵛ¹ᵛ² = commoninds(tn[v1], tn[v2]) + if !isempty(commoninds(tn[v1], tn[v2])) + e = v1 => v2 + if graph_dir(indsᵛ¹ᵛ²) == ITensors.In + e = reverse(e) + end + add_edge!(g, e) + end end - end - for v in vertices(g) - if hasuniqueinds(tn[v], tn[all_neighbors(g, v)]...) - # Add a self-loop - add_edge!(g, v => v) + for v in vertices(g) + if hasuniqueinds(tn[v], tn[all_neighbors(g, v)]...) + # Add a self-loop + add_edge!(g, v => v) + end end - end - return g + return g end # TODO: rename indsgraph, dispatch on QNs to DiGraph function MetaGraphs.MetaDiGraph(tn::Vector{ITensor}) - sg = SimpleDiGraph(tn) - mg = MetaDiGraph(sg) - for e in edges(mg) - indsₑ = if is_self_loop(e) - v = src(e) - # For self edges, the vertex itself is included as - # a neighbor so we must exclude it. - uniqueinds(tn[v], tn[setdiff(all_neighbors(mg, v), v)]...) - else - commoninds(tn[src(e)], tn[dst(e)]) + sg = SimpleDiGraph(tn) + mg = MetaDiGraph(sg) + for e in edges(mg) + indsₑ = if is_self_loop(e) + v = src(e) + # For self edges, the vertex itself is included as + # a neighbor so we must exclude it. + uniqueinds(tn[v], tn[setdiff(all_neighbors(mg, v), v)]...) + else + commoninds(tn[src(e)], tn[dst(e)]) + end + set_prop!(mg, e, :inds, indsₑ) end - set_prop!(mg, e, :inds, indsₑ) - end - return mg + return mg end default_linkspaces() = 1 @@ -65,51 +65,51 @@ default(x, x_default) = x default(x::Nothing, x_default) = x_default function itensornetwork( - g::AbstractGraph; linkspaces=default_linkspaces(), sitespaces=nothing -) - N = nv(g) - if !isnothing(sitespaces) && !any_self_loops(g) - g = copy(g) - for v in vertices(g) - add_edge!(g, v => v) + g::AbstractGraph; linkspaces = default_linkspaces(), sitespaces = nothing + ) + N = nv(g) + if !isnothing(sitespaces) && !any_self_loops(g) + g = copy(g) + for v in vertices(g) + add_edge!(g, v => v) + end + end + sitespaces = default(sitespaces, default_sitespaces()) + # TODO: Specialize to Index{typeof(linkspaces)} + inds_network = [Index[] for _ in 1:N] + for e in edges(g) + if !is_self_loop(e) + lₑ = Index(linkspaces; tags = "l=$(src(e))↔$(dst(e))") + push!(inds_network[src(e)], lₑ) + push!(inds_network[dst(e)], dag(lₑ)) + else + sₑ = Index(sitespaces; tags = "s=$(src(e))") + push!(inds_network[src(e)], sₑ) + end end - end - sitespaces = default(sitespaces, default_sitespaces()) - # TODO: Specialize to Index{typeof(linkspaces)} - inds_network = [Index[] for _ in 1:N] - for e in edges(g) - if !is_self_loop(e) - lₑ = Index(linkspaces; tags="l=$(src(e))↔$(dst(e))") - push!(inds_network[src(e)], lₑ) - push!(inds_network[dst(e)], dag(lₑ)) - else - sₑ = Index(sitespaces; tags="s=$(src(e))") - push!(inds_network[src(e)], sₑ) + tn = Vector{ITensor}(undef, N) + for n in 1:N + tn[n] = ITensor(inds_network[n]) end - end - tn = Vector{ITensor}(undef, N) - for n in 1:N - tn[n] = ITensor(inds_network[n]) - end - return tn + return tn end -sites(g::Tuple{String,<:Tuple}) = g[2] -sites(g::Tuple{String,<:Tuple,<:NamedTuple}) = g[2] -sites(g::Tuple{String,Int}) = g[2] -sites(g::Tuple{String,Vararg{Int}}) = Base.tail(g) -sites(g::Tuple{String,Int,<:NamedTuple}) = g[2] +sites(g::Tuple{String, <:Tuple}) = g[2] +sites(g::Tuple{String, <:Tuple, <:NamedTuple}) = g[2] +sites(g::Tuple{String, Int}) = g[2] +sites(g::Tuple{String, Vararg{Int}}) = Base.tail(g) +sites(g::Tuple{String, Int, <:NamedTuple}) = g[2] # Functionality for turning a list of gates into an ITensor # network. function circuit_network(gates, s::Vector{<:Index}) - s = copy(s) - U = ITensor[] - for g in gates - push!(U, op(g, s)) - for n in sites(g) - s[n] = s[n]' + s = copy(s) + U = ITensor[] + for g in gates + push!(U, op(g, s)) + for n in sites(g) + s[n] = s[n]' + end end - end - return U, s + return U, s end diff --git a/src/layered_layout.jl b/src/layered_layout.jl index 05bb134..6f85fbe 100644 --- a/src/layered_layout.jl +++ b/src/layered_layout.jl @@ -4,6 +4,6 @@ # layout(g) = layered_layout(solve_positions(Zarate(), g)) # function layered_layout(pos) - xs, ys, _ = pos - return Point.(zip(xs, ys)) + xs, ys, _ = pos + return Point.(zip(xs, ys)) end diff --git a/src/visualize.jl b/src/visualize.jl index fd41ef4..74edc53 100644 --- a/src/visualize.jl +++ b/src/visualize.jl @@ -6,57 +6,57 @@ using ITensorMPS: MPS # Tools for contracting a network with a sequence function _contract(label1::String, label2::String) - return string("(", label1, "*", label2, ")") + return string("(", label1, "*", label2, ")") end function _contract(tensor1::ITensor, tensor2::ITensor) - indsR = noncommoninds(tensor1, tensor2) - return isempty(indsR) ? ITensor() : ITensor(indsR) + indsR = noncommoninds(tensor1, tensor2) + return isempty(indsR) ? ITensor() : ITensor(indsR) end sequence_traversal(sequence) = reverse(collect(StatelessBFS(sequence))) -function contract_dict(tensors, sequence, traversal=sequence_traversal(sequence)) - net_tensors = Dict() - traversal = reverse(collect(StatelessBFS(sequence))) - for net in traversal - if net isa Int - net_tensors[net] = tensors[net] - else # net isa Vector - net_tensors[net] = _contract(net_tensors[net[1]], net_tensors[net[2]]) +function contract_dict(tensors, sequence, traversal = sequence_traversal(sequence)) + net_tensors = Dict() + traversal = reverse(collect(StatelessBFS(sequence))) + for net in traversal + if net isa Int + net_tensors[net] = tensors[net] + else # net isa Vector + net_tensors[net] = _contract(net_tensors[net[1]], net_tensors[net[2]]) + end end - end - return net_tensors + return net_tensors end # Return all of the contractions involved in the sequence. function contraction_sequence( - tensors, - sequence, - traversal=sequence_traversal(sequence), - contract_dict=contract_dict(tensors, sequence, traversal), -) - all_tensors = Any[] - tensors_1 = Vector{Union{Nothing,eltype(tensors)}}(tensors) - net_position = Dict() - N = length(tensors) - n = N + 1 - for net in traversal - if net isa Int - net_position[net] = net - else - net_position[net] = n - n += 1 + tensors, + sequence, + traversal = sequence_traversal(sequence), + contract_dict = contract_dict(tensors, sequence, traversal) + ) + all_tensors = Any[] + tensors_1 = Vector{Union{Nothing, eltype(tensors)}}(tensors) + net_position = Dict() + N = length(tensors) + n = N + 1 + for net in traversal + if net isa Int + net_position[net] = net + else + net_position[net] = n + n += 1 + end + if !isa(net, Int) + for n in net + tensors_1[net_position[n]] = nothing + end + push!(tensors_1, contract_dict[net]) + push!(all_tensors, copy(tensors_1)) + end end - if !isa(net, Int) - for n in net - tensors_1[net_position[n]] = nothing - end - push!(tensors_1, contract_dict[net]) - push!(all_tensors, copy(tensors_1)) - end - end - return convert.(Vector{eltype(tensors)}, filter.(!isnothing, all_tensors)) + return convert.(Vector{eltype(tensors)}, filter.(!isnothing, all_tensors)) end # @@ -64,184 +64,195 @@ end # struct Tree - x::Any + x::Any end function Base.getindex(tree::Tree, indices) - node = tree.x - for idx in indices - node = children(node)[idx] - end - return node + node = tree.x + for idx in indices + node = children(node)[idx] + end + return node end tree_to_graph(tr) = tree_to_graph(Tree(tr)) function tree_to_graph(tr::Tree) - g = SimpleDiGraph() - labels = Any[] - walk_tree!(g, labels, tr) - return (g, labels) + g = SimpleDiGraph() + labels = Any[] + walk_tree!(g, labels, tr) + return (g, labels) end function walk_tree!(g, labels, tr::Tree) - add_vertex!(g) - top_vertex = vertices(g)[end] - push!(labels, tr.x) - for i in 1:length(tr.x) - if isa(tr[i], Vector) - child = walk_tree!(g, labels, Tree(tr[i])) - add_edge!(g, child, top_vertex) - else - add_vertex!(g) - n = vertices(g)[end] - add_edge!(g, n, top_vertex) - push!(labels, tr[i]) + add_vertex!(g) + top_vertex = vertices(g)[end] + push!(labels, tr.x) + for i in 1:length(tr.x) + if isa(tr[i], Vector) + child = walk_tree!(g, labels, Tree(tr[i])) + add_edge!(g, child, top_vertex) + else + add_vertex!(g) + n = vertices(g)[end] + add_edge!(g, n, top_vertex) + push!(labels, tr[i]) + end end - end - return top_vertex + return top_vertex end # Visualization function interface. Ultimately calls a beckend. -function visualize(g::AbstractGraph, sequence=nothing; backend=get_backend(), kwargs...) - # TODO: do something with the sequence (show sequence, add labels indicating sequence, etc.) - return visualize(Backend(backend), g; kwargs...) +function visualize(g::AbstractGraph, sequence = nothing; backend = get_backend(), kwargs...) + # TODO: do something with the sequence (show sequence, add labels indicating sequence, etc.) + return visualize(Backend(backend), g; kwargs...) end -function visualize(tn::Vector{ITensor}, sequence=nothing; kwargs...) - return visualize(MetaDiGraph(tn), sequence; kwargs...) +function visualize(tn::Vector{ITensor}, sequence = nothing; kwargs...) + return visualize(MetaDiGraph(tn), sequence; kwargs...) end function visualize(tn::Tuple{Vector{ITensor}}, args...; kwargs...) - return visualize(only(tn), args...; kwargs...) + return visualize(only(tn), args...; kwargs...) end visualize(ψ::MPS, args...; kwargs...) = visualize(data(ψ), args...; kwargs...) -function visualize(tn::Tuple{ITensor,Vararg{ITensor}}, args...; kwargs...) - return visualize(collect(tn), args...; kwargs...) +function visualize(tn::Tuple{ITensor, Vararg{ITensor}}, args...; kwargs...) + return visualize(collect(tn), args...; kwargs...) end function visualize(t1::ITensor, tn_tail::ITensor...; kwargs...) - return visualize([t1, tn_tail...]; kwargs...) + return visualize([t1, tn_tail...]; kwargs...) end # Special case single ITensor -function visualize(t::ITensor, sequence=nothing; vertex_labels_prefix, kwargs...) - tn = [t] - vertex_labels = [vertex_labels_prefix] - return visualize(MetaDiGraph(tn), sequence; vertex_labels=vertex_labels, kwargs...) +function visualize(t::ITensor, sequence = nothing; vertex_labels_prefix, kwargs...) + tn = [t] + vertex_labels = [vertex_labels_prefix] + return visualize(MetaDiGraph(tn), sequence; vertex_labels = vertex_labels, kwargs...) end # Special case single ITensor function visualize(tn::Tuple{ITensor}, args...; kwargs...) - return visualize(only(tn), args...; kwargs...) + return visualize(only(tn), args...; kwargs...) end -function visualize!(fig, g::AbstractGraph; backend=get_backend(), kwargs...) - return visualize!(Backend(backend), fig, g; kwargs...) +function visualize!(fig, g::AbstractGraph; backend = get_backend(), kwargs...) + return visualize!(Backend(backend), fig, g; kwargs...) end -function visualize!(fig, tn::Vector{ITensor}, sequence=nothing; kwargs...) - return visualize!(fig, MetaDiGraph(tn); kwargs...) +function visualize!(fig, tn::Vector{ITensor}, sequence = nothing; kwargs...) + return visualize!(fig, MetaDiGraph(tn); kwargs...) end -visualize!(fig, ψ::MPS, sequence=nothing; kwargs...) = visualize!(fig, data(ψ); kwargs...) -function visualize!(fig, tn::Tuple{Vararg{ITensor}}, sequence=nothing; kwargs...) - return visualize!(fig, collect(tn); kwargs...) +visualize!(fig, ψ::MPS, sequence = nothing; kwargs...) = visualize!(fig, data(ψ); kwargs...) +function visualize!(fig, tn::Tuple{Vararg{ITensor}}, sequence = nothing; kwargs...) + return visualize!(fig, collect(tn); kwargs...) end visualize!(fig, tn::ITensor...; kwargs...) = visualize!(fig, collect(tn); kwargs...) -function visualize!(fig, tn::Tuple{Vector{ITensor}}, sequence=nothing; kwargs...) - return visualize!(fig, tn[1], sequence; kwargs...) +function visualize!(fig, tn::Tuple{Vector{ITensor}}, sequence = nothing; kwargs...) + return visualize!(fig, tn[1], sequence; kwargs...) end function visualize!( - fig, f::Function, tn::Tuple{Vararg{ITensor}}, sequence=nothing; kwargs... -) - return visualize!(fig, tn, sequence; kwargs...) + fig, f::Function, tn::Tuple{Vararg{ITensor}}, sequence = nothing; kwargs... + ) + return visualize!(fig, tn, sequence; kwargs...) end # Macro outputs a 1-tuple of the function arguments -function visualize(f::Union{Function,Type}, tn::Tuple{T}, sequence; kwargs...) where {T} - # TODO: specialize on the function type. Also accept a general collection. - return visualize(only(tn), sequence; kwargs...) +function visualize(f::Union{Function, Type}, tn::Tuple{T}, sequence; kwargs...) where {T} + # TODO: specialize on the function type. Also accept a general collection. + return visualize(only(tn), sequence; kwargs...) end # Macro outputs a tuple of ITensors to visualize -function visualize(f::Union{Function,Type}, tn::Tuple{Vararg{ITensor}}, sequence; kwargs...) - # TODO: specialize on the function type. Also accept a general collection. - return visualize(tn, sequence; kwargs...) +function visualize( + f::Union{Function, Type}, + tn::Tuple{Vararg{ITensor}}, + sequence; + kwargs... + ) + # TODO: specialize on the function type. Also accept a general collection. + return visualize(tn, sequence; kwargs...) end -function visualize!(fig, f::Union{Function,Type}, As...; kwargs...) - # TODO: specialize of the function type. Also accept a general collection. - return visualize!(fig, As...; kwargs...) +function visualize!(fig, f::Union{Function, Type}, As...; kwargs...) + # TODO: specialize of the function type. Also accept a general collection. + return visualize!(fig, As...; kwargs...) end function _visualize_sequence!(fig, tn, sequence, n; kwargs...) - return error("Not implemented") + return error("Not implemented") end function sequence_labels(sequence, all_sequences, vertex_labels) - traversal = sequence_traversal(sequence) - labels_dict = contract_dict(vertex_labels, sequence, traversal) - all_labels = [labels_dict[s] for s in all_sequences] - return all_labels + traversal = sequence_traversal(sequence) + labels_dict = contract_dict(vertex_labels, sequence, traversal) + all_labels = [labels_dict[s] for s in all_sequences] + return all_labels end function _graphplot(backend::Backend, graph; all_labels) - return error("Not implemented for backend $backend.") + return error("Not implemented for backend $backend.") end function visualize_sequence(sequence, vertex_labels) - graph, all_sequences = tree_to_graph(sequence) - all_labels = sequence_labels(sequence, all_sequences, vertex_labels) - fig = _graphplot(Backend"Makie"(), graph; all_labels=all_labels) - return fig + graph, all_sequences = tree_to_graph(sequence) + all_labels = sequence_labels(sequence, all_sequences, vertex_labels) + fig = _graphplot(Backend"Makie"(), graph; all_labels = all_labels) + return fig end function default_sequence(tn::Vector{ITensor}) - N = length(tn) - return foldl((x, y) -> [x, y], 1:N) + N = length(tn) + return foldl((x, y) -> [x, y], 1:N) end function visualize_sequence( - f::Union{Function,Type}, tn::Vector{ITensor}, sequence::Nothing; kwargs... -) - return visualize_sequence(f, tn, default_sequence(tn); kwargs...) + f::Union{Function, Type}, tn::Vector{ITensor}, sequence::Nothing; kwargs... + ) + return visualize_sequence(f, tn, default_sequence(tn); kwargs...) end function visualize_sequence( - f::Union{Function,Type}, tn::Vector{ITensor}, sequence=default_sequence(tn); kwargs... -) - N = length(tn) - - # TODO: clean this up a bit - vertex_labels_prefix = get( - kwargs, - :vertex_labels_prefix, - default_vertex_labels_prefix(Backend("Makie"), MetaDiGraph(tn)), - ) - vertex_labels = get( - kwargs, - :vertex_labels, - default_vertex_labels(Backend(""), MetaDiGraph(tn), vertex_labels_prefix), - ) - - fig = visualize_sequence(sequence, vertex_labels) - - visualize!(fig[1, 2], tn; vertex_labels=vertex_labels, kwargs...) - - traversal = sequence_traversal(sequence) - labels_sequence = contraction_sequence(vertex_labels, sequence, traversal) - - tn_sequence = contraction_sequence(tn, sequence, traversal) - - for n in 1:length(tn_sequence) - visualize!(fig[1, n + 2], tn_sequence[n]; vertex_labels=labels_sequence[n], kwargs...) - end + f::Union{Function, Type}, tn::Vector{ITensor}, sequence = default_sequence(tn); + kwargs... + ) + N = length(tn) + + # TODO: clean this up a bit + vertex_labels_prefix = get( + kwargs, + :vertex_labels_prefix, + default_vertex_labels_prefix(Backend("Makie"), MetaDiGraph(tn)) + ) + vertex_labels = get( + kwargs, + :vertex_labels, + default_vertex_labels(Backend(""), MetaDiGraph(tn), vertex_labels_prefix) + ) + + fig = visualize_sequence(sequence, vertex_labels) + + visualize!(fig[1, 2], tn; vertex_labels = vertex_labels, kwargs...) + + traversal = sequence_traversal(sequence) + labels_sequence = contraction_sequence(vertex_labels, sequence, traversal) + + tn_sequence = contraction_sequence(tn, sequence, traversal) + + for n in 1:length(tn_sequence) + visualize!( + fig[1, n + 2], + tn_sequence[n]; + vertex_labels = labels_sequence[n], + kwargs... + ) + end - return fig + return fig end function visualize_sequence( - f::Union{Function,Type}, tn::Tuple{Vector{ITensor}}, sequence; kwargs... -) - return visualize_sequence(f, tn[1], sequence; kwargs...) + f::Union{Function, Type}, tn::Tuple{Vector{ITensor}}, sequence; kwargs... + ) + return visualize_sequence(f, tn[1], sequence; kwargs...) end diff --git a/test/Project.toml b/test/Project.toml index cfb0965..d4a5312 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,7 +1,9 @@ [deps] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" ITensorMPS = "0d1a4710-d33b-49a5-8f18-73bdf49b47e2" +ITensorPkgSkeleton = "3d388ab1-018a-49f4-ae50-18094d5f71ea" ITensorVisualizationBase = "cd2553d2-8bef-4d93-8a38-c62f17d5ad23" ITensors = "9136182c-28ba-11e9-034c-db9fb085ebd5" LayeredLayouts = "f4a74d36-062a-4d48-97cd-1356bad1de4e" @@ -12,10 +14,13 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" path = ".." [compat] +Aqua = "0.8.9" GeometryBasics = "0.4.1, 0.5" Graphs = "1.4.1" ITensorMPS = "0.3" +ITensorPkgSkeleton = "0.3.42" ITensorVisualizationBase = "0.1" ITensors = "0.7, 0.8, 0.9" LayeredLayouts = "0.2" NetworkLayout = "0.4.3" +Test = "1.10" diff --git a/test/runtests.jl b/test/runtests.jl index 715d7ac..05baac8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,14 +1,3 @@ -using ITensors -using ITensorVisualizationBase -using Test +using ITensorPkgSkeleton: ITensorPkgSkeleton -starts_and_ends_with(file, st, en) = startswith(file, st) && endswith(file, en) -starts_and_ends_with(st, en) = file -> starts_and_ends_with(file, st, en) - -test_path = joinpath(@__DIR__) -test_files = filter(starts_and_ends_with("test_", ".jl"), readdir(test_path)) -@testset "ITensorVisualizationBase.jl" for file in test_files - file_path = joinpath(test_path, file) - println("Running test $(file_path)") - include(file_path) -end +ITensorPkgSkeleton.runtests(; testdir = @__DIR__) diff --git a/test/test_aqua.jl b/test/test_aqua.jl new file mode 100644 index 0000000..159517c --- /dev/null +++ b/test/test_aqua.jl @@ -0,0 +1,8 @@ +using Aqua: Aqua +using ITensorVisualizationBase: ITensorVisualizationBase +using Test: @testset + +@testset "Code quality (Aqua.jl)" begin + # ITensorVisualizationBase extends APIs from external packages by design. + Aqua.test_all(ITensorVisualizationBase; piracies = false) +end diff --git a/test/test_basics.jl b/test/test_basics.jl index 70b9b79..fb4907e 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -1,51 +1,51 @@ -using ITensors using ITensorVisualizationBase +using ITensors using Test @testset "Basic tests without any backend" begin - N = 10 - s(n) = Index([QN("Sz", 0) => 1, QN("Sz", 1) => 1]; tags="S=1/2,Site,n=$n") - l(n) = Index([QN("Sz", 0) => 10, QN("Sz", 1) => 10]; tags="Link,l=$n") - h(n) = Index([QN("Sz", 0) => 5, QN("Sz", 1) => 5]; tags="ham,Link,l=$n") - s⃗ = [s(n) for n in 1:N] - l⃗ = [l(n) for n in 1:(N - 1)] - h⃗ = [h(n) for n in 1:(N - 1)] - - # Add some more indices between two of the tensors - x = Index([QN("Sz", 0) => 2]; tags="X") - y = Index([QN("Sz", 0) => 2]; tags="Y") - - n = 2 - ψn1n2 = random_itensor(l⃗[n - 1], s⃗[n], s⃗[n + 1], l⃗[n + 1], dag(x), dag(y)) - hn1 = random_itensor(dag(h⃗[n - 1]), s⃗[n]', dag(s⃗[n]), h⃗[n], x, y) - hn2 = random_itensor(dag(h⃗[n]), s⃗[n + 1]', dag(s⃗[n + 1]), h⃗[n + 1]) - ELn0 = random_itensor(l⃗[n - 1]', h⃗[n - 1], dag(l⃗[n - 1])) - ERn2 = random_itensor(l⃗[n + 1]', dag(h⃗[n + 1]), dag(l⃗[n + 1])) - - tn = [ELn0, ψn1n2, hn1, hn2, ERn2] - - R = @visualize ELn0 * ψn1n2 * hn1 * hn2 * ERn2 - R1 = @visualize ELn0 * ψn1n2 * hn1 - R2 = @visualize R1 * hn2 * ERn2 vertex_labels = ["T1", "T2", "T3"] - tn2 = @visualize tn - T = @visualize ELn0 - - @test R ≈ ELn0 * ψn1n2 * hn1 * hn2 * ERn2 - @test R1 ≈ ELn0 * ψn1n2 * hn1 - @test R2 ≈ ELn0 * ψn1n2 * hn1 * hn2 * ERn2 - @test all(tn .== tn2) - @test T == ELn0 - - R = @visualize figR ELn0 * ψn1n2 * hn1 * hn2 * ERn2 - R1 = @visualize figR1 ELn0 * ψn1n2 * hn1 - R2 = @visualize figR2 R1 * hn2 * ERn2 vertex_labels = ["T1", "T2", "T3"] - T = @visualize figT T - - fig_tn = @visualize_noeval tn - - @test isnothing(figR) - @test isnothing(figR1) - @test isnothing(figR2) - @test isnothing(fig_tn) - @test isnothing(figT) + N = 10 + s(n) = Index([QN("Sz", 0) => 1, QN("Sz", 1) => 1]; tags = "S=1/2,Site,n=$n") + l(n) = Index([QN("Sz", 0) => 10, QN("Sz", 1) => 10]; tags = "Link,l=$n") + h(n) = Index([QN("Sz", 0) => 5, QN("Sz", 1) => 5]; tags = "ham,Link,l=$n") + s⃗ = [s(n) for n in 1:N] + l⃗ = [l(n) for n in 1:(N - 1)] + h⃗ = [h(n) for n in 1:(N - 1)] + + # Add some more indices between two of the tensors + x = Index([QN("Sz", 0) => 2]; tags = "X") + y = Index([QN("Sz", 0) => 2]; tags = "Y") + + n = 2 + ψn1n2 = random_itensor(l⃗[n - 1], s⃗[n], s⃗[n + 1], l⃗[n + 1], dag(x), dag(y)) + hn1 = random_itensor(dag(h⃗[n - 1]), s⃗[n]', dag(s⃗[n]), h⃗[n], x, y) + hn2 = random_itensor(dag(h⃗[n]), s⃗[n + 1]', dag(s⃗[n + 1]), h⃗[n + 1]) + ELn0 = random_itensor(l⃗[n - 1]', h⃗[n - 1], dag(l⃗[n - 1])) + ERn2 = random_itensor(l⃗[n + 1]', dag(h⃗[n + 1]), dag(l⃗[n + 1])) + + tn = [ELn0, ψn1n2, hn1, hn2, ERn2] + + R = @visualize ELn0 * ψn1n2 * hn1 * hn2 * ERn2 + R1 = @visualize ELn0 * ψn1n2 * hn1 + R2 = @visualize R1 * hn2 * ERn2 vertex_labels = ["T1", "T2", "T3"] + tn2 = @visualize tn + T = @visualize ELn0 + + @test R ≈ ELn0 * ψn1n2 * hn1 * hn2 * ERn2 + @test R1 ≈ ELn0 * ψn1n2 * hn1 + @test R2 ≈ ELn0 * ψn1n2 * hn1 * hn2 * ERn2 + @test all(tn .== tn2) + @test T == ELn0 + + R = @visualize figR ELn0 * ψn1n2 * hn1 * hn2 * ERn2 + R1 = @visualize figR1 ELn0 * ψn1n2 * hn1 + R2 = @visualize figR2 R1 * hn2 * ERn2 vertex_labels = ["T1", "T2", "T3"] + T = @visualize figT T + + fig_tn = @visualize_noeval tn + + @test isnothing(figR) + @test isnothing(figR1) + @test isnothing(figR2) + @test isnothing(fig_tn) + @test isnothing(figT) end diff --git a/test/test_examples.jl b/test/test_examples.jl index a406959..8ac41d9 100644 --- a/test/test_examples.jl +++ b/test/test_examples.jl @@ -1,15 +1,18 @@ using Test +starts_and_ends_with(file, st, en) = startswith(file, st) && endswith(file, en) +starts_and_ends_with(st, en) = file -> starts_and_ends_with(file, st, en) + @testset "Examples" begin - examples_path = joinpath(@__DIR__, "..", "examples") - example_files = filter(starts_and_ends_with("ex_", ".jl"), readdir(examples_path)) - for file in example_files - file_path = joinpath(examples_path, file) - println("Testing file $(file_path)") - empty!(ARGS) - push!(ARGS, "false") - res = include(file_path) - @test isnothing(res) || all(isnothing, res) - empty!(ARGS) - end + examples_path = joinpath(@__DIR__, "..", "examples") + example_files = filter(starts_and_ends_with("ex_", ".jl"), readdir(examples_path)) + for file in example_files + file_path = joinpath(examples_path, file) + println("Testing file $(file_path)") + empty!(ARGS) + push!(ARGS, "false") + res = include(file_path) + @test isnothing(res) || all(isnothing, res) + empty!(ARGS) + end end