From 0f1d8aca6253bcade732a79f08067667a1591105 Mon Sep 17 00:00:00 2001 From: watayo Date: Sun, 11 May 2025 14:43:58 +0900 Subject: [PATCH 01/13] manipulation of trees --- Manifest.toml | 1071 ++++++++++++++++++++++++++++++ samples/devtci.jl | 26 - samples/sample_structural_opt.jl | 29 + samples/sample_treetci.jl | 27 + samples/sample_treetci2.jl | 32 + src/TreeTCI.jl | 6 +- src/imports.jl | 21 + src/simpletci.jl | 75 +-- src/tree_utils.jl | 39 ++ 9 files changed, 1253 insertions(+), 73 deletions(-) create mode 100644 Manifest.toml delete mode 100644 samples/devtci.jl create mode 100644 samples/sample_structural_opt.jl create mode 100644 samples/sample_treetci.jl create mode 100644 samples/sample_treetci2.jl create mode 100644 src/imports.jl diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 0000000..a5895fa --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,1071 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.11.4" +manifest_format = "2.0" +project_hash = "9705615ba09efd74ca1cc4ab9edd817d69fb946c" + +[[deps.ADTypes]] +git-tree-sha1 = "e2478490447631aedba0823d4d7a80b2cc8cdb32" +uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +version = "1.14.0" + + [deps.ADTypes.extensions] + ADTypesChainRulesCoreExt = "ChainRulesCore" + ADTypesConstructionBaseExt = "ConstructionBase" + ADTypesEnzymeCoreExt = "EnzymeCore" + + [deps.ADTypes.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + +[[deps.AbstractLattices]] +git-tree-sha1 = "763b6f3f6bfabd72c7e262cbb5ddfd43fd5c6398" +uuid = "398f06c4-4d28-53ec-89ca-5b2656b7603d" +version = "0.3.1" + +[[deps.AbstractTrees]] +git-tree-sha1 = "2d9c9a55f9c93e8887ad391fbae72f8ef55e1177" +uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" +version = "0.4.5" + +[[deps.Adapt]] +deps = ["LinearAlgebra", "Requires"] +git-tree-sha1 = "f7817e2e585aa6d924fd714df1e2a84be7896c60" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "4.3.0" +weakdeps = ["SparseArrays", "StaticArrays"] + + [deps.Adapt.extensions] + AdaptSparseArraysExt = "SparseArrays" + AdaptStaticArraysExt = "StaticArrays" + +[[deps.AliasTables]] +deps = ["PtrArrays", "Random"] +git-tree-sha1 = "9876e1e164b144ca45e9e3198d0b689cadfed9ff" +uuid = "66dad0bd-aa9a-41b7-9441-69ab47430ed8" +version = "1.1.3" + +[[deps.ArnoldiMethod]] +deps = ["LinearAlgebra", "Random", "StaticArrays"] +git-tree-sha1 = "d57bd3762d308bded22c3b82d033bff85f6195c6" +uuid = "ec485272-7323-5ecc-a04f-4719b315124d" +version = "0.4.0" + +[[deps.ArrayInterface]] +deps = ["Adapt", "LinearAlgebra"] +git-tree-sha1 = "bebb10cd3f0796dd1429ba61e43990ba391186e9" +uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" +version = "7.18.1" + + [deps.ArrayInterface.extensions] + ArrayInterfaceBandedMatricesExt = "BandedMatrices" + ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" + ArrayInterfaceCUDAExt = "CUDA" + ArrayInterfaceCUDSSExt = "CUDSS" + ArrayInterfaceChainRulesCoreExt = "ChainRulesCore" + ArrayInterfaceChainRulesExt = "ChainRules" + ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore" + ArrayInterfaceReverseDiffExt = "ReverseDiff" + ArrayInterfaceSparseArraysExt = "SparseArrays" + ArrayInterfaceStaticArraysCoreExt = "StaticArraysCore" + ArrayInterfaceTrackerExt = "Tracker" + + [deps.ArrayInterface.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e" + ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2" + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" +version = "1.11.0" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +version = "1.11.0" + +[[deps.BenchmarkTools]] +deps = ["Compat", "JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "e38fbc49a620f5d0b660d7f543db1009fe0f8336" +uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +version = "1.6.0" + +[[deps.Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1b96ea4a01afe0ea4090c5c8039690672dd13f2e" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.9+0" + +[[deps.ChooseOptimizer]] +deps = ["HiGHS", "JuMP"] +git-tree-sha1 = "b1e44436d77031abcf850366d6b8cb82daa34aaa" +uuid = "858a232f-1959-5553-8cfc-91e1fd5304e2" +version = "0.3.1" + +[[deps.CodeTracking]] +deps = ["InteractiveUtils", "UUIDs"] +git-tree-sha1 = "062c5e1a5bf6ada13db96a4ae4749a4c2234f521" +uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" +version = "1.3.9" + +[[deps.CodecBzip2]] +deps = ["Bzip2_jll", "TranscodingStreams"] +git-tree-sha1 = "84990fa864b7f2b4901901ca12736e45ee79068c" +uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" +version = "0.8.5" + +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.8" + +[[deps.Combinatorics]] +git-tree-sha1 = "8010b6bb3388abe68d95743dcbea77650bb2eddf" +uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" +version = "1.0.3" + +[[deps.CommonMark]] +deps = ["PrecompileTools"] +git-tree-sha1 = "351d6f4eaf273b753001b2de4dffb8279b100769" +uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" +version = "0.9.1" + +[[deps.CommonSubexpressions]] +deps = ["MacroTools"] +git-tree-sha1 = "cda2cfaebb4be89c9084adaca7dd7333369715c5" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.1" + +[[deps.CommonWorldInvalidations]] +git-tree-sha1 = "ae52d1c52048455e85a387fbee9be553ec2b68d0" +uuid = "f70d9fcc-98c5-4d4a-abd7-e4cdeebd8ca8" +version = "1.0.0" + +[[deps.Compat]] +deps = ["TOML", "UUIDs"] +git-tree-sha1 = "8ae8d32e09f0dcf42a36b90d4e17f5dd2e4c4215" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.16.0" +weakdeps = ["Dates", "LinearAlgebra"] + + [deps.Compat.extensions] + CompatLinearAlgebraExt = "LinearAlgebra" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.1.1+0" + +[[deps.ConstructionBase]] +git-tree-sha1 = "76219f1ed5771adbb096743bff43fb5fdd4c1157" +uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +version = "1.5.8" + + [deps.ConstructionBase.extensions] + ConstructionBaseIntervalSetsExt = "IntervalSets" + ConstructionBaseLinearAlgebraExt = "LinearAlgebra" + ConstructionBaseStaticArraysExt = "StaticArrays" + + [deps.ConstructionBase.weakdeps] + IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[[deps.DataAPI]] +git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.16.0" + +[[deps.DataGraphs]] +deps = ["Dictionaries", "Graphs", "NamedGraphs", "SimpleTraits"] +git-tree-sha1 = "d644cf165008445c2a62d12ae9bc8ae5239f177b" +uuid = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" +version = "0.2.7" + + [deps.DataGraphs.extensions] + DataGraphsGraphsFlowsExt = "GraphsFlows" + + [deps.DataGraphs.weakdeps] + GraphsFlows = "06909019-6f44-4949-96fc-b9d9aaa02889" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "4e1fe97fdaed23e9dc21d4d664bea76b65fc50a0" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.22" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" +version = "1.11.0" + +[[deps.Dictionaries]] +deps = ["Indexing", "Random", "Serialization"] +git-tree-sha1 = "a86af9c4c4f33e16a2b2ff43c2113b2f390081fa" +uuid = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" +version = "0.4.5" + +[[deps.DiffResults]] +deps = ["StaticArraysCore"] +git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" +uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +version = "1.1.0" + +[[deps.DiffRules]] +deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] +git-tree-sha1 = "23163d55f885173722d1e4cf0f6110cdbaf7e272" +uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" +version = "1.15.1" + +[[deps.DifferentiationInterface]] +deps = ["ADTypes", "LinearAlgebra"] +git-tree-sha1 = "8b9f605f582f633eeb9c3ec14effaed2dca6ef5c" +uuid = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" +version = "0.6.53" + + [deps.DifferentiationInterface.extensions] + DifferentiationInterfaceChainRulesCoreExt = "ChainRulesCore" + DifferentiationInterfaceDiffractorExt = "Diffractor" + DifferentiationInterfaceEnzymeExt = ["EnzymeCore", "Enzyme"] + DifferentiationInterfaceFastDifferentiationExt = "FastDifferentiation" + DifferentiationInterfaceFiniteDiffExt = "FiniteDiff" + DifferentiationInterfaceFiniteDifferencesExt = "FiniteDifferences" + DifferentiationInterfaceForwardDiffExt = ["ForwardDiff", "DiffResults"] + DifferentiationInterfaceGPUArraysCoreExt = "GPUArraysCore" + DifferentiationInterfaceGTPSAExt = "GTPSA" + DifferentiationInterfaceMooncakeExt = "Mooncake" + DifferentiationInterfacePolyesterForwardDiffExt = ["PolyesterForwardDiff", "ForwardDiff", "DiffResults"] + DifferentiationInterfaceReverseDiffExt = ["ReverseDiff", "DiffResults"] + DifferentiationInterfaceSparseArraysExt = "SparseArrays" + DifferentiationInterfaceSparseConnectivityTracerExt = "SparseConnectivityTracer" + DifferentiationInterfaceSparseMatrixColoringsExt = "SparseMatrixColorings" + DifferentiationInterfaceStaticArraysExt = "StaticArrays" + DifferentiationInterfaceSymbolicsExt = "Symbolics" + DifferentiationInterfaceTrackerExt = "Tracker" + DifferentiationInterfaceZygoteExt = ["Zygote", "ForwardDiff"] + + [deps.DifferentiationInterface.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" + Diffractor = "9f5e2b26-1114-432f-b630-d3fe2085c51c" + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + FastDifferentiation = "eb9bf01b-bf85-4b60-bf87-ee5de06c00be" + FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" + FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" + GTPSA = "b27dd330-f138-47c5-815b-40db9dd9b6e8" + Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" + PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + SparseConnectivityTracer = "9f842d2f-2579-4b1d-911e-f412cf18a3f5" + SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" +version = "1.11.0" + +[[deps.Distributions]] +deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] +git-tree-sha1 = "6d8b535fd38293bc54b88455465a1386f8ac1c3c" +uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" +version = "0.25.119" + + [deps.Distributions.extensions] + DistributionsChainRulesCoreExt = "ChainRulesCore" + DistributionsDensityInterfaceExt = "DensityInterface" + DistributionsTestExt = "Test" + + [deps.Distributions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d" + Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.DocStringExtensions]] +git-tree-sha1 = "e7b7e6f178525d17c720ab9c081e4ef04429f860" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.4" + +[[deps.EllipsisNotation]] +deps = ["StaticArrayInterface"] +git-tree-sha1 = "3507300d4343e8e4ad080ad24e335274c2e297a9" +uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" +version = "1.8.0" + +[[deps.EnumX]] +git-tree-sha1 = "bddad79635af6aec424f53ed8aad5d7555dc6f00" +uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" +version = "1.0.5" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" +version = "1.11.0" + +[[deps.FillArrays]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "6a70198746448456524cb442b8af316927ff3e1a" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "1.13.0" +weakdeps = ["PDMats", "SparseArrays", "Statistics"] + + [deps.FillArrays.extensions] + FillArraysPDMatsExt = "PDMats" + FillArraysSparseArraysExt = "SparseArrays" + FillArraysStatisticsExt = "Statistics" + +[[deps.FiniteDiff]] +deps = ["ArrayInterface", "LinearAlgebra", "Setfield"] +git-tree-sha1 = "f089ab1f834470c525562030c8cfde4025d5e915" +uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" +version = "2.27.0" + + [deps.FiniteDiff.extensions] + FiniteDiffBandedMatricesExt = "BandedMatrices" + FiniteDiffBlockBandedMatricesExt = "BlockBandedMatrices" + FiniteDiffSparseArraysExt = "SparseArrays" + FiniteDiffStaticArraysExt = "StaticArrays" + + [deps.FiniteDiff.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[[deps.ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] +git-tree-sha1 = "910febccb28d493032495b7009dce7d7f7aee554" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "1.0.1" +weakdeps = ["StaticArrays"] + + [deps.ForwardDiff.extensions] + ForwardDiffStaticArraysExt = "StaticArrays" + +[[deps.Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" +version = "1.11.0" + +[[deps.Glob]] +git-tree-sha1 = "97285bbd5230dd766e9ef6749b80fc617126d496" +uuid = "c27321d9-0574-5035-807b-f59d2c89b15c" +version = "1.3.1" + +[[deps.Graphs]] +deps = ["ArnoldiMethod", "Compat", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] +git-tree-sha1 = "3169fd3440a02f35e549728b0890904cfd4ae58a" +uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" +version = "1.12.1" + +[[deps.HiGHS]] +deps = ["HiGHS_jll", "MathOptInterface", "PrecompileTools", "SparseArrays"] +git-tree-sha1 = "ffc9974c62b3bb8a7965a122901361a011bfd766" +uuid = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" +version = "1.17.0" + +[[deps.HiGHS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Zlib_jll"] +git-tree-sha1 = "72bceb63d4ae3683f091f812b6958a199c494a1b" +uuid = "8fd58aa0-07eb-5a78-9b36-339c94fd15ea" +version = "1.10.0+0" + +[[deps.HypergeometricFunctions]] +deps = ["LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] +git-tree-sha1 = "68c173f4f449de5b438ee67ed0c9c748dc31a2ec" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.28" + +[[deps.IfElse]] +git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" +uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" +version = "0.1.1" + +[[deps.Indexing]] +git-tree-sha1 = "ce1566720fd6b19ff3411404d4b977acd4814f9f" +uuid = "313cdc1a-70c2-5d6a-ae34-0150d3930a38" +version = "1.1.1" + +[[deps.Inflate]] +git-tree-sha1 = "d1b1b796e47d94588b3757fe84fbf65a5ec4a80d" +uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" +version = "0.1.5" + +[[deps.IntegerMathUtils]] +git-tree-sha1 = "b8ffb903da9f7b8cf695a8bead8e01814aa24b30" +uuid = "18e54dd8-cb9d-406c-a71d-865a43cbb235" +version = "0.1.2" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +version = "1.11.0" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "e2222959fbc6c19554dc15174c81bf7bf3aa691c" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.2.4" + +[[deps.IterTools]] +git-tree-sha1 = "42d5f897009e7ff2cf88db414a389e5ed1bdd023" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.10.0" + +[[deps.JLLWrappers]] +deps = ["Artifacts", "Preferences"] +git-tree-sha1 = "a007feb38b422fbdab534406aeca1b86823cb4d6" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.7.0" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.JSON3]] +deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"] +git-tree-sha1 = "196b41e5a854b387d99e5ede2de3fcb4d0422aae" +uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +version = "1.14.2" + + [deps.JSON3.extensions] + JSON3ArrowExt = ["ArrowTypes"] + + [deps.JSON3.weakdeps] + ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" + +[[deps.JuMP]] +deps = ["LinearAlgebra", "MacroTools", "MathOptInterface", "MutableArithmetics", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays"] +git-tree-sha1 = "c9ace86360c1dc0635de5f9e2ce5143b86c53311" +uuid = "4076af6c-e467-56ae-b986-b466b2749572" +version = "1.25.0" + + [deps.JuMP.extensions] + JuMPDimensionalDataExt = "DimensionalData" + + [deps.JuMP.weakdeps] + DimensionalData = "0703355e-b756-11e9-17c0-8b28908087d0" + +[[deps.JuliaFormatter]] +deps = ["CommonMark", "Glob", "JuliaSyntax", "PrecompileTools", "TOML"] +git-tree-sha1 = "56b382cd34b1a80f63211a0b009461915915bf9e" +uuid = "98e50ef6-434e-11e9-1051-2b60c6c9e899" +version = "2.1.2" + +[[deps.JuliaInterpreter]] +deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"] +git-tree-sha1 = "6ac9e4acc417a5b534ace12690bc6973c25b862f" +uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" +version = "0.10.3" + +[[deps.JuliaSyntax]] +git-tree-sha1 = "937da4713526b96ac9a178e2035019d3b78ead4a" +uuid = "70703baa-626e-46a2-a12c-08ffd08c73b4" +version = "0.4.10" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" +version = "1.11.0" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.7.2+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +version = "1.11.0" + +[[deps.Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "be484f5c92fad0bd8acfef35fe017900b0b73809" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.18.0+0" + +[[deps.LightXML]] +deps = ["Libdl", "XML2_jll"] +git-tree-sha1 = "3a994404d3f6709610701c7dabfc03fed87a81f8" +uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179" +version = "0.9.1" + +[[deps.LineSearches]] +deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] +git-tree-sha1 = "e4c3be53733db1051cc15ecf573b1042b3a712a1" +uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" +version = "7.3.0" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +version = "1.11.0" + +[[deps.LinearAlgebraX]] +deps = ["LinearAlgebra", "Mods", "Primes", "SimplePolynomials"] +git-tree-sha1 = "054fe197a75adcf517933f0c807051d79881f3f3" +uuid = "9b3f67b0-2d00-526e-9884-9e4938f8fb88" +version = "0.2.10" + +[[deps.LogExpFunctions]] +deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.29" + + [deps.LogExpFunctions.extensions] + LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" + LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables" + LogExpFunctionsInverseFunctionsExt = "InverseFunctions" + + [deps.LogExpFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" + InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" +version = "1.11.0" + +[[deps.LoweredCodeUtils]] +deps = ["JuliaInterpreter"] +git-tree-sha1 = "4ef1c538614e3ec30cb6383b9eb0326a5c3a9763" +uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" +version = "3.3.0" + +[[deps.MacroTools]] +git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.16" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +version = "1.11.0" + +[[deps.MathOptInterface]] +deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON3", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test"] +git-tree-sha1 = "22b3e0bd1442bf9f5d3cb76e7d34ca87b88d0f36" +uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +version = "1.40.0" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.6+0" + +[[deps.Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.2.0" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" +version = "1.11.0" + +[[deps.Mods]] +git-tree-sha1 = "0a3c164857cfc4defe0ac09e6b0123d61320abb1" +uuid = "7475f97c-0381-53b1-977b-4c60186c8d62" +version = "2.2.6" + +[[deps.Multisets]] +git-tree-sha1 = "8ef67bad0a3def6d77aebf1d3645119e7c8e5a54" +uuid = "3b2b4ff1-bcff-5658-a3ee-dbcf1ce5ac09" +version = "0.4.5" + +[[deps.MutableArithmetics]] +deps = ["LinearAlgebra", "SparseArrays", "Test"] +git-tree-sha1 = "491bdcdc943fcbc4c005900d7463c9f216aabf4c" +uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" +version = "1.6.4" + +[[deps.NLSolversBase]] +deps = ["ADTypes", "DifferentiationInterface", "Distributed", "FiniteDiff", "ForwardDiff"] +git-tree-sha1 = "b14c7be6046e7d48e9063a0053f95ee0fc954176" +uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" +version = "7.9.1" + +[[deps.NaNMath]] +deps = ["OpenLibm_jll"] +git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.1.3" + +[[deps.NamedGraphs]] +deps = ["AbstractTrees", "Combinatorics", "Dictionaries", "Graphs", "LinearAlgebra", "PackageExtensionCompat", "Random", "SimpleGraphAlgorithms", "SimpleGraphConverter", "SimpleTraits", "SparseArrays", "SplitApplyCombine", "Suppressor"] +git-tree-sha1 = "310cd2215b35643fd2efa2b6c40235fb11a9107d" +uuid = "678767b0-92e7-4007-89e4-4527a8725b19" +version = "0.6.8" + + [deps.NamedGraphs.extensions] + NamedGraphsGraphsFlowsExt = "GraphsFlows" + NamedGraphsKaHyParExt = "KaHyPar" + NamedGraphsMetisExt = "Metis" + NamedGraphsSimpleGraphAlgorithmsExt = "SimpleGraphAlgorithms" + NamedGraphsSymRCMExt = "SymRCM" + + [deps.NamedGraphs.weakdeps] + GraphsFlows = "06909019-6f44-4949-96fc-b9d9aaa02889" + KaHyPar = "2a6221f6-aa48-11e9-3542-2d9e0ef01880" + Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b" + SymRCM = "286e6d88-80af-4590-acc9-0001b223b9bd" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.27+1" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+4" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1346c9208249809840c91b26703912dff463d335" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.6+0" + +[[deps.Optim]] +deps = ["Compat", "EnumX", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] +git-tree-sha1 = "31b3b1b8e83ef9f1d50d74f1dd5f19a37a304a1f" +uuid = "429524aa-4258-5aef-a3af-852621145aeb" +version = "1.12.0" +weakdeps = ["MathOptInterface"] + + [deps.Optim.extensions] + OptimMOIExt = "MathOptInterface" + +[[deps.OrderedCollections]] +git-tree-sha1 = "cc4054e898b852042d7b503313f7ad03de99c3dd" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.8.0" + +[[deps.PDMats]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "f07c06228a1c670ae4c87d1276b92c7c597fdda0" +uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" +version = "0.11.35" + +[[deps.PackageExtensionCompat]] +git-tree-sha1 = "fb28e33b8a95c4cee25ce296c817d89cc2e53518" +uuid = "65ce6f38-6b18-4e1d-a461-8949797d7930" +version = "1.0.2" +weakdeps = ["Requires", "TOML"] + +[[deps.Parameters]] +deps = ["OrderedCollections", "UnPack"] +git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" +uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" +version = "0.12.3" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.3" + +[[deps.Permutations]] +deps = ["Combinatorics", "LinearAlgebra", "Random"] +git-tree-sha1 = "b1f03a4943c62552a12c7f95965b76c3f91cf5b7" +uuid = "2ae35dd2-176d-5d53-8349-f30d82d94d4f" +version = "0.4.23" + +[[deps.Polynomials]] +deps = ["LinearAlgebra", "OrderedCollections", "RecipesBase", "Requires", "Setfield", "SparseArrays"] +git-tree-sha1 = "555c272d20fc80a2658587fb9bbda60067b93b7c" +uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" +version = "4.0.19" + + [deps.Polynomials.extensions] + PolynomialsChainRulesCoreExt = "ChainRulesCore" + PolynomialsFFTWExt = "FFTW" + PolynomialsMakieCoreExt = "MakieCore" + PolynomialsMutableArithmeticsExt = "MutableArithmetics" + + [deps.Polynomials.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" + MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b" + MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" + +[[deps.PositiveFactorizations]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" +uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" +version = "0.2.4" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.3" + +[[deps.Primes]] +deps = ["IntegerMathUtils"] +git-tree-sha1 = "25cdd1d20cd005b52fc12cb6be3f75faaf59bb9b" +uuid = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae" +version = "0.5.7" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" +version = "1.11.0" + +[[deps.Profile]] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" +version = "1.11.0" + +[[deps.PtrArrays]] +git-tree-sha1 = "1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d" +uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" +version = "1.3.0" + +[[deps.QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "9da16da70037ba9d701192e27befedefb91ec284" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.11.2" + + [deps.QuadGK.extensions] + QuadGKEnzymeExt = "Enzyme" + + [deps.QuadGK.weakdeps] + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "StyledStrings", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" +version = "1.11.0" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +version = "1.11.0" + +[[deps.RecipesBase]] +deps = ["PrecompileTools"] +git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.3.4" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.1" + +[[deps.Revise]] +deps = ["CodeTracking", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "REPL", "Requires", "UUIDs", "Unicode"] +git-tree-sha1 = "cedc9f9013f7beabd8a9c6d2e22c0ca7c5c2a8ed" +uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" +version = "3.7.6" +weakdeps = ["Distributed"] + + [deps.Revise.extensions] + DistributedExt = "Distributed" + +[[deps.RingLists]] +deps = ["Random"] +git-tree-sha1 = "70d8d52c6d4238cace6ae1a7dd2c0c4d43acdf0b" +uuid = "286e9d63-9694-5540-9e3c-4e6708fa07b2" +version = "0.2.9" + +[[deps.Rmath]] +deps = ["Random", "Rmath_jll"] +git-tree-sha1 = "852bd0f55565a9e973fcfee83a84413270224dc4" +uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" +version = "0.8.0" + +[[deps.Rmath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "58cdd8fb2201a6267e1db87ff148dd6c1dbd8ad8" +uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" +version = "0.5.1+0" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +version = "1.11.0" + +[[deps.Setfield]] +deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] +git-tree-sha1 = "c5391c6ace3bc430ca630251d02ea9687169ca68" +uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" +version = "1.1.2" + +[[deps.SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" +version = "1.11.0" + +[[deps.SimpleGraphAlgorithms]] +deps = ["ChooseOptimizer", "JuMP", "LinearAlgebra", "SimpleGraphs", "SimplePartitions", "SimplePolynomials"] +git-tree-sha1 = "e333fd8f96c9e61b3beac3968b06c87d5f849d99" +uuid = "41400c72-0c58-5c16-8579-4ecbce768449" +version = "0.6.0" + +[[deps.SimpleGraphConverter]] +deps = ["Graphs", "SimpleGraphs"] +git-tree-sha1 = "30b6ee355f4fb9a79db85300f2d96e1582eb89aa" +uuid = "205b04f2-f585-4877-a239-566270b3f673" +version = "0.1.0" + +[[deps.SimpleGraphs]] +deps = ["AbstractLattices", "Combinatorics", "DataStructures", "IterTools", "LightXML", "LinearAlgebra", "LinearAlgebraX", "Optim", "Primes", "Random", "RingLists", "SimplePartitions", "SimplePolynomials", "SimpleRandom", "SparseArrays", "Statistics"] +git-tree-sha1 = "f65caa24a622f985cc341de81d3f9744435d0d0f" +uuid = "55797a34-41de-5266-9ec1-32ac4eb504d3" +version = "0.8.6" + +[[deps.SimplePartitions]] +deps = ["AbstractLattices", "DataStructures", "Permutations"] +git-tree-sha1 = "76cdce94e07849d1172ccb8f3a60a0bbbebe58b3" +uuid = "ec83eff0-a5b5-5643-ae32-5cbf6eedec9d" +version = "0.3.3" + +[[deps.SimplePolynomials]] +deps = ["Mods", "Multisets", "Polynomials", "Primes"] +git-tree-sha1 = "77b2c5e731f7e50bbd088ccc2810232e06c1afa3" +uuid = "cc47b68c-3164-5771-a705-2bc0097375a0" +version = "0.2.18" + +[[deps.SimpleRandom]] +deps = ["Distributions", "LinearAlgebra", "Random"] +git-tree-sha1 = "bb4f42b25b87f124478207a82f5b02dfafdb3e63" +uuid = "a6525b86-64cd-54fa-8f65-62fc48bdc0e8" +version = "0.3.2" + +[[deps.SimpleTensorNetworks]] +deps = ["DataGraphs", "Graphs", "NamedGraphs"] +git-tree-sha1 = "c425260a467bb77990a523e3b44d29d687bed4e5" +uuid = "3075f829-f72e-4896-a859-7fe0a9cabb9b" +version = "0.1.0" + +[[deps.SimpleTraits]] +deps = ["InteractiveUtils", "MacroTools"] +git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" +uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" +version = "0.9.4" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +version = "1.11.0" + +[[deps.SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.2.1" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.11.0" + +[[deps.SpecialFunctions]] +deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "41852b8679f78c8d8961eeadc8f62cef861a52e3" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.5.1" + + [deps.SpecialFunctions.extensions] + SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" + + [deps.SpecialFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + +[[deps.SplitApplyCombine]] +deps = ["Dictionaries", "Indexing"] +git-tree-sha1 = "c06d695d51cfb2187e6848e98d6252df9101c588" +uuid = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66" +version = "1.2.3" + +[[deps.Static]] +deps = ["CommonWorldInvalidations", "IfElse", "PrecompileTools"] +git-tree-sha1 = "f737d444cb0ad07e61b3c1bef8eb91203c321eff" +uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" +version = "1.2.0" + +[[deps.StaticArrayInterface]] +deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "PrecompileTools", "Static"] +git-tree-sha1 = "96381d50f1ce85f2663584c8e886a6ca97e60554" +uuid = "0d7ed370-da01-4f52-bd93-41d350b8b718" +version = "1.8.0" + + [deps.StaticArrayInterface.extensions] + StaticArrayInterfaceOffsetArraysExt = "OffsetArrays" + StaticArrayInterfaceStaticArraysExt = "StaticArrays" + + [deps.StaticArrayInterface.weakdeps] + OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] +git-tree-sha1 = "0feb6b9031bd5c51f9072393eb5ab3efd31bf9e4" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.9.13" + + [deps.StaticArrays.extensions] + StaticArraysChainRulesCoreExt = "ChainRulesCore" + StaticArraysStatisticsExt = "Statistics" + + [deps.StaticArrays.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[deps.StaticArraysCore]] +git-tree-sha1 = "192954ef1208c7019899fbf8049e717f92959682" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.4.3" + +[[deps.Statistics]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "ae3bb1eb3bba077cd276bc5cfc337cc65c3075c0" +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.11.1" +weakdeps = ["SparseArrays"] + + [deps.Statistics.extensions] + SparseArraysExt = ["SparseArrays"] + +[[deps.StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.7.0" + +[[deps.StatsBase]] +deps = ["AliasTables", "DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "b81c5035922cc89c2d9523afc6c54be512411466" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.34.5" + +[[deps.StatsFuns]] +deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "8e45cecc66f3b42633b8ce14d431e8e57a3e242e" +uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +version = "1.5.0" + + [deps.StatsFuns.extensions] + StatsFunsChainRulesCoreExt = "ChainRulesCore" + StatsFunsInverseFunctionsExt = "InverseFunctions" + + [deps.StatsFuns.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + +[[deps.StructTypes]] +deps = ["Dates", "UUIDs"] +git-tree-sha1 = "159331b30e94d7b11379037feeb9b690950cace8" +uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" +version = "1.11.0" + +[[deps.StyledStrings]] +uuid = "f489334b-da3d-4c2e-b8f0-e476e12c162b" +version = "1.11.0" + +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.7.0+0" + +[[deps.Suppressor]] +deps = ["Logging"] +git-tree-sha1 = "6dbb5b635c5437c68c28c2ac9e39b87138f37c0a" +uuid = "fd094767-a336-5f1f-9728-57cf17d0bbfb" +version = "0.2.8" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.TensorCrossInterpolation]] +deps = ["EllipsisNotation", "LinearAlgebra", "QuadGK"] +git-tree-sha1 = "378bca655cc4596c9db7adba9ac3e089bac9e3c5" +uuid = "b261b2ec-6378-4871-b32e-9173bb050604" +version = "0.9.14" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +version = "1.11.0" + +[[deps.TranscodingStreams]] +git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.11.3" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" +version = "1.11.0" + +[[deps.UnPack]] +git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" +uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" +version = "1.0.2" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" +version = "1.11.0" + +[[deps.XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] +git-tree-sha1 = "b8b243e47228b4a3877f1dd6aee0c5d56db7fcf4" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.13.6+1" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.11.0+0" diff --git a/samples/devtci.jl b/samples/devtci.jl deleted file mode 100644 index cfb77d6..0000000 --- a/samples/devtci.jl +++ /dev/null @@ -1,26 +0,0 @@ -using Revise -using TreeTCI -using NamedGraphs: NamedGraph, add_edge!, edges - -function main() - localdims = fill(2, 7) - g = NamedGraph(7) - add_edge!(g, 1, 2) - add_edge!(g, 2, 3) - add_edge!(g, 2, 4) - add_edge!(g, 4, 5) - add_edge!(g, 5, 6) - add_edge!(g, 5, 7) - - f(v) = 1 / (1 + v' * v) - tolerance = 1e-8 - - mpn, ranks, errors = TreeTCI.TCI.crossinterpolate2(Float64, f, localdims; tolerance = tolerance) - ttn, ranks, errors = TreeTCI.crossinterpolate(Float64, f, localdims, g) - @show f([1, 1, 1, 1, 2, 1, 1]), f([1, 2, 1, 2, 2, 1, 1]), f([2, 2, 2, 2, 2, 2, 2]) - @show mpn([1, 1, 1, 1, 2, 1, 1]), mpn([1, 2, 1, 2, 2, 1, 1]), mpn([2, 2, 2, 2, 2, 2, 2]) - @show ttn([1, 1, 1, 1, 2, 1, 1]), ttn([1, 2, 1, 2, 2, 1, 1]), ttn([2, 2, 2, 2, 2, 2, 2]) - nothing -end - -main() diff --git a/samples/sample_structural_opt.jl b/samples/sample_structural_opt.jl new file mode 100644 index 0000000..b848676 --- /dev/null +++ b/samples/sample_structural_opt.jl @@ -0,0 +1,29 @@ +using Test +using TreeTCI: SimpleTCI, optimize!, swap_2site!, add_subtree! +import NamedGraphs: NamedGraph, NamedEdge, add_edge!, vertices, edges, has_edge + +function main() + # make graph + g = NamedGraph(10) + add_edge!(g, 1, 2) + add_edge!(g, 2, 3) + add_edge!(g, 3, 4) + add_edge!(g, 4, 5) + add_edge!(g, 5, 6) + add_edge!(g, 6, 7) + add_edge!(g, 7, 8) + add_edge!(g, 8, 9) + add_edge!(g, 9, 10) + + localdims = fill(2, length(vertices(g))) + f(v) = 1 / (1 + v' * v) + kwargs = (maxbonddim = 20, maxiter = 10) + tci = SimpleTCI{Float64}(f, localdims, g, [ones(Int, length(localdims))]) + ranks, errors = optimize!(tci, f; kwargs...) + + # swap_2site!(g, 1 => 3) + add_subtree!(g, 6, NamedEdge(3 => 4)) + +end + +main() diff --git a/samples/sample_treetci.jl b/samples/sample_treetci.jl new file mode 100644 index 0000000..b0c5d3a --- /dev/null +++ b/samples/sample_treetci.jl @@ -0,0 +1,27 @@ +using Test +using TreeTCI +import NamedGraphs: NamedGraph, NamedEdge, add_edge!, vertices, edges, has_edge + +function main() + # make graph + g = NamedGraph(10) + add_edge!(g, 1, 3) + add_edge!(g, 2, 3) + add_edge!(g, 3, 5) + + add_edge!(g, 4, 5) + add_edge!(g, 5, 7) + add_edge!(g, 6, 7) + add_edge!(g, 7, 8) + add_edge!(g, 8, 9) + add_edge!(g, 8, 10) + + localdims = fill(2, length(vertices(g))) + f(v) = 1 / (1 + v' * v) + kwargs = (maxbonddim = 20, maxiter = 10) + ttn, ranks, errors = TreeTCI.crossinterpolate(Float64, f, localdims, g; kwargs...) + @show ttn([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]), f([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) + @show ttn([1, 2, 1, 2, 1, 2, 1, 2, 1, 2]), f([1, 2, 1, 2, 1, 2, 1, 2, 1, 2]) +end + +main() diff --git a/samples/sample_treetci2.jl b/samples/sample_treetci2.jl new file mode 100644 index 0000000..4628ce5 --- /dev/null +++ b/samples/sample_treetci2.jl @@ -0,0 +1,32 @@ +using Test +using TreeTCI +import NamedGraphs: NamedGraph, NamedEdge, add_edge!, vertices, edges, has_edge + +function f_pairwise(v::Vector{Int}) + s = 0.0 + for i in 1:2:length(v)-1 + s += v[i] * v[i+1] + end + return 1 / (1+s) +end + + +function main() + # make graph + g = NamedGraph(8) + add_edge!(g, 1, 2) + add_edge!(g, 2, 3) + add_edge!(g, 3, 4) + add_edge!(g, 4, 5) + add_edge!(g, 5, 6) + add_edge!(g, 6, 7) + add_edge!(g, 7, 8) + + localdims = fill(8, length(vertices(g))) + f(v) = f_pairwise(v) + kwargs = (maxbonddim = 64, maxiter = 10) + ttn, ranks, errors = TreeTCI.crossinterpolate(Float64, f, localdims, g; kwargs...) + +end + +main() diff --git a/src/TreeTCI.jl b/src/TreeTCI.jl index aab7804..e6452b2 100644 --- a/src/TreeTCI.jl +++ b/src/TreeTCI.jl @@ -1,10 +1,6 @@ module TreeTCI -import Graphs -import NamedGraphs: - NamedGraph, NamedEdge, is_directed, outneighbors, has_edge, edges, vertices, src, dst, namedgraph_dijkstra_shortest_paths -import TensorCrossInterpolation as TCI -import SimpleTensorNetworks: TensorNetwork, IndexedArray, Index, complete_contraction, getindex, contract +include("imports.jl") include("tree_utils.jl") include("simpletci.jl") include("simpletci_utils.jl") diff --git a/src/imports.jl b/src/imports.jl new file mode 100644 index 0000000..d49be5a --- /dev/null +++ b/src/imports.jl @@ -0,0 +1,21 @@ +using Graphs: simplecycles_limited_length, has_edge, SimpleGraph, center, steiner_tree +using NamedGraphs: + NamedGraph, + NamedEdge, + is_cyclic, + is_directed, + neighbors, + outneighbors, + has_edge, + edges, + vertices, + namedgraph_dijkstra_shortest_paths +using NamedGraphs.GraphsExtensions: + src, + dst, + is_connected, + degree, + add_vertices!, add_vertex!, rem_vertices!, rem_vertex!, + rem_edge!, add_edge! +import TensorCrossInterpolation as TCI +import SimpleTensorNetworks: TensorNetwork, IndexedArray, Index, complete_contraction, getindex, contract diff --git a/src/simpletci.jl b/src/simpletci.jl index 0299bad..bdd156b 100644 --- a/src/simpletci.jl +++ b/src/simpletci.jl @@ -5,6 +5,7 @@ using Base: SimpleLogger mutable struct SimpleTCI{ValueType} IJset::Dict{SubTreeVertex,Vector{MultiIndex}} + converged_IJset::Dict{SubTreeVertex,Vector{MultiIndex}} localdims::Vector{Int} g::NamedGraph #"Error estimate per bond by 2site sweep." @@ -13,26 +14,25 @@ mutable struct SimpleTCI{ValueType} pivoterrors::Vector{Float64} # key is the bond id #"Maximum sample for error normalization." maxsamplevalue::Float64 - IJset_history::Vector{Dict{SubTreeVertex,Vector{MultiIndex}}} function SimpleTCI{ValueType}(localdims::Vector{Int}, g::NamedGraph) where {ValueType} length(localdims) > 1 || error("localdims should have at least 2 elements!") n = length(localdims) # assign the key for each bond - bonderrors = Dict(e => 0.0 for e in edges(g)) + bonderrors = Dict(e => typemax(Float64) for e in edges(g)) - !Graphs.is_cyclic(g) || + !is_cyclic(g) || error("TreeTensorNetwork is not supported for loopy tensor network.") new{ValueType}( Dict{SubTreeVertex,Vector{MultiIndex}}(), # IJset + Dict{SubTreeVertex,Vector{MultiIndex}}(), # converged_IJset localdims, g, bonderrors, Float64[], 0.0, # maxsamplevalue - Vector{Dict{SubTreeVertex,Vector{MultiIndex}}}(), # IJset_history ) end end @@ -120,7 +120,7 @@ function optimize!( pivottolerance::Union{Float64,Nothing} = nothing, maxbonddim::Int = typemax(Int), maxiter::Int = 20, - sweepstrategy::Symbol = :backandforth, # TODO: Implement for Tree structure + sweepstrategy::Symbol = :backandforth, pivotsearch::Symbol = :full, verbosity::Int = 0, loginterval::Int = 10, @@ -185,9 +185,7 @@ function optimize!( sweep2site!( tci, - f, - 2; - iter1 = 1, + f; abstol = abstol, maxbonddim = maxbonddim, pivotsearch = pivotsearch, @@ -212,6 +210,7 @@ function optimize!( ) flush(stdout) end + end errornormalization = normalizeerror ? tci.maxsamplevalue : 1.0 @@ -220,14 +219,10 @@ end @doc""" Perform 2site sweeps on a SimpleTCI. -!TODO: Implement for Tree structure - """ function sweep2site!( tci::SimpleTCI{ValueType}, - f, - niter::Int; - iter1::Int = 1, + f; abstol::Float64 = 1e-8, maxbonddim::Int = typemax(Int), sweepstrategy::Symbol = :backandforth, @@ -237,28 +232,23 @@ function sweep2site!( edge_path = generate_sweep2site_path(DefaultSweep2sitePathProper(), tci) + extraIJset = tci.IJset + for (key, pivots) in tci.converged_IJset + extraIJset[key] = pivots + end - for iter = iter1:iter1+niter-1 - extraIJset = Dict(key => MultiIndex[] for key in keys(tci.IJset)) - if length(tci.IJset_history) > 0 - extraIJset = tci.IJset_history[end] - end - - push!(tci.IJset_history, deepcopy(tci.IJset)) - - flushpivoterror!(tci) + flushpivoterror!(tci) - for edge in edge_path - updatepivots!( - tci, - edge, - f; - abstol = abstol, - maxbonddim = maxbonddim, - verbosity = verbosity, - extraIJset = extraIJset, - ) - end + for edge in edge_path + updatepivots!( + tci, + edge, + f; + abstol = abstol, + maxbonddim = maxbonddim, + verbosity = verbosity, + extraIJset = extraIJset, + ) end nothing @@ -317,10 +307,6 @@ function updatepivots!( updatemaxsample!(tci, Pi) luci = TCI.MatrixLUCI(Pi, reltol = reltol, abstol = abstol, maxrank = maxbonddim) - # TODO: we will implement luci according to optimal index subsets by following step - # 1. Compute the optimal index subsets (We also need the indices to set new pivots) - # 2. Reshape the Pi matrix by the optimal index subsets - # 3. Compute the LUCI by the reshaped Pi matrix t3 = time_ns() if verbosity > 2 @@ -328,15 +314,20 @@ function updatepivots!( println( " Computing Pi ($x x $y) at bond $b: $(1e-9*(t2-t1)) sec, LU: $(1e-9*(t3-t2)) sec", ) - end + end + tci.IJset[Ikey] = combinedIJset[Ikey][TCI.rowindices(luci)] + tci.IJset[Jkey] = combinedIJset[Jkey][TCI.colindices(luci)] - tci.IJset[Ikey] = combinedIJset[Ikey][TCI.rowindices(luci)] - tci.IJset[Jkey] = combinedIJset[Jkey][TCI.colindices(luci)] + updateerrors!(tci, edge, TCI.pivoterrors(luci)) - updateerrors!(tci, edge, TCI.pivoterrors(luci)) - nothing + # Add the converged pivots + if tci.bonderrors[edge] < abstol + tci.converged_IJset[Ikey] = tci.IJset[Ikey] + tci.converged_IJset[Jkey] = tci.IJset[Jkey] end + nothing +end function updatemaxsample!(tci::SimpleTCI{V}, samples::Array{V}) where {V} tci.maxsamplevalue = TCI.maxabs(tci.maxsamplevalue, samples) diff --git a/src/tree_utils.jl b/src/tree_utils.jl index bb688f1..ae302fd 100644 --- a/src/tree_utils.jl +++ b/src/tree_utils.jl @@ -85,3 +85,42 @@ function distanceBFSedge( end return distances end + +function swap_2site!( + g::NamedGraph, + vs::Pair{Int, Int}, +) + p, q = vs + p_neighbors = neighbors(g, p) + q_neighbors = neighbors(g, q) + + rem_vertices!(g, [p, q]) + + add_vertex!(g, p) + add_vertex!(g, q) + + for p_i in p_neighbors + add_edge!(g, NamedEdge(p_i => q)) + end + + for q_i in q_neighbors + add_edge!(g, NamedEdge(q_i => p)) + end + + p_neighbors = neighbors(g, p) + q_neighbors = neighbors(g, q) + return g +end + +function add_subtree!( + g::NamedGraph, + v::Int, + edge::NamedEdge, +) + p, q = separatevertices(g, edge) + p_regions = subtreevertices(g, q => p) + q_regions = subtreevertices(g, p => q) + parent = v in p_regions ? q : p + rem_edge!(g, edge) + add_edge!(g, NamedEdge(parent => v)) +end \ No newline at end of file From ae8a1fe21714890d287f107c0aec51bcb8e8ed69 Mon Sep 17 00:00:00 2001 From: watayo Date: Sun, 11 May 2025 18:09:21 +0900 Subject: [PATCH 02/13] merge --- samples/sample_structural_opt.jl | 12 ++++++++++-- src/abstracttreetensornetwork.jl | 1 - 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/samples/sample_structural_opt.jl b/samples/sample_structural_opt.jl index b848676..bac20df 100644 --- a/samples/sample_structural_opt.jl +++ b/samples/sample_structural_opt.jl @@ -17,13 +17,21 @@ function main() localdims = fill(2, length(vertices(g))) f(v) = 1 / (1 + v' * v) - kwargs = (maxbonddim = 20, maxiter = 10) + kwargs = (maxbonddim = 5, maxiter = 10) tci = SimpleTCI{Float64}(f, localdims, g, [ones(Int, length(localdims))]) ranks, errors = optimize!(tci, f; kwargs...) # swap_2site!(g, 1 => 3) - add_subtree!(g, 6, NamedEdge(3 => 4)) + tci_new = deepcopy(tci) + add_subtree!(tci_new.g, 6, NamedEdge(3 => 4)) # structural change + + tci_new = SimpleTCI{Float64}(f, localdims, tci_new.g, [ones(Int, length(localdims))]) + tci_new.converged_IJset = tci.converged_IJset + ranks, errors = optimize!(tci_new, f; kwargs...) + + # TODO: Check the criterion between two structures. + return 0 end main() diff --git a/src/abstracttreetensornetwork.jl b/src/abstracttreetensornetwork.jl index 0a83d47..acfe542 100644 --- a/src/abstracttreetensornetwork.jl +++ b/src/abstracttreetensornetwork.jl @@ -20,7 +20,6 @@ function evaluate( ) end sitetensors = IndexedArray[] - # TODO: site tensorを作る関数を作成 for (Tinfo, i) in zip(ttn.sitetensors, indexset) T, edges = Tinfo inds = (i, ntuple(_ -> :, ndims(T) - 1)...) From c00c06e3883cc631334c990b4ba3102327b3544e Mon Sep 17 00:00:00 2001 From: watayo Date: Sun, 11 May 2025 19:43:26 +0900 Subject: [PATCH 03/13] solove confilict --- samples/sample_structural_opt.jl | 2 + src/TreeTCI.jl | 2 +- src/pivotcandidateproposer.jl | 7 +- src/simpletci.jl | 286 +------------------------------ src/simpletci_optimize.jl | 36 ++-- 5 files changed, 21 insertions(+), 312 deletions(-) diff --git a/samples/sample_structural_opt.jl b/samples/sample_structural_opt.jl index bac20df..84e412d 100644 --- a/samples/sample_structural_opt.jl +++ b/samples/sample_structural_opt.jl @@ -30,6 +30,8 @@ function main() tci_new.converged_IJset = tci.converged_IJset ranks, errors = optimize!(tci_new, f; kwargs...) + @show tci.pivoterrors + @show tci_new.pivoterrors # TODO: Check the criterion between two structures. return 0 end diff --git a/src/TreeTCI.jl b/src/TreeTCI.jl index ee71d6d..d3f7f4a 100644 --- a/src/TreeTCI.jl +++ b/src/TreeTCI.jl @@ -1,7 +1,7 @@ module TreeTCI include("imports.jl") -include("tree_utils.jl") +include("treegraph_utils.jl") include("simpletci.jl") include("pivotcandidateproposer.jl") include("sweep2sitepathproposer.jl") diff --git a/src/pivotcandidateproposer.jl b/src/pivotcandidateproposer.jl index 5a65ca2..3659493 100644 --- a/src/pivotcandidateproposer.jl +++ b/src/pivotcandidateproposer.jl @@ -44,10 +44,9 @@ function generate_pivot_candidates( Iset = kronecker(Ipivots, Isite_index, tci.localdims[vp]) Jset = kronecker(Jpivots, Jsite_index, tci.localdims[vq]) - extraIJset = if length(tci.IJset_history) > 0 - extraIJset = tci.IJset_history[end] - else - Dict(key => MultiIndex[] for key in keys(tci.IJset)) + extraIJset = tci.IJset + for (key, pivots) in tci.converged_IJset + extraIJset[key] = pivots end Icombined = union(Iset, extraIJset[Ikey]) diff --git a/src/simpletci.jl b/src/simpletci.jl index e9f0dda..9f91c50 100644 --- a/src/simpletci.jl +++ b/src/simpletci.jl @@ -47,7 +47,7 @@ mutable struct SimpleTCI{ValueType} n == length(vertices(g)) || error( "The number of vertices in the graph must be equal to the length of localdims.", ) - !Graphs.is_cyclic(g) || + !is_cyclic(g) || error("SimpleTCI is not supported for loopy tensor network.") # assign the key for each bond @@ -118,290 +118,6 @@ function addglobalpivots!( nothing end -@doc""" - optimize!(tci::SimpleTCI{ValueType}, f; kwargs...) - -Optimize the tensor cross interpolation (TCI) by iteratively updating pivots. - -# Arguments -- `tci`: The SimpleTCI object to optimize -- `f`: The function to interpolate - -# Keywords -- `tolerance::Union{Float64,Nothing} = nothing`: Error tolerance for convergence -- `pivottolerance::Union{Float64,Nothing} = nothing`: Deprecated, use tolerance instead -- `maxbonddim::Int = typemax(Int)`: Maximum bond dimension -- `maxiter::Int = 20`: Maximum number of iterations -- `sweepstrategy::Symbol = :backandforth`: Strategy for sweeping -- `pivotsearch::Symbol = :full`: Strategy for pivot search -- `verbosity::Int = 0`: Verbosity level -- `loginterval::Int = 10`: Interval for logging -- `normalizeerror::Bool = true`: Whether to normalize errors -- `ncheckhistory::Int = 3`: Number of history steps to check -- `maxnglobalpivot::Int = 5`: Maximum number of global pivots -- `nsearchglobalpivot::Int = 5`: Number of global pivots to search -- `tolmarginglobalsearch::Float64 = 10.0`: Tolerance margin for global search -- `strictlynested::Bool = false`: Whether to enforce strict nesting -- `checkbatchevaluatable::Bool = false`: Whether to check if function is batch evaluatable - -# Returns -- `ranks`: Vector of ranks at each iteration -- `errors`: Vector of normalized errors at each iteration -""" -function optimize!( - tci::SimpleTCI{ValueType}, - f; - tolerance::Union{Float64,Nothing} = nothing, - pivottolerance::Union{Float64,Nothing} = nothing, - maxbonddim::Int = typemax(Int), - maxiter::Int = 20, - sweepstrategy::Symbol = :backandforth, - pivotsearch::Symbol = :full, - verbosity::Int = 0, - loginterval::Int = 10, - normalizeerror::Bool = true, - ncheckhistory::Int = 3, - maxnglobalpivot::Int = 5, - nsearchglobalpivot::Int = 5, - tolmarginglobalsearch::Float64 = 10.0, - strictlynested::Bool = false, - checkbatchevaluatable::Bool = false, -) where {ValueType} - errors = Float64[] - ranks = Int[] - nglobalpivots = Int[] - local tol::Float64 - - if checkbatchevaluatable && !(f isa BatchEvaluator) - error("Function `f` is not batch evaluatable") - end - - if nsearchglobalpivot > 0 && nsearchglobalpivot < maxnglobalpivot - error("nsearchglobalpivot < maxnglobalpivot!") - end - - # Deprecate the pivottolerance option - if !isnothing(pivottolerance) - if !isnothing(tolerance) && (tolerance != pivottolerance) - throw( - ArgumentError( - "Got different values for pivottolerance and tolerance in optimize!(TCI2). For TCI2, both of these options have the same meaning. Please assign only `tolerance`.", - ), - ) - else - @warn "The option `pivottolerance` of `optimize!(tci::TensorCI2, f)` is deprecated. Please update your code to use `tolerance`, as `pivottolerance` will be removed in the future." - tol = pivottolerance - end - elseif !isnothing(tolerance) - tol = tolerance - else # pivottolerance == tolerance == nothing, therefore set tol to default value - tol = 1e-8 - end - - tstart = time_ns() - - if maxbonddim >= typemax(Int) && tol <= 0 - throw( - ArgumentError( - "Specify either tolerance > 0 or some maxbonddim; otherwise, the convergence criterion is not reachable!", - ), - ) - end - - globalpivots = MultiIndex[] - for iter = 1:maxiter - errornormalization = normalizeerror ? tci.maxsamplevalue : 1.0 - abstol = tol * errornormalization - - if verbosity > 1 - println(" Walltime $(1e-9*(time_ns() - tstart)) sec: starting 2site sweep") - flush(stdout) - end - - sweep2site!( - tci, - f; - abstol = abstol, - maxbonddim = maxbonddim, - pivotsearch = pivotsearch, - verbosity = verbosity, - sweepstrategy = sweepstrategy, - ) - if verbosity > 0 && length(globalpivots) > 0 && mod(iter, loginterval) == 0 - abserr = [abs(evaluate(tci, p) - f(p)) for p in globalpivots] - nrejections = length(abserr .> abstol) - if nrejections > 0 - println( - " Rejected $(nrejections) global pivots added in the previous iteration, errors are $(abserr)", - ) - flush(stdout) - end - end - push!(errors, last(pivoterror(tci))) - - if verbosity > 1 - println( - " Walltime $(1e-9*(time_ns() - tstart)) sec: start searching global pivots", - ) - flush(stdout) - end - - end - - errornormalization = normalizeerror ? tci.maxsamplevalue : 1.0 - return ranks, errors ./ errornormalization -end - -@doc""" -Perform 2site sweeps on a SimpleTCI. -""" -function sweep2site!( - tci::SimpleTCI{ValueType}, - f; - abstol::Float64 = 1e-8, - maxbonddim::Int = typemax(Int), - sweepstrategy::Symbol = :backandforth, - pivotsearch::Symbol = :full, - verbosity::Int = 0, -) where {ValueType} - - edge_path = generate_sweep2site_path(DefaultSweep2sitePathProper(), tci) - - extraIJset = tci.IJset - for (key, pivots) in tci.converged_IJset - extraIJset[key] = pivots - end - - flushpivoterror!(tci) - - for edge in edge_path - updatepivots!( - tci, - edge, - f; - abstol = abstol, - maxbonddim = maxbonddim, - verbosity = verbosity, - extraIJset = extraIJset, - ) - end - - nothing -end - - -function flushpivoterror!(tci::SimpleTCI{ValueType}) where {ValueType} - tci.pivoterrors = Float64[] - nothing -end - -""" -Update pivots at bond `b` of `tci` using the TCI2 algorithm. -Site tensors will be invalidated. -""" -function updatepivots!( - tci::SimpleTCI{ValueType}, - edge::NamedEdge, - f::F; - reltol::Float64 = 1e-14, - abstol::Float64 = 0.0, - maxbonddim::Int = typemax(Int), - verbosity::Int = 0, - extraIJset::Dict{SubTreeVertex,Vector{MultiIndex}} = Dict{ - SubTreeVertex, - Vector{MultiIndex}, - }(), - ) where {F,ValueType} - - N = length(tci.localdims) - - (IJkey, combinedIJset) = generate_pivot_candidates( - DefaultPivotCandidateProper(), - tci, - edge, - extraIJset, - ) - Ikey, Jkey = first(IJkey), last(IJkey) - - t1 = time_ns() - Pi = reshape( - filltensor( - ValueType, - f, - tci.localdims, - combinedIJset, - [Ikey], - [Jkey], - Val(0), - ), - length(combinedIJset[Ikey]), - length(combinedIJset[Jkey]), - ) - t2 = time_ns() - - updatemaxsample!(tci, Pi) - - luci = TCI.MatrixLUCI(Pi, reltol = reltol, abstol = abstol, maxrank = maxbonddim) - - t3 = time_ns() - if verbosity > 2 - x, y = length(combinedIJset[Ikey]), length(combinedIJset[Jkey]), - println( - " Computing Pi ($x x $y) at bond $b: $(1e-9*(t2-t1)) sec, LU: $(1e-9*(t3-t2)) sec", - ) - end - tci.IJset[Ikey] = combinedIJset[Ikey][TCI.rowindices(luci)] - tci.IJset[Jkey] = combinedIJset[Jkey][TCI.colindices(luci)] - - updateerrors!(tci, edge, TCI.pivoterrors(luci)) - - # Add the converged pivots - if tci.bonderrors[edge] < abstol - tci.converged_IJset[Ikey] = tci.IJset[Ikey] - tci.converged_IJset[Jkey] = tci.IJset[Jkey] - end - - nothing -end - -function updatemaxsample!(tci::SimpleTCI{V}, samples::Array{V}) where {V} - tci.maxsamplevalue = TCI.maxabs(tci.maxsamplevalue, samples) -end - -function updateerrors!( - tci::SimpleTCI{T}, - edge::NamedEdge, - errors::AbstractVector{Float64}, -) where {T} - updateedgeerror!(tci, edge, last(errors)) - updatepivoterror!(tci, errors) - nothing -end - -function updateedgeerror!( - tci::SimpleTCI{T}, - edge::NamedEdge, - error::Float64, -) where {T} - tci.bonderrors[edge] = error - nothing -end - -function updatepivoterror!(tci::SimpleTCI{T}, errors::AbstractVector{Float64}) where {T} - erroriter = Iterators.map(max, TCI.padzero(tci.pivoterrors), TCI.padzero(errors)) - tci.pivoterrors = - Iterators.take(erroriter, max(length(tci.pivoterrors), length(errors))) |> collect - nothing -end - -function pivoterror(tci::SimpleTCI{T}) where {T} - return maxbonderror(tci) -end - -function maxbonderror(tci::SimpleTCI{T}) where {T} - return maximum(values(tci.bonderrors)) -end - """ Return if site tensors are available """ diff --git a/src/simpletci_optimize.jl b/src/simpletci_optimize.jl index 04a8f3f..b875c95 100644 --- a/src/simpletci_optimize.jl +++ b/src/simpletci_optimize.jl @@ -74,8 +74,7 @@ function optimize!( sweep2site!( tci, - f, - 2; + f; abstol = abstol, maxbonddim = maxbonddim, verbosity = verbosity, @@ -111,8 +110,7 @@ end """ function sweep2site!( tci::SimpleTCI{ValueType}, - f, - niter::Int; + f; abstol::Float64 = 1e-8, maxbonddim::Int = typemax(Int), sweepstrategy::AbstractSweep2sitePathProposer = DefaultSweep2sitePathProposer(), @@ -122,24 +120,18 @@ function sweep2site!( edge_path = generate_sweep2site_path(sweepstrategy, tci) - for _ = 1:niter - extraIJset = Dict(key => MultiIndex[] for key in keys(tci.IJset)) - - push!(tci.IJset_history, deepcopy(tci.IJset)) - - flushpivoterror!(tci) + flushpivoterror!(tci) - for edge in edge_path - updatepivots!( - tci, - edge, - f; - abstol = abstol, - maxbonddim = maxbonddim, - pivotstrategy = pivotstrategy, - verbosity = verbosity, - ) - end + for edge in edge_path + updatepivots!( + tci, + edge, + f; + abstol = abstol, + maxbonddim = maxbonddim, + pivotstrategy = pivotstrategy, + verbosity = verbosity, + ) end nothing @@ -230,4 +222,4 @@ end function maxbonderror(tci::SimpleTCI{T}) where {T} return maximum(values(tci.bonderrors)) -end +end \ No newline at end of file From 6d535c43dd4c5ac172b8ec2f40d2cd74e1ca3c76 Mon Sep 17 00:00:00 2001 From: watayo Date: Fri, 16 May 2025 16:06:47 +0900 Subject: [PATCH 04/13] convergence --- Project.toml | 2 ++ src/simpletci.jl | 3 --- src/simpletci_optimize.jl | 54 ++++++++++++++++++++++++++------------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/Project.toml b/Project.toml index bccfef1..39a1b7b 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.1.0" [deps] DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SimpleTensorNetworks = "3075f829-f72e-4896-a859-7fe0a9cabb9b" @@ -14,6 +15,7 @@ TensorCrossInterpolation = "b261b2ec-6378-4871-b32e-9173bb050604" [compat] DataGraphs = "0.2.5" Graphs = "1.12.0" +LinearAlgebra = "1.11.0" NamedGraphs = "0.6.4" Random = "1.10" SimpleTensorNetworks = "0.1.0" diff --git a/src/simpletci.jl b/src/simpletci.jl index 9f91c50..4d49f29 100644 --- a/src/simpletci.jl +++ b/src/simpletci.jl @@ -118,9 +118,6 @@ function addglobalpivots!( nothing end -""" -Return if site tensors are available -""" function pushunique!(collection, item) if !(item in collection) diff --git a/src/simpletci_optimize.jl b/src/simpletci_optimize.jl index b875c95..929da7c 100644 --- a/src/simpletci_optimize.jl +++ b/src/simpletci_optimize.jl @@ -48,7 +48,9 @@ function optimize!( loginterval::Int = 10, normalizeerror::Bool = true, ncheckhistory::Int = 3, -) where {ValueType} + ) where {ValueType} + + # Histories of properties for checking convergence. errors = Float64[] ranks = Int[] @@ -62,7 +64,6 @@ function optimize!( ) end - globalpivots = MultiIndex[] for iter = 1:maxiter errornormalization = normalizeerror ? tci.maxsamplevalue : 1.0 abstol = tolerance * errornormalization @@ -81,24 +82,20 @@ function optimize!( sweepstrategy = sweepstrategy, pivotstrategy = pivotstrategy, ) - if verbosity > 0 && length(globalpivots) > 0 && mod(iter, loginterval) == 0 - abserr = [abs(evaluate(tci, p) - f(p)) for p in globalpivots] - nrejections = length(abserr .> abstol) - if nrejections > 0 - println( - " Rejected $(nrejections) global pivots added in the previous iteration, errors are $(abserr)", - ) - flush(stdout) - end - end - push!(errors, last(pivoterror(tci))) - if verbosity > 1 - println( - " Walltime $(1e-9*(time_ns() - tstart)) sec: start searching global pivots", - ) - flush(stdout) + push!(ranks, rank(tci)) + push!(errors, pivoterror(tci)) + + if convergencecriterion( + ranks, + errors; + maxbonddim=maxbonddim, + tolerance=tolerance + ) + println("Converged at $(iter)th-sweep.") + break end + end errornormalization = normalizeerror ? tci.maxsamplevalue : 1.0 @@ -216,10 +213,31 @@ function updatepivoterror!(tci::SimpleTCI{T}, errors::AbstractVector{Float64}) w nothing end +function rank(tci::SimpleTCI{ValueType}) where {ValueType} + return maximum(length(IJset) for IJset in values(tci.IJset)) +end + function pivoterror(tci::SimpleTCI{T}) where {T} return maxbonderror(tci) end function maxbonderror(tci::SimpleTCI{T}) where {T} return maximum(values(tci.bonderrors)) +end + +function convergencecriterion( + ranks::AbstractVector{Int}, + errors::AbstractVector{Float64}; + maxbonddim::Int = typemax(Int), + tolerance::Float64 = 1e-8, + ncheckhistory::Int = 2, +)::Bool + if length(errors) < ncheckhistory + return false + end + lastranks = last(ranks, ncheckhistory) + return ( + all(last(errors, ncheckhistory) .< tolerance) && + minimum(lastranks) == lastranks[end] + ) || all(lastranks .>= maxbonddim) end \ No newline at end of file From 0e201e9d4b2d556a9b37b9c9b42b6cd821e9e8f9 Mon Sep 17 00:00:00 2001 From: watayo Date: Fri, 16 May 2025 16:09:41 +0900 Subject: [PATCH 05/13] converged_IJset --- src/simpletci_optimize.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simpletci_optimize.jl b/src/simpletci_optimize.jl index 929da7c..bc8ad4a 100644 --- a/src/simpletci_optimize.jl +++ b/src/simpletci_optimize.jl @@ -93,9 +93,9 @@ function optimize!( tolerance=tolerance ) println("Converged at $(iter)th-sweep.") + tci.converged_IJset = deepcopy(tci.IJset) break end - end errornormalization = normalizeerror ? tci.maxsamplevalue : 1.0 From 8eeadad392367cb380b7af8bf2f2f17d060e9422 Mon Sep 17 00:00:00 2001 From: watayo Date: Fri, 16 May 2025 22:21:37 +0900 Subject: [PATCH 06/13] structual search --- Project.toml | 2 -- samples/sample_structural_opt.jl | 51 +++++++++++++++++++------------- src/TreeTCI.jl | 1 + src/imports.jl | 1 + src/newstructureproposer.jl | 36 ++++++++++++++++++++++ src/simpletci_optimize.jl | 15 +++++----- src/simpletci_tensors.jl | 22 +++++++------- src/treegraph_utils.jl | 23 +++++++------- src/treetensornetwork.jl | 32 +++++++++++++++++++- 9 files changed, 131 insertions(+), 52 deletions(-) create mode 100644 src/newstructureproposer.jl diff --git a/Project.toml b/Project.toml index 39a1b7b..bccfef1 100644 --- a/Project.toml +++ b/Project.toml @@ -6,7 +6,6 @@ version = "0.1.0" [deps] DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SimpleTensorNetworks = "3075f829-f72e-4896-a859-7fe0a9cabb9b" @@ -15,7 +14,6 @@ TensorCrossInterpolation = "b261b2ec-6378-4871-b32e-9173bb050604" [compat] DataGraphs = "0.2.5" Graphs = "1.12.0" -LinearAlgebra = "1.11.0" NamedGraphs = "0.6.4" Random = "1.10" SimpleTensorNetworks = "0.1.0" diff --git a/samples/sample_structural_opt.jl b/samples/sample_structural_opt.jl index 84e412d..250c572 100644 --- a/samples/sample_structural_opt.jl +++ b/samples/sample_structural_opt.jl @@ -1,10 +1,32 @@ using Test -using TreeTCI: SimpleTCI, optimize!, swap_2site!, add_subtree! -import NamedGraphs: NamedGraph, NamedEdge, add_edge!, vertices, edges, has_edge +using TreeTCI: crossinterpolate_adaptivetree, crossinterpolate +using NamedGraphs: NamedGraph, add_edge!, vertices +using Random + +function evaluate_error_sampled(f, ttn1, ttn2, localdims::Vector{Int}, nsamples::Int; rng=Random.default_rng()) + total_error1 = 0.0 + total_error2 = 0.0 + + for _ in 1:nsamples + xvec = [rand(rng, 1:d) for d in localdims] + fx = f(xvec) + total_error1 += abs(fx - ttn1(xvec)) + total_error2 += abs(fx - ttn2(xvec)) + end + + mean_error1 = total_error1 / nsamples + mean_error2 = total_error2 / nsamples + + println("Sampled mean |f(x) - original(x)| = ", mean_error1) + println("Sampled mean |f(x) - optimized(x)| = ", mean_error2) + + return mean_error1, mean_error2 +end + function main() # make graph - g = NamedGraph(10) + g = NamedGraph(8) add_edge!(g, 1, 2) add_edge!(g, 2, 3) add_edge!(g, 3, 4) @@ -12,27 +34,14 @@ function main() add_edge!(g, 5, 6) add_edge!(g, 6, 7) add_edge!(g, 7, 8) - add_edge!(g, 8, 9) - add_edge!(g, 9, 10) - localdims = fill(2, length(vertices(g))) + localdims = fill(10, length(vertices(g))) f(v) = 1 / (1 + v' * v) - kwargs = (maxbonddim = 5, maxiter = 10) - tci = SimpleTCI{Float64}(f, localdims, g, [ones(Int, length(localdims))]) - ranks, errors = optimize!(tci, f; kwargs...) - - # swap_2site!(g, 1 => 3) - tci_new = deepcopy(tci) - - add_subtree!(tci_new.g, 6, NamedEdge(3 => 4)) # structural change - - tci_new = SimpleTCI{Float64}(f, localdims, tci_new.g, [ones(Int, length(localdims))]) - tci_new.converged_IJset = tci.converged_IJset - ranks, errors = optimize!(tci_new, f; kwargs...) + kwargs = (maxbonddim = 20, maxiter = 10) + tt, ranks, errors = crossinterpolate(Float64, f, localdims, g; kwargs...) + optimized_tt, ranks, errors = crossinterpolate_adaptivetree(Float64, f, localdims, g, 20; kwargs...) - @show tci.pivoterrors - @show tci_new.pivoterrors - # TODO: Check the criterion between two structures. + evaluate_error_sampled(f, tt, optimized_tt, localdims, 1000) return 0 end diff --git a/src/TreeTCI.jl b/src/TreeTCI.jl index d3f7f4a..6b9df46 100644 --- a/src/TreeTCI.jl +++ b/src/TreeTCI.jl @@ -3,6 +3,7 @@ module TreeTCI include("imports.jl") include("treegraph_utils.jl") include("simpletci.jl") +include("newstructureproposer.jl") include("pivotcandidateproposer.jl") include("sweep2sitepathproposer.jl") include("simpletci_optimize.jl") diff --git a/src/imports.jl b/src/imports.jl index d49be5a..940df06 100644 --- a/src/imports.jl +++ b/src/imports.jl @@ -1,3 +1,4 @@ +using Random using Graphs: simplecycles_limited_length, has_edge, SimpleGraph, center, steiner_tree using NamedGraphs: NamedGraph, diff --git a/src/newstructureproposer.jl b/src/newstructureproposer.jl new file mode 100644 index 0000000..afee3fe --- /dev/null +++ b/src/newstructureproposer.jl @@ -0,0 +1,36 @@ +""" +Abstract type for structure proposal methods +""" +abstract type AbstractNewStructureProposer end + +struct NewStructureLocalSwap <: AbstractNewStructureProposer end + +struct NewStructureGlobalSwap <: AbstractNewStructureProposer end + +function generate_new_structure( + ::NewStructureLocalSwap, + tci::SimpleTCI{ValueType}, +) where {ValueType} + es = collect(edges(tci.g)) + edge = rand(es) + vs = src(edge) => dst(edge) + return swap_2site(tci.g, vs) +end + +function generate_new_structure( + ::NewStructureGlobalSwap, + tci::SimpleTCI{ValueType}, +) where {ValueType} + vs = collect(vertices(tci.g)) + es = Set(edges(tci.g)) + + all_pairs = Set((v1 => v2) for v1 in vs for v2 in vs if v1 < v2) + + es_symmetric = Set(min(src(e), dst(e)) => max(src(e), dst(e)) for e in es) + + candidate_pairs = setdiff(all_pairs, es_symmetric) + + e = rand(candidate_pairs) + @show e + return swap_2site(tci.g, first(e) => last(e)) +end diff --git a/src/simpletci_optimize.jl b/src/simpletci_optimize.jl index bc8ad4a..3f64b99 100644 --- a/src/simpletci_optimize.jl +++ b/src/simpletci_optimize.jl @@ -88,9 +88,10 @@ function optimize!( if convergencecriterion( ranks, - errors; - maxbonddim=maxbonddim, - tolerance=tolerance + errors, + maxbonddim, + tolerance, + ncheckhistory ) println("Converged at $(iter)th-sweep.") tci.converged_IJset = deepcopy(tci.IJset) @@ -227,10 +228,10 @@ end function convergencecriterion( ranks::AbstractVector{Int}, - errors::AbstractVector{Float64}; - maxbonddim::Int = typemax(Int), - tolerance::Float64 = 1e-8, - ncheckhistory::Int = 2, + errors::AbstractVector{Float64}, + maxbonddim::Int, + tolerance::Float64, + ncheckhistory::Int, )::Bool if length(errors) < ncheckhistory return false diff --git a/src/simpletci_tensors.jl b/src/simpletci_tensors.jl index a5d9ea7..f5adc98 100644 --- a/src/simpletci_tensors.jl +++ b/src/simpletci_tensors.jl @@ -70,8 +70,8 @@ function sitetensor( return reshape( T, tci.localdims[site], - [length(tci.IJset[key]) for key in Inkeys]..., - [length(tci.IJset[key]) for key in Outkeys]..., + [length(tci.converged_IJset[key]) for key in Inkeys]..., + [length(tci.converged_IJset[key]) for key in Outkeys]..., ) end @@ -85,11 +85,11 @@ function sitetensor( ) where {ValueType} Inkeys, Outkeys = InOutkeys L = length(tci.localdims) - Pi1 = filltensor(ValueType, f, tci.localdims, tci.IJset, Inkeys, Outkeys, Val(1)) + Pi1 = filltensor(ValueType, f, tci.localdims, tci.converged_IJset, Inkeys, Outkeys, Val(1)) Pi1 = reshape( Pi1, - prod(vcat([tci.localdims[site]], [length(tci.IJset[key]) for key in Inkeys])), - prod([length(tci.IJset[key]) for key in Outkeys]), + prod(vcat([tci.localdims[site]], [length(tci.converged_IJset[key]) for key in Inkeys])), + prod([length(tci.converged_IJset[key]) for key in Outkeys]), ) updatemaxsample!(tci, Pi1) @@ -106,17 +106,17 @@ function sitetensor( end P = reshape( - filltensor(ValueType, f, tci.localdims, tci.IJset, [I1key], Outkeys, Val(0)), - length(tci.IJset[I1key]), - prod([length(tci.IJset[key]) for key in Outkeys]), + filltensor(ValueType, f, tci.localdims, tci.converged_IJset, [I1key], Outkeys, Val(0)), + length(tci.converged_IJset[I1key]), + prod([length(tci.converged_IJset[key]) for key in Outkeys]), ) - length(tci.IJset[I1key]) == sum([length(tci.IJset[key]) for key in Outkeys]) || error("Pivot matrix at bond $(site) is not square!") + length(tci.converged_IJset[I1key]) == sum([length(tci.converged_IJset[key]) for key in Outkeys]) || error("Pivot matrix at bond $(site) is not square!") Tmat = transpose(transpose(P) \ transpose(Pi1)) T = reshape( Tmat, tci.localdims[site], - [length(tci.IJset[key]) for key in Inkeys]..., - [length(tci.IJset[key]) for key in Outkeys]..., + [length(tci.converged_IJset[key]) for key in Inkeys]..., + [length(tci.converged_IJset[key]) for key in Outkeys]..., ) return T end diff --git a/src/treegraph_utils.jl b/src/treegraph_utils.jl index 19a111a..49e1d30 100644 --- a/src/treegraph_utils.jl +++ b/src/treegraph_utils.jl @@ -83,41 +83,44 @@ function distanceedges(g::NamedGraph, edge::NamedEdge)::Dict{NamedEdge,Int} return distances end -function swap_2site!( - g::NamedGraph, - vs::Pair{Int, Int}, -) +function swap_2site(g_old::NamedGraph, vs::Pair{Int, Int}) + g = deepcopy(g_old) p, q = vs p_neighbors = neighbors(g, p) q_neighbors = neighbors(g, q) rem_vertices!(g, [p, q]) - add_vertex!(g, p) add_vertex!(g, q) for p_i in p_neighbors + p_i == q && continue # avoid self-loop add_edge!(g, NamedEdge(p_i => q)) end for q_i in q_neighbors - add_edge!(g, NamedEdge(q_i => p)) + q_i == p && continue # avoid self-loop + add_edge!(g, NamedEdge(q_i => p)) + end + + if has_edge(g_old, NamedEdge(p => q)) + add_edge!(g, NamedEdge(p => q)) end - p_neighbors = neighbors(g, p) - q_neighbors = neighbors(g, q) return g end -function add_subtree!( - g::NamedGraph, +function add_subtree( + g_old::NamedGraph, v::Int, edge::NamedEdge, ) + g = deepcopy(g_old) p, q = separatevertices(g, edge) p_regions = subtreevertices(g, q => p) q_regions = subtreevertices(g, p => q) parent = v in p_regions ? q : p rem_edge!(g, edge) add_edge!(g, NamedEdge(parent => v)) + return g end \ No newline at end of file diff --git a/src/treetensornetwork.jl b/src/treetensornetwork.jl index 1499d90..76982db 100644 --- a/src/treetensornetwork.jl +++ b/src/treetensornetwork.jl @@ -5,7 +5,7 @@ mutable struct TreeTensorNetwork{ValueType} g::NamedGraph, sitetensors::Vector{Pair{Array{ValueType},Vector{NamedEdge}}}, ) where {ValueType} - !Graphs.is_cyclic(g) || + !is_cyclic(g) || error("TreeTensorNetwork is not supported for loopy tensor network.") ttntensors = Vector{IndexedArray}() for (i, (T, edges)) in enumerate(sitetensors) @@ -90,6 +90,36 @@ function crossinterpolate( return TreeTensorNetwork(tci.g, sitetensors), ranks, errors end +function crossinterpolate_adaptivetree( + ::Type{ValueType}, + f, + localdims::Union{Vector{Int},NTuple{N,Int}}, + g::NamedGraph, + nsearch:: Int = 10, + initialpivots::Vector{MultiIndex} = [ones(Int, length(localdims))]; + kwargs..., +) where {ValueType,N} + + tci = SimpleTCI{ValueType}(f, localdims, g, initialpivots) + ranks, errors = optimize!(tci, f; kwargs...) + + for i = 1:nsearch + # Generate a new structure + g_new = generate_new_structure(NewStructureLocalSwap(), tci) + tci_new = SimpleTCI{ValueType}(f, localdims, g_new, initialpivots) + tci_new.converged_IJset = tci.converged_IJset + ranks_new, errors_new = optimize!(tci_new, f; kwargs...) + if sum(errors_new) < sum(errors) + println("Structure is changed") + tci = tci_new + ranks = ranks_new + errors = errors_new + end + end + sitetensors = fillsitetensors(tci, f) + return TreeTensorNetwork(tci.g, sitetensors), ranks, errors +end + function evaluate( ttn::TreeTensorNetwork{ValueType}, indexset::Union{AbstractVector{Int},NTuple{N,Int}}, From ee46795bf332b390f02d0c90c4953cac10c88aaa Mon Sep 17 00:00:00 2001 From: watayo Date: Mon, 30 Jun 2025 18:16:50 +0900 Subject: [PATCH 07/13] src --- src/TreeTCI.jl | 1 + src/imports.jl | 3 + src/newstructureproposer.jl | 20 ++--- src/rl_structuralsearch.jl | 149 ++++++++++++++++++++++++++++++++++++ src/simpletci_optimize.jl | 4 +- src/simpletci_tensors.jl | 2 +- 6 files changed, 163 insertions(+), 16 deletions(-) create mode 100644 src/rl_structuralsearch.jl diff --git a/src/TreeTCI.jl b/src/TreeTCI.jl index 6b9df46..5175791 100644 --- a/src/TreeTCI.jl +++ b/src/TreeTCI.jl @@ -9,4 +9,5 @@ include("sweep2sitepathproposer.jl") include("simpletci_optimize.jl") include("simpletci_tensors.jl") include("treetensornetwork.jl") +include("rl_structuralsearch.jl") end diff --git a/src/imports.jl b/src/imports.jl index 940df06..70665cb 100644 --- a/src/imports.jl +++ b/src/imports.jl @@ -1,4 +1,5 @@ using Random +using Statistics using Graphs: simplecycles_limited_length, has_edge, SimpleGraph, center, steiner_tree using NamedGraphs: NamedGraph, @@ -20,3 +21,5 @@ using NamedGraphs.GraphsExtensions: rem_edge!, add_edge! import TensorCrossInterpolation as TCI import SimpleTensorNetworks: TensorNetwork, IndexedArray, Index, complete_contraction, getindex, contract +import ReinforcementLearning + diff --git a/src/newstructureproposer.jl b/src/newstructureproposer.jl index afee3fe..6c092c2 100644 --- a/src/newstructureproposer.jl +++ b/src/newstructureproposer.jl @@ -10,9 +10,9 @@ struct NewStructureGlobalSwap <: AbstractNewStructureProposer end function generate_new_structure( ::NewStructureLocalSwap, tci::SimpleTCI{ValueType}, + edge::NamedEdge, ) where {ValueType} - es = collect(edges(tci.g)) - edge = rand(es) + edge in edges(tci.g) || error("Edge $edge not in graph") vs = src(edge) => dst(edge) return swap_2site(tci.g, vs) end @@ -20,17 +20,9 @@ end function generate_new_structure( ::NewStructureGlobalSwap, tci::SimpleTCI{ValueType}, + vs::Pair{Int, Int}, ) where {ValueType} - vs = collect(vertices(tci.g)) - es = Set(edges(tci.g)) - - all_pairs = Set((v1 => v2) for v1 in vs for v2 in vs if v1 < v2) - - es_symmetric = Set(min(src(e), dst(e)) => max(src(e), dst(e)) for e in es) - - candidate_pairs = setdiff(all_pairs, es_symmetric) - - e = rand(candidate_pairs) - @show e - return swap_2site(tci.g, first(e) => last(e)) + first(vs) in vertices(tci.g) || error("Vertex $first(vs) not in graph") + last(vs) in vertices(tci.g) || error("Vertex $last(vs) not in graph") + return swap_2site(tci.g, vs) end diff --git a/src/rl_structuralsearch.jl b/src/rl_structuralsearch.jl new file mode 100644 index 0000000..83c7033 --- /dev/null +++ b/src/rl_structuralsearch.jl @@ -0,0 +1,149 @@ +using ReinforcementLearning +const RLBase = ReinforcementLearningBase + +abstract type AbstractAction end + +struct LocalSwapAction <: AbstractAction + edge::NamedEdge +end + +struct GlobalSwapAction <: AbstractAction + pair::Pair{Int,Int} +end + +mutable struct TCIEnv{ValueType} <: AbstractEnv + f + localdims::Vector{Int} + g::NamedGraph + initialpivots::Vector{MultiIndex} + maxstep::Int + tol::Float64 + kwargs + + # runtime variables + tci::SimpleTCI{ValueType} + step::Int + reward::Float64 +end + +# コンストラクタを修正 +function TCIEnv{ValueType}( + f, + localdims::Vector{Int}, + g::NamedGraph; + initialpivots::Vector{MultiIndex} = [ones(Int, length(localdims))], + maxstep::Int = 20, + tol::Float64 = 1e-8, + kwargs = (maxbonddim=typemax(Int), tolerance=nothing, maxiter=20) +) where {ValueType} + # SimpleTCIの初期化を修正 + tci0 = SimpleTCI{ValueType}(f, localdims, g, initialpivots) + return TCIEnv{ValueType}(f, localdims, g, initialpivots, maxstep, tol, kwargs, + tci0, 0, -Inf) +end + +function RLBase.state_space(::TCIEnv{ValueType}) where {ValueType} + return nothing +end + +function RLBase.state(env::TCIEnv{ValueType}, _obs, _player) where {ValueType} + errors = collect(values(env.tci.bonderrors)) + + max_err = maximum(errors) + mean_err = mean(errors) + + return [max_err, mean_err] +end + +RLBase.is_terminated(env::TCIEnv{ValueType}) where {ValueType} = + env.step ≥ env.maxstep || maximum(values(env.tci.bonderrors)) < env.tol + +RLBase.reward(env::TCIEnv{ValueType}) where {ValueType} = env.reward + +function RLBase.reset!(env::TCIEnv{ValueType}) where {ValueType} + env.step = 0 + env.tci = SimpleTCI{ValueType}(env.f, env.localdims, env.g, env.initialpivots) + _, errs = TreeTCI.optimize!(env.tci, env.f; env.kwargs...) + env.reward = -maximum(errs) + return RLBase.state(env, nothing, nothing) +end + + +function classify_pattern(tci::SimpleTCI, tol::Float64) + err_max, e_max = findmax(tci.bonderrors) + err_max < tol && return :none, nothing + + p, q = src(e_max), dst(e_max) + C = Set{Int}() + stack = [p, q] + while !isempty(stack) + v = pop!(stack) + if v in C + continue + end + push!(C, v) + for nb in outneighbors(tci.g, v) + e = NamedEdge(v=>nb) + if get(tci.bonderrors, e, 0.0) ≥ tol + push!(stack, nb) + end + e = NamedEdge(nb=>v) + if get(tci.bonderrors, e, 0.0) ≥ tol + push!(stack, nb) + end + end + end + length(C) > 1 ? (:cluster, collect(C)) : (:peak, e_max) +end + +function RLBase.action_space(env::TCIEnv{ValueType}) where {ValueType} + pat, info = classify_pattern(env.tci, env.tol) + acts = Vector{AbstractAction}() + + if pat == :cluster + C = Set(info) + outer = [nb for v in C for nb in outneighbors(env.tci.g,v) if nb ∉ C] + + for v in C + for nb in outneighbors(env.tci.g,v) + if nb ∉ C + if NamedEdge(v=>nb) in edges(env.tci.g) + push!(acts, LocalSwapAction(NamedEdge(v=>nb))) + elseif NamedEdge(nb=>v) in edges(env.tci.g) + push!(acts, LocalSwapAction(NamedEdge(nb=>v))) + else + error("Edge between $v and $nb not found in graph") + end + end + end + end + for v in C, leaf in outer + v ≠ leaf && push!(acts, GlobalSwapAction(v=>leaf)) + end + + elseif pat == :peak + push!(acts, LocalSwapAction(info)) + end + acts +end + +function RLBase.act!(env::TCIEnv{ValueType}, act::AbstractAction) where {ValueType} + current_err = maximum(values(env.tci.bonderrors)) + + if act isa LocalSwapAction + g_new = generate_new_structure(NewStructureLocalSwap(), env.tci, act.edge) + elseif act isa GlobalSwapAction + g_new = generate_new_structure(NewStructureGlobalSwap(), env.tci, act.pair) + else + error("Unknown action") + end + + tci_new = SimpleTCI{ValueType}(env.f, env.localdims, g_new, env.initialpivots) + tci_new.converged_IJset = env.tci.converged_IJset + _, errs = TreeTCI.optimize!(tci_new, env.f; env.kwargs...) + new_err = maximum(errs) + + env.reward = current_err - new_err + env.tci, env.step = tci_new, env.step + 1 + return RLBase.state(env, nothing, nothing), env.reward, RLBase.is_terminated(env), nothing +end \ No newline at end of file diff --git a/src/simpletci_optimize.jl b/src/simpletci_optimize.jl index 3f64b99..557b28f 100644 --- a/src/simpletci_optimize.jl +++ b/src/simpletci_optimize.jl @@ -93,7 +93,9 @@ function optimize!( tolerance, ncheckhistory ) - println("Converged at $(iter)th-sweep.") + if verbosity > 1 + println("Converged at $(iter)th-sweep.") + end tci.converged_IJset = deepcopy(tci.IJset) break end diff --git a/src/simpletci_tensors.jl b/src/simpletci_tensors.jl index f5adc98..cf9df99 100644 --- a/src/simpletci_tensors.jl +++ b/src/simpletci_tensors.jl @@ -18,7 +18,7 @@ function fillsitetensors( tci::SimpleTCI{ValueType}, f; - center_vertex::Int = 0, + center_vertex::Int = 1, ) where {ValueType} sitetensors = From 9500598d901d3b71539da4a83c3a9364257b9756 Mon Sep 17 00:00:00 2001 From: watayo Date: Mon, 30 Jun 2025 18:36:05 +0900 Subject: [PATCH 08/13] project --- .gitignore | 4 +- Project.toml | 8 ++++ samples/reinforcementlearning_example.jl | 61 ++++++++++++++++++++++++ samples/sample_structural_opt.jl | 48 ------------------- 4 files changed, 72 insertions(+), 49 deletions(-) create mode 100644 samples/reinforcementlearning_example.jl delete mode 100644 samples/sample_structural_opt.jl diff --git a/.gitignore b/.gitignore index 2251642..802a2c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -Manifest.toml \ No newline at end of file +./samples/ +Manifest.toml +.DS_Store \ No newline at end of file diff --git a/Project.toml b/Project.toml index bccfef1..6c4593a 100644 --- a/Project.toml +++ b/Project.toml @@ -5,18 +5,26 @@ version = "0.1.0" [deps] DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +ReinforcementLearning = "158674fc-8238-5cab-b5ba-03dfc80d1318" SimpleTensorNetworks = "3075f829-f72e-4896-a859-7fe0a9cabb9b" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" TensorCrossInterpolation = "b261b2ec-6378-4871-b32e-9173bb050604" [compat] DataGraphs = "0.2.5" +Distributions = "0.25.120" +Flux = "0.16.4" Graphs = "1.12.0" NamedGraphs = "0.6.4" Random = "1.10" +ReinforcementLearning = "0.11.0" SimpleTensorNetworks = "0.1.0" +Statistics = "1.11.1" TensorCrossInterpolation = "0.9.13" [extras] diff --git a/samples/reinforcementlearning_example.jl b/samples/reinforcementlearning_example.jl new file mode 100644 index 0000000..8297073 --- /dev/null +++ b/samples/reinforcementlearning_example.jl @@ -0,0 +1,61 @@ +using Random +using LinearAlgebra +using TreeTCI: TCIEnv, SimpleTCI +using Statistics +using Distributions +using NamedGraphs: NamedGraph, add_edge!, edges +using QuanticsGrids +const QG = QuanticsGrids +using ReinforcementLearning + + +function build_problem() + Random.seed!(1234) + R = 4 + μ = zeros(3) + Σ = rand(LKJ(3, 50.0)) + dist = MvNormal(μ, Hermitian(Σ)) + f(x,y,z) = pdf(dist, [x,y,z]) + + grid = QG.DiscretizedGrid{3}(R, (-5,-5,-5), (5,5,5); unfoldingscheme=:interleaved) + fq = QG.quanticsfunction(Float64, grid, f) + + nsites = 3R + g = NamedGraph(nsites) + for i in 1:(nsites-1) + add_edge!(g, i, i+1) + end + localdims = fill(grid.base, nsites) + + return fq, localdims, g +end + +function main() + + fq, localdims, g = build_problem() + + env = TCIEnv{Float64}( + fq, + localdims, + g; + maxstep = 100, + tol = 1e-8, + kwargs = (maxbonddim=10, maxiter=10, tolerance=1e-12) + ) + + RLBase.reset!(env) + + println("学習前 最大誤差: ", maximum(RLBase.state(env, nothing, nothing))) + + println("学習開始...") + history = run( + RandomPolicy(), + env, + StopAfterNEpisodes(10) + ) + + # 結果確認 + println("学習後 最大誤差: ", maximum(RLBase.state(env, nothing, nothing))) +end + +main() \ No newline at end of file diff --git a/samples/sample_structural_opt.jl b/samples/sample_structural_opt.jl deleted file mode 100644 index 250c572..0000000 --- a/samples/sample_structural_opt.jl +++ /dev/null @@ -1,48 +0,0 @@ -using Test -using TreeTCI: crossinterpolate_adaptivetree, crossinterpolate -using NamedGraphs: NamedGraph, add_edge!, vertices -using Random - -function evaluate_error_sampled(f, ttn1, ttn2, localdims::Vector{Int}, nsamples::Int; rng=Random.default_rng()) - total_error1 = 0.0 - total_error2 = 0.0 - - for _ in 1:nsamples - xvec = [rand(rng, 1:d) for d in localdims] - fx = f(xvec) - total_error1 += abs(fx - ttn1(xvec)) - total_error2 += abs(fx - ttn2(xvec)) - end - - mean_error1 = total_error1 / nsamples - mean_error2 = total_error2 / nsamples - - println("Sampled mean |f(x) - original(x)| = ", mean_error1) - println("Sampled mean |f(x) - optimized(x)| = ", mean_error2) - - return mean_error1, mean_error2 -end - - -function main() - # make graph - g = NamedGraph(8) - add_edge!(g, 1, 2) - add_edge!(g, 2, 3) - add_edge!(g, 3, 4) - add_edge!(g, 4, 5) - add_edge!(g, 5, 6) - add_edge!(g, 6, 7) - add_edge!(g, 7, 8) - - localdims = fill(10, length(vertices(g))) - f(v) = 1 / (1 + v' * v) - kwargs = (maxbonddim = 20, maxiter = 10) - tt, ranks, errors = crossinterpolate(Float64, f, localdims, g; kwargs...) - optimized_tt, ranks, errors = crossinterpolate_adaptivetree(Float64, f, localdims, g, 20; kwargs...) - - evaluate_error_sampled(f, tt, optimized_tt, localdims, 1000) - return 0 -end - -main() From 3452ad9d4471dfc7a2d41167d34c4583ef1f217c Mon Sep 17 00:00:00 2001 From: Ryo Watanabe Date: Tue, 30 Sep 2025 13:03:18 +0900 Subject: [PATCH 09/13] stractural search --- Project.toml | 10 +- ...g_example.jl => sample_strucuralsearch.jl} | 30 +- src/TreeTCI.jl | 2 +- src/imports.jl | 4 +- src/rl_structuralsearch.jl | 149 -------- src/structuralsearch.jl | 355 ++++++++++++++++++ src/sweep2sitepathproposer.jl | 4 +- src/treegraph_utils.jl | 2 +- src/treetensornetwork.jl | 45 +-- 9 files changed, 392 insertions(+), 209 deletions(-) rename samples/{reinforcementlearning_example.jl => sample_strucuralsearch.jl} (55%) delete mode 100644 src/rl_structuralsearch.jl create mode 100644 src/structuralsearch.jl diff --git a/Project.toml b/Project.toml index 6c4593a..580357d 100644 --- a/Project.toml +++ b/Project.toml @@ -4,27 +4,33 @@ authors = ["Ryo Watanabe "] version = "0.1.0" [deps] +Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" +QuanticsGrids = "634c7f73-3e90-4749-a1bd-001b8efc642d" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -ReinforcementLearning = "158674fc-8238-5cab-b5ba-03dfc80d1318" SimpleTensorNetworks = "3075f829-f72e-4896-a859-7fe0a9cabb9b" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +T4ARegistrator = "52e3f0f8-52ab-4798-a033-7b9fb81451b4" TensorCrossInterpolation = "b261b2ec-6378-4871-b32e-9173bb050604" [compat] +Combinatorics = "1.0.3" DataGraphs = "0.2.5" +DataStructures = "0.18.22" Distributions = "0.25.120" Flux = "0.16.4" Graphs = "1.12.0" NamedGraphs = "0.6.4" +QuanticsGrids = "0.6.0" Random = "1.10" -ReinforcementLearning = "0.11.0" SimpleTensorNetworks = "0.1.0" Statistics = "1.11.1" +T4ARegistrator = "0.2.1" TensorCrossInterpolation = "0.9.13" [extras] diff --git a/samples/reinforcementlearning_example.jl b/samples/sample_strucuralsearch.jl similarity index 55% rename from samples/reinforcementlearning_example.jl rename to samples/sample_strucuralsearch.jl index 8297073..6979df3 100644 --- a/samples/reinforcementlearning_example.jl +++ b/samples/sample_strucuralsearch.jl @@ -1,12 +1,11 @@ using Random using LinearAlgebra -using TreeTCI: TCIEnv, SimpleTCI +using TreeTCI: crossinterpolate_with_3site_swapping using Statistics using Distributions using NamedGraphs: NamedGraph, add_edge!, edges using QuanticsGrids const QG = QuanticsGrids -using ReinforcementLearning function build_problem() @@ -34,28 +33,15 @@ function main() fq, localdims, g = build_problem() - env = TCIEnv{Float64}( - fq, - localdims, - g; - maxstep = 100, - tol = 1e-8, - kwargs = (maxbonddim=10, maxiter=10, tolerance=1e-12) - ) + kwargs = ( + maxbonddim = 10, + tolerance = 1e-10, + maxiter = 100, + ) - RLBase.reset!(env) + tci = crossinterpolate_with_3site_swapping(Float64, fq, localdims, g; kwargs...) - println("学習前 最大誤差: ", maximum(RLBase.state(env, nothing, nothing))) - - println("学習開始...") - history = run( - RandomPolicy(), - env, - StopAfterNEpisodes(10) - ) - - # 結果確認 - println("学習後 最大誤差: ", maximum(RLBase.state(env, nothing, nothing))) + return tci end main() \ No newline at end of file diff --git a/src/TreeTCI.jl b/src/TreeTCI.jl index 5175791..fed40f1 100644 --- a/src/TreeTCI.jl +++ b/src/TreeTCI.jl @@ -9,5 +9,5 @@ include("sweep2sitepathproposer.jl") include("simpletci_optimize.jl") include("simpletci_tensors.jl") include("treetensornetwork.jl") -include("rl_structuralsearch.jl") +include("structuralsearch.jl") end diff --git a/src/imports.jl b/src/imports.jl index 70665cb..9709932 100644 --- a/src/imports.jl +++ b/src/imports.jl @@ -1,5 +1,5 @@ using Random -using Statistics +using Combinatorics using Graphs: simplecycles_limited_length, has_edge, SimpleGraph, center, steiner_tree using NamedGraphs: NamedGraph, @@ -21,5 +21,5 @@ using NamedGraphs.GraphsExtensions: rem_edge!, add_edge! import TensorCrossInterpolation as TCI import SimpleTensorNetworks: TensorNetwork, IndexedArray, Index, complete_contraction, getindex, contract -import ReinforcementLearning +import DataGraphs: underlying_graph diff --git a/src/rl_structuralsearch.jl b/src/rl_structuralsearch.jl deleted file mode 100644 index 83c7033..0000000 --- a/src/rl_structuralsearch.jl +++ /dev/null @@ -1,149 +0,0 @@ -using ReinforcementLearning -const RLBase = ReinforcementLearningBase - -abstract type AbstractAction end - -struct LocalSwapAction <: AbstractAction - edge::NamedEdge -end - -struct GlobalSwapAction <: AbstractAction - pair::Pair{Int,Int} -end - -mutable struct TCIEnv{ValueType} <: AbstractEnv - f - localdims::Vector{Int} - g::NamedGraph - initialpivots::Vector{MultiIndex} - maxstep::Int - tol::Float64 - kwargs - - # runtime variables - tci::SimpleTCI{ValueType} - step::Int - reward::Float64 -end - -# コンストラクタを修正 -function TCIEnv{ValueType}( - f, - localdims::Vector{Int}, - g::NamedGraph; - initialpivots::Vector{MultiIndex} = [ones(Int, length(localdims))], - maxstep::Int = 20, - tol::Float64 = 1e-8, - kwargs = (maxbonddim=typemax(Int), tolerance=nothing, maxiter=20) -) where {ValueType} - # SimpleTCIの初期化を修正 - tci0 = SimpleTCI{ValueType}(f, localdims, g, initialpivots) - return TCIEnv{ValueType}(f, localdims, g, initialpivots, maxstep, tol, kwargs, - tci0, 0, -Inf) -end - -function RLBase.state_space(::TCIEnv{ValueType}) where {ValueType} - return nothing -end - -function RLBase.state(env::TCIEnv{ValueType}, _obs, _player) where {ValueType} - errors = collect(values(env.tci.bonderrors)) - - max_err = maximum(errors) - mean_err = mean(errors) - - return [max_err, mean_err] -end - -RLBase.is_terminated(env::TCIEnv{ValueType}) where {ValueType} = - env.step ≥ env.maxstep || maximum(values(env.tci.bonderrors)) < env.tol - -RLBase.reward(env::TCIEnv{ValueType}) where {ValueType} = env.reward - -function RLBase.reset!(env::TCIEnv{ValueType}) where {ValueType} - env.step = 0 - env.tci = SimpleTCI{ValueType}(env.f, env.localdims, env.g, env.initialpivots) - _, errs = TreeTCI.optimize!(env.tci, env.f; env.kwargs...) - env.reward = -maximum(errs) - return RLBase.state(env, nothing, nothing) -end - - -function classify_pattern(tci::SimpleTCI, tol::Float64) - err_max, e_max = findmax(tci.bonderrors) - err_max < tol && return :none, nothing - - p, q = src(e_max), dst(e_max) - C = Set{Int}() - stack = [p, q] - while !isempty(stack) - v = pop!(stack) - if v in C - continue - end - push!(C, v) - for nb in outneighbors(tci.g, v) - e = NamedEdge(v=>nb) - if get(tci.bonderrors, e, 0.0) ≥ tol - push!(stack, nb) - end - e = NamedEdge(nb=>v) - if get(tci.bonderrors, e, 0.0) ≥ tol - push!(stack, nb) - end - end - end - length(C) > 1 ? (:cluster, collect(C)) : (:peak, e_max) -end - -function RLBase.action_space(env::TCIEnv{ValueType}) where {ValueType} - pat, info = classify_pattern(env.tci, env.tol) - acts = Vector{AbstractAction}() - - if pat == :cluster - C = Set(info) - outer = [nb for v in C for nb in outneighbors(env.tci.g,v) if nb ∉ C] - - for v in C - for nb in outneighbors(env.tci.g,v) - if nb ∉ C - if NamedEdge(v=>nb) in edges(env.tci.g) - push!(acts, LocalSwapAction(NamedEdge(v=>nb))) - elseif NamedEdge(nb=>v) in edges(env.tci.g) - push!(acts, LocalSwapAction(NamedEdge(nb=>v))) - else - error("Edge between $v and $nb not found in graph") - end - end - end - end - for v in C, leaf in outer - v ≠ leaf && push!(acts, GlobalSwapAction(v=>leaf)) - end - - elseif pat == :peak - push!(acts, LocalSwapAction(info)) - end - acts -end - -function RLBase.act!(env::TCIEnv{ValueType}, act::AbstractAction) where {ValueType} - current_err = maximum(values(env.tci.bonderrors)) - - if act isa LocalSwapAction - g_new = generate_new_structure(NewStructureLocalSwap(), env.tci, act.edge) - elseif act isa GlobalSwapAction - g_new = generate_new_structure(NewStructureGlobalSwap(), env.tci, act.pair) - else - error("Unknown action") - end - - tci_new = SimpleTCI{ValueType}(env.f, env.localdims, g_new, env.initialpivots) - tci_new.converged_IJset = env.tci.converged_IJset - _, errs = TreeTCI.optimize!(tci_new, env.f; env.kwargs...) - new_err = maximum(errs) - - env.reward = current_err - new_err - env.tci, env.step = tci_new, env.step + 1 - return RLBase.state(env, nothing, nothing), env.reward, RLBase.is_terminated(env), nothing -end \ No newline at end of file diff --git a/src/structuralsearch.jl b/src/structuralsearch.jl new file mode 100644 index 0000000..b5f9eb2 --- /dev/null +++ b/src/structuralsearch.jl @@ -0,0 +1,355 @@ +function crossinterpolate_with_3site_swapping( + ::Type{ValueType}, + f, + localdims::Union{Vector{Int},NTuple{N,Int}}, + g::NamedGraph, + nsweeps:: Int = 100, + origin_edge = nothing, + initialpivots::Vector{MultiIndex} = [ones(Int, length(localdims))]; + kwargs..., +) where {ValueType,N} + + tci = SimpleTCI{ValueType}(f, localdims, g, initialpivots) + ranks, errors = optimize!(tci, f; kwargs...) + n = length(vertices(tci.g)) + + + g_tmp = deepcopy(tci.g) + + if origin_edge == nothing + d = n + for e in edges(tci.g) + p, q = separatevertices(tci.g, e) + Iset = length(subtreevertices(tci.g, p => q)) + Jset = length(subtreevertices(tci.g, q => p)) + d_tmp = abs(Iset - Jset) + if d_tmp < d + d = d_tmp + origin_edge = e + end + end + end + + id2edge = collect(edges(tci.g)) + edge2id = Dict{NamedEdge,Int}(e => i for (i,e) in enumerate(id2edge)) + center_edge = origin_edge + center_edge_id = edge2id[center_edge] + origin_edge_id = edge2id[origin_edge] + previous_center_edge_id = center_edge_id + + for i = 1:nsweeps + # Init flags + flags = Dict(k => 0 for k in 1:length(id2edge)) + while true + # update next center edge + candidates = candidateedges(tci.g, id2edge[previous_center_edge_id]) + candidates = [e for e in candidates if flags[edge2id[e]] == 0] + + # If candidates is empty, exit while loop + if isempty(candidates) + break + end + + distances = distanceedges(tci.g, id2edge[origin_edge_id]) + max_distance = maximum(distances[e] for e in candidates) + candidates = filter(e -> distances[e] == max_distance, candidates) + + center_edge_ = first(candidates) + center_edge_id = edge2id[center_edge_] + + p, q = separatevertices(tci.g, id2edge[previous_center_edge_id]) + v = center_edge_ in adjacentedges(tci.g, p) ? q : p # + incomings = [edge for edge in adjacentedges(tci.g, v) if edge != id2edge[previous_center_edge_id]] + + # Update flags - ID management + if all(flags[edge2id[e]] == 1 for e in incomings) && center_edge_id != origin_edge_id + flags[center_edge_id] = 1 + end + + # update center edge + center_edge = center_edge_ + + # Structural search + tci, id2edge = optimize_with_3site_swapping(tci, f, initialpivots, id2edge[center_edge_id], id2edge[previous_center_edge_id], id2edge, edge2id; kwargs...) + edge2id = Dict(e => i for (i, e) in enumerate(id2edge)) + + previous_center_edge_id = center_edge_id + end + if tci.g == g_tmp + @show "converged" + break + end + g_tmp = deepcopy(tci.g) # update g_tmp + end + sitetensors = fillsitetensors(tci, f) + + ranks, errors = optimize!(tci, f; kwargs...) + return TreeTensorNetwork(tci.g, sitetensors), ranks, errors +end + +function crossinterpolate_with_structuralsearch( + ::Type{ValueType}, + f, + localdims::Union{Vector{Int},NTuple{N,Int}}, + g::NamedGraph, + max_degree::Int = 1, + nsweeps:: Int = 100, + origin_edge = nothing, + initialpivots::Vector{MultiIndex} = [ones(Int, length(localdims))]; + kwargs..., +) where {ValueType,N} + + tci = SimpleTCI{ValueType}(f, localdims, g, initialpivots) + ranks, errors = optimize!(tci, f; kwargs...) + n = length(vertices(tci.g)) + + g_tmp = deepcopy(tci.g) + + if origin_edge == nothing + d = n + for e in edges(tci.g) + p, q = separatevertices(tci.g, e) + Iset = length(subtreevertices(tci.g, p => q)) + Jset = length(subtreevertices(tci.g, q => p)) + d_tmp = abs(Iset - Jset) + if d_tmp < d + d = d_tmp + origin_edge = e + end + end + end + + id2edge = collect(edges(tci.g)) + edge2id = Dict{NamedEdge,Int}(e => i for (i,e) in enumerate(id2edge)) + center_edge = origin_edge + origin_edge_id = edge2id[origin_edge] + + for i = 1:nsweeps + # Init flags + flags = Dict(k => 0 for k in 1:length(id2edge)) + while true + + # Structural search + tci, id2edge = optimize_with_localmanipulation(tci, f, initialpivots, center_edge, max_degree, id2edge, edge2id; kwargs...) + edge2id = Dict(e => i for (i, e) in enumerate(id2edge)) + + # update next center edge + candidates = candidateedges(tci.g, center_edge) + candidates = [e for e in candidates if flags[edge2id[e]] == 0] + + # If candidates is empty, exit while loop + if isempty(candidates) + break + end + + distances = distanceedges(tci.g, id2edge[origin_edge_id]) + max_distance = maximum(distances[e] for e in candidates) + candidates = filter(e -> distances[e] == max_distance, candidates) + + center_edge_ = first(candidates) + center_edge_id = edge2id[center_edge_] + + p, q = separatevertices(tci.g, center_edge) + v = center_edge_ in adjacentedges(tci.g, p) ? q : p # + incomings = [edge for edge in adjacentedges(tci.g, v) if edge != center_edge] + + # Update flags - ID management + if all(flags[edge2id[e]] == 1 for e in incomings) && center_edge_id != origin_edge_id + flags[center_edge_id] = 1 + end + + # update center edge + center_edge = center_edge_ + end + if tci.g == g_tmp + @show "converged" + break + end + g_tmp = deepcopy(tci.g) # update g_tmp + end + sitetensors = fillsitetensors(tci, f) + + ranks, errors = optimize!(tci, f; kwargs...) + return TreeTensorNetwork(tci.g, sitetensors), ranks, errors +end + +# Optimization with local 3-site tensor swapping +function optimize_with_3site_swapping( + tci::SimpleTCI{ValueType}, + f, + initialpivots::Vector{MultiIndex}, + center_edge::NamedEdge, + adjacent_edge::NamedEdge, + id2edge, + edge2id; + kwargs... +) where {ValueType} + best_err = maximum(values(tci.bonderrors)) + + tci_best = tci + id2edge_best = id2edge + + + # center_edgeとadjacent_edgeからp,q,rを抽出(qが両方に接続) + tmp1, tmp2 = src(center_edge), dst(center_edge) + tmp3, tmp4 = src(adjacent_edge), dst(adjacent_edge) + + # qが両方のエッジに接続するようにp, q, rを決定 + if tmp1 in (tmp3, tmp4) + q = tmp1 + p = tmp2 + r = tmp1 == tmp3 ? tmp4 : tmp3 + elseif tmp2 in (tmp3, tmp4) + q = tmp2 + p = tmp1 + r = tmp2 == tmp3 ? tmp4 : tmp3 + else + @warn "No common node between center_edge and adjacent_edge" + return tci, id2edge + end + + @assert r != p && r != q + + # get the subtree sets that are connected to each node + p_sub = filter(x -> x ∉ (q, r), neighbors(tci.g, p)) + q_sub = filter(x -> x ∉ (p, r), neighbors(tci.g, q)) + r_sub = filter(x -> x ∉ (p, q), neighbors(tci.g, r)) + + for (a, b, c) in permutations((p, q, r)) + g_new = deepcopy(tci.g) + id2edge_new = deepcopy(id2edge) + + for (v1, v2) in ((p, q), (q, r)) + e_old = NamedEdge(min(v1, v2) => max(v1, v2)) + if has_edge(g_new, e_old) + e_old_id = edge2id[e_old] + rem_edge!(g_new, e_old) + end + end + + e_ab = NamedEdge(min(a, b) => max(a, b)) + e_bc = NamedEdge(min(b, c) => max(b, c)) + add_edge!(g_new, e_ab) + add_edge!(g_new, e_bc) + + # 3ノード間エッジのID更新(optimize_with_localmanipulationと同じパターン) + if haskey(edge2id, NamedEdge(min(p, q) => max(p, q))) + e_pq_id = edge2id[NamedEdge(min(p, q) => max(p, q))] + id2edge_new[e_pq_id] = e_ab + end + if haskey(edge2id, NamedEdge(min(q, r) => max(q, r))) + e_qr_id = edge2id[NamedEdge(min(q, r) => max(q, r))] + id2edge_new[e_qr_id] = e_bc + end + + # サブグラフの再接続(重複エッジを避ける) + # 各ノードのサブグラフを新しい親に再接続 + for (old_node, new_node) in [(p, a), (q, b), (r, c)] + if old_node != new_node # ノードが変わった場合のみ再接続 + # 元のノードからサブグラフを取得 + old_sub = filter(x -> x ∉ (p, q, r), neighbors(tci.g, old_node)) + + # 新しいノードにサブグラフを再接続 + for sub_node in old_sub + e_old = NamedEdge(min(old_node, sub_node) => max(old_node, sub_node)) + if has_edge(g_new, e_old) && haskey(edge2id, e_old) + e_old_id = edge2id[e_old] + rem_edge!(g_new, e_old) + + # 新しいエッジを追加 + e_new = NamedEdge(min(new_node, sub_node) => max(new_node, sub_node)) + id2edge_new[e_old_id] = e_new + add_edge!(g_new, e_new) + end + end + end + end + + tci_tmp = SimpleTCI{ValueType}(f, tci.localdims, g_new, initialpivots) + # tci_tmp.converged_IJset = tci.converged_IJset + _, _ = optimize!(tci_tmp, f; kwargs...) + err = maximum(values(tci_tmp.bonderrors)) + + # 7. update best + if err < best_err + best_err = err + tci_best = deepcopy(tci_tmp) + id2edge_best = deepcopy(id2edge_new) + end + end + + return tci_best, id2edge_best +end + +# Optimization with local 2-site tensor manipulation +function optimize_with_localmanipulation( + tci::SimpleTCI{ValueType}, + f, + initialpivots::Vector{MultiIndex}, + center_edge::NamedEdge, + max_degree::Int, + id2edge, + edge2id; + kwargs... +) where {ValueType} + + best_err = maximum(values(tci.bonderrors)) + tci_best = tci + id2edge_best = id2edge + + # calculate the two ends of the split object and its child node list + p, q = src(center_edge), dst(center_edge) + subI = filter(x->x!=q, neighbors(tci.g,p)) + subJ = filter(x->x!=p, neighbors(tci.g,q)) + children = vcat(subI, subJ) + n = length(children) + limit = max_degree + + # k nodes are left (p side), the rest are right (q side) + for k in 0:n + if k ≤ limit && (n-k) ≤ limit + for left in combinations(children, k) + leftset = Set(left) + + # copy the graph and replace one by one + g_new = deepcopy(tci.g) + id2edge_new = deepcopy(id2edge) + rem_edge!(g_new, center_edge) + + + for v in children + # remove the old parent + old_parent = (v in subI ? p : q) + + e_old = old_parent < v ? NamedEdge(old_parent=>v) : NamedEdge(v=>old_parent) + e_old_id = edge2id[e_old] + + rem_edge!(g_new, e_old) + # connect the new parent + new_parent = (v in leftset ? p : q) + e_new = new_parent < v ? NamedEdge(new_parent=>v) : NamedEdge(v=>new_parent) + + id2edge_new[e_old_id] = e_new + add_edge!(g_new, e_new) + end + add_edge!(g_new, center_edge) + + # optimize + tci_tmp = SimpleTCI{ValueType}(f, tci.localdims, g_new, initialpivots) + # tci_tmp.converged_IJset = tci.converged_IJset + _, _ = optimize!(tci_tmp, f; kwargs...) + err = maximum(values(tci_tmp.bonderrors)) + + # update best + if err < best_err && !(err ≈ best_err) + best_err = err + tci_best = deepcopy(tci_tmp) + id2edge_best = deepcopy(id2edge_new) + end + + end + end + end + + return tci_best, id2edge_best +end \ No newline at end of file diff --git a/src/sweep2sitepathproposer.jl b/src/sweep2sitepathproposer.jl index ae1139b..5dce04b 100644 --- a/src/sweep2sitepathproposer.jl +++ b/src/sweep2sitepathproposer.jl @@ -44,14 +44,14 @@ LocalAdjacent strategy that runs through within all indices of site tensor accor function generate_sweep2site_path( ::LocalAdjacentSweep2sitePathProposer, tci::SimpleTCI{ValueType}; - origin_edge = undef, + origin_edge = nothing, ) where {ValueType} edge_path = Vector{NamedEdge}() n = length(vertices(tci.g)) # choose the center bond id. - if origin_edge == undef + if origin_edge == nothing d = n for e in edges(tci.g) p, q = separatevertices(tci.g, e) diff --git a/src/treegraph_utils.jl b/src/treegraph_utils.jl index 49e1d30..9f37fee 100644 --- a/src/treegraph_utils.jl +++ b/src/treegraph_utils.jl @@ -123,4 +123,4 @@ function add_subtree( rem_edge!(g, edge) add_edge!(g, NamedEdge(parent => v)) return g -end \ No newline at end of file +end diff --git a/src/treetensornetwork.jl b/src/treetensornetwork.jl index 76982db..8bcda43 100644 --- a/src/treetensornetwork.jl +++ b/src/treetensornetwork.jl @@ -90,36 +90,6 @@ function crossinterpolate( return TreeTensorNetwork(tci.g, sitetensors), ranks, errors end -function crossinterpolate_adaptivetree( - ::Type{ValueType}, - f, - localdims::Union{Vector{Int},NTuple{N,Int}}, - g::NamedGraph, - nsearch:: Int = 10, - initialpivots::Vector{MultiIndex} = [ones(Int, length(localdims))]; - kwargs..., -) where {ValueType,N} - - tci = SimpleTCI{ValueType}(f, localdims, g, initialpivots) - ranks, errors = optimize!(tci, f; kwargs...) - - for i = 1:nsearch - # Generate a new structure - g_new = generate_new_structure(NewStructureLocalSwap(), tci) - tci_new = SimpleTCI{ValueType}(f, localdims, g_new, initialpivots) - tci_new.converged_IJset = tci.converged_IJset - ranks_new, errors_new = optimize!(tci_new, f; kwargs...) - if sum(errors_new) < sum(errors) - println("Structure is changed") - tci = tci_new - ranks = ranks_new - errors = errors_new - end - end - sitetensors = fillsitetensors(tci, f) - return TreeTensorNetwork(tci.g, sitetensors), ranks, errors -end - function evaluate( ttn::TreeTensorNetwork{ValueType}, indexset::Union{AbstractVector{Int},NTuple{N,Int}}, @@ -151,3 +121,18 @@ end function Base.length(ttn::TreeTensorNetwork) return length(vertices(ttn.tensornetwork.data_graph)) end + +# Add method to get graph structure from TreeTensorNetwork +function get_graph(ttn::TreeTensorNetwork) + return ttn.tensornetwork.data_graph +end + +# Add method to get vertices from TreeTensorNetwork +function get_vertices(ttn::TreeTensorNetwork) + return vertices(ttn.tensornetwork.data_graph) +end + +# Add method to get edges from TreeTensorNetwork +function get_edges(ttn::TreeTensorNetwork) + return edges(ttn.tensornetwork.data_graph) +end From 46d34c0a467c7a4c0807949aee2d791e061e4e31 Mon Sep 17 00:00:00 2001 From: Ryo Watanabe Date: Tue, 30 Sep 2025 14:02:18 +0900 Subject: [PATCH 10/13] structural_search --- samples/sample_strucuralsearch.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/sample_strucuralsearch.jl b/samples/sample_strucuralsearch.jl index 6979df3..2644844 100644 --- a/samples/sample_strucuralsearch.jl +++ b/samples/sample_strucuralsearch.jl @@ -41,6 +41,8 @@ function main() tci = crossinterpolate_with_3site_swapping(Float64, fq, localdims, g; kwargs...) + ttn = TreeTensorNetwork(tci.g, tci.sitetensors) + return tci end From 67252f7cf99353ceb7e093f749b95595ced140b2 Mon Sep 17 00:00:00 2001 From: Ryo Watanabe Date: Wed, 1 Oct 2025 04:13:32 +0900 Subject: [PATCH 11/13] structural_search --- Project.toml | 4 + samples/1d_tightbinding_model.jl | 67 ++++++++++ samples/graphs.jl | 9 ++ samples/utils.jl | 111 +++++++++++++++ src/structuralsearch.jl | 15 +-- src/ttnopt.jl | 223 +++++++++++++++++++++++++++++++ 6 files changed, 421 insertions(+), 8 deletions(-) create mode 100644 samples/1d_tightbinding_model.jl create mode 100644 samples/graphs.jl create mode 100644 samples/utils.jl create mode 100644 src/ttnopt.jl diff --git a/Project.toml b/Project.toml index 580357d..09fdd6c 100644 --- a/Project.toml +++ b/Project.toml @@ -13,7 +13,9 @@ Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" QuanticsGrids = "634c7f73-3e90-4749-a1bd-001b8efc642d" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" SimpleTensorNetworks = "3075f829-f72e-4896-a859-7fe0a9cabb9b" +SparseIR = "4fe2279e-80f0-4adb-8463-ee114ff56b7d" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" T4ARegistrator = "52e3f0f8-52ab-4798-a033-7b9fb81451b4" TensorCrossInterpolation = "b261b2ec-6378-4871-b32e-9173bb050604" @@ -28,7 +30,9 @@ Graphs = "1.12.0" NamedGraphs = "0.6.4" QuanticsGrids = "0.6.0" Random = "1.10" +Revise = "3.9.0" SimpleTensorNetworks = "0.1.0" +SparseIR = "1.1.4" Statistics = "1.11.1" T4ARegistrator = "0.2.1" TensorCrossInterpolation = "0.9.13" diff --git a/samples/1d_tightbinding_model.jl b/samples/1d_tightbinding_model.jl new file mode 100644 index 0000000..d6114c2 --- /dev/null +++ b/samples/1d_tightbinding_model.jl @@ -0,0 +1,67 @@ +using Random +using LinearAlgebra +using TreeTCI: crossinterpolate, crossinterpolate_with_structuralsearch, crossinterpolate_with_3site_swapping +using NamedGraphs: NamedGraph, add_edge! +using QuanticsGrids +const QG = QuanticsGrids +using SparseIR +include("utils.jl") +include("graphs.jl") + +ε(k) = 2*cos(k) + cos(5*k) + 2*cos(20*k) + +gk(m::Int, kx::Float64; β::Float64=10.0) = begin + m = 2 * m + 1 + ν = FermionicFreq(m) + iν = SparseIR.valueim(ν, β) + return 1 / (iν - ε(kx)) +end + +function gkb(b::Vector{Int}, n_m::Int, n_kx::Int; β::Float64=10.0, layout::Symbol=:block) + @assert length(b) == n_m + n_kx + parts = split_bits(b; group_bits=[n_m, n_kx], layout=layout) + mb, kxb = parts + mbit = length(mb) + kxbit = length(kxb) + Nm = 2^mbit + Nkx = 2^kxbit + im = frombins(mb) + ikx = frombins(kxb) + @assert im ≤ Nm + @assert ikx ≤ Nkx + kx = 2π * (ikx - 1)/Nkx + m = (im - 1) + return gk(m, kx) +end + +function main() + nkx_bit = 10 + nm_bit = 10 + localdims = fill(2, nkx_bit + nm_bit) + f(v) = gkb(v, nm_bit, nkx_bit; layout=:block) + g = graph_TT(nkx_bit + nm_bit) + maxbonddim = 500 + kwargs = (maxbonddim = maxbonddim, maxiter = 50, tolerance = 1e-10) + # ttn, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g; kwargs...) + + ttn, ranks, errors = crossinterpolate_with_structuralsearch(ComplexF64, f, localdims, g, 1; kwargs...) + # ttn_tree, ranks, errors = crossinterpolate_with_structuralsearch(ComplexF64, f, localdims, g, 2; kwargs...) + # ttn_ttnopt, ranks, errors = crossinterpolate_with_3site_swapping(ComplexF64, f, localdims, g; kwargs...) + + # @show ttn.data_graph.underlying_graph + # @show ttn_2site_swapping.data_graph.underlying_graph + # @show ttn_3site_swapping.data_graph.underlying_graph + + # for _ in 1:10 + # test_input = rand([1,2], nkx_bit + nm_bit) + # result = ttn(test_input) + # expected = f(test_input) + # end + + @show ttn.tensornetwork.data_graph.underlying_graph + @show last(ranks) + @show last(errors) + return 0 +end + +main() \ No newline at end of file diff --git a/samples/graphs.jl b/samples/graphs.jl new file mode 100644 index 0000000..72ec755 --- /dev/null +++ b/samples/graphs.jl @@ -0,0 +1,9 @@ +using NamedGraphs: NamedGraph, add_edge! + +function graph_TT(R::Int) + g = NamedGraph(R) + for i in 1:R-1 + add_edge!(g, i, i+1) + end + return g +end \ No newline at end of file diff --git a/samples/utils.jl b/samples/utils.jl new file mode 100644 index 0000000..1d51a1b --- /dev/null +++ b/samples/utils.jl @@ -0,0 +1,111 @@ +""" + split_bits(b; group_bits, layout=:block) + +Split a bit sequence b of length `length(b)` (where each element is 1/2) into groups +with bit counts specified by `group_bits`. + +Arguments +- b::AbstractVector{<:Integer} : Bit sequence of 1/2 (MSB-first) +- group_bits::AbstractVector{<:Integer} : Number of bits in each group (e.g., [mbit, kxbit, …]) +- layout::Symbol = :block | :interleave + - :block → Assumes b = [ grp1..., grp2..., … ] concatenation + - :interleave → Assumes b = [ g1_1, g2_1, …, gG_1, g1_2, g2_2, … ] order + Assumes all groups have equal bit counts + +Returns +- Vector{Vector{Int}} : Bit sequences for each group (each element is 1/2) +""" +function split_bits(b::AbstractVector{<:Integer}; group_bits::AbstractVector{<:Integer}, layout::Symbol=:block) + @assert all(x -> x ≥ 0, group_bits) "group_bits must be nonnegative" + G = length(group_bits) + total = sum(group_bits) + @assert length(b) == total "length(b) must equal sum(group_bits)" + + if layout === :block + parts = Vector{Vector{Int}}(undef, G) + start = 1 + @inbounds for g in 1:G + len = group_bits[g] + parts[g] = collect(b[start:start+len-1]) + start += len + end + return parts + + elseif layout === :interleave + @assert length(unique(group_bits)) == 1 "interleave layout requires all group lengths equal" + L = group_bits[1] # 各グループの長さ + @assert L * G == length(b) + parts = [Vector{Int}(undef, L) for _ in 1:G] + # b = [ g1_1, g2_1, …, gG_1, g1_2, g2_2, …, gG_2, … ] + @inbounds for j in 1:L + base = (j-1)*G + for g in 1:G + parts[g][j] = b[base + g] + end + end + return parts + + else + error("layout must be :block or :interleave") + end +end + + +""" + join_bits(parts; layout=:block) + +Inverse of `split_bits`. Combines bit sequences `parts` from each group (1/2 1-based) +to return a single bit sequence b. + +Arguments +- parts::Vector{<:AbstractVector{<:Integer}} : Bit sequences for each group +- layout::Symbol = :block | :interleave + +Note +- For :interleave, assumes all groups have equal length. +""" +function join_bits(parts::Vector{<:AbstractVector{<:Integer}}; layout::Symbol=:block) + G = length(parts) + if layout === :block + return vcat(parts...) + elseif layout === :interleave + Lset = length.(parts) + @assert length(unique(Lset)) == 1 ":interleave requires equal group lengths" + L = Lset[1] + out = Vector{Int}(undef, L*G) + # out = [ g1_1, g2_1, …, gG_1, g1_2, g2_2, …, gG_2, … ] + @inbounds for j in 1:L + base = (j-1)*G + for g in 1:G + out[base + g] = parts[g][j] + end + end + return out + else + error("layout must be :block or :interleave") + end +end + + +function tobins(i, nbit) + @assert 1 ≤ i ≤ 2^nbit + mask = 1 << (nbit-1) + bin = ones(Int, nbit) + for n in 1:nbit + bin[n] = (mask & (i-1)) >> (nbit-n) + 1 + mask = mask >> 1 + end + return bin +end + +function frombins(bin) + @assert all(1 .≤ bin .≤ 2) + nbit = length(bin) + i = 1 + tmp = 2^(nbit-1) + for n in eachindex(bin) + i += tmp * (bin[n] -1) + tmp = tmp >> 1 + end + return i +end diff --git a/src/structuralsearch.jl b/src/structuralsearch.jl index b5f9eb2..6442bca 100644 --- a/src/structuralsearch.jl +++ b/src/structuralsearch.jl @@ -55,13 +55,13 @@ function crossinterpolate_with_3site_swapping( candidates = filter(e -> distances[e] == max_distance, candidates) center_edge_ = first(candidates) - center_edge_id = edge2id[center_edge_] - + p, q = separatevertices(tci.g, id2edge[previous_center_edge_id]) v = center_edge_ in adjacentedges(tci.g, p) ? q : p # incomings = [edge for edge in adjacentedges(tci.g, v) if edge != id2edge[previous_center_edge_id]] - + # Update flags - ID management + center_edge_id = edge2id[center_edge] if all(flags[edge2id[e]] == 1 for e in incomings) && center_edge_id != origin_edge_id flags[center_edge_id] = 1 end @@ -81,7 +81,7 @@ function crossinterpolate_with_3site_swapping( end g_tmp = deepcopy(tci.g) # update g_tmp end - sitetensors = fillsitetensors(tci, f) + sitetensors, center_vertex = fillsitetensors(tci, f) ranks, errors = optimize!(tci, f; kwargs...) return TreeTensorNetwork(tci.g, sitetensors), ranks, errors @@ -147,13 +147,13 @@ function crossinterpolate_with_structuralsearch( candidates = filter(e -> distances[e] == max_distance, candidates) center_edge_ = first(candidates) - center_edge_id = edge2id[center_edge_] - + p, q = separatevertices(tci.g, center_edge) v = center_edge_ in adjacentedges(tci.g, p) ? q : p # incomings = [edge for edge in adjacentedges(tci.g, v) if edge != center_edge] - + # Update flags - ID management + center_edge_id = edge2id[center_edge] if all(flags[edge2id[e]] == 1 for e in incomings) && center_edge_id != origin_edge_id flags[center_edge_id] = 1 end @@ -316,7 +316,6 @@ function optimize_with_localmanipulation( id2edge_new = deepcopy(id2edge) rem_edge!(g_new, center_edge) - for v in children # remove the old parent old_parent = (v in subI ? p : q) diff --git a/src/ttnopt.jl b/src/ttnopt.jl new file mode 100644 index 0000000..7c1c868 --- /dev/null +++ b/src/ttnopt.jl @@ -0,0 +1,223 @@ +using TreeTCI: TreeTensorNetwork +using SimpleTensorNetworks: permute, IndexedArray, hascommondindices +using LinearAlgebra +using ITensors + +function ttnopt( + ttn::TreeTensorNetwork{V}; + maxbonddim::Int = typemax(Int), + tolerance::Float64 = 0.0, + max_degree::Int = 2, + nsweeps::Int = 10, + T0::Float64 = 0.0, + +) where {V} + + tn = ttn.tensornetwork.data_graph + tn_g = tn.underlying_graph + center_vertex = ttn.center_vertex + neighbor_vertices = neighbors(tn_g, center_vertex) + origin_edge = NamedEdge(min(center_vertex, first(neighbor_vertices)) => max(center_vertex, first(neighbor_vertices))) + + id2edge = collect(edges(tn_g)) + edge2id = Dict{NamedEdge,Int}(e => i for (i,e) in enumerate(id2edge)) + center_edge = origin_edge + origin_edge_id = edge2id[origin_edge] + + for i = 1:nsweeps + @show i + # Init flags + flags = Dict(k => 0 for k in 1:length(id2edge)) + while true + ttn, center_edge, id2edge, edge2id, flags, finish = optimize_structure(ttn, center_edge, id2edge, edge2id, flags, origin_edge_id, i, nsweeps; max_degree = max_degree, T0 = T0, maxbonddim = maxbonddim, tolerance = tolerance) + @show center_edge + if finish + @show "converged" + break + end + end + end + + + return 0 +end + +function optimize_structure( + ttn, + center_edge, + id2edge, + edge2id, + flags, + origin_edge_id, + nowstep::Int, + nsweeps::Int; + max_degree::Int = 1, + T0::Float64 = 0.0, + maxbonddim::Int = typemax(Int), + tolerance::Float64 = 0.0, +) + tn = ttn.tensornetwork.data_graph + tn_g = tn.underlying_graph + p, q = separatevertices(tn_g, center_edge) + subI = filter(x->x!=q, neighbors(tn_g, p)) + subJ = filter(x->x!=p, neighbors(tn_g, q)) + children = vcat(subI, subJ) + ψ = contract(tn[p], tn[q]) + + n = length(children) + limit = max_degree + + ψ_inds = ψ.indices + s1 = ψ_inds[1] + s2 = ψ_inds[2] + other_inds = ψ_inds[3:end] + + entanglements = Float64[] + virtual_indices_pairs = [] + gs = [] + id2edges = [] + + for k in 0:n + if k <= limit && (n-k) <= limit + for left in combinations(children, k) + leftset = Set(left) + + # split virtual bonds into left and right + left_bonds = other_inds[1:k] + right_bonds = other_inds[(k+1):end] + + # left: s1 + left_bonds, right: s2 + right_bonds + left_indices = [s1; left_bonds] + right_indices = [s2; right_bonds] + + ψ_permuted = permute(ψ, [left_indices; right_indices]) + + # size of left and right + left_size = prod([ind.dim for ind in left_indices]) + right_size = prod([ind.dim for ind in right_indices]) + + # reshape and SVD + reshaped = reshape(ψ_permuted.data, left_size, right_size) + _, S, _ = svd(reshaped) + + S2 = S.^2 + S2 = S2 / sum(S2) + S2 = S2[S2 .> 0.0] + ee = -sum(S2 .* log.(S2)) + + # graphs + push!(entanglements, ee) + push!(virtual_indices_pairs, (left_indices, right_indices)) + + g_new = deepcopy(tn_g) + id2edge_new = deepcopy(id2edge) + rem_edge!(g_new, center_edge) + + for v in children + # remove the old parent + old_parent = (v in subI ? p : q) + + e_old = old_parent < v ? NamedEdge(old_parent=>v) : NamedEdge(v=>old_parent) + e_old_id = edge2id[e_old] + + rem_edge!(g_new, e_old) + # connect the new parent + new_parent = (v in leftset ? p : q) + e_new = new_parent < v ? NamedEdge(new_parent=>v) : NamedEdge(v=>new_parent) + + id2edge_new[e_old_id] = e_new + add_edge!(g_new, e_new) + end + add_edge!(g_new, center_edge) + + push!(gs, g_new) + push!(id2edges, id2edge_new) + end + end + end + + index = propose_structure(entanglements, nowstep, nsweeps; T0 = T0) + + edge2id = Dict(e => i for (i, e) in enumerate(id2edge)) + + tn_g = gs[index] + id2edge = id2edges[index] + edge2id = Dict(e => i for (i, e) in enumerate(id2edge)) + + # update next center edge + candidates = candidateedges(tn_g, center_edge) + candidates = [e for e in candidates if flags[edge2id[e]] == 0] + + # If candidates is empty, exit while loop + if isempty(candidates) + return tn, tn_g, center_edge, id2edge, edge2id, flags, true + end + + distances = distanceedges(tn_g, id2edge[origin_edge_id]) + max_distance = maximum(distances[e] for e in candidates) + candidates = filter(e -> distances[e] == max_distance, candidates) + + center_edge_ = first(candidates) + center_edge_id = edge2id[center_edge_] + + p, q = separatevertices(tn_g, center_edge) + v = center_edge_ in adjacentedges(tn_g, p) ? q : p # + incomings = [edge for edge in adjacentedges(tn_g, v) if edge != center_edge] + + # Update flags - ID management + if !isempty(incomings) && all(flags[edge2id[e]] == 1 for e in incomings) && center_edge_id != origin_edge_id + flags[center_edge_id] = 1 + end + + U, V = update_tn(ψ, v, first(virtual_indices_pairs[index]), last(virtual_indices_pairs[index]); maxbonddim = maxbonddim, tolerance = tolerance) + ttn = TreeTensorNetwork(tn_g, sitetensors, ttn.center_vertex) + + # update center edge + center_edge = center_edge_ + + return ttn, center_edge, id2edge, edge2id, flags, false +end + +function propose_structure(entanglements::Vector{Float64}, nowstep::Int, nsteps::Int; T0::Float64 = 0.0) + index = 0 + if T0 > 0.0 + T = T0 * (nsteps - nowstep) / nsteps + p = exp.(-entanglements / T) + p = p / sum(p) + index = sample(1:length(entanglements), Weights(p)) + else + index = argmin(entanglements) + end + return index +end + +function update_tn( + ψ, + next_vertex, + left_indices, + right_indices; + maxbonddim::Int = typemax(Int), + tolerance::Float64 = 0.0, +) + ψ_permuted = permute(ψ, [left_indices; right_indices]) + + # TODO: SimpleTensorNetworks SVD + # ここで left/right 側の結合次元を出してSVD → u,s,v を返す処理へ発展 + left_inds = [ITensors.Index(left_indices[i].dim) for i in 1:length(left_indices)] + right_inds = [ITensors.Index(right_indices[i].dim) for i in 1:length(right_indices)] + ψ_permuted = ITensors.ITensor(ψ_permuted.data, vcat(left_inds, right_inds)...) + u_resolve = left_indices[1].name == "s$(next_vertex)" + v_resolve = right_indices[1].name == "s$(next_vertex)" + u, s, v = svd(ψ_permuted, left_inds; maxdim = maxbonddim, cutoff = tolerance) + d = first(size(s)) + if u_resolve + u = u * s + elseif v_resolve + v = v * s + end + + u = Array(u, ITensors.inds(u)...) + v = Array(v, ITensors.inds(v)...) + + return u, v +end From 1fd3a07929844346c67533bcbbb72d2bb0da5a7e Mon Sep 17 00:00:00 2001 From: Ryo Watanabe Date: Wed, 1 Oct 2025 04:16:22 +0900 Subject: [PATCH 12/13] structural_search --- samples/1d_tightbinding_model.jl | 6 +++--- src/simpletci_optimize.jl | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/1d_tightbinding_model.jl b/samples/1d_tightbinding_model.jl index d6114c2..703d15b 100644 --- a/samples/1d_tightbinding_model.jl +++ b/samples/1d_tightbinding_model.jl @@ -40,11 +40,11 @@ function main() localdims = fill(2, nkx_bit + nm_bit) f(v) = gkb(v, nm_bit, nkx_bit; layout=:block) g = graph_TT(nkx_bit + nm_bit) - maxbonddim = 500 - kwargs = (maxbonddim = maxbonddim, maxiter = 50, tolerance = 1e-10) + maxbonddim = 10 + kwargs = (maxbonddim = maxbonddim, maxiter = 2, tolerance = 1e-10) # ttn, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g; kwargs...) - ttn, ranks, errors = crossinterpolate_with_structuralsearch(ComplexF64, f, localdims, g, 1; kwargs...) + ttn, ranks, errors = crossinterpolate_with_structuralsearch(ComplexF64, f, localdims, g, 2; kwargs...) # ttn_tree, ranks, errors = crossinterpolate_with_structuralsearch(ComplexF64, f, localdims, g, 2; kwargs...) # ttn_ttnopt, ranks, errors = crossinterpolate_with_3site_swapping(ComplexF64, f, localdims, g; kwargs...) diff --git a/src/simpletci_optimize.jl b/src/simpletci_optimize.jl index 557b28f..7417fbc 100644 --- a/src/simpletci_optimize.jl +++ b/src/simpletci_optimize.jl @@ -96,11 +96,11 @@ function optimize!( if verbosity > 1 println("Converged at $(iter)th-sweep.") end - tci.converged_IJset = deepcopy(tci.IJset) break end end - + + tci.converged_IJset = deepcopy(tci.IJset) errornormalization = normalizeerror ? tci.maxsamplevalue : 1.0 return ranks, errors ./ errornormalization end From d8c9a111ce8fed8c03eefae412b8ab93830c882f Mon Sep 17 00:00:00 2001 From: Ryo Watanabe Date: Thu, 9 Oct 2025 00:33:13 +0200 Subject: [PATCH 13/13] sample_green's func --- Project.toml | 8 + samples/1d_tightbinding_model.jl | 44 ++-- samples/2d_model.jl | 92 +++++++++ src/TreeTCI.jl | 1 + src/structuralsearch.jl | 4 + src/treetensornetwork.jl | 3 +- src/ttnopt.jl | 336 ++++++++++++++----------------- 7 files changed, 280 insertions(+), 208 deletions(-) create mode 100644 samples/2d_model.jl diff --git a/Project.toml b/Project.toml index 09fdd6c..0579f89 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,11 @@ DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" +GraphTikZ = "cef0280d-a2bf-4776-a511-cf6253a7debc" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" +ITensorNetworks = "2919e153-833c-4bdc-8836-1ea460a35fc7" +ITensors = "9136182c-28ba-11e9-034c-db9fb085ebd5" +NPZ = "15e1cf62-19b3-5cfa-8e77-841668bca605" NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" QuanticsGrids = "634c7f73-3e90-4749-a1bd-001b8efc642d" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" @@ -26,7 +30,11 @@ DataGraphs = "0.2.5" DataStructures = "0.18.22" Distributions = "0.25.120" Flux = "0.16.4" +GraphTikZ = "0.1.0" Graphs = "1.12.0" +ITensorNetworks = "0.14.1" +ITensors = "0.9.11" +NPZ = "0.4.3" NamedGraphs = "0.6.4" QuanticsGrids = "0.6.0" Random = "1.10" diff --git a/samples/1d_tightbinding_model.jl b/samples/1d_tightbinding_model.jl index 703d15b..ef3476a 100644 --- a/samples/1d_tightbinding_model.jl +++ b/samples/1d_tightbinding_model.jl @@ -1,13 +1,19 @@ using Random using LinearAlgebra using TreeTCI: crossinterpolate, crossinterpolate_with_structuralsearch, crossinterpolate_with_3site_swapping -using NamedGraphs: NamedGraph, add_edge! +using NamedGraphs: NamedGraph, add_edge!, edges, src, dst using QuanticsGrids const QG = QuanticsGrids using SparseIR +using ITensorNetworks +using TreeTCI: ttnopt +const ITN = ITensorNetworks +using ITensors +using NPZ include("utils.jl") include("graphs.jl") + ε(k) = 2*cos(k) + cos(5*k) + 2*cos(20*k) gk(m::Int, kx::Float64; β::Float64=10.0) = begin @@ -17,7 +23,7 @@ gk(m::Int, kx::Float64; β::Float64=10.0) = begin return 1 / (iν - ε(kx)) end -function gkb(b::Vector{Int}, n_m::Int, n_kx::Int; β::Float64=10.0, layout::Symbol=:block) +function gkb(b::Vector{Int}, n_m::Int, n_kx::Int; mu::Float64=0.0, β::Float64=10.0, layout::Symbol=:block) @assert length(b) == n_m + n_kx parts = split_bits(b; group_bits=[n_m, n_kx], layout=layout) mb, kxb = parts @@ -31,36 +37,28 @@ function gkb(b::Vector{Int}, n_m::Int, n_kx::Int; β::Float64=10.0, layout::Symb @assert ikx ≤ Nkx kx = 2π * (ikx - 1)/Nkx m = (im - 1) - return gk(m, kx) + return gk(m, kx; mu=mu, β=β) end function main() nkx_bit = 10 nm_bit = 10 localdims = fill(2, nkx_bit + nm_bit) - f(v) = gkb(v, nm_bit, nkx_bit; layout=:block) + f(v) = gkb(v, nm_bit, nkx_bit; layout=:interleave) g = graph_TT(nkx_bit + nm_bit) - maxbonddim = 10 - kwargs = (maxbonddim = maxbonddim, maxiter = 2, tolerance = 1e-10) - # ttn, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g; kwargs...) - - ttn, ranks, errors = crossinterpolate_with_structuralsearch(ComplexF64, f, localdims, g, 2; kwargs...) - # ttn_tree, ranks, errors = crossinterpolate_with_structuralsearch(ComplexF64, f, localdims, g, 2; kwargs...) - # ttn_ttnopt, ranks, errors = crossinterpolate_with_3site_swapping(ComplexF64, f, localdims, g; kwargs...) - - # @show ttn.data_graph.underlying_graph - # @show ttn_2site_swapping.data_graph.underlying_graph - # @show ttn_3site_swapping.data_graph.underlying_graph - - # for _ in 1:10 - # test_input = rand([1,2], nkx_bit + nm_bit) - # result = ttn(test_input) - # expected = f(test_input) - # end + maxbonddim = 200 + kwargs = (maxbonddim = maxbonddim, maxiter = 100, tolerance = 1e-13) + center_vertex = (nkx_bit + nm_bit) ÷ 2 + # center_vertex = 1 - @show ttn.tensornetwork.data_graph.underlying_graph + ttn, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g; center_vertex = center_vertex, kwargs...) @show last(ranks) - @show last(errors) + + + g_tmp, original_entanglements, entanglements = ttnopt(ttn; ortho_vertex = center_vertex, max_degree = 2) + ttn_, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g_tmp; center_vertex = center_vertex, kwargs...) + @show last(ranks) + return 0 end diff --git a/samples/2d_model.jl b/samples/2d_model.jl new file mode 100644 index 0000000..8983ed6 --- /dev/null +++ b/samples/2d_model.jl @@ -0,0 +1,92 @@ +using Random +using LinearAlgebra +using TreeTCI: crossinterpolate, crossinterpolate_with_structuralsearch, crossinterpolate_with_3site_swapping +using NamedGraphs: NamedGraph, add_edge!, edges, src, dst +using QuanticsGrids +const QG = QuanticsGrids +using SparseIR +using ITensorNetworks +using TreeTCI: ttnopt +const ITN = ITensorNetworks +using ITensors +using NPZ +include("utils.jl") +include("graphs.jl") + + +ε(kx, ky) = -2*cos(kx) - 2*cos(ky) + +gk(kx::Float64, ky::Float64; mu::Float64=0.0, β::Float64=10.0) = begin + m = 1 + ν = FermionicFreq(m) + iν = SparseIR.valueim(ν, β) + return 1 / (iν - ε(kx, ky) + mu) +end + +function gkb(b::Vector{Int}, n_kx::Int, n_ky; mu::Float64=0.0, β::Float64=10.0, layout::Symbol=:block) + @assert length(b) == n_kx + n_ky + parts = split_bits(b; group_bits=[n_kx, n_ky], layout=layout) + kxb, kyb = parts + kxbit = length(kxb) + kybit = length(kyb) + Nkx = 2^kxbit + Nky = 2^kybit + iky = frombins(kyb) + ikx = frombins(kxb) + @assert ikx ≤ Nkx + @assert iky ≤ Nky + kx = 2π * (ikx - 1)/Nkx + ky = 2π * (iky - 1)/Nky + return gk(kx, ky; mu=mu, β=β) +end + + +function calculate_entanglements(entanglements) + ee = 0.0 + edges = [] + edge_vals = [] + for (key, value) in entanglements + ee += value + push!(edges, key) + push!(edge_vals, value) + end + @show ee / length(edges) + @show edges + @show edge_vals +end + +function main() + nkx_bit = 10 + nky_bit = 10 + localdims = fill(2, nkx_bit + nky_bit) + f(v) = gkb(v, nky_bit, nkx_bit; layout=:interleave, mu=-1.0, β=10.0) + g = graph_TT(nkx_bit + nky_bit) + maxbonddim = 200 + kwargs = (maxbonddim = maxbonddim, maxiter = 100, tolerance = 1e-13) + center_vertex = (nkx_bit + nky_bit) ÷ 2 + + ttn, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g; center_vertex = center_vertex, kwargs...) + + g_tmp, original_entanglements, entanglements = ttnopt(ttn; ortho_vertex = center_vertex, max_degree = 1) + ttn_, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g_tmp; center_vertex = center_vertex, kwargs...) + println("original_entanglements") + calculate_entanglements(original_entanglements) + @show last(ranks) + + println("--------------------------------") + println("ΔG = 2") + calculate_entanglements(entanglements) + @show last(ranks) + + g_tmp, original_entanglements, entanglements = ttnopt(ttn; ortho_vertex = center_vertex, max_degree = 2) + ttn_, ranks, errors = crossinterpolate(ComplexF64, f, localdims, g_tmp; center_vertex = center_vertex, kwargs...) + + println("--------------------------------") + println("ΔG = 3") + calculate_entanglements(entanglements) + @show last(ranks) + + return 0 +end + +main() \ No newline at end of file diff --git a/src/TreeTCI.jl b/src/TreeTCI.jl index fed40f1..590aa40 100644 --- a/src/TreeTCI.jl +++ b/src/TreeTCI.jl @@ -10,4 +10,5 @@ include("simpletci_optimize.jl") include("simpletci_tensors.jl") include("treetensornetwork.jl") include("structuralsearch.jl") +include("ttnopt.jl") end diff --git a/src/structuralsearch.jl b/src/structuralsearch.jl index 6442bca..311f0b1 100644 --- a/src/structuralsearch.jl +++ b/src/structuralsearch.jl @@ -41,6 +41,10 @@ function crossinterpolate_with_3site_swapping( # Init flags flags = Dict(k => 0 for k in 1:length(id2edge)) while true + + tci, id2edge = optimize_with_3site_swapping(tci, f, initialpivots, id2edge[center_edge_id], id2edge[previous_center_edge_id], id2edge, edge2id; kwargs...) + edge2id = Dict(e => i for (i, e) in enumerate(id2edge)) + # update next center edge candidates = candidateedges(tci.g, id2edge[previous_center_edge_id]) candidates = [e for e in candidates if flags[edge2id[e]] == 0] diff --git a/src/treetensornetwork.jl b/src/treetensornetwork.jl index 8bcda43..43836f9 100644 --- a/src/treetensornetwork.jl +++ b/src/treetensornetwork.jl @@ -82,11 +82,12 @@ function crossinterpolate( localdims::Union{Vector{Int},NTuple{N,Int}}, g::NamedGraph, initialpivots::Vector{MultiIndex} = [ones(Int, length(localdims))]; + center_vertex::Int = 1, kwargs..., ) where {ValueType,N} tci = SimpleTCI{ValueType}(f, localdims, g, initialpivots) ranks, errors = optimize!(tci, f; kwargs...) - sitetensors = fillsitetensors(tci, f) + sitetensors = fillsitetensors(tci, f; center_vertex = center_vertex) return TreeTensorNetwork(tci.g, sitetensors), ranks, errors end diff --git a/src/ttnopt.jl b/src/ttnopt.jl index 7c1c868..4c765c6 100644 --- a/src/ttnopt.jl +++ b/src/ttnopt.jl @@ -1,187 +1,133 @@ -using TreeTCI: TreeTensorNetwork -using SimpleTensorNetworks: permute, IndexedArray, hascommondindices -using LinearAlgebra using ITensors - -function ttnopt( - ttn::TreeTensorNetwork{V}; - maxbonddim::Int = typemax(Int), - tolerance::Float64 = 0.0, - max_degree::Int = 2, - nsweeps::Int = 10, - T0::Float64 = 0.0, - -) where {V} - - tn = ttn.tensornetwork.data_graph - tn_g = tn.underlying_graph - center_vertex = ttn.center_vertex - neighbor_vertices = neighbors(tn_g, center_vertex) - origin_edge = NamedEdge(min(center_vertex, first(neighbor_vertices)) => max(center_vertex, first(neighbor_vertices))) - - id2edge = collect(edges(tn_g)) - edge2id = Dict{NamedEdge,Int}(e => i for (i,e) in enumerate(id2edge)) - center_edge = origin_edge - origin_edge_id = edge2id[origin_edge] - - for i = 1:nsweeps - @show i - # Init flags - flags = Dict(k => 0 for k in 1:length(id2edge)) - while true - ttn, center_edge, id2edge, edge2id, flags, finish = optimize_structure(ttn, center_edge, id2edge, edge2id, flags, origin_edge_id, i, nsweeps; max_degree = max_degree, T0 = T0, maxbonddim = maxbonddim, tolerance = tolerance) - @show center_edge - if finish - @show "converged" - break - end - end - end - - - return 0 +using ITensorNetworks +const ITN = ITensorNetworks + +function entanglements_entropy(s) + s = diag(s) + s2 = s.^2 + s2 = s2 / sum(s2) + s2 = s2[s2 .> 0.0] + return -sum(s2 .* log.(s2)) end -function optimize_structure( - ttn, - center_edge, - id2edge, - edge2id, - flags, - origin_edge_id, - nowstep::Int, - nsweeps::Int; +function ttnopt( + ttn::TreeTensorNetwork, + nsweeps::Int=50; + ortho_vertex::Int=1, max_degree::Int = 1, T0::Float64 = 0.0, - maxbonddim::Int = typemax(Int), - tolerance::Float64 = 0.0, ) - tn = ttn.tensornetwork.data_graph - tn_g = tn.underlying_graph - p, q = separatevertices(tn_g, center_edge) - subI = filter(x->x!=q, neighbors(tn_g, p)) - subJ = filter(x->x!=p, neighbors(tn_g, q)) - children = vcat(subI, subJ) - ψ = contract(tn[p], tn[q]) - - n = length(children) - limit = max_degree - - ψ_inds = ψ.indices - s1 = ψ_inds[1] - s2 = ψ_inds[2] - other_inds = ψ_inds[3:end] - - entanglements = Float64[] - virtual_indices_pairs = [] - gs = [] - id2edges = [] - - for k in 0:n - if k <= limit && (n-k) <= limit - for left in combinations(children, k) - leftset = Set(left) - - # split virtual bonds into left and right - left_bonds = other_inds[1:k] - right_bonds = other_inds[(k+1):end] - - # left: s1 + left_bonds, right: s2 + right_bonds - left_indices = [s1; left_bonds] - right_indices = [s2; right_bonds] - - ψ_permuted = permute(ψ, [left_indices; right_indices]) - - # size of left and right - left_size = prod([ind.dim for ind in left_indices]) - right_size = prod([ind.dim for ind in right_indices]) - - # reshape and SVD - reshaped = reshape(ψ_permuted.data, left_size, right_size) - _, S, _ = svd(reshaped) + ttn = convert_ITensorNetwork(ttn, ortho_vertex) + normalize!(ttn) + neighbor_vertices = neighbors(ttn, ortho_vertex) + next_vertex = first(neighbor_vertices) + origin_edge = NamedEdge(min(ortho_vertex, next_vertex) => max(ortho_vertex, next_vertex)) + center_edge = origin_edge - S2 = S.^2 - S2 = S2 / sum(S2) - S2 = S2[S2 .> 0.0] - ee = -sum(S2 .* log.(S2)) + flag_indices = [tags(first(ITN.linkinds(ttn, e))) for e in edges(ttn)] + origin_flag_index = tags(first(ITN.linkinds(ttn, origin_edge))) - # graphs - push!(entanglements, ee) - push!(virtual_indices_pairs, (left_indices, right_indices)) + edge_list = [[src(e), dst(e)] for e in edges(ttn)] - g_new = deepcopy(tn_g) - id2edge_new = deepcopy(id2edge) - rem_edge!(g_new, center_edge) + original_entanglements = Dict() + final_entanglements = Dict() - for v in children - # remove the old parent - old_parent = (v in subI ? p : q) + for sweep = 0:nsweeps + flags = Dict(flag_indices[i] => 0 for i in 1:length(flag_indices)) + final_entanglements = Dict() + while true + g = ttn.tensornetwork.data_graph.underlying_graph + p, q = separatevertices(g, center_edge) + linkind = first(ITN.linkinds(ttn, center_edge)) + maxbonddim = dim(linkind) + tag = tags(linkind) + siteindices = [ITN.siteinds(ttn, p); ITN.siteinds(ttn, q)] + + ψ = ITensors.contract(ttn[p], ttn[q]) + if sweep == 0 + leftinds = filter(ind -> ind != ITN.siteinds(ttn, p), inds(ttn[p])) + _, s, _ = ITensors.svd(ψ, leftinds; cutoff = 0.0) + ee = entanglements_entropy(s) + original_entanglements[src(center_edge), dst(center_edge)] = ee + else + entanglements, leftinds_list = propose_structure(ψ, siteindices, max_degree) + index = decide_structure(entanglements, sweep, nsweeps; T0 = T0) + leftinds = leftinds_list[index] + ee = entanglements[index] + final_entanglements[src(center_edge), dst(center_edge)] = ee + end - e_old = old_parent < v ? NamedEdge(old_parent=>v) : NamedEdge(v=>old_parent) - e_old_id = edge2id[e_old] + u, s, v = ITensors.svd(ψ, leftinds; maxdim = maxbonddim, lefttags = tag, righttags = tag) + ttn[p] = u + ttn[q] = v * s - rem_edge!(g_new, e_old) - # connect the new parent - new_parent = (v in leftset ? p : q) - e_new = new_parent < v ? NamedEdge(new_parent=>v) : NamedEdge(v=>new_parent) + # update next center edge + g = ttn.tensornetwork.data_graph.underlying_graph - id2edge_new[e_old_id] = e_new - add_edge!(g_new, e_new) - end - add_edge!(g_new, center_edge) + candidates = candidateedges(g, center_edge) + candidates = [e for e in candidates if flags[tags(first(ITN.linkinds(ttn, e)))] == 0] - push!(gs, g_new) - push!(id2edges, id2edge_new) + # If candidates is empty, exit while loop + if isempty(candidates) + break end - end - end - - index = propose_structure(entanglements, nowstep, nsweeps; T0 = T0) - edge2id = Dict(e => i for (i, e) in enumerate(id2edge)) + same_index_edge = first([e for e in edges(ttn) if tags(first(ITN.linkinds(ttn, e))) == origin_flag_index]) + distances = distanceedges(g, same_index_edge) + max_distance = maximum(distances[e] for e in candidates) + candidates = filter(e -> distances[e] == max_distance, candidates) + center_edge_ = first(candidates) + prev_vertex, next_vertex = center_edge_ in adjacentedges(g, p) ? (q, p) : (p, q) # + incomings = [first(ITN.linkinds(ttn, edge)) for edge in adjacentedges(g, prev_vertex) if edge != center_edge] + center_flag_index = tags(first(ITN.linkinds(ttn, center_edge))) + + if all(flags[tags(e)] == 1 for e in incomings) && center_flag_index != origin_flag_index + flags[center_flag_index] = 1 + end - tn_g = gs[index] - id2edge = id2edges[index] - edge2id = Dict(e => i for (i, e) in enumerate(id2edge)) + if next_vertex == p + ttn[next_vertex] = u * s + ttn[prev_vertex] = v + end + center_edge = center_edge_ - # update next center edge - candidates = candidateedges(tn_g, center_edge) - candidates = [e for e in candidates if flags[edge2id[e]] == 0] + end - # If candidates is empty, exit while loop - if isempty(candidates) - return tn, tn_g, center_edge, id2edge, edge2id, flags, true + new_edge_list = [[src(e), dst(e)] for e in edges(ttn)] + if sweep > 1 && Set(edge_list) == Set(new_edge_list) + break + end + edge_list = new_edge_list end + return ttn.tensornetwork.data_graph.underlying_graph, original_entanglements, final_entanglements +end - distances = distanceedges(tn_g, id2edge[origin_edge_id]) - max_distance = maximum(distances[e] for e in candidates) - candidates = filter(e -> distances[e] == max_distance, candidates) - - center_edge_ = first(candidates) - center_edge_id = edge2id[center_edge_] +function propose_structure(ψ, siteindices, max_degree::Int) + s1_ind = siteindices[1] + s2_ind = siteindices[2] - p, q = separatevertices(tn_g, center_edge) - v = center_edge_ in adjacentedges(tn_g, p) ? q : p # - incomings = [edge for edge in adjacentedges(tn_g, v) if edge != center_edge] + remain_inds = filter(ind -> ind != s1_ind && ind != s2_ind, inds(ψ)) + n = length(remain_inds) - # Update flags - ID management - if !isempty(incomings) && all(flags[edge2id[e]] == 1 for e in incomings) && center_edge_id != origin_edge_id - flags[center_edge_id] = 1 + entanglements = Float64[] + leftinds_list = [] + for k = 0:n + if k <= max_degree && (n-k) <= max_degree + for left in combinations(remain_inds, k) + leftinds = [s1_ind; left] + _, s, _ = svd(ψ, leftinds, cutoff = 0.0) + ee = entanglements_entropy(s) + push!(entanglements, ee) + push!(leftinds_list, leftinds) + end + end end - - U, V = update_tn(ψ, v, first(virtual_indices_pairs[index]), last(virtual_indices_pairs[index]); maxbonddim = maxbonddim, tolerance = tolerance) - ttn = TreeTensorNetwork(tn_g, sitetensors, ttn.center_vertex) - - # update center edge - center_edge = center_edge_ - - return ttn, center_edge, id2edge, edge2id, flags, false + return entanglements, leftinds_list end -function propose_structure(entanglements::Vector{Float64}, nowstep::Int, nsteps::Int; T0::Float64 = 0.0) - index = 0 +function decide_structure(entanglements, nowsweep, nsweeps; T0::Float64 = 0.0) if T0 > 0.0 - T = T0 * (nsteps - nowstep) / nsteps + T = T0 * nowsweep / nsweeps p = exp.(-entanglements / T) p = p / sum(p) index = sample(1:length(entanglements), Weights(p)) @@ -191,33 +137,55 @@ function propose_structure(entanglements::Vector{Float64}, nowstep::Int, nsteps: return index end -function update_tn( - ψ, - next_vertex, - left_indices, - right_indices; - maxbonddim::Int = typemax(Int), - tolerance::Float64 = 0.0, -) - ψ_permuted = permute(ψ, [left_indices; right_indices]) - - # TODO: SimpleTensorNetworks SVD - # ここで left/right 側の結合次元を出してSVD → u,s,v を返す処理へ発展 - left_inds = [ITensors.Index(left_indices[i].dim) for i in 1:length(left_indices)] - right_inds = [ITensors.Index(right_indices[i].dim) for i in 1:length(right_indices)] - ψ_permuted = ITensors.ITensor(ψ_permuted.data, vcat(left_inds, right_inds)...) - u_resolve = left_indices[1].name == "s$(next_vertex)" - v_resolve = right_indices[1].name == "s$(next_vertex)" - u, s, v = svd(ψ_permuted, left_inds; maxdim = maxbonddim, cutoff = tolerance) - d = first(size(s)) - if u_resolve - u = u * s - elseif v_resolve - v = v * s +function convert_ITensorNetwork(ttn::TreeTensorNetwork, ortho_vertex::Int=1) + g = ttn.tensornetwork.data_graph.underlying_graph + siteinds = [] + edge_inds = Dict{NamedEdge, ITensors.Index}() + itensors = ITensors.ITensor[] + for v in vertices(g) + tns = ttn.tensornetwork.data_graph[v] + tns_data = tns.data + tns_inds = tns.indices + # Add site index + site = ITensors.Index(tns_inds[1].dim; tags="s$v") + push!(siteinds, site) + # Add edge indices + inds = [] + for ind in tns_inds[2:end] + tag = ind.name + parts = split(tag, "=>") + src, dst = parse(Int, parts[1]), parse(Int, parts[2]) + e = NamedEdge(src, dst) + # Get edge ID from mapping + edge_id = findfirst(edge -> edge == e, collect(edges(g))) + ind = get!(edge_inds, NamedEdge(src, dst), ITensors.Index(ind.dim; tags="e$edge_id")) + push!(inds, ind) + end + # Add itensor + itensor = ITensors.ITensor(tns_data, [site; inds]) + push!(itensors, itensor) end - u = Array(u, ITensors.inds(u)...) - v = Array(v, ITensors.inds(v)...) + # ortho normalize + state = namedgraph_dijkstra_shortest_paths(g, ortho_vertex) + distances = state.dists + max_distance = maximum(distances[v] for v in vertices(g)) + for d = max_distance:-1:1 + children = filter(v -> distances[v] == d, vertices(g)) + for child in children + parent = state.parents[child] + ψ = ITensors.contract(itensors[parent], itensors[child]) + virtualindex = commonind(itensors[parent], itensors[child]) + child_inds = inds(itensors[child]) + left_inds = filter(i -> i != virtualindex, child_inds) + u, s, v = svd(ψ, left_inds, maxdim = dim(virtualindex); lefttags=tags(virtualindex), righttags=tags(virtualindex)) + v = v * s + itensors[child] = u + itensors[parent] = v + end + end - return u, v -end + ttn = ITN.ITensorNetwork(itensors) + ttn = ITN.TreeTensorNetwork(ttn, ortho_region=vertices(ttn)[ortho_vertex]) + return ttn +end \ No newline at end of file