diff --git a/Project.toml b/Project.toml index e95a22b..e4378f9 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SpatiotemporalGPs" uuid = "73b3b457-46a4-4dae-aece-b1ff83e37843" authors = ["Devansh Ramgopal Agrawal and contributors"] -version = "1.0.1-DEV" +version = "1.1.0-DEV" [deps] Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" @@ -12,11 +12,23 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +[weakdeps] +Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + + +[extensions] +CudaExt = ["CUDA", "Adapt"] + [compat] +Adapt = "4.3.0" +CUDA = "5.8.3" julia = "1.9.4" [extras] +Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test"] +test = ["Test", "CUDA", "Adapt"] diff --git a/examples/Manifest.toml b/examples/Manifest.toml index 4aadd6b..9eabe3c 100644 --- a/examples/Manifest.toml +++ b/examples/Manifest.toml @@ -1,25 +1,62 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.10.2" +julia_version = "1.11.2" manifest_format = "2.0" -project_hash = "e383ce36eae45d99e436f68b4f0f8f929fb8e157" +project_hash = "ede3ab4b27c56952ad1fa470fb383403a3f3859c" + +[[deps.AbstractFFTs]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "d92ad398961a3ed262d8bf04a1a2b8340f915fef" +uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" +version = "1.5.0" +weakdeps = ["ChainRulesCore", "Test"] + + [deps.AbstractFFTs.extensions] + AbstractFFTsChainRulesCoreExt = "ChainRulesCore" + AbstractFFTsTestExt = "Test" [[deps.Adapt]] deps = ["LinearAlgebra", "Requires"] -git-tree-sha1 = "6a55b747d1812e699320963ffde36f1ebdda4099" +git-tree-sha1 = "f7817e2e585aa6d924fd714df1e2a84be7896c60" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.0.4" -weakdeps = ["StaticArrays"] +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.ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" -version = "1.1.1" +version = "1.1.2" [[deps.Artifacts]] uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" +version = "1.11.0" + +[[deps.Atomix]] +deps = ["UnsafeAtomics"] +git-tree-sha1 = "b5bb4dc6248fde467be2a863eb8452993e74d402" +uuid = "a9b6321e-bd34-4604-b9c9-b65b8de01458" +version = "1.1.1" + + [deps.Atomix.extensions] + AtomixCUDAExt = "CUDA" + AtomixMetalExt = "Metal" + AtomixOpenCLExt = "OpenCL" + AtomixoneAPIExt = "oneAPI" + + [deps.Atomix.weakdeps] + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + Metal = "dde4c033-4e86-420c-a63e-0dd931031962" + OpenCL = "08131aa3-fb12-5dee-8b74-c09406e224a2" + oneAPI = "8f75cd03-7ff8-4ecb-9b8f-daf728133b1b" [[deps.AxisAlgorithms]] deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] @@ -27,8 +64,15 @@ git-tree-sha1 = "01b8ccb13d68535d73d2b0c23e39bd23155fb712" uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" version = "1.1.0" +[[deps.BFloat16s]] +deps = ["LinearAlgebra", "Printf", "Random"] +git-tree-sha1 = "3b642331600250f592719140c60cf12372b82d66" +uuid = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" +version = "0.5.1" + [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +version = "1.11.0" [[deps.BitFlags]] git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d" @@ -36,22 +80,69 @@ uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" version = "0.1.9" [[deps.Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "9e2a6b69137e6969bab0152632dcb3bc108c8bdd" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1b96ea4a01afe0ea4090c5c8039690672dd13f2e" uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.8+1" +version = "1.0.9+0" + +[[deps.CEnum]] +git-tree-sha1 = "389ad5c84de1ae7cf0e28e381131c98ea87d54fc" +uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" +version = "0.5.0" + +[[deps.CUDA]] +deps = ["AbstractFFTs", "Adapt", "BFloat16s", "CEnum", "CUDA_Compiler_jll", "CUDA_Driver_jll", "CUDA_Runtime_Discovery", "CUDA_Runtime_jll", "Crayons", "DataFrames", "ExprTools", "GPUArrays", "GPUCompiler", "GPUToolbox", "KernelAbstractions", "LLVM", "LLVMLoopInfo", "LazyArtifacts", "Libdl", "LinearAlgebra", "Logging", "NVTX", "Preferences", "PrettyTables", "Printf", "Random", "Random123", "RandomNumbers", "Reexport", "Requires", "SparseArrays", "StaticArrays", "Statistics", "demumble_jll"] +git-tree-sha1 = "27f69b3923e58730f0a71396070e9114fc0bba40" +uuid = "052768ef-5323-5732-b1bb-66c8b64840ba" +version = "5.8.3" + + [deps.CUDA.extensions] + ChainRulesCoreExt = "ChainRulesCore" + EnzymeCoreExt = "EnzymeCore" + SparseMatricesCSRExt = "SparseMatricesCSR" + SpecialFunctionsExt = "SpecialFunctions" + + [deps.CUDA.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + SparseMatricesCSR = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1" + SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" + +[[deps.CUDA_Compiler_jll]] +deps = ["Artifacts", "CUDA_Driver_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"] +git-tree-sha1 = "144046baf05523e2e8510505d45e50fe5d18feef" +uuid = "d1e2174e-dfdc-576e-b43e-73b79eb1aca8" +version = "0.2.0+0" + +[[deps.CUDA_Driver_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "12621de83838b5ce6a185050db5a184f4540679b" +uuid = "4ee394cb-3365-5eb0-8335-949819d2adfc" +version = "13.0.0+0" + +[[deps.CUDA_Runtime_Discovery]] +deps = ["Libdl"] +git-tree-sha1 = "f9a521f52d236fe49f1028d69e549e7f2644bb72" +uuid = "1af6417a-86b4-443c-805f-a4643ffb695f" +version = "1.0.0" + +[[deps.CUDA_Runtime_jll]] +deps = ["Artifacts", "CUDA_Driver_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"] +git-tree-sha1 = "cc727d90c9769db27945219f9ba149dbddc74f06" +uuid = "76a88914-d11a-5bdc-97e0-2f5a05c973a2" +version = "0.19.0+0" [[deps.Cairo_jll]] deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "a2f1c8c668c8e3cb4cca4e57a8efdb09067bb3fd" +git-tree-sha1 = "fde3bf89aead2e723284a8ff9cdf5b551ed700e8" uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.18.0+2" +version = "1.18.5+0" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra"] -git-tree-sha1 = "71acdbf594aab5bbb2cec89b208c41b4c411e49f" +git-tree-sha1 = "06ee8d1aa558d2833aa799f6f0b31b30cada405f" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.24.0" +version = "1.25.2" weakdeps = ["SparseArrays"] [deps.ChainRulesCore.extensions] @@ -59,27 +150,31 @@ weakdeps = ["SparseArrays"] [[deps.CodecZlib]] deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759" +git-tree-sha1 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.6" +version = "0.7.8" [[deps.ColorSchemes]] deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] -git-tree-sha1 = "b5278586822443594ff615963b0c09755771b3e0" +git-tree-sha1 = "a656525c8b46aa6a1c76891552ed5381bb32ae7b" uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.26.0" +version = "3.30.0" [[deps.ColorTypes]] deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d" +git-tree-sha1 = "67e11ee83a43eb71ddc950302c53bf33f0690dfe" uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.11.5" +version = "0.12.1" +weakdeps = ["StyledStrings"] + + [deps.ColorTypes.extensions] + StyledStringsExt = "StyledStrings" [[deps.ColorVectorSpace]] deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"] -git-tree-sha1 = "a1f44953f2382ebb937d60dafbe2deea4bd23249" +git-tree-sha1 = "8b3b6f87ce8f65a2b4f857528fd8d70086cd72b1" uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" -version = "0.10.0" +version = "0.11.0" weakdeps = ["SpecialFunctions"] [deps.ColorVectorSpace.extensions] @@ -87,15 +182,15 @@ weakdeps = ["SpecialFunctions"] [[deps.Colors]] deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] -git-tree-sha1 = "362a287c3aa50601b0bc359053d5c2468f0e7ce0" +git-tree-sha1 = "37ea44092930b1811e666c3bc38065d7d87fcc74" uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" -version = "0.12.11" +version = "0.13.1" [[deps.Compat]] deps = ["TOML", "UUIDs"] -git-tree-sha1 = "8ae8d32e09f0dcf42a36b90d4e17f5dd2e4c4215" +git-tree-sha1 = "0037835448781bb46feb39866934e243886d756a" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.16.0" +version = "4.18.0" weakdeps = ["Dates", "LinearAlgebra"] [deps.Compat.extensions] @@ -104,39 +199,56 @@ weakdeps = ["Dates", "LinearAlgebra"] [[deps.CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "1.1.0+0" +version = "1.1.1+0" [[deps.ConcurrentUtilities]] deps = ["Serialization", "Sockets"] -git-tree-sha1 = "ea32b83ca4fefa1768dc84e504cc0a94fb1ab8d1" +git-tree-sha1 = "d9d26935a0bcffc87d2613ce14c527c99fc543fd" uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" -version = "2.4.2" +version = "2.5.0" [[deps.Contour]] git-tree-sha1 = "439e35b0b36e2e5881738abc8857bd92ad6ff9a8" uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" version = "0.6.3" +[[deps.Crayons]] +git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" +uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" +version = "4.1.1" + [[deps.DataAPI]] git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" version = "1.16.0" +[[deps.DataFrames]] +deps = ["Compat", "DataAPI", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SentinelArrays", "SnoopPrecompile", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] +git-tree-sha1 = "aa51303df86f8626a962fccb878430cdb0a97eee" +uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +version = "1.5.0" + [[deps.DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" +deps = ["OrderedCollections"] +git-tree-sha1 = "76b3b7c3925d943edf158ddb7f693ba54eb297a5" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.20" +version = "0.19.0" + +[[deps.DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" [[deps.Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" +version = "1.11.0" [[deps.Dbus_jll]] deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "fc173b380865f70627d7dd1190dc2fce6cc105af" +git-tree-sha1 = "473e9afc9cf30814eb67ffa5f2db7df82c3ad9fd" uuid = "ee1fde0b-3d02-5ea6-8484-8dfef6360eab" -version = "1.14.10+0" +version = "1.16.2+0" [[deps.DelimitedFiles]] deps = ["Mmap"] @@ -147,12 +259,12 @@ version = "1.9.1" [[deps.Distributed]] deps = ["Random", "Serialization", "Sockets"] uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" +version = "1.11.0" [[deps.DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" +git-tree-sha1 = "7442a5dfe1ebb773c29cc2962a8980f47221d76c" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.9.3" +version = "0.9.5" [[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] @@ -161,36 +273,42 @@ version = "1.6.0" [[deps.EpollShim_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "8e9441ee83492030ace98f9789a654a6d0b1f643" +git-tree-sha1 = "8a4be429317c42cfae6a7fc03c31bad1970c310d" uuid = "2702e6a9-849d-5ed8-8c21-79e8b8f9ee43" -version = "0.0.20230411+0" +version = "0.0.20230411+1" [[deps.ExceptionUnwrapping]] deps = ["Test"] -git-tree-sha1 = "dcb08a0d93ec0b1cdc4af184b26b591e9695423a" +git-tree-sha1 = "d36f682e590a83d63d1c7dbd287573764682d12a" uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4" -version = "0.1.10" +version = "0.1.11" [[deps.Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1c6317308b9dc757616f0b5cb379db10494443a7" +git-tree-sha1 = "d55dffd9ae73ff72f1c0482454dcf2ec6c6c4a63" uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.6.2+0" +version = "2.6.5+0" + +[[deps.ExprTools]] +git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec" +uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" +version = "0.1.10" [[deps.FFMPEG]] deps = ["FFMPEG_jll"] -git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +git-tree-sha1 = "83dc665d0312b41367b7263e8a4d172eac1897f4" uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" -version = "0.4.1" +version = "0.4.4" [[deps.FFMPEG_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "466d45dc38e15794ec7d5d63ec03d776a9aff36e" +git-tree-sha1 = "3a948313e7a41eb1db7a1e733e6335f17b4ab3c4" uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "4.4.4+1" +version = "7.1.1+0" [[deps.FileWatching]] uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" +version = "1.11.0" [[deps.FixedPointNumbers]] deps = ["Statistics"] @@ -200,9 +318,9 @@ version = "0.8.5" [[deps.Fontconfig_jll]] deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Zlib_jll"] -git-tree-sha1 = "db16beca600632c95fc8aca29890d83788dd8b23" +git-tree-sha1 = "301b5d5d731a0654825f1f2e906990f7141a106b" uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" -version = "2.13.96+0" +version = "2.16.0+0" [[deps.Format]] git-tree-sha1 = "9c68794ef81b08086aeb32eeaf33531668d5f5fc" @@ -211,51 +329,80 @@ version = "1.3.7" [[deps.FreeType2_jll]] deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "5c1d8ae0efc6c2e7b1fc502cbe25def8f661b7bc" +git-tree-sha1 = "2c5512e11c791d1baed2049c5652441b28fc6a31" uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" -version = "2.13.2+0" +version = "2.13.4+0" [[deps.FriBidi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1ed150b39aebcc805c26b93a8d0122c940f64ce2" +git-tree-sha1 = "7a214fdac5ed5f59a22c2d9a885a16da1c74bbc7" uuid = "559328eb-81f9-559d-9380-de523a88c83c" -version = "1.0.14+0" +version = "1.0.17+0" + +[[deps.Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" +version = "1.11.0" [[deps.GLFW_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll", "libdecor_jll", "xkbcommon_jll"] -git-tree-sha1 = "532f9126ad901533af1d4f5c198867227a7bb077" +git-tree-sha1 = "fcb0584ff34e25155876418979d4c8971243bb89" uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" -version = "3.4.0+1" +version = "3.4.0+2" + +[[deps.GPUArrays]] +deps = ["Adapt", "GPUArraysCore", "KernelAbstractions", "LLVM", "LinearAlgebra", "Printf", "Random", "Reexport", "ScopedValues", "Serialization", "Statistics"] +git-tree-sha1 = "be941842a40b6daac98496994ea69054ba4c5144" +uuid = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7" +version = "11.2.3" + +[[deps.GPUArraysCore]] +deps = ["Adapt"] +git-tree-sha1 = "83cf05ab16a73219e5f6bd1bdfa9848fa24ac627" +uuid = "46192b85-c4d5-4398-a991-12ede77f4527" +version = "0.2.0" + +[[deps.GPUCompiler]] +deps = ["ExprTools", "InteractiveUtils", "LLVM", "Libdl", "Logging", "PrecompileTools", "Preferences", "Scratch", "Serialization", "TOML", "Tracy", "UUIDs"] +git-tree-sha1 = "eb1e212e12cc058fa16712082d44be499d23638c" +uuid = "61eb1bfa-7361-4325-ad38-22787b887f55" +version = "1.6.1" + +[[deps.GPUToolbox]] +deps = ["LLVM"] +git-tree-sha1 = "5bfe837129bf49e2e049b4f1517546055cc16a93" +uuid = "096a3bc2-3ced-46d0-87f4-dd12716f4bfc" +version = "0.3.0" [[deps.GR]] deps = ["Artifacts", "Base64", "DelimitedFiles", "Downloads", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Preferences", "Printf", "Qt6Wayland_jll", "Random", "Serialization", "Sockets", "TOML", "Tar", "Test", "p7zip_jll"] -git-tree-sha1 = "629693584cef594c3f6f99e76e7a7ad17e60e8d5" +git-tree-sha1 = "1828eb7275491981fa5f1752a5e126e8f26f8741" uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" -version = "0.73.7" +version = "0.73.17" [[deps.GR_jll]] deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "FreeType2_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Qt6Base_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "a8863b69c2a0859f2c2c87ebdc4c6712e88bdf0d" +git-tree-sha1 = "27299071cc29e409488ada41ec7643e0ab19091f" uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" -version = "0.73.7+0" +version = "0.73.17+0" -[[deps.Gettext_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" -uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" -version = "0.21.0+0" +[[deps.GettextRuntime_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll"] +git-tree-sha1 = "45288942190db7c5f760f59c04495064eedf9340" +uuid = "b0724c58-0f36-5564-988d-3bb0596ebc4a" +version = "0.22.4+0" [[deps.Glib_jll]] -deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] -git-tree-sha1 = "7c82e6a6cd34e9d935e9aa4051b66c6ff3af59ba" +deps = ["Artifacts", "GettextRuntime_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] +git-tree-sha1 = "35fbd0cefb04a516104b8e183ce0df11b70a3f1a" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.80.2+0" +version = "2.84.3+0" [[deps.Graphite2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "8a6dbda1fd736d60cc477d99f2e7a042acfa46e8" uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" -version = "1.3.14+0" +version = "1.3.15+0" [[deps.Grisu]] git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" @@ -263,47 +410,80 @@ uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" version = "1.0.2" [[deps.HTTP]] -deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] -git-tree-sha1 = "d1d712be3164d61d1fb98e7ce9bcbc6cc06b45ed" +deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "PrecompileTools", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] +git-tree-sha1 = "ed5e9c58612c4e081aecdb6e1a479e18462e041e" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "1.10.8" +version = "1.10.17" [[deps.HarfBuzz_jll]] -deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] -git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll"] +git-tree-sha1 = "f923f9a774fcf3f5cb761bfa43aeadd689714813" uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" -version = "2.8.1+1" +version = "8.5.1+0" + +[[deps.HashArrayMappedTries]] +git-tree-sha1 = "2eaa69a7cab70a52b9687c8bf950a5a93ec895ae" +uuid = "076d061b-32b6-4027-95e0-9a2c6f6d7e74" +version = "0.2.0" + +[[deps.InlineStrings]] +git-tree-sha1 = "8594fac023c5ce1ef78260f24d1ad18b4327b420" +uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" +version = "1.4.4" + + [deps.InlineStrings.extensions] + ArrowTypesExt = "ArrowTypes" + ParsersExt = "Parsers" + + [deps.InlineStrings.weakdeps] + ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" + Parsers = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" [[deps.InteractiveUtils]] deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +version = "1.11.0" [[deps.Interpolations]] deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] -git-tree-sha1 = "88a101217d7cb38a7b481ccd50d21876e1d1b0e0" +git-tree-sha1 = "f2905febca224eade352a573e129ef43aa593354" uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" -version = "0.15.1" -weakdeps = ["Unitful"] +version = "0.16.1" [deps.Interpolations.extensions] + InterpolationsForwardDiffExt = "ForwardDiff" InterpolationsUnitfulExt = "Unitful" + [deps.Interpolations.weakdeps] + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + +[[deps.InvertedIndices]] +git-tree-sha1 = "6da3c4316095de0f5ee2ebd875df8721e7e0bdbe" +uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" +version = "1.3.1" + [[deps.IrrationalConstants]] -git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" +git-tree-sha1 = "e2222959fbc6c19554dc15174c81bf7bf3aa691c" uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.2.2" +version = "0.2.4" + +[[deps.IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" [[deps.JLFzf]] -deps = ["Pipe", "REPL", "Random", "fzf_jll"] -git-tree-sha1 = "39d64b09147620f5ffbf6b2d3255be3c901bec63" +deps = ["REPL", "Random", "fzf_jll"] +git-tree-sha1 = "82f7acdc599b65e0f8ccd270ffa1467c21cb647b" uuid = "1019f520-868f-41f5-a6de-eb00f4b6a39c" -version = "0.1.8" +version = "0.1.11" [[deps.JLLWrappers]] deps = ["Artifacts", "Preferences"] -git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca" +git-tree-sha1 = "0533e564aae234aff59ab625543145446d8b6ec2" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.5.0" +version = "1.7.1" [[deps.JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] @@ -313,9 +493,31 @@ version = "0.21.4" [[deps.JpegTurbo_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "c84a835e1a09b289ffcd2271bf2a337bbdda6637" +git-tree-sha1 = "eac1206917768cb54957c65a615460d87b455fc1" uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "3.0.3+0" +version = "3.1.1+0" + +[[deps.JuliaNVTXCallbacks_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "af433a10f3942e882d3c671aacb203e006a5808f" +uuid = "9c1d0b0a-7046-5b2e-a33f-ea22f176ac7e" +version = "0.2.1+0" + +[[deps.KernelAbstractions]] +deps = ["Adapt", "Atomix", "InteractiveUtils", "MacroTools", "PrecompileTools", "Requires", "StaticArrays", "UUIDs"] +git-tree-sha1 = "83c617e9e9b02306a7acab79e05ec10253db7c87" +uuid = "63c18a36-062a-441e-b654-da1e3ab1ce7c" +version = "0.9.38" + + [deps.KernelAbstractions.extensions] + EnzymeExt = "EnzymeCore" + LinearAlgebraExt = "LinearAlgebra" + SparseArraysExt = "SparseArrays" + + [deps.KernelAbstractions.weakdeps] + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [[deps.Kronecker]] deps = ["LinearAlgebra", "NamedDims", "SparseArrays", "StatsBase"] @@ -325,48 +527,76 @@ version = "0.5.5" [[deps.LAME_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "170b660facf5df5de098d866564877e119141cbd" +git-tree-sha1 = "059aabebaa7c82ccb853dd4a0ee9d17796f7e1bc" uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" -version = "3.100.2+0" +version = "3.100.3+0" [[deps.LERC_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "aaafe88dccbd957a8d82f7d05be9b69172e0cee3" uuid = "88015f11-f218-50d7-93a8-a6af411a945d" -version = "3.0.0+1" +version = "4.0.1+0" + +[[deps.LLVM]] +deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Preferences", "Printf", "Unicode"] +git-tree-sha1 = "9c7c721cfd800d87d48c745d8bfb65144f0a91df" +uuid = "929cbde3-209d-540e-8aea-75f648917ca0" +version = "9.4.2" +weakdeps = ["BFloat16s"] + + [deps.LLVM.extensions] + BFloat16sExt = "BFloat16s" + +[[deps.LLVMExtra_jll]] +deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"] +git-tree-sha1 = "2ea068aac1e7f0337d381b0eae3110581e3f3216" +uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab" +version = "0.0.37+2" + +[[deps.LLVMLoopInfo]] +git-tree-sha1 = "2e5c102cfc41f48ae4740c7eca7743cc7e7b75ea" +uuid = "8b046642-f1f6-4319-8d3c-209ddc03c586" +version = "1.0.0" [[deps.LLVMOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e16271d212accd09d52ee0ae98956b8a05c4b626" +git-tree-sha1 = "eb62a3deb62fc6d8822c0c4bef73e4412419c5d8" uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" -version = "17.0.6+0" +version = "18.1.8+0" [[deps.LZO_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "70c5da094887fd2cae843b8db33920bac4b6f07d" +git-tree-sha1 = "1c602b1127f4751facb671441ca72715cc95938a" uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" -version = "2.10.2+0" +version = "2.10.3+0" [[deps.LaTeXStrings]] -git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec" +git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c" uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" -version = "1.3.1" +version = "1.4.0" [[deps.Latexify]] deps = ["Format", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Requires"] -git-tree-sha1 = "ce5f5621cac23a86011836badfedf664a612cee4" +git-tree-sha1 = "4f34eaabe49ecb3fb0d58d6015e32fd31a733199" uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.16.5" +version = "0.16.8" [deps.Latexify.extensions] DataFramesExt = "DataFrames" SparseArraysExt = "SparseArrays" SymEngineExt = "SymEngine" + TectonicExt = "tectonic_jll" [deps.Latexify.weakdeps] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8" + tectonic_jll = "d7dd28d6-a5e6-559c-9131-7eb760cdacc5" + +[[deps.LazyArtifacts]] +deps = ["Artifacts", "Pkg"] +uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" +version = "1.11.0" [[deps.LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] @@ -376,82 +606,79 @@ version = "0.6.4" [[deps.LibCURL_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.4.0+0" +version = "8.6.0+0" [[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.6.4+0" +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.LibTracyClient_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "d2bc4e1034b2d43076b50f0e34ea094c2cb0a717" +uuid = "ad6e5548-8b26-5c9f-8ef3-ef0ad883f3a5" +version = "0.9.1+6" + [[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +version = "1.11.0" [[deps.Libffi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "c8da7e6a91781c41a863611c7e966098d783c57a" uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" -version = "3.2.2+1" - -[[deps.Libgcrypt_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll"] -git-tree-sha1 = "9fd170c4bbfd8b935fdc5f8b7aa33532c991a673" -uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" -version = "1.8.11+0" +version = "3.4.7+0" [[deps.Libglvnd_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] -git-tree-sha1 = "6f73d1dd803986947b2c750138528a999a6c7733" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll", "Xorg_libXext_jll"] +git-tree-sha1 = "d36c21b9e7c172a44a10484125024495e2625ac0" uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" -version = "1.6.0+0" - -[[deps.Libgpg_error_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "fbb1f2bef882392312feb1ede3615ddc1e9b99ed" -uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" -version = "1.49.0+0" +version = "1.7.1+1" [[deps.Libiconv_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "f9557a255370125b405568f9767d6d195822a175" +git-tree-sha1 = "be484f5c92fad0bd8acfef35fe017900b0b73809" uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.17.0+0" +version = "1.18.0+0" [[deps.Libmount_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "0c4f9c4f1a50d8f35048fa0532dabbadf702f81e" +git-tree-sha1 = "a31572773ac1b745e0343fe5e2c8ddda7a37e997" uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" -version = "2.40.1+0" +version = "2.41.0+0" [[deps.Libtiff_jll]] deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "2da088d113af58221c52828a80378e16be7d037a" +git-tree-sha1 = "4ab7581296671007fc33f07a721631b8855f4b1d" uuid = "89763e89-9b03-5906-acba-b20f662cd828" -version = "4.5.1+1" +version = "4.7.1+0" [[deps.Libuuid_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "5ee6203157c120d79034c748a2acba45b82b8807" +git-tree-sha1 = "321ccef73a96ba828cd51f2ab5b9f917fa73945a" uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" -version = "2.40.1+0" +version = "2.41.0+0" [[deps.LinearAlgebra]] deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +version = "1.11.0" [[deps.LogExpFunctions]] deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "a2d09619db4e765091ee5c6ffe8872849de0feea" +git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.28" +version = "0.3.29" [deps.LogExpFunctions.extensions] LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" @@ -465,22 +692,23 @@ version = "0.3.28" [[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" +version = "1.11.0" [[deps.LoggingExtras]] deps = ["Dates", "Logging"] -git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075" +git-tree-sha1 = "f02b56007b064fbfddb4c9cd60161b6dd0f40df3" uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" -version = "1.0.3" +version = "1.1.0" [[deps.MacroTools]] -deps = ["Markdown", "Random"] -git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" +git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.13" +version = "0.5.16" [[deps.Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +version = "1.11.0" [[deps.MbedTLS]] deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] @@ -491,7 +719,7 @@ version = "1.1.9" [[deps.MbedTLS_jll]] deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.2+1" +version = "2.28.6+0" [[deps.Measures]] git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102" @@ -506,22 +734,35 @@ version = "1.2.0" [[deps.Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" +version = "1.11.0" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2023.1.10" +version = "2023.12.12" + +[[deps.NVTX]] +deps = ["Colors", "JuliaNVTXCallbacks_jll", "Libdl", "NVTX_jll"] +git-tree-sha1 = "6b573a3e66decc7fc747afd1edbf083ff78c813a" +uuid = "5da4648a-3479-48b8-97b9-01cb529c0a1f" +version = "1.0.1" + +[[deps.NVTX_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "af2232f69447494514c25742ba1503ec7e9877fe" +uuid = "e98f9f5b-d649-5603-91fd-7774390e6439" +version = "3.2.2+0" [[deps.NaNMath]] deps = ["OpenLibm_jll"] -git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" +git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "1.0.2" +version = "1.1.3" [[deps.NamedDims]] -deps = ["LinearAlgebra", "Pkg", "Statistics"] -git-tree-sha1 = "90178dc801073728b8b2d0d8677d10909feb94d8" +deps = ["LinearAlgebra", "Statistics"] +git-tree-sha1 = "f9e4a49ecd1ea2eccfb749a506fa882c094152b4" uuid = "356022a1-0364-5f58-8944-0da4b18d706f" -version = "1.2.2" +version = "1.2.3" [deps.NamedDims.extensions] AbstractFFTsExt = "AbstractFFTs" @@ -541,24 +782,24 @@ uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" [[deps.OffsetArrays]] -git-tree-sha1 = "1a27764e945a152f7ca7efa04de513d473e9542e" +git-tree-sha1 = "117432e406b5c023f665fa73dc26e79ec3630151" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.14.1" +version = "1.17.0" weakdeps = ["Adapt"] [deps.OffsetArrays.extensions] OffsetArraysAdaptExt = "Adapt" [[deps.Ogg_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "b6aa4566bb7ae78498a5e68943863fa8b5231b59" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" -version = "1.3.5+1" +version = "1.3.6+0" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.23+4" +version = "0.3.27+1" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] @@ -567,32 +808,32 @@ version = "0.8.1+2" [[deps.OpenSSL]] deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] -git-tree-sha1 = "38cb508d080d21dc1128f7fb04f20387ed4c0af4" +git-tree-sha1 = "f1a7e086c677df53e064e0fdd2c9d0b0833e3f6e" uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" -version = "1.4.3" +version = "1.5.0" [[deps.OpenSSL_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "a028ee3cb5641cccc4c24e90c36b0a4f7707bdf5" +git-tree-sha1 = "2ae7d4ddec2e13ad3bddf5c0796f7547cf682391" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.0.14+0" +version = "3.5.2+0" [[deps.OpenSpecFun_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1346c9208249809840c91b26703912dff463d335" uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.5+0" +version = "0.5.6+0" [[deps.Opus_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "c392fc5dd032381919e3b22dd32d6443760ce7ea" uuid = "91d4177d-7536-5919-b921-800302f37372" -version = "1.3.2+0" +version = "1.5.2+0" [[deps.OrderedCollections]] -git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" +git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.6.3" +version = "1.8.1" [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] @@ -601,49 +842,48 @@ version = "10.42.0+1" [[deps.Pango_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "9dd97171646850ee607593965ce1f55063d8d3f9" +git-tree-sha1 = "275a9a6d85dc86c24d03d1837a0010226a96f540" uuid = "36c8627f-9965-5494-a995-c6b170f724f3" -version = "1.54.0+0" +version = "1.56.3+0" [[deps.Parsers]] deps = ["Dates", "PrecompileTools", "UUIDs"] -git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" +git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.8.1" - -[[deps.Pipe]] -git-tree-sha1 = "6842804e7867b115ca9de748a0cf6b364523c16d" -uuid = "b98c9c47-44ae-5843-9183-064241ee97a0" -version = "1.3.0" +version = "2.8.3" [[deps.Pixman_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"] -git-tree-sha1 = "35621f10a7531bc8fa58f74610b1bfb70a3cfc6b" +git-tree-sha1 = "db76b1ecd5e9715f3d043cec13b2ec93ce015d53" uuid = "30392449-352a-5448-841d-b1acce4e97dc" -version = "0.43.4+0" +version = "0.44.2+0" [[deps.Pkg]] -deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" -version = "1.10.0" +version = "1.11.0" +weakdeps = ["REPL"] + + [deps.Pkg.extensions] + REPLExt = "REPL" [[deps.PlotThemes]] deps = ["PlotUtils", "Statistics"] -git-tree-sha1 = "6e55c6841ce3411ccb3457ee52fc48cb698d6fb0" +git-tree-sha1 = "41031ef3a1be6f5bbbf3e8073f210556daeae5ca" uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" -version = "3.2.0" +version = "3.3.0" [[deps.PlotUtils]] -deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "Statistics"] -git-tree-sha1 = "7b1a9df27f072ac4c9c7cbe5efb198489258d1f5" +deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "StableRNGs", "Statistics"] +git-tree-sha1 = "3ca9a356cd2e113c420f2c13bea19f8d3fb1cb18" uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" -version = "1.4.1" +version = "1.4.3" [[deps.Plots]] deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "TOML", "UUIDs", "UnicodeFun", "UnitfulLatexify", "Unzip"] -git-tree-sha1 = "082f0c4b70c202c37784ce4bfbc33c9f437685bf" +git-tree-sha1 = "3db9167c618b290a05d4345ca70de6d95304a32a" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.40.5" +version = "1.40.17" [deps.Plots.extensions] FileIOExt = "FileIO" @@ -659,6 +899,12 @@ version = "1.40.5" ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +[[deps.PooledArrays]] +deps = ["DataAPI", "Future"] +git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" +uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" +version = "1.4.3" + [[deps.PrecompileTools]] deps = ["Preferences"] git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" @@ -671,41 +917,67 @@ git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" uuid = "21216c6a-2e73-6563-6e65-726566657250" version = "1.4.3" +[[deps.PrettyTables]] +deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"] +git-tree-sha1 = "1101cd475833706e4d0e7b122218257178f48f34" +uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" +version = "2.4.0" + [[deps.Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" +version = "1.11.0" + +[[deps.PtrArrays]] +git-tree-sha1 = "1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d" +uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" +version = "1.3.0" [[deps.Qt6Base_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Vulkan_Loader_jll", "Xorg_libSM_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_cursor_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "libinput_jll", "xkbcommon_jll"] -git-tree-sha1 = "492601870742dcd38f233b23c3ec629628c1d724" +git-tree-sha1 = "eb38d376097f47316fe089fc62cb7c6d85383a52" uuid = "c0090381-4147-56d7-9ebc-da0b1113ec56" -version = "6.7.1+1" +version = "6.8.2+1" [[deps.Qt6Declarative_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Qt6Base_jll", "Qt6ShaderTools_jll"] -git-tree-sha1 = "e5dd466bf2569fe08c91a2cc29c1003f4797ac3b" +git-tree-sha1 = "da7adf145cce0d44e892626e647f9dcbe9cb3e10" uuid = "629bc702-f1f5-5709-abd5-49b8460ea067" -version = "6.7.1+2" +version = "6.8.2+1" [[deps.Qt6ShaderTools_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Qt6Base_jll"] -git-tree-sha1 = "1a180aeced866700d4bebc3120ea1451201f16bc" +git-tree-sha1 = "9eca9fc3fe515d619ce004c83c31ffd3f85c7ccf" uuid = "ce943373-25bb-56aa-8eca-768745ed7b5a" -version = "6.7.1+1" +version = "6.8.2+1" [[deps.Qt6Wayland_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Qt6Base_jll", "Qt6Declarative_jll"] -git-tree-sha1 = "729927532d48cf79f49070341e1d918a65aba6b0" +git-tree-sha1 = "e1d5e16d0f65762396f9ca4644a5f4ddab8d452b" uuid = "e99dba38-086e-5de3-a5b1-6e4c66e897c3" -version = "6.7.1+1" +version = "6.8.2+1" [[deps.REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +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.Random123]] +deps = ["Random", "RandomNumbers"] +git-tree-sha1 = "dbe5fd0b334694e905cb9fda73cd8554333c46e2" +uuid = "74087812-796a-5b5d-8853-05524746bad3" +version = "1.7.1" + +[[deps.RandomNumbers]] +deps = ["Random"] +git-tree-sha1 = "c6ec94d2aaba1ab2ff983052cf6a606ca5985902" +uuid = "e6cf234a-135c-5ec9-84dd-332b85af5143" +version = "1.6.0" [[deps.Ratios]] deps = ["Requires"] @@ -742,26 +1014,40 @@ version = "1.0.1" [[deps.Requires]] deps = ["UUIDs"] -git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64" uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.3.0" +version = "1.3.1" [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" version = "0.7.0" +[[deps.ScopedValues]] +deps = ["HashArrayMappedTries", "Logging"] +git-tree-sha1 = "7f44eef6b1d284465fafc66baf4d9bdcc239a15b" +uuid = "7e506255-f358-4e82-b7e4-beb19740aa63" +version = "1.4.0" + [[deps.Scratch]] deps = ["Dates"] -git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386" +git-tree-sha1 = "9b81b8393e50b7d4e6d0a9f14e192294d3b7c109" uuid = "6c6a2e73-6563-6170-7368-637461726353" -version = "1.2.1" +version = "1.3.0" + +[[deps.SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "712fb0231ee6f9120e005ccd56297abbc053e7e0" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.4.8" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +version = "1.11.0" [[deps.SharedArrays]] deps = ["Distributed", "Mmap", "Random", "Serialization"] uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" +version = "1.11.0" [[deps.Showoff]] deps = ["Dates", "Grisu"] @@ -770,45 +1056,58 @@ uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" version = "1.0.3" [[deps.SimpleBufferStream]] -git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" +git-tree-sha1 = "f305871d2f381d21527c770d4788c06c097c9bc1" uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" -version = "1.1.0" +version = "1.2.0" + +[[deps.SnoopPrecompile]] +deps = ["Preferences"] +git-tree-sha1 = "e760a70afdcd461cf01a575947738d359234665c" +uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" +version = "1.0.3" [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +version = "1.11.0" [[deps.SortingAlgorithms]] deps = ["DataStructures"] -git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085" +git-tree-sha1 = "64d974c2e6fdf07f8155b5b2ca2ffa9069b608d9" uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" -version = "1.2.1" +version = "1.2.2" [[deps.SparseArrays]] deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -version = "1.10.0" +version = "1.11.0" [[deps.SpatiotemporalGPs]] deps = ["Interpolations", "Kronecker", "LinearAlgebra", "RecipesBase", "Reexport", "SpecialFunctions", "StaticArrays"] path = ".." uuid = "73b3b457-46a4-4dae-aece-b1ff83e37843" -version = "1.0.0-DEV" +version = "1.0.1-DEV" [[deps.SpecialFunctions]] deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "2f5d4697f21388cbe1ff299430dd169ef97d7e14" +git-tree-sha1 = "41852b8679f78c8d8961eeadc8f62cef861a52e3" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.4.0" +version = "2.5.1" weakdeps = ["ChainRulesCore"] [deps.SpecialFunctions.extensions] SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" +[[deps.StableRNGs]] +deps = ["Random"] +git-tree-sha1 = "95af145932c2ed859b63329952ce8d633719f091" +uuid = "860ef19b-820b-49d6-a774-d7a799459cd3" +version = "1.0.3" + [[deps.StaticArrays]] deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] -git-tree-sha1 = "eeafab08ae20c62c44c8399ccb9354a04b80db50" +git-tree-sha1 = "cbea8a6bd7bed51b1619658dec70035e07b8502f" uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.9.7" +version = "1.9.14" weakdeps = ["ChainRulesCore", "Statistics"] [deps.StaticArrays.extensions] @@ -821,32 +1120,59 @@ uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" version = "1.4.3" [[deps.Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] +deps = ["LinearAlgebra"] +git-tree-sha1 = "ae3bb1eb3bba077cd276bc5cfc337cc65c3075c0" uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -version = "1.10.0" +version = "1.11.1" +weakdeps = ["SparseArrays"] + + [deps.Statistics.extensions] + SparseArraysExt = ["SparseArrays"] [[deps.StatsAPI]] deps = ["LinearAlgebra"] -git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed" +git-tree-sha1 = "9d72a13a3f4dd3795a195ac5a44d7d6ff5f552ff" uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.7.0" +version = "1.7.1" [[deps.StatsBase]] -deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "5cf7606d6cef84b543b483848d4ae08ad9832b21" +deps = ["AliasTables", "DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "2c962245732371acd51700dbb268af311bddd719" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.34.3" +version = "0.34.6" + +[[deps.StringManipulation]] +deps = ["PrecompileTools"] +git-tree-sha1 = "725421ae8e530ec29bcbdddbe91ff8053421d023" +uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" +version = "0.4.1" + +[[deps.StyledStrings]] +uuid = "f489334b-da3d-4c2e-b8f0-e476e12c162b" +version = "1.11.0" [[deps.SuiteSparse_jll]] deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.2.1+1" +version = "7.7.0+0" [[deps.TOML]] deps = ["Dates"] uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" version = "1.0.3" +[[deps.TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[deps.Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "OrderedCollections", "TableTraits"] +git-tree-sha1 = "f2c1efbc8f3a609aadf318094f8fc5204bdaf344" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.12.1" + [[deps.Tar]] deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" @@ -861,23 +1187,38 @@ version = "0.1.1" [[deps.Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +version = "1.11.0" + +[[deps.Tracy]] +deps = ["ExprTools", "LibTracyClient_jll", "Libdl"] +git-tree-sha1 = "91dbaee0f50faa4357f7e9fc69442c7b6364dfe5" +uuid = "e689c965-62c8-4b79-b2c5-8359227902fd" +version = "0.1.5" + + [deps.Tracy.extensions] + TracyProfilerExt = "TracyProfiler_jll" + + [deps.Tracy.weakdeps] + TracyProfiler_jll = "0c351ed6-8a68-550e-8b79-de6f926da83c" [[deps.TranscodingStreams]] -git-tree-sha1 = "e84b3a11b9bece70d14cce63406bbc79ed3464d2" +git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742" uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" -version = "0.11.2" +version = "0.11.3" [[deps.URIs]] -git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" +git-tree-sha1 = "bef26fb046d031353ef97a82e3fdb6afe7f21b1a" uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.5.1" +version = "1.6.1" [[deps.UUIDs]] deps = ["Random", "SHA"] uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" +version = "1.11.0" [[deps.Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" +version = "1.11.0" [[deps.UnicodeFun]] deps = ["REPL"] @@ -887,23 +1228,36 @@ version = "0.4.1" [[deps.Unitful]] deps = ["Dates", "LinearAlgebra", "Random"] -git-tree-sha1 = "d95fe458f26209c66a187b1114df96fd70839efd" +git-tree-sha1 = "6258d453843c466d84c17a58732dda5deeb8d3af" uuid = "1986cc42-f94f-5a68-af5c-568840ba703d" -version = "1.21.0" +version = "1.24.0" [deps.Unitful.extensions] ConstructionBaseUnitfulExt = "ConstructionBase" + ForwardDiffExt = "ForwardDiff" InverseFunctionsUnitfulExt = "InverseFunctions" + PrintfExt = "Printf" [deps.Unitful.weakdeps] ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" [[deps.UnitfulLatexify]] deps = ["LaTeXStrings", "Latexify", "Unitful"] -git-tree-sha1 = "975c354fcd5f7e1ddcc1f1a23e6e091d99e99bc8" +git-tree-sha1 = "af305cc62419f9bd61b6644d19170a4d258c7967" uuid = "45397f5d-5981-4c77-b2b3-fc36d6e9b728" -version = "1.6.4" +version = "1.7.0" + +[[deps.UnsafeAtomics]] +git-tree-sha1 = "b13c4edda90890e5b04ba24e20a310fbe6f249ff" +uuid = "013be700-e6cd-48c3-b4a1-df204f14c38f" +version = "0.3.0" +weakdeps = ["LLVM"] + + [deps.UnsafeAtomics.extensions] + UnsafeAtomicsLLVM = ["LLVM"] [[deps.Unzip]] git-tree-sha1 = "ca0969166a028236229f63514992fc073799bb78" @@ -917,16 +1271,10 @@ uuid = "a44049a8-05dd-5a78-86c9-5fde0876e88c" version = "1.3.243+0" [[deps.Wayland_jll]] -deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "7558e29847e99bc3f04d6569e82d0f5c54460703" +deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll"] +git-tree-sha1 = "96478df35bbc2f3e1e791bc7a3d0eeee559e60e9" uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" -version = "1.21.0+1" - -[[deps.Wayland_protocols_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "93f43ab61b16ddfb2fd3bb13b3ce241cafb0e6c9" -uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" -version = "1.31.0+0" +version = "1.24.0+0" [[deps.WoodburyMatrices]] deps = ["LinearAlgebra", "SparseArrays"] @@ -934,167 +1282,149 @@ git-tree-sha1 = "c1a7aa6219628fcd757dede0ca95e245c5cd9511" uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" version = "1.0.0" -[[deps.XML2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] -git-tree-sha1 = "1165b0443d0eca63ac1e32b8c0eb69ed2f4f8127" -uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.13.3+0" - -[[deps.XSLT_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "XML2_jll", "Zlib_jll"] -git-tree-sha1 = "a54ee957f4c86b526460a720dbc882fa5edcbefc" -uuid = "aed1982a-8fda-507f-9586-7b0439959a61" -version = "1.1.41+0" - [[deps.XZ_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "ac88fb95ae6447c8dda6a5503f3bafd496ae8632" +git-tree-sha1 = "fee71455b0aaa3440dfdd54a9a36ccef829be7d4" uuid = "ffd25f8a-64ca-5728-b0f7-c24cf3aae800" -version = "5.4.6+0" +version = "5.8.1+0" [[deps.Xorg_libICE_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "326b4fea307b0b39892b3e85fa451692eda8d46c" +git-tree-sha1 = "a3ea76ee3f4facd7a64684f9af25310825ee3668" uuid = "f67eecfb-183a-506d-b269-f58e52b52d7c" -version = "1.1.1+0" +version = "1.1.2+0" [[deps.Xorg_libSM_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libICE_jll"] -git-tree-sha1 = "3796722887072218eabafb494a13c963209754ce" +git-tree-sha1 = "9c7ad99c629a44f81e7799eb05ec2746abb5d588" uuid = "c834827a-8449-5923-a945-d239c165b7dd" -version = "1.2.4+0" +version = "1.2.6+0" [[deps.Xorg_libX11_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] -git-tree-sha1 = "afead5aba5aa507ad5a3bf01f58f82c8d1403495" +git-tree-sha1 = "b5899b25d17bf1889d25906fb9deed5da0c15b3b" uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" -version = "1.8.6+0" +version = "1.8.12+0" [[deps.Xorg_libXau_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6035850dcc70518ca32f012e46015b9beeda49d8" +git-tree-sha1 = "aa1261ebbac3ccc8d16558ae6799524c450ed16b" uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" -version = "1.0.11+0" +version = "1.0.13+0" [[deps.Xorg_libXcursor_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "6c74ca84bbabc18c4547014765d194ff0b4dc9da" uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" -version = "1.2.0+4" +version = "1.2.4+0" [[deps.Xorg_libXdmcp_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "34d526d318358a859d7de23da945578e8e8727b7" +git-tree-sha1 = "52858d64353db33a56e13c341d7bf44cd0d7b309" uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" -version = "1.1.4+0" +version = "1.1.6+0" [[deps.Xorg_libXext_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "d2d1a5c49fae4ba39983f63de6afcbea47194e85" +git-tree-sha1 = "a4c0ee07ad36bf8bbce1c3bb52d21fb1e0b987fb" uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" -version = "1.3.6+0" +version = "1.3.7+0" [[deps.Xorg_libXfixes_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] +git-tree-sha1 = "9caba99d38404b285db8801d5c45ef4f4f425a6d" uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" -version = "5.0.3+4" +version = "6.0.1+0" [[deps.Xorg_libXi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] -git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] +git-tree-sha1 = "a376af5c7ae60d29825164db40787f15c80c7c54" uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" -version = "1.7.10+4" +version = "1.8.3+0" [[deps.Xorg_libXinerama_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] -git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll"] +git-tree-sha1 = "a5bc75478d323358a90dc36766f3c99ba7feb024" uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" -version = "1.1.4+4" +version = "1.1.6+0" [[deps.Xorg_libXrandr_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "aff463c82a773cb86061bce8d53a0d976854923e" uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" -version = "1.5.2+4" +version = "1.5.5+0" [[deps.Xorg_libXrender_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "47e45cd78224c53109495b3e324df0c37bb61fbe" +git-tree-sha1 = "7ed9347888fac59a618302ee38216dd0379c480d" uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" -version = "0.9.11+0" - -[[deps.Xorg_libpthread_stubs_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "8fdda4c692503d44d04a0603d9ac0982054635f9" -uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" -version = "0.1.1+0" +version = "0.9.12+0" [[deps.Xorg_libxcb_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] -git-tree-sha1 = "bcd466676fef0878338c61e655629fa7bbc69d8e" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXau_jll", "Xorg_libXdmcp_jll"] +git-tree-sha1 = "bfcaf7ec088eaba362093393fe11aa141fa15422" uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" -version = "1.17.0+0" +version = "1.17.1+0" [[deps.Xorg_libxkbfile_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "730eeca102434283c50ccf7d1ecdadf521a765a4" +git-tree-sha1 = "e3150c7400c41e207012b41659591f083f3ef795" uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" -version = "1.1.2+0" +version = "1.1.3+0" [[deps.Xorg_xcb_util_cursor_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_jll", "Xorg_xcb_util_renderutil_jll"] -git-tree-sha1 = "04341cb870f29dcd5e39055f895c39d016e18ccd" +git-tree-sha1 = "c5bf2dad6a03dfef57ea0a170a1fe493601603f2" uuid = "e920d4aa-a673-5f3a-b3d7-f755a4d47c43" -version = "0.1.4+0" +version = "0.1.5+0" [[deps.Xorg_xcb_util_image_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] +git-tree-sha1 = "f4fc02e384b74418679983a97385644b67e1263b" uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" -version = "0.4.0+1" +version = "0.4.1+0" [[deps.Xorg_xcb_util_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] -git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll"] +git-tree-sha1 = "68da27247e7d8d8dafd1fcf0c3654ad6506f5f97" uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" -version = "0.4.0+1" +version = "0.4.1+0" [[deps.Xorg_xcb_util_keysyms_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] +git-tree-sha1 = "44ec54b0e2acd408b0fb361e1e9244c60c9c3dd4" uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" -version = "0.4.0+1" +version = "0.4.1+0" [[deps.Xorg_xcb_util_renderutil_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] +git-tree-sha1 = "5b0263b6d080716a02544c55fdff2c8d7f9a16a0" uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" -version = "0.3.9+1" +version = "0.3.10+0" [[deps.Xorg_xcb_util_wm_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] +git-tree-sha1 = "f233c83cad1fa0e70b7771e0e21b061a116f2763" uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" -version = "0.4.1+1" +version = "0.4.2+0" [[deps.Xorg_xkbcomp_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxkbfile_jll"] -git-tree-sha1 = "330f955bc41bb8f5270a369c473fc4a5a4e4d3cb" +git-tree-sha1 = "801a858fc9fb90c11ffddee1801bb06a738bda9b" uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" -version = "1.4.6+0" +version = "1.4.7+0" [[deps.Xorg_xkeyboard_config_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xkbcomp_jll"] -git-tree-sha1 = "691634e5453ad362044e2ad653e79f3ee3bb98c3" +git-tree-sha1 = "00af7ebdc563c9217ecc67776d1bbf037dbcebf4" uuid = "33bec58e-1273-512f-9401-5d533626f822" -version = "2.39.0+0" +version = "2.44.0+0" [[deps.Xorg_xtrans_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e92a1a012a10506618f10b7047e478403a046c77" +git-tree-sha1 = "a63799ff68005991f9d9491b6e95bd3478d783cb" uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" -version = "1.5.0+0" +version = "1.6.0+0" [[deps.Zlib_jll]] deps = ["Libdl"] @@ -1103,44 +1433,44 @@ version = "1.2.13+1" [[deps.Zstd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e678132f07ddb5bfa46857f0d7620fb9be675d3b" +git-tree-sha1 = "446b23e73536f84e8037f5dce465e92275f6a308" uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" -version = "1.5.6+0" +version = "1.5.7+1" + +[[deps.demumble_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "6498e3581023f8e530f34760d18f75a69e3a4ea8" +uuid = "1e29f10c-031c-5a83-9565-69cddfc27673" +version = "1.3.0+0" [[deps.eudev_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "gperf_jll"] -git-tree-sha1 = "431b678a28ebb559d224c0b6b6d01afce87c51ba" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "c3b0e6196d50eab0c5ed34021aaa0bb463489510" uuid = "35ca27e7-8b34-5b7f-bca9-bdc33f59eb06" -version = "3.2.9+0" +version = "3.2.14+0" [[deps.fzf_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "936081b536ae4aa65415d869287d43ef3cb576b2" +git-tree-sha1 = "b6a34e0e0960190ac2a4363a1bd003504772d631" uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09" -version = "0.53.0+0" - -[[deps.gperf_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "3516a5630f741c9eecb3720b1ec9d8edc3ecc033" -uuid = "1a1c6b14-54f6-533d-8383-74cd7377aa70" -version = "3.1.1+0" +version = "0.61.1+0" [[deps.libaom_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1827acba325fdcdf1d2647fc8d5301dd9ba43a9d" +git-tree-sha1 = "4bba74fa59ab0755167ad24f98800fe5d727175b" uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" -version = "3.9.0+0" +version = "3.12.1+0" [[deps.libass_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Zlib_jll"] +git-tree-sha1 = "125eedcb0a4a0bba65b657251ce1d27c8714e9d6" uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" -version = "0.15.1+0" +version = "0.17.4+0" [[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.8.0+1" +version = "5.11.0+0" [[deps.libdecor_jll]] deps = ["Artifacts", "Dbus_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pango_jll", "Wayland_jll", "xkbcommon_jll"] @@ -1149,45 +1479,45 @@ uuid = "1183f4f0-6f2a-5f1a-908b-139f9cdfea6f" version = "0.2.2+0" [[deps.libevdev_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "141fe65dc3efabb0b1d5ba74e91f6ad26f84cc22" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "56d643b57b188d30cccc25e331d416d3d358e557" uuid = "2db6ffa8-e38f-5e21-84af-90c45d0032cc" -version = "1.11.0+0" +version = "1.13.4+0" [[deps.libfdk_aac_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "646634dd19587a56ee2f1199563ec056c5f228df" uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" -version = "2.0.2+0" +version = "2.0.4+0" [[deps.libinput_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "eudev_jll", "libevdev_jll", "mtdev_jll"] -git-tree-sha1 = "ad50e5b90f222cfe78aa3d5183a20a12de1322ce" +deps = ["Artifacts", "JLLWrappers", "Libdl", "eudev_jll", "libevdev_jll", "mtdev_jll"] +git-tree-sha1 = "91d05d7f4a9f67205bd6cf395e488009fe85b499" uuid = "36db933b-70db-51c0-b978-0f229ee0e533" -version = "1.18.0+0" +version = "1.28.1+0" [[deps.libpng_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "d7015d2e18a5fd9a4f47de711837e980519781a4" +git-tree-sha1 = "07b6a107d926093898e82b3b1db657ebe33134ec" uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.43+1" +version = "1.6.50+0" [[deps.libvorbis_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] -git-tree-sha1 = "490376214c4721cdaca654041f635213c6165cb3" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll"] +git-tree-sha1 = "11e1772e7f3cc987e9d3de991dd4f6b2602663a5" uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" -version = "1.3.7+2" +version = "1.3.8+0" [[deps.mtdev_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "814e154bdb7be91d78b6802843f76b6ece642f11" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "b4d631fd51f2e9cdd93724ae25b2efc198b059b1" uuid = "009596ad-96f7-51b1-9f1b-5ce2d5e8a71e" -version = "1.1.6+0" +version = "1.1.7+0" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.52.0+1" +version = "1.59.0+0" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] @@ -1195,19 +1525,19 @@ uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" version = "17.4.0+2" [[deps.x264_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "14cc7083fc6dff3cc44f2bc435ee96d06ed79aa7" uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" -version = "2021.5.5+0" +version = "10164.0.1+0" [[deps.x265_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "e7b67590c14d487e734dcb925924c5dc43ec85f3" uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" -version = "3.5.0+0" +version = "4.1.0+0" [[deps.xkbcommon_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] -git-tree-sha1 = "9c304562909ab2bab0262639bd4f444d7bc2be37" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "fbf139bce07a534df0e699dbb5f5cc9346f95cc1" uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" -version = "1.4.1+1" +version = "1.9.2+0" diff --git a/examples/Project.toml b/examples/Project.toml index 8267939..10b71b7 100644 --- a/examples/Project.toml +++ b/examples/Project.toml @@ -1,4 +1,5 @@ [deps] +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" SpatiotemporalGPs = "73b3b457-46a4-4dae-aece-b1ff83e37843" diff --git a/examples/Untitled.ipynb b/examples/Untitled.ipynb new file mode 100644 index 0000000..a9b6996 --- /dev/null +++ b/examples/Untitled.ipynb @@ -0,0 +1,1087 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "7a9b981e", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/devansh/kernel_tests_jl/SpatiotemporalGPs.jl/examples`\n" + ] + } + ], + "source": [ + "] activate ." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "75b06b3f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1mStatus\u001b[22m\u001b[39m `~/devansh/kernel_tests_jl/SpatiotemporalGPs.jl/examples/Project.toml`\n", + " \u001b[90m[052768ef] \u001b[39mCUDA v5.8.3\n", + " \u001b[90m[91a5bcdd] \u001b[39mPlots v1.40.17\n", + " \u001b[90m[73b3b457] \u001b[39mSpatiotemporalGPs v1.0.1-DEV `..`\n", + " \u001b[90m[90137ffa] \u001b[39mStaticArrays v1.9.14\n", + " \u001b[90m[37e2e46d] \u001b[39mLinearAlgebra v1.11.0\n" + ] + } + ], + "source": [ + "] st" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2f23ad5b", + "metadata": {}, + "outputs": [], + "source": [ + "using StaticArrays, LinearAlgebra, Plots" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "33f79699", + "metadata": {}, + "outputs": [], + "source": [ + "using SpatiotemporalGPs" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "1d874c22", + "metadata": {}, + "outputs": [], + "source": [ + "using CUDA" + ] + }, + { + "cell_type": "code", + "execution_count": 213, + "id": "f5641f82", + "metadata": {}, + "outputs": [], + "source": [ + "CUDA.allowscalar(false)" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "bee13e71", + "metadata": {}, + "outputs": [], + "source": [ + "# PREDICTION\n", + "\n", + "N = 2000\n", + "\n", + "x = randn(N)\n", + "sqrtP = randn(N, N)\n", + "P = sqrtP * sqrtP' + I\n", + "s = KFState(μ = x, Σ = P)\n", + "\n", + "# dynamics (integrator)\n", + "A = [[zeros(N - 1);; I(N - 1)]; zeros(N)' ]\n", + "dt = 0.1\n", + "Ad = exp(A * dt) # convert to discrete time\n", + "\n", + "# process noise\n", + "sqrtW = randn(N, N)\n", + "W = sqrtW * sqrtW' + I\n", + "\n", + "# run the prediction\n", + "s_new = predict(s, Ad, W)\n", + "\n", + "# test\n", + "P_new = Ad * P * Ad' + W\n", + "@assert get_μ(s_new) ≈ Ad * x\n", + "@assert Matrix(get_Σ(s_new)) ≈ P_new\n", + "@assert get_σ(s_new) ≈ sqrt.(diag(P_new))" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "dec18c7e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2000×2000 CuArray{Float32, 2, CUDA.DeviceMemory}:\n", + " 2086.31 -34.3683 7.52918 … -52.1772 -20.589 5.50405\n", + " -34.3683 1901.58 2.50776 27.5546 36.5319 -121.013\n", + " 7.52918 2.50776 2084.8 -24.9908 27.8135 4.80853\n", + " -14.173 89.2155 -34.4028 4.09446 -41.9967 -29.1783\n", + " 49.7332 4.45525 32.3991 27.0447 -39.5735 10.9267\n", + " 21.141 -6.33734 -62.9753 … -60.0278 36.2865 23.0426\n", + " -18.6475 -8.70819 83.202 2.61105 -8.97352 -55.8248\n", + " 23.3832 30.2151 7.75125 -77.7133 45.4139 -16.1058\n", + " 8.56066 53.7993 -97.9641 -12.0454 -33.0456 11.8201\n", + " 96.4461 -74.4212 84.8421 -140.866 -44.9739 63.2264\n", + " 55.7669 36.907 72.0425 … -78.593 20.057 37.3046\n", + " -15.9766 -3.6254 29.9792 -26.9436 26.8883 -7.18497\n", + " 14.015 3.39508 102.975 37.6167 -33.0048 25.8972\n", + " ⋮ ⋱ \n", + " -3.83672 32.8457 2.46309 -29.4242 -42.2399 -2.18306\n", + " 76.248 -10.2296 -40.806 32.245 83.6767 34.2532\n", + " 2.03889 -36.2201 -39.0813 … 20.9833 62.2778 -8.84033\n", + " -12.6052 -38.4309 -4.16037 38.5273 -33.1449 0.848209\n", + " 42.762 -34.2476 0.93434 43.7132 -37.8048 24.2727\n", + " -38.195 -18.5713 -36.9364 -30.3571 -96.0909 -58.0962\n", + " 57.2464 19.7917 3.86658 103.525 42.9157 7.36924\n", + " -22.1331 -99.742 90.4321 … 23.4187 -16.395 -42.5396\n", + " -17.7267 -21.2192 24.2099 37.3946 38.5358 7.25473\n", + " -52.1772 27.5546 -24.9908 1964.11 21.7234 47.6307\n", + " -20.589 36.5319 27.8135 21.7234 1954.53 -38.3955\n", + " 5.50405 -121.013 4.80853 47.6307 -38.3955 1957.16" + ] + }, + "execution_count": 93, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cu_Ad = cu(Ad)\n", + "cu_W = cu(W)" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "id": "3b84bd04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "KFState{Float32, CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}}(Float32[0.7607673, -0.37473425, -0.22030148, 0.6501609, -0.059927046, -0.25715062, 0.5726773, -1.2294395, -0.6407994, 0.69411564 … -1.303271, 0.44722098, 0.40530306, -0.36949694, 1.3502496, 0.30447897, 0.9890992, 0.5694994, -1.5600749, 0.9025672], Float32[44.050087 -0.81025654 … -0.42445502 0.50706; 0.0 46.854286 … -0.9299517 -0.47178712; … ; 0.0 0.0 … 6.154907 -0.77384627; 0.0 0.0 … 0.0 7.4848113])" + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cu_s = KFState(μ = cu(x), Σ=cu(P))" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "id": "a1312fc1", + "metadata": {}, + "outputs": [], + "source": [ + "function LinearAlgebra.mul!(C::CuArray{F, 2, M},\n", + " A::UpperTriangular{F, CuArray{F, 2, M}},\n", + " B::Adjoint{F, CuArray{F, 2, M}}) where {F, M}\n", + " \n", + " # force the copy when running with adjoint\n", + " return mul!(C, A, copy(B))\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "id": "986267ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2000×2000 Matrix{Float64}:\n", + " 1.0 0.1 0.005 0.000166667 4.16667e-6 … 0.0 0.0\n", + " 0.0 1.0 0.1 0.005 0.000166667 0.0 0.0\n", + " 0.0 0.0 1.0 0.1 0.005 0.0 0.0\n", + " 0.0 0.0 0.0 1.0 0.1 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 1.0 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", + " 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", + " ⋮ ⋱ \n", + " 0.0 0.0 0.0 0.0 0.0 2.75573e-17 2.51515e-19\n", + " 0.0 0.0 0.0 0.0 0.0 2.75573e-15 2.75573e-17\n", + " 0.0 0.0 0.0 0.0 0.0 … 2.48016e-13 2.75573e-15\n", + " 0.0 0.0 0.0 0.0 0.0 1.98413e-11 2.48016e-13\n", + " 0.0 0.0 0.0 0.0 0.0 1.38889e-9 1.98413e-11\n", + " 0.0 0.0 0.0 0.0 0.0 8.33333e-8 1.38889e-9\n", + " 0.0 0.0 0.0 0.0 0.0 4.16667e-6 8.33333e-8\n", + " 0.0 0.0 0.0 0.0 0.0 … 0.000166667 4.16667e-6\n", + " 0.0 0.0 0.0 0.0 0.0 0.005 0.000166667\n", + " 0.0 0.0 0.0 0.0 0.0 0.1 0.005\n", + " 0.0 0.0 0.0 0.0 0.0 1.0 0.1\n", + " 0.0 0.0 0.0 0.0 0.0 0.0 1.0" + ] + }, + "execution_count": 120, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Ad" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "id": "9cd83212", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2000×2000 Matrix{Float64}:\n", + " -4.01108e-6 3.0468e-8 2.81875e-9 … -3.25528e-8 1.97626e-9\n", + " -3.94875e-7 -4.37599e-6 3.29017e-7 -4.73096e-8 -4.82878e-8\n", + " 8.45592e-9 -1.71586e-7 -2.24346e-6 8.14345e-9 -7.3781e-9\n", + " 8.18399e-14 -1.21041e-8 -3.79883e-7 -1.94871e-8 4.30027e-9\n", + " -2.38603e-11 6.86126e-11 -1.22452e-8 6.85821e-8 2.61664e-8\n", + " 9.72791e-14 3.10391e-12 1.02754e-10 … 6.60143e-9 -5.29671e-9\n", + " 2.16133e-15 3.4137e-14 -5.13321e-12 3.45271e-8 7.89488e-8\n", + " 1.12597e-17 4.76271e-16 -3.0728e-13 1.8272e-7 -1.62526e-9\n", + " 7.04232e-20 7.15234e-17 1.11182e-14 5.3286e-8 -1.02933e-7\n", + " 3.19572e-22 -9.53069e-20 1.23446e-16 -1.49819e-8 1.03289e-9\n", + " -1.50732e-22 -1.95073e-20 -7.37011e-19 … 1.95969e-8 6.95371e-9\n", + " -3.04913e-25 1.17967e-22 9.89833e-21 2.07357e-7 -1.8408e-8\n", + " -9.78132e-27 -1.16305e-24 5.09278e-24 -3.11174e-8 1.46163e-7\n", + " ⋮ ⋱ \n", + " 0.0 0.0 0.0 -2.50114e-5 4.82258e-6\n", + " 0.0 0.0 0.0 -1.48335e-5 8.23964e-6\n", + " 0.0 0.0 0.0 … 9.38613e-6 -9.12196e-6\n", + " 0.0 0.0 0.0 4.90396e-6 7.75097e-5\n", + " 0.0 0.0 0.0 -3.08892e-5 1.4648e-5\n", + " 0.0 0.0 0.0 2.48923e-5 3.94315e-5\n", + " 0.0 0.0 0.0 -1.58521e-5 -2.74132e-6\n", + " 0.0 0.0 0.0 … -4.79254e-6 -3.25745e-5\n", + " 0.0 0.0 0.0 -4.33408e-5 -1.28816e-5\n", + " 0.0 0.0 0.0 1.5724e-6 -7.65186e-6\n", + " 0.0 0.0 0.0 3.94188e-5 -6.90703e-6\n", + " 0.0 0.0 0.0 2.02033e-6 2.04417e-5" + ] + }, + "execution_count": 125, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.U * Ad' - Array(cu_s.U * cu_Ad')" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "id": "ec2f37ef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2000×2000 Matrix{Float64}:\n", + " 43.9694 -0.804618 … -1.8606 -0.373749 0.50706\n", + " 4.69329 47.0139 -1.13893 -0.97713 -0.471787\n", + " 0.228157 4.56392 1.54791 0.267806 0.830712\n", + " 0.00768145 0.230371 0.551663 -1.84754 0.0946586\n", + " 0.000190535 0.00762133 0.178177 0.505496 0.683629\n", + " 3.7776e-6 0.000188866 … -0.936341 -0.172302 -0.148329\n", + " 6.22873e-8 3.73677e-6 -0.615118 -0.113249 0.988164\n", + " 8.87218e-10 6.21076e-8 -1.1028 -2.01637 -0.0950044\n", + " 1.09597e-11 8.76748e-10 0.191241 -0.779269 0.856368\n", + " 1.22065e-13 1.09857e-11 0.609887 0.837244 -0.117233\n", + " 1.21338e-15 1.21339e-13 … 1.34766 0.484832 0.120008\n", + " 1.10103e-17 1.20636e-15 0.633573 2.53289 0.745401\n", + " 9.90254e-20 1.13878e-17 0.681617 0.0660949 2.65288\n", + " ⋮ ⋱ \n", + " 0.0 0.0 -1.10474 0.0186257 0.962264\n", + " 0.0 0.0 -0.41532 -0.605442 -1.41708\n", + " 0.0 0.0 … 0.147442 0.61859 -0.303325\n", + " 0.0 0.0 0.178674 0.715764 0.106118\n", + " 0.0 0.0 0.591454 0.428626 0.16287\n", + " 0.0 0.0 -0.387514 -1.3155 0.603825\n", + " 0.0 0.0 0.522268 0.17175 -0.100608\n", + " 0.0 0.0 … -1.0122 -0.42565 -0.443956\n", + " 0.0 0.0 -0.0417363 -0.600424 -1.54531\n", + " 0.0 0.0 7.1758 -0.110897 0.961507\n", + " 0.0 0.0 0.611625 6.07756 -0.773853\n", + " 0.0 0.0 0.0374242 0.748483 7.48483" + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.U * Ad'" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "id": "f68b357b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "true" + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "CUDA.functional()" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "id": "b5407694", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "gpu_predict (generic function with 1 method)" + ] + }, + "execution_count": 95, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "function cpu_predict(s::S, A, W) where {S <: KFState}\n", + " N = length(s.μ)\n", + " Γw = SpatiotemporalGPs.KalmanFilter.chol_sqrt(W)\n", + "\n", + " μ_new = A * s.μ\n", + " F_new = SpatiotemporalGPs.KalmanFilter.qrr(s.U * A', Γw)\n", + "\n", + " return KFState(μ_new, F_new)\n", + "end\n", + "\n", + "function gpu_predict(s::S, A, W) where {S <: KFState}\n", + " N = length(s.μ)\n", + " Γw = SpatiotemporalGPs.KalmanFilter.chol_sqrt(W)\n", + "\n", + " μ_new = A * s.μ\n", + " F_new = SpatiotemporalGPs.KalmanFilter.qrr(s.U * copy(A'), Γw) # copy forces the transpose to be computed\n", + "\n", + " return KFState(μ_new, F_new)\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "id": "491690f8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "KFState{Float64, Vector{Float64}, Matrix{Float64}}([0.7223004505834603, -0.3935246026061397, -0.15562559976489074, 0.6429727326021715, -0.0829862428584563, -0.20613397432235928, 0.4466466491895085, -1.289985564739438, -0.5694870822100945, 0.7322131735093408 … -1.2565783737430432, 0.4861301878682574, 0.3751595184571401, -0.23278247292074047, 1.3857315828411458, 0.405980149788793, 1.038399184159426, 0.41800473321025206, -1.4698181459094153, 0.9025672264413219], [-63.57434970243688 -2.3900451289108204 … 0.6537462729727389 -0.4054363217372071; 0.0 -64.24717067309281 … 0.10495538938400317 2.190789607527197; … ; 0.0 0.0 … -44.529992476133316 -1.9089202374239993; 0.0 0.0 … 0.0 -44.1241915051616])" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cpu_predict(s, Ad, W)" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "id": "8c1dbf7f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "KFState{Float32, CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}}(Float32[0.7223004, -0.39352462, -0.1556256, 0.6429727, -0.08298624, -0.20613396, 0.44664666, -1.2899857, -0.5694871, 0.73221314 … -1.2565784, 0.4861302, 0.37515953, -0.2327825, 1.3857315, 0.40598014, 1.0383992, 0.41800472, -1.4698182, 0.9025672], Float32[-63.574356 -2.3900452 … 0.65374625 -0.4054364; 0.0 -64.24718 … 0.104955316 2.1907895; … ; 0.0 0.0 … -44.529995 -1.9089196; 0.0 0.0 … 0.0 -44.124187])" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gpu_predict(cu_s, cu_Ad, cu_W)" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "id": "0ea2b7c7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "KFState{Float32, CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}}(Float32[0.7223004, -0.39352462, -0.1556256, 0.6429727, -0.08298624, -0.20613396, 0.44664666, -1.2899857, -0.5694871, 0.73221314 … -1.2565784, 0.4861302, 0.37515953, -0.2327825, 1.3857315, 0.40598014, 1.0383992, 0.41800472, -1.4698182, 0.9025672], Float32[-63.574356 -2.3900452 … 0.65374625 -0.4054364; 0.0 -64.24718 … 0.104955316 2.1907895; … ; 0.0 0.0 … -44.529995 -1.9089196; 0.0 0.0 … 0.0 -44.124187])" + ] + }, + "execution_count": 126, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cpu_predict(cu_s, cu_Ad, cu_W)" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "id": "bb33065e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.555934 seconds (26 allocations: 153.107 MiB, 21.69% gc time)\n", + " 0.049398 seconds (686 allocations: 23.594 KiB)\n" + ] + }, + { + "data": { + "text/plain": [ + "KFState{Float32, CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}}(Float32[0.7223004, -0.39352462, -0.1556256, 0.6429727, -0.08298624, -0.20613396, 0.44664666, -1.2899857, -0.5694871, 0.73221314 … -1.2565784, 0.4861302, 0.37515953, -0.2327825, 1.3857315, 0.40598014, 1.0383992, 0.41800472, -1.4698182, 0.9025672], Float32[-63.574356 -2.3900452 … 0.65374625 -0.4054364; 0.0 -64.24718 … 0.104955316 2.1907895; … ; 0.0 0.0 … -44.529995 -1.9089196; 0.0 0.0 … 0.0 -44.124187])" + ] + }, + "execution_count": 98, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@time cpu_predict(s, Ad, W);\n", + "@time gpu_predict(cu_s, cu_Ad, cu_W)" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "id": "c5381b1f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(Float32[1.0 0.1 … 0.0 0.0; 0.0 1.0 … 0.0 0.0; … ; 0.0 0.0 … 1.0 0.1; 0.0 0.0 … 0.0 1.0], Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])" + ] + }, + "execution_count": 104, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res = LinearAlgebra.LAPACK.geqrf!(cu_Ad)" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "id": "9e7465bd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "geqrf!(A::StridedCuMatrix{Float32}) in CUDA.CUSOLVER at /home/dasc3/.julia/packages/CUDA/Wfi8S/lib/cusolver/dense.jl:1027" + ], + "text/plain": [ + "geqrf!(\u001b[90mA\u001b[39m::\u001b[1mStridedCuMatrix\u001b[22m\u001b[0m{Float32})\n", + "\u001b[90m @\u001b[39m \u001b[90mCUDA.CUSOLVER\u001b[39m \u001b[90m~/.julia/packages/CUDA/Wfi8S/lib/cusolver/\u001b[39m\u001b[90m\u001b[4mdense.jl:1027\u001b[24m\u001b[39m" + ] + }, + "execution_count": 106, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@which LinearAlgebra.LAPACK.geqrf!(cu_Ad)" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "id": "67c49299", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.122271 seconds (8 allocations: 515.812 KiB)\n" + ] + }, + { + "data": { + "text/plain": [ + "([1.0 0.1 … 0.0 0.0; 0.0 1.0 … 0.0 0.0; … ; 0.0 0.0 … 1.0 0.1; 0.0 0.0 … 0.0 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@time LinearAlgebra.LAPACK.geqrf!(Ad)" + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "id": "f16cbf73", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.014520 seconds (50 allocations: 1.203 KiB)\n" + ] + }, + { + "data": { + "text/plain": [ + "(Float32[1.0 0.1 … 0.0 0.0; 0.0 1.0 … 0.0 0.0; … ; 0.0 0.0 … 1.0 0.1; 0.0 0.0 … 0.0 1.0], Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])" + ] + }, + "execution_count": 111, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@time LinearAlgebra.LAPACK.geqrf!(cu_Ad)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "36b46620", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "400×400 UpperTriangular{Float32, CuArray{Float32, 2, CUDA.DeviceMemory}}:\n", + " -28.4465 -3.45956 -0.652481 -1.4248 … -1.41766 -0.957981\n", + " ⋅ -29.358 -1.37015 -0.0776581 -1.75754 -1.06353\n", + " ⋅ ⋅ -28.6769 -2.2 1.28626 2.91681\n", + " ⋅ ⋅ ⋅ -26.7087 0.98485 1.47749\n", + " ⋅ ⋅ ⋅ ⋅ -0.253504 -0.968145\n", + " ⋅ ⋅ ⋅ ⋅ … -0.928715 -1.18538\n", + " ⋅ ⋅ ⋅ ⋅ -0.067205 0.25622\n", + " ⋅ ⋅ ⋅ ⋅ -0.507518 2.16967\n", + " ⋅ ⋅ ⋅ ⋅ -1.44664 -0.416979\n", + " ⋅ ⋅ ⋅ ⋅ 0.426546 -0.734503\n", + " ⋅ ⋅ ⋅ ⋅ … 0.485032 0.433648\n", + " ⋅ ⋅ ⋅ ⋅ 1.23284 0.268297\n", + " ⋅ ⋅ ⋅ ⋅ 0.635549 0.747187\n", + " ⋮ ⋱ \n", + " ⋅ ⋅ ⋅ ⋅ -0.836371 1.96662\n", + " ⋅ ⋅ ⋅ ⋅ -0.206756 0.551261\n", + " ⋅ ⋅ ⋅ ⋅ … -1.25216 -0.288592\n", + " ⋅ ⋅ ⋅ ⋅ -0.0702065 -0.953823\n", + " ⋅ ⋅ ⋅ ⋅ 0.122213 -1.21569\n", + " ⋅ ⋅ ⋅ ⋅ -0.106531 0.7664\n", + " ⋅ ⋅ ⋅ ⋅ 0.221164 -0.828972\n", + " ⋅ ⋅ ⋅ ⋅ … 0.124895 -0.176632\n", + " ⋅ ⋅ ⋅ ⋅ -0.63533 1.92608\n", + " ⋅ ⋅ ⋅ ⋅ -1.84899 -0.462196\n", + " ⋅ ⋅ ⋅ ⋅ -20.6234 -0.131476\n", + " ⋅ ⋅ ⋅ ⋅ ⋅ -20.4071" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cu_Γw = SpatiotemporalGPs.KalmanFilter.chol_sqrt(cu_W)\n", + "blah = cu_s.U * copy(cu_Ad')\n", + "blah2 = SpatiotemporalGPs.KalmanFilter.qrr(blah, cu_Γw)\n", + "# SpatiotemporalGPs.KalmanFilter.qrr(blah, cu_Γw)" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "bcacb0ed", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.003019 seconds (257 allocations: 7.312 KiB)\n" + ] + }, + { + "data": { + "text/plain": [ + "400×400 UpperTriangular{Float32, CuArray{Float32, 2, CUDA.DeviceMemory}}:\n", + " -28.4465 -3.45956 -0.652481 -1.4248 … -1.41766 -0.957981\n", + " ⋅ -29.358 -1.37015 -0.0776581 -1.75754 -1.06353\n", + " ⋅ ⋅ -28.6769 -2.2 1.28626 2.91681\n", + " ⋅ ⋅ ⋅ -26.7087 0.98485 1.47749\n", + " ⋅ ⋅ ⋅ ⋅ -0.253504 -0.968145\n", + " ⋅ ⋅ ⋅ ⋅ … -0.928715 -1.18538\n", + " ⋅ ⋅ ⋅ ⋅ -0.067205 0.25622\n", + " ⋅ ⋅ ⋅ ⋅ -0.507518 2.16967\n", + " ⋅ ⋅ ⋅ ⋅ -1.44664 -0.416979\n", + " ⋅ ⋅ ⋅ ⋅ 0.426546 -0.734503\n", + " ⋅ ⋅ ⋅ ⋅ … 0.485032 0.433648\n", + " ⋅ ⋅ ⋅ ⋅ 1.23284 0.268297\n", + " ⋅ ⋅ ⋅ ⋅ 0.635549 0.747187\n", + " ⋮ ⋱ \n", + " ⋅ ⋅ ⋅ ⋅ -0.836371 1.96662\n", + " ⋅ ⋅ ⋅ ⋅ -0.206756 0.551261\n", + " ⋅ ⋅ ⋅ ⋅ … -1.25216 -0.288592\n", + " ⋅ ⋅ ⋅ ⋅ -0.0702065 -0.953823\n", + " ⋅ ⋅ ⋅ ⋅ 0.122213 -1.21569\n", + " ⋅ ⋅ ⋅ ⋅ -0.106531 0.7664\n", + " ⋅ ⋅ ⋅ ⋅ 0.221164 -0.828972\n", + " ⋅ ⋅ ⋅ ⋅ … 0.124895 -0.176632\n", + " ⋅ ⋅ ⋅ ⋅ -0.63533 1.92608\n", + " ⋅ ⋅ ⋅ ⋅ -1.84899 -0.462196\n", + " ⋅ ⋅ ⋅ ⋅ -20.6234 -0.131476\n", + " ⋅ ⋅ ⋅ ⋅ ⋅ -20.4071" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@time blah2 = SpatiotemporalGPs.KalmanFilter.qrr(blah, cu_Γw)" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "id": "015cca8e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "KFState{Float32, CuArray{Float32, 1, CUDA.DeviceMemory}, CuArray{Float32, 2, CUDA.DeviceMemory}}(Float32[0.7223004, -0.39352462, -0.1556256, 0.6429727, -0.08298624, -0.20613396, 0.44664666, -1.2899857, -0.5694871, 0.73221314 … -1.2565784, 0.4861302, 0.37515953, -0.2327825, 1.3857315, 0.40598014, 1.0383992, 0.41800472, -1.4698182, 0.9025672], Float32[-63.574356 -2.3900452 … 0.65374625 -0.4054364; 0.0 -64.24718 … 0.104955316 2.1907895; … ; 0.0 0.0 … -44.529995 -1.9089196; 0.0 0.0 … 0.0 -44.124187])" + ] + }, + "execution_count": 128, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# run the prediction\n", + "cu_s_new = predict(cu_s, cu_Ad, cu_W)" + ] + }, + { + "cell_type": "code", + "execution_count": 218, + "id": "b6f5d548", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.194858 seconds (69 allocations: 122.912 MiB, 1.35% gc time)\n", + " 0.170288 seconds (69 allocations: 122.912 MiB, 1.52% gc time)\n" + ] + } + ], + "source": [ + "## CORRECTION\n", + "N = 2000 # number of states\n", + "M = 2 # number of measurements\n", + "\n", + "x = randn(N)\n", + "sqrtP = randn(N, N)\n", + "P = sqrtP * sqrtP' + I\n", + "s = KFState(μ = x, Σ = P)\n", + "\n", + "# measurement matrix\n", + "C = randn(M, N)\n", + "\n", + "# measurement noise\n", + "sqrtV = randn(M, M)\n", + "V = sqrtV * sqrtV' + I\n", + "\n", + "# create a measurement\n", + "y = C * x + randn(M)\n", + "\n", + "# run the correction\n", + "@time s_new = correct(s, y, C, V)\n", + "@time s_new = correct(s, y, C, V)\n", + "\n", + "\n", + "# test\n", + "K = P * C' * inv(C * P * C' + V)\n", + "P_new = (I - K * C) * P\n", + "@assert get_μ(s_new) ≈ x + K * (y - C * x)\n", + "@assert Matrix(get_Σ(s_new)) ≈ P_new\n", + "@assert get_σ(s_new) ≈ sqrt.(diag(P_new))" + ] + }, + { + "cell_type": "code", + "execution_count": 219, + "id": "b67ef1cb", + "metadata": {}, + "outputs": [], + "source": [ + "cu_y = cu(y)\n", + "cu_C = cu(C)\n", + "cu_V = cu(V);" + ] + }, + { + "cell_type": "code", + "execution_count": 221, + "id": "79d8e160", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.009822 seconds (87 allocations: 15.268 MiB)\n", + " 0.021394 seconds (1.79 k allocations: 52.828 KiB)\n" + ] + } + ], + "source": [ + "@time cu_s = KFState(μ=cu(x), Σ=cu(P))\n", + "@time cu_s_new = correct(cu_s, cu_y, cu_C, cu_V);" + ] + }, + { + "cell_type": "code", + "execution_count": 223, + "id": "058e1041", + "metadata": {}, + "outputs": [], + "source": [ + "CUDA.@profile correct(cu_s, cu_y, cu_C, cu_V);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf7b78ff", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a47eb4e4", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0e444db", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f7a48b5", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 224, + "id": "d1ee299e", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "8.172857142857142" + ] + }, + "execution_count": 224, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "0.171630/ 0.021" + ] + }, + { + "cell_type": "code", + "execution_count": 225, + "id": "1617f512", + "metadata": {}, + "outputs": [], + "source": [ + "@assert Array(cu_s_new.μ) ≈ s_new.μ" + ] + }, + { + "cell_type": "code", + "execution_count": 226, + "id": "902175f8", + "metadata": {}, + "outputs": [], + "source": [ + "@assert Array(cu_s_new.U) ≈ Array(s_new.U)" + ] + }, + { + "cell_type": "code", + "execution_count": 229, + "id": "398d235a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.004345 seconds (28 allocations: 188.891 KiB)\n" + ] + }, + { + "data": { + "text/plain": [ + "2000×2 Matrix{Float64}:\n", + " -0.00105975 -0.000152324\n", + " -0.000975537 -6.76566e-5\n", + " 9.97867e-5 -0.000775277\n", + " 6.09883e-5 0.000255586\n", + " 6.03293e-5 0.000346151\n", + " 0.000106381 0.000628322\n", + " 0.000773994 -9.43852e-6\n", + " -7.66492e-5 -0.00011326\n", + " -0.000719201 -0.000791741\n", + " -0.00104664 -0.00074154\n", + " -0.00142005 0.000191627\n", + " 0.000297327 -0.000451129\n", + " 0.00010966 -0.000158431\n", + " ⋮ \n", + " -0.000118535 0.000271826\n", + " 0.000740012 -0.000346647\n", + " 1.56628e-5 -0.000421732\n", + " -0.000310472 0.00110964\n", + " -0.00103628 -0.000380726\n", + " -0.000578972 -0.000930993\n", + " -0.00152721 -0.000403254\n", + " -0.00037572 0.000654503\n", + " 0.000130465 -0.000888194\n", + " 0.000532167 -5.7655e-5\n", + " 0.000389704 0.000509015\n", + " -0.00102962 -0.000705708" + ] + }, + "execution_count": 229, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Γv = SpatiotemporalGPs.KalmanFilter.chol_sqrt(V)\n", + "@time L = SpatiotemporalGPs.KalmanFilter.kalman_gain(s, C, Γv)" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "id": "283b115c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.000685 seconds (546 allocations: 14.641 KiB)\n" + ] + } + ], + "source": [ + "cu_Γv = SpatiotemporalGPs.KalmanFilter.chol_sqrt(cu(V))\n", + "@time CUDA.@sync cu_L = SpatiotemporalGPs.KalmanFilter.kalman_gain(cu_s, cu_C, cu_Γv);" + ] + }, + { + "cell_type": "code", + "execution_count": 238, + "id": "6cc30860", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.000041 seconds (5 allocations: 15.734 KiB)\n" + ] + } + ], + "source": [ + "@time diag(s.U);" + ] + }, + { + "cell_type": "code", + "execution_count": 240, + "id": "be560f5e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.000169 seconds (67 allocations: 1.828 KiB)\n" + ] + } + ], + "source": [ + "@time diag(cu_s.U);" + ] + }, + { + "cell_type": "code", + "execution_count": 244, + "id": "5779e396", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.000246 seconds (73 allocations: 9.750 KiB)\n" + ] + }, + { + "data": { + "text/plain": [ + "2000-element Vector{Float32}:\n", + " 44.80356\n", + " 44.274902\n", + " 45.297863\n", + " 44.530224\n", + " 45.11142\n", + " 45.301605\n", + " 43.80436\n", + " 45.17369\n", + " 44.556824\n", + " 45.01669\n", + " 43.412277\n", + " 44.10099\n", + " 44.867603\n", + " ⋮\n", + " 6.9623632\n", + " 6.983687\n", + " 7.260053\n", + " 7.9759383\n", + " 6.6886916\n", + " 6.9924436\n", + " 8.79238\n", + " 6.5129313\n", + " 7.421658\n", + " 6.83312\n", + " 7.452277\n", + " 7.142562" + ] + }, + "execution_count": 244, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@time Array(diag(cu_s.U))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0169f3e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08e9502b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia (4 threads) 1.11.2", + "language": "julia", + "name": "julia-_4-threads_-1.11" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/synthetic_data.ipynb b/examples/synthetic_data.ipynb index 6b1d63a..6359cce 100644 --- a/examples/synthetic_data.ipynb +++ b/examples/synthetic_data.ipynb @@ -2,16 +2,24 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/devansh/kernel_tests_jl/SpatiotemporalGPs.jl/examples`\n" + ] + } + ], "source": [ "] activate ." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -20,7 +28,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -29,16 +37,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1mStatus\u001b[22m\u001b[39m `~/devansh/kernel_tests_jl/SpatiotemporalGPs.jl/examples/Project.toml`\n", + " \u001b[90m[052768ef] \u001b[39mCUDA v5.8.3\n", + " \u001b[90m[91a5bcdd] \u001b[39mPlots v1.40.17\n", + " \u001b[90m[73b3b457] \u001b[39mSpatiotemporalGPs v1.0.1-DEV `..`\n", + " \u001b[90m[90137ffa] \u001b[39mStaticArrays v1.9.14\n", + " \u001b[90m[37e2e46d] \u001b[39mLinearAlgebra v1.11.0\n" + ] + } + ], "source": [ "] st" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -47,22 +68,164 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[36m\u001b[1m[ \u001b[22m\u001b[39m\u001b[36m\u001b[1mInfo: \u001b[22m\u001b[39mPrecompiling SpatiotemporalGPs [73b3b457-46a4-4dae-aece-b1ff83e37843] (cache misses: include_dependency fsize change (2), wrong dep version loaded (2))\n" + ] + } + ], "source": [ - "using SpatiotemporalGPs" + "using SpatiotemporalGPs\n", + "# include(\"../src/SpatiotemporalGPs.jl\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "using StaticArrays, LinearAlgebra, Plots" ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "## CUDA\n", + "using CUDA\n", + "using BenchmarkTools" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "capability(device) = v\"8.6.0\"\n" + ] + } + ], + "source": [ + "for device in CUDA.devices()\n", + " @show capability(device)\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CUDA toolchain: \n", + "- runtime 12.9, artifact installation\n", + "- driver 535.183.1 for 12.2\n", + "- compiler 12.9\n", + "\n", + "CUDA libraries: \n", + "- CUBLAS: 12.9.1\n", + "- CURAND: 10.3.10\n", + "- CUFFT: 11.4.1\n", + "- CUSOLVER: 11.7.5\n", + "- CUSPARSE: 12.5.10\n", + "- CUPTI: 2025.2.1 (API 28.0.0)\n", + "- NVML: 12.0.0+535.183.1\n", + "\n", + "Julia packages: \n", + "- CUDA: 5.8.3\n", + "- CUDA_Driver_jll: 13.0.0+0\n", + "- CUDA_Compiler_jll: 0.2.0+0\n", + "- CUDA_Runtime_jll: 0.19.0+0\n", + "\n", + "Toolchain:\n", + "- Julia: 1.11.2\n", + "- LLVM: 16.0.6\n", + "\n", + "1 device:\n", + " 0: NVIDIA GeForce RTX 3050 Ti Laptop GPU (sm_86, 3.198 GiB / 4.000 GiB available)\n" + ] + } + ], + "source": [ + "CUDA.versioninfo()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# if CUDA.functional()\n", + " \n", + "# println(\"Praise be - cuda is available!!\")\n", + " \n", + "# # provide a overload for A * B' that works with CUDA\n", + "# function LinearAlgebra.mul!(C::CuArray{F, 2, M},\n", + "# A::UpperTriangular{F, CuArray{F, 2, M}},\n", + "# B::Adjoint{F, CuArray{F, 2, M}}) where {F, M}\n", + " \n", + "# # force the copy when running with adjoint\n", + "# return mul!(C, A, copy(B) )\n", + "# end\n", + "# end" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3193.1875" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "CUDA.free_memory() / 2^20" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3902.1875" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "CUDA.total_memory() / 2^20" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -72,7 +235,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -87,7 +250,7 @@ "\n", "# determine the temporal step size\n", "Δt = 5.0 # minutes\n", - "Δx = 0.25 # km\n", + "Δx = 3.0 # km\n", "\n", "# create the spatial domain\n", "xs = 0:Δx:7.0\n", @@ -105,7 +268,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -116,9 +279,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "length(synthetic_data.ts) = 48\n", + "prod(size(synthetic_data.data)) = 576\n" + ] + } + ], "source": [ "@show length(synthetic_data.ts)\n", "@show prod(size(synthetic_data.data));" @@ -126,18 +298,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ - "# visualize the ground truth data\n", - "@gif for k=1:length(synthetic_data.ts)\n", - " heatmap(synthetic_data.xs, synthetic_data.ys, synthetic_data.data[:, :, k]', clims=(-5,5))\n", - " title!(\"k = $k\")\n", - " xlabel!(\"x\")\n", - " ylabel!(\"y\")\n", - " plot!(aspect_ratio=:equal)\n", - "end" + "# # visualize the ground truth data\n", + "# @gif for k=1:length(synthetic_data.ts)\n", + "# heatmap(synthetic_data.xs, synthetic_data.ys, synthetic_data.data[:, :, k]', clims=(-5,5))\n", + "# title!(\"k = $k\")\n", + "# xlabel!(\"x\")\n", + "# ylabel!(\"y\")\n", + "# plot!(aspect_ratio=:equal)\n", + "# end" ] }, { @@ -149,9 +321,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "STGPKFProblem{SVector{2, Float64}, Float64, Vector{SVector{2, Float64}}, SpatiotemporalGPs.STGPKF.Matern12{Float64}, SpatiotemporalGPs.STGPKF.Matern32{Float64}, SpatiotemporalGPs.STGPKF.DiscreteTimeStateSpaceModel{SMatrix{2, 2, Float64, 4}, SMatrix{2, 2, Float64, 4}, SMatrix{1, 2, Float64, 2}, Float64}, Symmetric{Float64, Matrix{Float64}}, Symmetric{Float64, Matrix{Float64}}}(SVector{2, Float64}[[0.0, 0.0], [3.0, 0.0], [6.0, 0.0], [0.0, 3.0], [3.0, 3.0], [6.0, 3.0], [0.0, 6.0], [3.0, 6.0], [6.0, 6.0], [0.0, 9.0], [3.0, 9.0], [6.0, 9.0]], SpatiotemporalGPs.STGPKF.Matern12{Float64}(1.0, 0.3333333333333333), SpatiotemporalGPs.STGPKF.Matern32{Float64}(4.0, 0.005555555555555556), 5.0, SpatiotemporalGPs.STGPKF.DiscreteTimeStateSpaceModel{SMatrix{2, 2, Float64, 4}, SMatrix{2, 2, Float64, 4}, SMatrix{1, 2, Float64, 2}, Float64}([0.9988790551645961 4.7651327208952186; -0.0004412159926754832 0.9071740331934912], [38.77234383141914 11.353244923873133; 11.353244923873133 4.5448880013854955], [0.00377565387743805 0.0], 5.0), [0.9633067996428762 0.17010207956123574 … 0.00931872740158996 0.0053741627707129; 0.17010207956123574 0.9473141062281818 … 0.010933987503153265 0.009318727401589963; … ; 0.00931872740158996 0.010933987503153265 … 0.9473141062281814 0.17010207956123563; 0.0053741627707129 0.009318727401589963 … 0.17010207956123563 0.963306799642876], [1.1041059753688673 -0.1717965919914523 … -2.0418583868188156e-5 1.3785732395839418e-5; -0.1717965919914523 1.1506990737720846 … -0.00031464147218624686 -2.0418583868206743e-5; … ; -2.0418583868188156e-5 -0.00031464147218624686 … 1.1506990737720848 -0.1717965919914524; 1.3785732395839418e-5 -2.0418583868206743e-5 … -0.1717965919914524 1.1041059753688676])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# create the STGPKF Problem\n", "problem = STGPKFProblem(grid_pts, ks, kt, Δt)" @@ -159,19 +342,140 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "LoadError", + "evalue": "UndefVarError: `CudaExt` not defined in `SpatiotemporalGPs`\nSuggestion: check for spelling errors or missing imports.", + "output_type": "error", + "traceback": [ + "UndefVarError: `CudaExt` not defined in `SpatiotemporalGPs`\nSuggestion: check for spelling errors or missing imports.", + "", + "Stacktrace:", + " [1] getproperty(x::Module, f::Symbol)", + " @ Base ./Base.jl:42", + " [2] top-level scope", + " @ In[21]:1" + ] + } + ], + "source": [ + "cu_problem = SpatiotemporalGPs.CudaExt.CudaSTGPKFProblem(grid_pts, ks, kt, Δt)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "ename": "LoadError", + "evalue": "UndefVarError: `CudaSTGPKFProblem` not defined in `SpatiotemporalGPs`\nSuggestion: check for spelling errors or missing imports.", + "output_type": "error", + "traceback": [ + "UndefVarError: `CudaSTGPKFProblem` not defined in `SpatiotemporalGPs`\nSuggestion: check for spelling errors or missing imports.", + "", + "Stacktrace:", + " [1] getproperty(x::Module, f::Symbol)", + " @ Base ./Base.jl:42", + " [2] top-level scope", + " @ In[23]:1" + ] + } + ], + "source": [ + "SpatiotemporalGPs.CudaSTGPKFProblem" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.242323 seconds (726.38 k allocations: 37.676 MiB, 6.41% gc time, 99.90% compilation time)\n" + ] + }, + { + "data": { + "text/plain": [ + "KFState{Float64, Vector{Float64}, Matrix{Float64}}([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [529.7095721488881 0.0 … 0.0 0.0; 0.0 5.0971327345413675 … 0.0 0.0; … ; 0.0 0.0 … 529.7095721488881 0.0; 0.0 0.0 … 0.0 5.0971327345413675])" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# construct the state at time 0 conditioned on no measurements\n", - "state_initial = stgpkf_initialize(problem) " + "@time state_initial = stgpkf_initialize(problem) " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "24-element Vector{Float64}:\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "state_initial.μ" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.8098823558956093" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# do some measurements\n", "\n", @@ -194,18 +498,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.453247 seconds (98 allocations: 173.458 MiB, 12.67% gc time)\n" + ] + }, + { + "data": { + "text/plain": [ + "KFState{Float64, Vector{Float64}, Matrix{Float64}}([1.331344128421188, 0.0, 1.3396459133314789, 0.0, 1.3419218911592683, 0.0, 1.338768041267331, 0.0, 1.330487087592918, 0.0 … 0.5827199571011528, 0.0, 0.5427111154889805, 0.0, 0.504904534625856, 0.0, 0.46925897423739854, 0.0, 0.43569791360571686, 0.0], [-529.6996406145371 0.0 … 0.006500482135228051 0.0; 0.0 5.0971327345413675 … 0.0 0.0; … ; 0.0 0.0 … -529.6247696641767 0.0; 0.0 0.0 … 0.0 5.0971327345413675])" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# do the correction\n", "\n", - "state_1_1 = stgpkf_correct(problem, state_initial, measure_pt, measure_y, measure_σ)" + "@time state_1_1 = stgpkf_correct(problem, state_initial, measure_pt, measure_y, measure_σ)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ @@ -214,9 +536,520 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAIAAAD9V4nPAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nO3deVwT19oH8DNh3w0CioiiAiougCCCKyourdZq3RVb61VR8Vbtx1art7Vq7XVrrdbWa7222mqtiltvrVv1Yt1ARXAFK4KCslQRZIeQzPvHePOmyYAzkyEDmd/3kz+SkzMzT4Dw5EzOeYaiaZoAAADIlULqAAAAAKSERAggplmzZr333ntSRwEAPFA4NQrAV3Fx8U8//eTl5TVs2DC9p2xsbNzd3R89emSyYDIzM0+dOtW1a9fw8HCTHRTAnGBECMDbkydPYmJiNmzYYPhUZGRkz549TRlMUlJSTEzMgQMHTHlQAHNiKXUAAGblxIkTUocAAPwgEYIcVVdXnz17Ni0tTa1Wt2/ffsCAATY2Nnp9MjIykpKSHj16ZGtr6+npGRER0axZM0JITk7OrVu3CCHFxcVJSUlMZw8PD29vb0JIcnKypaVlly5dmPbi4uJ79+65u7u3atUqMzPz9OnTZWVl3bt3144aKyoqjh49+vDhQ+ZEq5OTk14Yubm5ly9fzsrKUqvVbdu2HTBggKOjo/bZ+/fvZ2RkEELy8vK0wbRu3drNzU3b5+HDh2fPns3Pz2/atGlkZGTbtm3F+SECmA0aQGZOnDjRqlUr3XeBj49PYmKitoNarY6NjaUoSrcPRVFHjx6laXrZsmWG76O///3vzLbW1tZeXl7aXR07dowQMnv27JUrVyoU//9NxOTJk2tqas6dO8ckV4a3t3d6erpuqEOGDNELw9XV9dChQ9oOI0aMMAxm+/btzLPl5eVvv/227nEVCsWcOXNUKlX9/XgBGh0kQpCXs2fPWllZOTs7r1mz5urVq8nJyatWrbKxsVEqlVlZWUyf77//nhDSvXv3Y8eOPXz4MDU19dixY7NmzTp16hRN0/fv39+5cychJDg4+NT/pKWlMduyJsLWrVu7uLhs3rz5ypUrhw4d8vHxIYSsWLFCqVTOmjXrzJkz58+fHz16NCFkyJAhutH27t17+fLlzP6vXLmyatUqR0dHGxub1NRUpkNKSspHH31ECBk7dqw2mMePH9M0rVarX3nlFUJI//79f/3117S0tOPHjzMTat59910T/KgBGgskQpARjUbTsWNHhUIRHx+v2/71118TQmJjY5mHU6dOJYQkJCTUtp/09HRCyMCBAw2fYk2EFEWdP39e26j9HnH+/PnaxsrKymbNmikUiufPn9fxEpgcrLvh/v37CSELFy7U67l3714mSLVarW0sLy9v06aNlZUVkywBgKZpzBoFGbl69WpqamqfPn369eun2z59+nRra2smaRFCmjRpQgi5dOmSWMcNDw/v1auX9mHfvn2ZE54LFizQNtrY2ERERGg0mgcPHtSxq9dff50Qcvny5Zce9IcffiCELF26VPfUqJ2d3bRp01Qq1alTp3i/DAAzhckyICPJycmEkJKSksWLF+s9ZWdn9/DhQ41Go1AopkyZsnnz5gULFuzcuXPo0KH9+/fv16+f4Wwa7vz9/XUf2traOjo61tTUMPNrtNzd3Qkh+fn52panT5+uXbuWOdv55MkTbXtBQcFLD8q82EOHDulNZL19+zYhpO50CyArSIQgI4WFhYSQ1NTUzMxMvacUCoWzs7NKpbKxsenWrdvFixc//vjj06dPp6SkrF692snJacGCBf/4xz+srKwEHNfe3t7wcLa2tnoTYZihm0ajYR4+ffq0e/fuDx486Nat25QpU5RKJXP0xYsX19TUvPSgRUVFhJBdu3YZPqVUKgW8CgBzhUQIMsIsTpg2bdrmzZvr7tm9e/ejR4+WlpZeuHDh5MmT33777YoVK2iaXrFihUkiJYSQr7766sGDB+++++5nn32mbczLyzMczrJycnIqKytLTU3VnZgKAIbwHSHISHBwMCHk4sWLHPs7OjoOGTLks88+i4+PJ4TExcUx7czIjMuwzBjXr18nhEyYMEG38dq1a3rdaguG74sFkC0kQpCRHj16BAQEJCcnMzMq9ZSWlurd0WrRogUhpKqqinno6empUCjqu6Aosyg+KytL26JWqw2HpF5eXoQQw2DefvttQsjKlSvLy8v1nqqsrFSpVKIHDNBI4dQoyIhCodi+fXv//v2jo6MvXLgwZMiQVq1a5efn//HHH3v27OncufOWLVsIIW+88YaNjc2YMWP8/f2bNm2akZHx6aefEkLGjRvH7MfKyiowMDA5OTk6OjosLMzW1rZTp06680JF0b9//23bts2bN0+lUgUHB2dnZ69Zs0Z3ygyjQ4cOjo6OP//88/z58/38/KysrPr169e+ffsxY8aMHj36wIED3bt3nz9/fpcuXSwtLR88eHD+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", + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "plot(problem, state_1_1; plot_type=:estimate, clims=(-5, 5), cmap=:bluesreds, aspect_ratio=:equal)\n", "scatter!([measure_pt[1]], [measure_pt[2]], label=\"measured pt\")" @@ -224,25 +1057,1117 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAIAAAD9V4nPAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nO3daXwUVbrA4dOddAhkgQAJSwhr2AQCCCIoCALBjeDAGHDDqzIaRCSMAyogDIqiDHMFd0QERFxAB7h6GQeJqFxEZEkAAUEgQDAsQhYSQtauuh96JpNJTkJVd3VX0vV/fv2hu3Kq6u1A5+1z6rx1bKqqCgAArMpudgAAAJiJRAjURgcOHEhKSvrkk0/MDgTwfyRCwEc++OCD5cuXa2yckZGxdOnS7du3ezUkAEKIQLMDAKxi2rRpBQUFDz/8sNmBAPgP9AgBAJZGjxAwTFZW1vfff3/q1CkhRGRkZJ8+fTp27CiEyMvLO3r0aFlZmaIoe/bscTVu0KBB165dy/c9dOjQt99+W1ZW1qtXr0GDBpkSP2BNJELAGEuXLp06dWphYWHFjXPmzHnuuee2b99+2223ubb07du3/MmuXbuEEIqiJCcnv/nmm+W1TIMHD3700Ud9GDtgaSRCwACHDx+eNGlSZGTke++917dvX4fDkZGRkZKS0qRJEyHEddddt3nz5sTExKKioi+++MK1S3h4uOvJ/Pnz33jjjc6dOy9evLhbt26//PLLk08+OX36dNPeDGAxNgrqAc+98847EydOXLRo0dSpU6tr06xZs4KCgsuXL1fceOnSpZYtW5aWlh45cqRdu3aujefPn+/QoUNBQcETTzzx2muveTd0wPKYLAMYICIiQgixa9eusrIyXTtu2rTpypUrY8aMKc+CQohmzZrdf//9BocIoBokQsAAt9xyS3R09EcffdShQ4dJkyatXbs2NzdXy46HDh0SQvTs2bPS9l69ehkfJQAZEiFggIYNG+7YseO//uu/8vLy3n777XHjxkVFRT3wwAMXL16seUfXSGlkZGSl7VFRUd6KFcB/YrIMYIxWrVqtXLmyrKxs165dW7ZsWb58+QcffHD27NnNmzfXsFdYWJgQ4rfffqu0/fz5816MFUAF9AgBIwUGBg4YMGDWrFn79u2LiopKSUkpHyN1OBxVryB2795dCJGWllZpe2pqqg+iBSBIhIAhKs0FFUKEhIS4CiSKi4tdW6Kjo4uLiy9cuFCx2YgRI0JDQzds2HDs2LHyjWfPnv3www+9HDKAfwqYO3eu2TEAdd7zzz8/Y8aM4uLigoKCsrKyn3/+ec6cOd98883gwYMnT57sarN3795du3b9+OOP2dnZBw4cyMjI6Nq1a7169RwOx6ZNmzZu3NiqVSuHw/H9998/8MADDofj0qVL119/fXklPgBvUQF47K233mrQoEGlD9ewYcPOnj1b3ubChQsjR450OByun/bt29e1XVGUp59+2m7/9/BMfHy8awGmJ554wqQ3BFgIBfWAMUpKSlJTU0+cOJGXl9e8efOuXbt26tSpajNFUc6dO1dUVFSvXr3o6Ojy7SdOnNi6dWtZWVmPHj369et35cqVc+fOhYeHN23a1IdvArAiEiEAwNKYLAMAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAqL1WrFjRqVOn+vXrt2jRYvLkycXFxVXbbN68uUuXLmFhYcOHDz99+rTeU5AIAQC1V+/evTdu3Jifn//9999v27Zt4cKFlRrk5+cnJia+9NJL2dnZ3bp1S0pK0nuKQINCBQDAeL169XI9ad++fXx8/PHjxys1+Oyzzzp16jR69GghxLPPPhsdHZ2ZmRkdHa39FCRCAECt9ttvv6Wmph49evR//ud/Vq9eXemnR44c6dGjh+t5ZGRkVFTUsWPHzE+EpaWlBw4c2L9/f1hY2JgxY8q3q6r60UcfpaWlxcbGPvzww0FBQVX33bVr12effRYWFvbggw+2atWqulOUlJQEBgba7QztAkDdpijKsWPHAgP/Ix+1aNGifv36rucnT55cvnz5sWPHWrdu3aJFi0q75+TkhIaGlr8MDw/PysrSFYBXEuFbb721ePHiRo0aBQQEVEyE06dP37x586OPPrp27dqvvvpq3bp1lXb85ptvRo8ePWvWrF9//fW6667bv39/ZGSk9BSPP/74iBEjEhMTvRG/J65cudKgQQOzo/Cpy+8/63pSVlZW6b9yJapP4vGcTf8uiqIIIYz5Zqbj9D77jV7lRP/+p3fjd1eBdO+Q8fM9OqiXWfAjXzNV/KSqBbp2efOtv82csSQqKqrixnvvvXfevHmu5/369Vu7dq0Q4sknn3z88cc///zzii2bNGly7ty58pe5ublNmzbVFYBXEuETTzyRnJy8evXqxYsXl2/Mycl5++2309LSOnXq9MADD7Ro0eLgwYPdunWruOOCBQueffbZadOmCSFOnDixbNmyGTNmSE9RXFxcVFTkjeA95HQ6zQ7B14q+//cXmrLyZ7K/nH6YCOVNPXujmk9v034iz/KTlnfkNOJEdTERWvAjXzNVPa2KHF27REc7hw8fvn79+qu27NevX0pKSqWNnTp1+uqrr1zPf/vtt4sXL8bGxuoKwCtDi9LvxTt37mzWrFmnTp2EEGFhYQMGDPjuu+8qtfnuu+9GjBjhej5ixIiqDQAAtZmiOhW1TNdDFTV9mfjkk0+OHz9++fLltLS0v/71r7feeqtr+6OPPrpz504hxF133ZWenr5mzZorV67MnTv3lltuadmypa6YfTdZ5ty5cxXHOZs1a3bmzJmKDXJycoqKisp7x1FRUWfPnq3uaBkZGe+99155phwzZszQoUO9ELVuRUVFDofD7CgA/1E7x37KWeoj73A4AgICam6jCqeq6uslq6pSw0/3798/e/bsixcvNm/e/K677nr22X9eizl16tSVK1eEEKGhoevXr09OTp40adKAAQPeffddXWcXvkyEgYGBFccQSktLK/3vcb0sK/vn6FpZWVkN/71CQ0MjIyP79u3retm6deta8n/R4XDUkkgA/1DLP1CW+shruQquqE5VLbtqs4pqTpzz58+fP18yPL5p06by54MHD967d6+uk1bku0TYsmXLil3AzMzM+Pj4ig1CQ0PDw8PPnDnjmiyamZlZQ/e2cePGQ4cOHT9+vPcCdk9AQMBVvzEB0K6Wf6D4yFfmRiKscWjUB3xXfjBgwIDS0tJt27YJIU6fPr1nz57bbrtNCHH27Nldu3a52owcOfLTTz8VQiiKsm7duoSEBJ+FBwDwnKqU6X/UNDTqA17pEaampj799NPnzp3LyMiIj4/v16/fiy++GBwc/MILL9x1110JCQlff/311KlTXQWPGzduXLRo0cGDB4UQs2bNGjJkSGZm5pkzZ0pLS++77z5vhAcA8BK1DvYIvZIIY2NjX3755fKXDRs2dD1JSkoaOHDg3r17H3nkkX79+rk23nnnneXPr7nmmp9//jklJSUsLGzYsGH16tXzRngwlqq9WED1dBa/b8jfkE17RYjkbcrfuY5jyhrapEeV7C89j1w1gWo8kTz4uvHPDmOoQnciFDon1xjOK4kwPDy8T58+0h9169atUu1gZGRkxdmkTZo0GTdunDeiAgB4m2u0U+culrlGCABALcRNtwEAxlGdQu/QqPDHyTIAAIsyuo7QB0iEAADjqE6h8xqhf06WAQBYlFImlFKdu5AIUddpLoqoptCiFk6ul1UgeBanKq+U8EKhhaymopqiBg/rH4yvqagr65OgJmqZ/muETiHMvDsPiRAAYBw3hkYVEiEAwG8oXCMEAFiZG+UTNS7D5AMU1AMALI0eIQDAOGqZTefQqI2hUQCA/1AU3eUQfrkMEyxFlZZP6JgIr3W6vzdoL4nQE5JH1RfSQgub9Jcsr1/QGql08YpaWFOBusWmOOkRAgAsTHXq7hGaPVmGRAgAMI4b5RPcWQYA4DdsitNGjxAAYGFu1BHSIwQA+AuboujtEdrM7hFSUA8AsDR6hPCUnvIJjwotPKypkM/r96x+QlaAoH1v+WZpoUU1i1dIQ/KogKE21lSgblGYNQoAsDCbqn9olIJ6AID/oEcIALA0NybL0CMEAPgPVdF971DN9wX0EhIhAMAwNjduus3QKADAf7hxr1GGRlHnKZqXj9BcrODh7tXsLV3VQdpWutSD8aM3mqsKdK2SoXntC80lGTpqKnTQ/u5Rp9TBHiEF9QAAS6NHCAAwjE3RPVnG9FuskQgBAMZRWaEeAGBl+nuElE8AAPyHTVF1D43SIwQA+A83yifMvkbIrFF4SlFtVR+qYpc9bFUfimKv+tC+u56H5Jjys6s2yUN7SLLdhexRTUtR9SFvKSU9keSQ8pbVHFMWkrBVfUhbwlpcPUJdjxqHRl9//fXu3bsHBQVFR0fPmTNHqdJ9vHDhQocKXnvtNb0h0yMEABjHjVusKTUlQlVVly9f3rt376NHj95yyy1t2rSZMGFCxQZOp/P06dOHDx92vYyIiNAZMYkQAGAcm9GrT0yZMsX15JprrrntttvS0tIkJ7XZ2rdvr++kFTA0CgCoA4qKir799tsbbrih6o/Kyso6dOjQqVOnSZMmZWdn6z0yPUIAgHH0zxoVilJQUJCenl5xW2RkZFhYWPlLVVUnTZrUrl27e+65p9LeYWFhGzdu7NWr14ULF6ZOnTp+/PiNGzfqOj+JEABgHP3XCE+dL92+fXt8fHzFjffdd9/zzz9f/vLJJ588dOjQ5s2bbVXufBsSEnLrrbcKIZo3b/7OO+906tTp8uXLoaGh2gMgEQIAjKO/R9gm0h4fP3T9+vXVNZg1a9a333779ddfV+wjStntdiGEqrNCn0QIT6mK7EqzbCJ+Nf85tbf0iLwyQLZVvk6FtA5AtiyDfFUH+UZpTFobytepkK8pIfsly9+mFxaF0LGghkcLjKBWcOPOMjXOGp07d+6yZctWr1594sSJEydOREREuObFJCUl3X///YMGDfr+++9VVe3cufPFixenTp06YsSIq+bLSkiEAAADKfoL5GtKhL/88ktMTMyMGTNcL4cOHfqXv/xFCHHhwoXCwkIhxKVLl2bPnn369OlGjRoNHz684oCqRiRCAIBx3JosU8MPP/roI+n2devWuZ7cfvvtt99+u74z/icSIQDAONx0GwBgaW7cWcbsREhBPQDA0ugRAgCMo1xlFqhsF4ZGUcdJyyekayPIxz+kLeVn8mhuvbyuQHNLebGBfKPsoLLBFz2VClpLHTytqZCeSHOgqqypvPIE/oprhAAAS1NV3T08EiEAwH8YXT7hAyRCAIBx3OkReicSzUiEAADjKELo7eCZ3CEkEQIADKSq+q/5cY0QAOA36BHCghSn9vIJrRvlU/M1L01QzcIGWteUsNm1VkroWGhCvniFbKNd+18FL9RUyM+jeZENrWUa1fySWHwCZiARAgCMo+rv4TFZBgDgN1SDV2HyBRIhAMA4bvQIuUYIAPAfbkyWsVSPMDU1Va0wrTYqKiomJqZig+zs7BMnTpS/7Ny5c2hoqO/iAwB4SLEJReesJ89uI+w5nybCxx9/vLS01PX8p59+mjNnzqxZsyo2+Pvf/z558uTY2FjXy+XLl8fFxfkyQgCAJ1TVJp8KXtMuXopFK58mwh9++MH15Ndff23fvv39999ftc2NN964ceNGX0YFDynS1SdkXwkVVWuhhXxhBM8+LdWsFCHbKLtBlLSmwi4rdZAfUzZaZJMuSSH7fXpcUyFtJ10pQtZS/o60L56hZ5kN1HV18BqhOQvzLl++/Oabb27Tpk3VHxUUFHz77bc///yzYvZtWAEAuin/Gh3V/rDU0KiLqqqrVq168cUXpT89ffr0Cy+8cPjw4ejo6M8//7xZs2bSZjk5OVu2bCkoKBBC2Gy2IUOGlA+omsvpdDqdTrOjAPxHLf9AWeojb7fbbfLVKes2ExLhli1bcnJy7rzzzqo/SkxMdI2XlpSUjB49etasWcuWLZMeJC8vLy8vz27/Z482Ojq60rwbs5SUlBQXF5sdBeA/avkHylIf+aCgoMDAq2QNVbVLF+uucRfr3Wv0vffeu++++4KDg6v+qF69eq4nQUFB995778KFC6s7SJs2beLj48ePH++tKN3ldDobNGhgdhSA/6jlHyg+8pW5MWvU7Otgvk6Ely5d2rBhw/bt28u3qKpaVFRUv379Si0PHDjQsmVL30YHAPCM6sY1P4tdI1y9enXXrl179epVvuX48eMdO3b87bffIiMjJ0+e3LBhw1atWu3bt2/16tX/+Mc/fBweAMATqiKfNF4Tve2N5utE2Lx580WLFlXcEhkZuXjxYlfh/N13352SknLw4MF27dr99NNP7dq183F4cIPiDJBslJZPSAstPFynQjPt5RPSogi77DKGNCT57vKgZENC8poK2XvXfCFGvv6DhwUMnhVK6FiSAnWLahc6rxFabtbo73//+0pbGjZsmJyc7Ho+cODAgQMH+jgkAIBhFJveHqGH33E9x71GAQDGceMaodkjASRCAIBhVNWmu3xC71Cq0Uw+PQAA5qJHCAAwjjurT3gnEs1IhAAAw6gqk2VgPU6nZIDdKa+pkLT0tKZCFpL0U2WTVjVoLp8ICJDWVMjOpPnrrfaaCtUuXaND64mqKUuQFYSwJAU8o6p2VbbOTI37kAgBAH5D0V8gTyIEAPgN1Y06QqvdWQYA4NfsQu/QqNXuNQoA8Gfu9QhNLeUjEQIADOPOTbfNvkZIQT0AoPZavHhxly5dgoODo6KiZsyYoSiSadVfffVVu3btGjRocP311x89elTvKegRwlNlZZL/RU5ZUYS0psKpaF28QjonW7q0dTVrSkg2Btidso2yAgZV1lISu5Bf8ND8lVda0SGfj67KFq+QlkrI6xeklRK+WpICfsvge40GBQV9/PHHcXFx6enpw4YNa9++/SOPPFKxQUFBwd13371ixYqEhIS5c+c+9NBD27Zt03V+eoQAAMOoil33o8bJNZMmTerdu3dAQEDHjh1vvfXWffv2VWqwYcOG1q1b33nnnXa7ffr06bt379bbKSQRAgAMo6o2/Q9NR75y5cqWLVuqLtV39OjRbt26uZ6HhYXFxMQcO3ZMV8wMjQIADONGHaGi2AoKCtLT0ytubNq0aXh4+L8Pq6oTJ07s1KnTuHHjKu2em5sbEhJS/jI8PDw7O1tXACRCAIBxVJveFepP5zm379seHx9fceODDz44e/bsfx5SVZ944on09PRNmzbZqlzbbtq06YEDB8pf5uTkREZG6gqARAgAMI5q03sT7dZhjvj4+PXr11fXYMaMGdu3b//6668r9vzKdenSZfXq1a7n2dnZmZmZnTt31hUA1wgBAIZxDY3qfdRwwNmzZ69cuXLhwoXp6el79uwpH0GdMGHCd999J4RISEi4dOnSkiVLcnJyZs2aNXTo0DZt2uiKmR4hPCUtiihzSv5rlZZJW2quqZAvSSEJqZo1JSQbAwMkRRGBAWVVNzo8rfmVrtUgq5SwyapEbJJKCZs0JO1xapyiUG1NhOyfQ74khdaDml1XDQOoQnePsGYXLlzo0aPHyy+/7Ho5aNCgOXPmCCEuX75cWloqhKhXr94XX3wxderU559/vn///suXL9d7ChIhAKD2WrJkiXT7mjVryp/37dtXb+1gRSRCAIBhVMWm6pwso7e94UiEAADDqPony0iXg/YlEiEAwDBu1BEK2b0CfYlECAAwED1CAICVKTahu0dIIkQdJ61/KCmVlk9INpZICy2kJRmyK+rS75IBskn8gbKFJhyySomgQM/KEmSkC2LYZBUd0hsvSr9iy793yzZKzy5/RzrepfZ1KqQHZaEK/6Sqtppvoi3dxUvBaEQiBAAYhskyAABLU9W6N1mGW6wBACyNHiEAwDAMjQIALE1V5bcFrnEXEiEAwF+oql33LdZIhKjrymRFEdJKiaIyR9WNhaVBkpbymgrt5ROSi+/1ZAtNBAdKP7HSCgRZO1n9g12RnF2R/WmQtlTtWislpKtHyAsl5JUSWusfqGmAdu4MjZIIAQB+w41EqKMk1TtIhAAAw6iK0Fs+QY8QAOBHGBoFAFiZ4SvU+wAF9QAAS6NHCAAwjKra9d90mxXqUceVKbLVJ2T1D0WlkvKJAln5RL6sZWGZ5ERO2dz+ILukLCE0ULLQhLTy1y6rK7DLjhkgW9FCscvKPDQvHyGfaCD9QyEfgNK+1IPmhh4OdLHOhJUoik3RO1mGZZgAAP5D1T35xezqCRIhAMA4bkyWMX1yDYkQAGAY7iwDALA0RbXpvum2l0LRjEQIADAMPUIAgLXpnyxTzfxn3yERwlNlskUhSp2SUocip6Qo4rKsUiK7WFJTkV0iq9OQTbwOc0hKHZxB0nUqJKMyDtk6FQ6nZKMzQPLeFVlRlHT1CXn5hKywoJqWEvIlKWQt5X995KtXyHan/gH+gkQIADCMOwX1Zn+rIhECAAyjqBTUAwAszJ3JMl4KRTMSIQDAOMwaBQBYmaLKb+FbAxIhAMB/uHOLNS+FohmJEJ6SVgs4ZRtLZSUEhbJCixxZpcTxfMnZs0tLqm6MDZVUX9SzS/63hzgkS1KUyeKUfsmVzo6TFjBIyf9eeOOvghfqH6qp09BckgE/pQqb/lmg9AgBAP5C1X+LNb3tDccK9QAAS6NHCAAwjBvlE9xiDQDgP9yYNaqYfRG5Ng6Nnj17Nicnx+woAAC6uXqE+h41Tpb561//OnTo0A4dOqxatUraYOHChR0qyMvL0xuzPBHedNNNCxYsuHjxot7D1SwqKsr2L4mJiVUb5OTkDBo0qF+/frGxsZMmTVK1T78DANQCrskyuh41D6WGhIRMnjy5adOmly5dkjbIycm54447dv9LWFiY3pjlQ6MtWrSYOXPm3LlzExMTk5KSbrzxRr3Hrc7hw4c7d+5c3U/nz5/fpEmTrVu35ubm9unTZ+PGjSNHjjTq1PAl6XcY6UbpKEqZbGN+maTUId2eUXVjjDNWdiJpSNJPoNb1H6S0rxQB+B936ghr/Hg89thjQoi33367hjbBwcERERG6TlqRvEe4Zs2a06dPz507d+vWrQMHDuzSpcuCBQuysrLcPk05RVFKSiSFXy4ffvjh5MmTbTZbRETEfffd99FHH3l+RgCAz7gxNOp5HeF7770XERERFxe3YsUKN3av9hphy5Ytn3766WPHjm3YsKFDhw4zZ85s3br1Qw89tGPHDg+iFf3792/YsGG/fv127txZ6UfFxcXnzp3r2LGj62XHjh1PnjxZ3XFKSkpOnjy5518KCgo8iQoAYAhV2BSdD6cqLl26tOc/ZWdnazzj2LFjd+3alZGR8eKLLyYnJ3/xxRd6Y77KrNHAwMA777xz4MCB8+bNe/XVV1euXLly5coBAwa88sor/fv313uylJSUuLi40tLS+fPnjxo16ujRoxUHc/Py8lRVrV+/vutlSEhIdSPCQojjx4/v2LFj3bp1rpcTJ06899579cbjDZcvXzY7BMCv5OfLbilUa1jqIx8cHOxwSFbSrkjVv0L9+eLCtLSfk5KSKm4cPXr0rFmztOzeq1cv15OEhIQJEyZs2LAhISFBVwA1JUJVVbdu3bp06dJ169bZbLaHHnro0UcfPXPmzEsvvTRkyJAjR460adNG18ni4uKEEA6HY86cOa+99trevXsHDRpU/tMmTZoEBgbm5uZGRUUJIXJycpo1a1bdobp27TplypTx48frCsA33LhUC6A6tf8DVfsjrOWa12swZMiQ9evXe36osrKygADJDRprJh8azcrKeuWVV6655pohQ4bs3r17/vz5mZmZy5cv79+//5gxY77//vvQ0NBt27a5HWtRUVFRUVGDBg3+IxS7vXv37j/++KPr5Y8//tizZ0+3TwEA8D29U0aVq92S7cCBAykpKdnZ2UeOHElJSTl//rwQYseOHWPHjnU1WLJkyf79+zMzMz/44IPly5dLSxJqJu8R9uzZ8/z586NGjXr99deHDRtms/1HlEFBQX369LlqB7mSvXv3btu2rU+fPsXFxQsXLuzSpYsrz61bt2716tWuQc7HH3/8ueeei42NzczMXLt2rYfXIwEAPqaqOu47r8UXX3yxZcuWxo0bHzlyZMGCBbNnz27WrJmiKGX/mkZ+8ODB119//fLlyx06dPjwww/j4+P1nkKeCKdNm5aYmBgdHV3dbps2bdJ7prCwsJ07d3700Uf16tXr16/fqlWrAgMDhRARERGxsf+c7D5hwoSCgoLp06eHhISsXbu2a9eues8C37PL1hYIkG0MtEs21gtwVt0Y5lCqbuwQKvnvGi2rlGhcr+o2UT9AcsxAu2RjgE2yUfo2bbKyCJu8pYTNZzeW8sKJfBc86hRVGHzT7RkzZsyYMaPSxhtuuKF8jsjrr7+u63RVyRPh1KlTPTxuVdXdF+Dmm2+++eabXc9tNltycnJycrLhZwcA+IBbyzCZjHuNAgAMc9VrftJdvBSMRiRCAIBh3CifML0HSSIEABjGVVCvcxeTkQgBAIZxY9ao6csr1MZlmAAA8Bl6hPCUXVaBECgriggKkCwfERIouQ1EkyDJV7R6dklLp+xqRLCsUiLcUVp1Y/1ASUgOWfCBdslG6XuXF1rINkrHhHS0lLXTMSjljesy8uBhIW5MltG9or3RSIQAAMO4swwTk2UAAH7DrckyJEIAgL9QVN11gaZPliERAgAMUxdnjZIIAQCGYWgUAGBpqspkGViPtK5AWoEQLKtVkH5mpBUI0kILSfmCEIGy3aWVEvUDJTUV9WRlHtKCkABp+YR8o6z+QbpR9jdBvtSD5gUxqqG5ZR27hTLMpFTzqax5F3NRUA8AsDR6hAAA4+gfGjX9ZqMkQgCAYViGCQBgaW5cIzS7Q0giBAAYx51brNEjBAD4DZUeISxIvtCEKqlAkJJWSjhkJRllqqR8QgeH+28AABbvSURBVHpPCvkxZXFKKyXqyWoqHLLqC+l7l5ZP2GzSdSqkLbUuSVFNTYV0oxcWr9CO6gsrcWuFepORCAEAhmEZJgCA1ent4ZneI6SgHgBgafQIAQCGYWgUAGBp1BECACzNrdUnTEYihKcCZXUFUtKFEaQlBI4A2UITiuSStvQjJC2fkK4UIa1/cMhqKqTlEwHSJSm011TIl6TQWlMhfffSX7L2Sgk9i1doZ/ofOviOG3WEpq8+QSIEABjGjTvLCK4RAgD8hqIKRecQgN72hiMRAgAMwy3WAACW5tYt1kweGqWgHgBgafQIAQCGoY4QViStQJAvgaC5qsGpSo6pKpKjSj9C0mUZpHUaAQGymgrZ2hfSoojAQGlL2UIT0o2erj4he/eaV5+Q//KkNRU6ijc0813xBnxKVeVrwtS8i7lIhAAAw6jCpui85md2HiQRAgCM40b5BD1CAID/UE1ahqm4uNhutzscDjf2ZdYoAMAwqmpT9D5qHEp96aWXBg0aFBkZ+e6770oblJSUPPDAA1FRUU2bNn3iiScURfct20iEAADDqP+aL6P9UXOXMDIy8qmnnoqNjS0qKpI2WLJkyc8//3z27NmTJ09u3rx5zZo1emMmEQIADKO49ajBH/7wh4SEhNDQ0OoarFq1avLkyQ0aNIiIiHjkkUfef/99vTFzjRCekpdPSKf7yxZbkJZPSBf21H67CnkFgexE8nUqNC8fIa+UkFVf6Fl9Qvb1WNpSR6GF5JDSjTrIf8ueHRPQ79ixY127dnU979q16zvvvKP3CCRCAIBx3FiPUBW5ubl79uypuLF9+/YRERFX3VdRlPz8/JCQENfL0NDQnJwcXWcXJEIAgIHcuLPMJeflvXv3JyUlVdw4ZsyYmTNnXnVfu93epEmT3Nxc18ucnJyoqCid5ycRAgCM40YdYVhA2JBBQ9avX+/eGa+55pq0tLQbb7xRCJGWlnbNNdfoPQKTZQAAhlHdetTgwIEDKSkp2dnZR44cSUlJOX/+vBBi+/btY8aMcTVISkr67//+759++mnnzp1Lliyp1LPUgh4hAMAwqlt3lqnhouIXX3yxZcuWxo0bHzlyZMGCBbNnz27WrJndbg8M/Gf+uueeezIzM++5557AwMB58+YNHz5cb8wkQgCAYdy76XYNiXDGjBkzZsyotLF///5r164tfzlt2rRp06bpO2sFJEJ4KkC2AoNN9p3QLrvjg2KXjM9LZ53pnYpWOSRZXYG0qsEur2qQtjR+o03zkhTSmgodC03o2Kid2XeNhNkUbroNALAyVegeGlVUEeCdYDRisgwAwNLoEQIADOPG6hOmIxECAAzjRh2h7tUijEYiBAAYhh4hAMDS3Kgj1NvecCRCeMquffUJ2XoH0hKCaiolZBulHyEdKzBIW2pdKaKa+gfNLTWvPuHhmhLyhSZ0tJSdXdZQTnqiutdtgCZuDI3qrTs0HIkQAGAYN4ZGzc6DJEIAgHHcucWadyLRjkQIADBMXewRUlAPALA0eoQAAMPUxckyvusRKooyc+bMPn36REdHDxky5Jtvvqna5ssvv+xbwf79+30WHgDAc+q/FqDQ9TCX73qETqczJyfnzTffbNu27YYNG0aOHHn48OGYmJiKbbKysoKDg1999VXXy/bt2/ssPLhNXv8gnXBv17ymhHT1Cenp5eUT0m3ayxI8q2qQt9RcPqE9JOlCE5o3ynfXzsPd5cc0/pDwMVX/nWLMzoM+TIQOh+Ptt992PZ84ceKCBQtSU1MrJUIhRMOGDfv06eOzqAAABqqLt1gzZ7LMyZMnz54926NHj6o/2r17d58+fUaMGLF69WrV9A4zAEAP/cOi5v+dN2GyTGFh4T333PPkk09WHfmMi4tbsWJF69at9+/fn5ycXFRU9Ic//EF6kP379//tb3+bMmWK6+WcOXOqa+ljly9fNjsEwK/k5+ebHUJNLPWRDw4OdjgcNbfhFmtXV1xcPHr06A4dOrzwwgtVfxoXFxcXFyeE6N69+4ULF1atWlVdeuvRo8fEiRPHjRsnhLDZbI0aNfJq2LqEhYWZHYJP5ZgdAPxb7f9A1f4IfcmdyS+WSoQlJSWJiYnh4eErV660268yKhsWFlZUVFTdT202W0hISEREhNExAgDcp+i/5meha4ROp/Puu+++cOHCvHnzMjIy0tPT8/LyhBAXLlx49NFHXcMLKSkpv/32mxDi4MGDCxcuvOOOO3wWHgDAmnzXI8zLy9u3b58Q4vbbb3dtmTdv3r333nvlypWUlJSSkhIhxKZNm8aOHZufnx8ZGTl+/PgZM2b4LDy4Tbr6hI6iCM0bPaS9WsDTAgYvFEVor5So5m1qHnvSvMxFNbtLt5k98gUf4l6jNYmIiDh+/HjV7W3atElPT3c9X7hw4cKFC1VVla7XAwCo5dyYCGr6xNHaeIs1siAA1FGK/lmgphfK1cZECACoo+ri6hMkQgCAYVRVVXR28Uy/dwqJEABgmLpYPkEiBAAYRlVV03t4epEI4Sm7rFpA+kmQFkXYpDPuZZ8j7Z8tHbOttFcLeKXUQdZQ++7yX4ln70jW0CsXcZgS56fcWH3C9B4hK9QDACyNHiEAwDCKKpgsAwCwLsonAACWpgpV4c4yAADLUtypI/RSLFqRCAEAhuFeo7Aim10y+dkmXVNCXhUhbSk7kWf1EzoKA7RXNUhP7uFKETrO7oVKCe2/Ze0LTVApYSVulE+Y3SEkEQIAjKPov0aot73hSIQAAMOo+oc6tbQuKSkpKSkJDQ11L6qaUVAPAKjVnn/++cjIyDZt2sTHx+fk5FT6qaqqjSuYPn263uPTIwQAGEYRiqLzKqFaY/vt27e/8cYbBw4ciI6OHjt27Ny5c1999dVKbXJyctLT0xs1aiSEqFevnt6Y6RECAAzjqiPU9ah5aPSDDz4YO3ZsTEyM3W7/4x//+MEHH0ibNWrUKCIiIiIiokGDBnpjJhECAAyjNwtedXLN8ePHu3Tp4nrepUuXnJyc7Ozsqs3atm3bqFGjkSNHHj9+XG/MDI3CUzbZ6hM6SmTlS1KYSXulhI7FKzwrdagzlRKeMn0iPTzlXh1hbm7unj17Km5s1apVs2bNhBCXLl0KCQlxbXRNlsnNzW3cuHF5S5vN9n//93/9+vXLz8+fNm3anXfeuX//frtdRzePRAgAMIwqVL3XCIvVy3v3Hk1KSqq48a677nrmmWeEEFFRUbm5ua6NridRUVGVjjBw4EAhRJMmTd54443w8PDjx4937NhRewAkQgCAYRSbqui4+YUQQjjsDYYMGbJ+/XrpT7t3717eWdy9e3fbtm1rKKIoKipSVVXvfBkSIQDAMKo7s0ZrSpwTJky49tprP//88y5duvz5z3+eOHGia3tSUtLw4cMTExN/+OGHjIyMuLi4/Pz82bNnDxw4MCYmRlcAJEIAgGFUodZcDiHbpab2sbGxH3/88UsvvZSbm/u73/3uT3/6k2t7SEhIUFCQEMLhcKxaterEiROhoaGDBg2aOXOmrZoL9dUhEQIAarU77rjjjjvuqLTxlVdecT3p27fvxo0bPTk+iRAAYBi3Cuq51yjqOJtN9p9eOjShY1EJzbvLY5Ju1bx8hGfH1F4+4eEyF7WxUkLHiBSVEv5JsamK9G9Cjbt4KRiNSIQAAMO4NVlG78JNBiMRAgAMowpF/2QZeoQAAH+h6C+oJxECAPyHG0OjetsbjkQIADCMYlP0TpahRwgA8B+qUFTh1LuLl4LRiEQIT+mZ7i/bKN9ba7GBV2gvIdAckoe71/FKCc3MXXYEVkUiBAAYhvIJAICluXWvUa4RAgD8haI6FZVrhAAAq6JHCACwNFU4Fd2zRvW1NxyJEABgGG6xBkvSPF9fx6oO3vhceDo1X/tCE5pp/9V5tp6G2ZUSphbDwLcUoejvEXKNEADgL1RVUVWdPULV5B6h3dzTAwBgLnqEAAADuTFrlKFRAIC/cKeOUOdQquFIhAAAw1BHCACwNFU4VZ09QkGPEHWdpzP75Qf1aG/f0b7Ug3RvLxyzNlZKwFq4RggAsDBFVRS95RNmf38iEQIADMPCvAAAS6OgHgCAOoYeIQDAQG7cdJuhUQCAv1BVVXeBvNlDoyRCeMomm+5vkUn0OtbT8FU9SW2slNARPOo8d64Rmv0Hg0QIADCMW7NGWZgXAOAv3OgRMjQKAPAnitA9+YVECADwF6rQPVmG1ScAAP7EjfIJKxXUFxYWzps3b8yYMU899VR2dra0zWeffZaYmPjwww/v2bPHl7EBAKzJp4kwKSlp69atjzzyyJkzZxISEqo2+OyzzyZPnjxu3LiePXsOGzbs1KlTvgwPbrKpVR82+UNIHsLUhzQk+UPyjqTvXQjpQ/qr0/qwCVXjQ8eb18Gzd+RRQ9Q1qqL7YXaP0HdDo2fPnl2zZs3JkydbtGgxfPjwZs2a7dixo3///hXbLFq06Pnnn7/rrruEELt27Vq6dOmLL77oswgBAB5yo3xCy+SawsLCwsLCxo0buxdVzXzXI0xLS2vbtm2LFi2EEA6Ho3///jt37qzYQFXV3bt3Dxo0yPVy4MCBlRrUCZs3bzY7BAC+w0e+CsWtR01mz57dokWLrl27Dh48OCsry/CIfdcjPHfuXMVk3qRJk3PnzlVskJWVVVJSUt6madOmZ8+ere5oR48e3b1794oVK1wvH3roodGjR3shan0KCwvvu+++CxcumB0I4D8uX75sdgg1SUxMzM3NtVWzPrWfCQ4ODgy8WtZQVf0rztc0NLpt27alS5ceOnSoRYsWd99999y5c19//XWdx78K3yXCkJCQ4uLi8pdFRUUhISGVGgghytsUFhaGhoZWd7SWLVsOHjx4+PDhrpc9evSoobHPBAQE2Gy22hCJLxWZHQD8Wy3/QKmqGhoaapFEqIUqVP2zQGtqv3r16rFjx7Zs2VIIkZycfMcdd7z22mvG/sJ9lwhbtWqVkZGhKIrdbhdCnDx5stJ8mfr16zdp0uTkyZOtW7cWQpw6dapVq1bVHS0kJKRbt27liRAAUDsYXFCfnp4+atQo1/MuXbrk5ubm5OQYe7HQd4mwf//+DRo0+Pzzz3/3u9/t37//559/HjlypBDil19+OXDgwJgxY4QQY8eOXbFixU033VRYWPjJJ5/Mnj27uqMVFRWdPHmytpVYFBcXK4pS26LytjZmBwD/Vvs/UHv27LFIj7Bly5aueR41qn5ScfW75ObmVvqHLj9XXl5e+fCh60lubq6xidDmy6WBP//884cffjguLu6nn3567rnnJk2aJIRYtmzZokWLDh48KIT49ddfhw0b1qhRo6ysrO7du3/66acOh0N6qHHjxu3fv7/S4KrpVFU9depU27ZtzQ7EHJmZmZGRkUFBQWYHYoKcnBybzdaoUSOzAzFBcXFxVlaWa+TKgk6cONGuXTuzo/CRu+++e9q0aYYfdv369cnJyVFRUdJzJSQkDB069I9//KMQ4ty5cy1atMjPzzd2wNyniVAIkZube/jw4Xbt2jVr1sy1paioqLCwMCIiwvWyrKwsLS0tPDy8c+fOvgwMAFALzZw589SpUx9++KEQ4n//93+nTJmSnp5u7Cl8nQgBANDu+PHjvXv3XrFiRZcuXcaPH3/PPfdMnz7d2FOQCAEAtdo//vGPBQsW5OTkjB49+tlnnw0ICDD2+CRCAICl+fReowAA1DYkQgCApZEIvSI1NTU+Pr5NmzYdO3acMGGC3990LS8v76GHHmrVqtV1112XkpJidjg+9f777/fr169Vq1ZxcXHz589XFJOXGPWxzMzM+++/PyYmpnPnzosWLTI7HJ/aunXr4MGDY2JiEhISWCqnTiMRekVYWNhTTz31ww8//P3vfz9//vxjjz1mdkTe5VpgMjU19Zlnnvn9739/8eJFsyPynXbt2r355pupqanvvPPOu+++u3TpUrMj8p0rV64MGzYsKirqu+++27hx47XXXmt2RL6TkZExcuTI5OTkQ4cOXXfddYmJiWZHBPcxWcbr1q1bN3PmzMOHD5sdiLdcuXIlKirqhx9+6NGjhxBixIgRt99++9SpU82OywSPPfZYYGCg4XcErrWWLFmybNmy3bt3mx2ICZYtW7Zy5cpt27YJIZxOZ3h4+LfffnvdddeZHRfc4btbrFlNaWnp/v37z5w585e//MV1Dx1/derUqeLi4u7du7te9u7d+9ChQ+aG5GNZWVnHjh07cuTIpk2bPvnkE7PD8Z3U1NTrr79+4sSJ+/bt6969+7x585o3b252UD7idDpdt00WQthsNpvN5uoamhsV3EMidFNeXt6mTZuqbh8yZEhkZKQQIj8//5lnnjl//rwQ4qabbvJ1fD6UlZUVFhZWfq/FRo0a/fLLL+aG5GOpqakvv/zy0aNHr7/++o4dO5odju/8+uuv33zzzdKlS6dNm/byyy+PGjXqxx9/tMhdN4cNG/bkk09++eWXw4YNW7x48ZUrV/x+KoAfIxG6KS8vb926dVW3d+/e3ZUIGzdu7Fqxc9myZaNGjTp16pS//oGIiIi4fPmyqqquN5iXl9ekSROzg/Kp+Pj4+Ph4p9M5fvz4P/3pT8uXLzc7Ih+JiIgYNGjQ+PHjhRCLFi1q2LDhyZMnLXLjzdjYWNfCAElJSaNGjerTp491esP+h0ToplatWn388cdaWsbHxz/yyCOXL18OCwvzdlSmiImJsdlsx48fj42NFUIcOnSof//+ZgdlgoCAgKFDh1onCwohOnbsWFBQ4HoeHBwcEBBQcc1Rv5eQkOBaSy43NzcmJqZnz55mRwQ3MWvUK7Zt23b69GkhxKVLl1566aU+ffr4axYUQoSHh48ZM2bBggVOp3PXrl1btmy5//77zQ7KdzZu3JiXlyeESE9Pf/fddwcPHmx2RL7z4IMPfvPNN66lY9588802bdq4vgxZxN69exVFyc7Onjhx4k033eSaLIa6iEToFQcOHLjhhhuCg4NjYmLOnTu3du1asyPyrkWLFqWnp0dERIwcOXLJkiUxMTFmR+Q7n376aevWrYODg2+44YYBAwb8+c9/Njsi32nbtu1bb70VHx8fGRn5ySef/O1vfwsMtNAg05QpU0JCQqKjo4OCgjSOD6F2onzCi5xOp+E3h63NrPZ+K7LyexdCKIpSPoXSUiz+7+43SIQAAEuz4pc4AADKkQgBAJZGIgQAWBqJEABgaSRCAIClkQgBAJZGIgQAWBqJEABgaSRCAIClkQgBX/j0008//PDDilu+/PLL9957r7S01KyQALiQCAFfqF+//vjx499++23Xy61btyYkJGRmZjocDnMDA8C9RgEfSU5Ofuedd3744YdWrVr17t07Njb266+/5pbNgOlIhICPlJSU3HjjjXl5eW3btt23b19aWlqLFi3MDgoAiRDwoePHj8fFxRUWFm7atCk+Pt7scAAIIYSFVtEETJeWlnblyhUhREZGhtmxAPgneoSAj2RkZPTu3Xv48OERERHvv//+jh07evbsaXZQAEiEgE+UlpYOHjz4woULe/bsCQoKGjBgQElJya5duxo0aGB2aIDVUT4B+MLTTz+dmpq6Zs2a8PDw4ODgtWvXnj59esqUKWbHBYBECHhffn5+8+bN161bd+2117q2dOzYcd26dR07dszKyjI3NgAMjQIALI0eIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0kiEAABLIxECACyNRAgAsDQSIQDA0v4fPB4JIN95UzQAAAAASUVORK5CYII=", + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "plot(problem, state_1_1; plot_type=:std, clims=(0, 3), aspect_ratio=:equal)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAIAAAD9V4nPAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nO3dd1wUx/8/8Lk7QHoVkKagIBbEAipGwQpJFFFR7ORri2jix5KIJPZEY/mYRBNjw26MsYX4MRrFmqixIVixxAoooIL0dnC7vz/28+FHYDhv7/bugH09H/fHMje7Oxgu75vZec9IWJYlAAAAYiXVdwMAAAD0CYEQQB0ZGRkTJ05cu3Ztnb0gAKgIgRBAHTk5Odu2bTtx4oT2Lnjnzp3Y2Njbt28LdQsAoEIgBKgTzMzMevXq5evrW1ly+vTpqKioU6dO6bFVAGJgoO8GAAAhhDRr1uzs2bP6bgWAGCEQAtSKYZjLly/fvHmzpKTE2dk5ICDA3d1def0bN27cvXv35cuX5ubmfn5+/v7+1eo8ePCgsLCwXbt2MpnszJkz9+7ds7S0HDduXGlpaXJysrW1dYsWLQgh9+7de/78OSHk+fPniYmJ3LleXl55eXmvXr1q2rSpvb19tSunpqa+fv26WbNmjRs3FupfAEAUWACguXTpUuvWrat9XhYsWMC9m5ycTAgJDQ2trJ+QkODo6FitflBQUGZmZtXLBgYGEkL+/PNPHx8fro67u3vNC/r5+dX8tB4/fjwuLo4QMmbMmJoN7tChAyHk7t272voXAWig0CMEoLhx40afPn3KyspmzJgxevRoGxub1NTUkydPKjnlzZs3vr6+Y8aM8fb2trOzS0lJ+e67744cOTJ27NiaJ0ZGRnp6eu7Zs8fd3Z3r+VWzfv36nTt3rl+/fsqUKUOHDuUKO3bsaGVl5erqevDgwdWrV1ftFF66dOnGjRu9e/euGbwBQDkEQgCKadOmlZSUrFmzZsaMGVyJl5dX3759lZwSEhISEhJS+aOXl1efPn169+596tSpu3fvtmnTpmplOzu7+Ph4A4NaP4BdunS5dOkSIaRly5b9+vWr+takSZMWL168e/fuWbNmVRbGxsYSQqKionj8kgBACMGsUYCaUlJS/vrrL2dn52nTpmlyHalUOnDgQELI1atXq7316aefKomCyk2ePNnQ0HDTpk3s/5aFysvL279/f+PGjQcPHqxJgwHECYEQoLqbN28SQnx9fWUyGa8Tz507Fx4e3rJlS1NTU4lEIpFIoqOjCSFZWVnVarZt21bt5jk5OYWFhT148OD8+fNcyY8//lhcXDx+/PhGjRqpfVkA0cLQKEB1+fn5hBAnJydeZ+3ZsycyMtLY2Pi9994bNmyYlZUVIeTq1atxcXEVFRXVKms4sXPq1Km//PLL5s2bg4KCCCFbt26VSCSTJk3S5JoAooVACFAdF8NevHih+iksy8bExBgYGFy8eLF9+/aV5UuXLuXmeQqrT58+3t7eBw4c+Pbbbx89enTjxo2+ffu2bNlS8BsBiAGGRgGq69ixIyHk1q1bNXtytcnOzn7+/HmbNm2qRkFCSFJSktrNMDIyIoQoFIqab0kkkqioqLKyst27d2OaDICGEAgBqnN1de3Tp09mZubq1atVPMXKysrIyCgzM1Mul1cWJiYm/uc//1G7Gc7OzoSQtLQ06rvjxo0zMTFZv379/v37HR0dBw0apPaNAEQOQ6MAFGvXrg0ICIiJiXn06NGoUaPs7e1TU1NPnDhhbGy8fPnymvUNDQ27d+9+9uzZ4cOHz5kzx9bW9ty5c/Pnz3d3d3/y5Il6bejYsaNMJtu+fbuxsbG7u7tMJuvfv7+rqyv3ro2NzciRI7dv304ImT59Otd9BAB16DujH6COSkpK4tZqqSSTyb766ivu3Zoryzx69KjaU7qoqKgNGzYQQpYvX15ZjVtZJi0trdrtal6QZdmtW7dy/ULO8ePHq77LZWVIpdJHjx4J/MsDiImExQ71ALXg1g69fft2WVmZk5NT165dHRwcuLfkcnlKSoq5uXnVyaXl5eV//fXX48ePGzVq1L17dw8Pj4KCgtevX9va2lpbW3N10tPTS0tLmzZtWi2PkHpBTlFR0cuXLwkhTk5OJiYmleV//fVXjx49goODBdwNCkCEEAgB6qvhw4cfOHDg8OHDXNo+AKgHgRCgnsnKysrPzz9x4sRHH33Utm3bW7duSSQSfTcKoB5DIASoZz7++OP169cTQszMzP7444+aOz0BAC+YNQpQzwwaNKhp06aOjo7vvfdekyZN9N0cgHoPPUIAABA1JNQDAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAICoIRACAEDdtWHDhiFDhnh7e+/atYtaQaFQzJo1y87OzsHBYfHixWrcwkCjBgIAAGhTUVFRWFhYampqXl4etcK2bdtOnjx5//790tLSwMDADh06DB48mNct0CMEAIC6a/bs2ePHj7e1ta2twrZt22bOnGlvb+/m5jZlypRt27bxvQUCIQAA1GMPHjzw8fHhjn18fP7++2++V9DK0Gh5efmdO3du3bplYWERHh5eWc6y7J49e65fv+7p6TlhwgQjI6Oa5yYkJBw8eNDCwmLcuHGurq613UIulxsYGEilCOQAAPUbwzCPHj0yMPhHPHJycjIxMXnruSzL5uXlWVhYcD9aWlpmZWXxbYBWAuH69evXrFljbW0tk8mqBsLo6OiTJ09Onjx5//79J06ciIuLq3bi2bNnhwwZMm/evOfPn3fu3PnWrVv29vbUW3z88cchISERERHaaL8miouLTU1N9d0Knfpm6m7uoKKiotqfsngwDEMI4f/NjBW4np5o9T/97A2RWrqyIET4kVeOJbdZtojXKevW/zL3840ODg5VC0ePHr1kyZK3niuRSGxsbPLz87kf8/LyaosaSmjlb/df//rXjBkzdu/evWbNmsrCnJycDRs2XL9+vWXLlh988IGTk1NycnLbtm2rnrhy5cr58+fPnj2bEPL06dMtW7Z8/vnn1FuUlZWVlpZqo/EaUigU+m6Crh3fdVHwa0oEv2It9B1gGkggVE7DxtfxQCjCj7xyLJvGkhxep7i4KPr16/frr7+qd0dvb+/bt29369aNEHL79u2WLVvyvYJWhhap34uvXr3q6OjINdHCwqJbt25//vlntTp//vlnSEgIdxwSElKzAgAA1GUMq2DYCl4vlij7MvH06dPExMT8/Py0tLTExMScnBxCyLVr1yZNmsRVmDhx4po1a9LT0x8/frxx48aJEyfybbPuBrIyMzOr9lgdHR3T09OrVsjJySktLa3sHTs4OGRkZNR2tdTU1K1bt1ZGyvDw8D59+mih1byVlpYaGhrquxUADUfdHPupJKqPvKGhoUwmU16HJQqW5ddLZllGybvbtm07duwYIeTMmTNnzpxZsWJFv379iouLU1JSuArjxo17+PChv7+/TCb7+OOPw8LCeN2d6DIQGhgYVB1DKC8vr/bXw/1YUVHB/VhRUaHkz8vc3Nze3t7f35/7sWnTpnXkb9HQ0LCOtASgYajjHyhRfeRV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", + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "plot(problem, state_1_1; plot_type=:clarity, clims=(0, 1), aspect_ratio=:equal)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ @@ -251,18 +2176,1504 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.875670 seconds (51 allocations: 173.222 MiB, 0.45% gc time)\n" + ] + }, + { + "data": { + "text/plain": [ + "KFState{Float64, Vector{Float64}, Matrix{Float64}}([1.3298517650962889, -0.0005874103212140304, 1.33814424416366, -0.0005910732014842028, 1.340417670745858, -0.0005920773993007984, 1.3372673561456687, -0.0005906858702899778, 1.3289956849635092, -0.0005870321810942219 … 0.5820667601747535, -0.00025710536432420013, 0.5421027662669569, -0.00023945282355648936, 0.5043385644953952, -0.00022277195545129997, 0.4687329608137602, -0.00020704456414003282, 0.43520952027966425, -0.00019223688745818328], [529.6996628676703 8.754161421542506e-6 … -0.006485916666963342 2.8649015572292096e-6; 0.0 -5.097132533612237 … -0.00029773488481363 1.3151281136385414e-7; … ; 0.0 0.0 … 529.625870244218 7.394996825355049e-5; 0.0 0.0 … 0.0 -5.0971310369744005])" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "state_2_1 = stgpkf_predict(problem, state_1_1)" + "@time state_2_1 = stgpkf_predict(problem, state_1_1)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 39, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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o6Onp2dbathkA+Chhx5qyznBwmygMcpx3MyZM2fOnJmXl3fgwIEffvjh+++/j4uLS0xMFNN0CCHTp09funTphg0bXnzxxe3btxcVFc2ZM6fxXA/mJsbbf/7zHzHFr+3EFMK8vDzZ9FKGiX05hYWFHTp0kD4uTo2ht2XLllOnTk2ePHnr1q36hjLP8ytXrjTmKu+++25ubu7y5ctXrVqlfzA9PV0cSAdgmBgsq1atWrRokeE9x40bN27cuNLS0j///POXX3758ssv58+f7+rq+thjj1miooQQQl599dWSkpL//ve/0kbw4cOHjYl08Zm6uroWFxc3nrUKwMqJLcW8vDzjDykvL1+1alWHDh1OnTolnVtGnCiQuYcffvi5557bsGHD8uXLxQbA3LlzLd8AgLawpU/G4ODgadOmffvtt6tWreJ5fseOHfpNLi4u06ZNy8/P//XXX8XuB+kIMOOpVCo7OzvZ/23GE++nHzlypMU9HRwcjLmKeEL9tGpGuuWWW8i/t0H1tFqtbKSOOAZg6tSp0i7bCxcu1NXVyaoqHi67ini2Bx98UPrgqVOnTKoqtFvie9v4waDe3t733XdfQkLCV199RQgRs/RI8+9PtsR3u6yvpfG7XZyCTdbT6erq2rVr14qKivPnz5u1kgDmIC5jZtJne2pqan19/fDhw2WzHLblC0KM9CZvI7i5uT3yyCPSBsDcuXNbfSFQhLU3Rnmer6mpkT0o3i+QjkEh/45iXr58+aFDhwYMGDBgwIBWXE6lUgUFBRUWFspObqQRI0Z07tz5yJEjP/zwQ+Ot0mSIjh07lpaWNn5qMuK8Tu+8805RUZHx1RCTtN59911p3H799dfijNx64l172ShScSYdKfHTpPGK9uL0AtLDNRrNK6+8Ynw9oT279957fX19d+7c2WR7VB8sjVOIZOEvvj/F3Hnzafxur6qqatwtKqYGN67MjBkzCCEvvPBC469SwzlSAIobOnRo586djx079v333xt5iPjlIguE7du3nz17ttXVaC64ROIs2i+++GJbGgCgIGu/TV9XVyd2iMbGxoqzJp04cWLZsmUcx4nzj+r16NFj1KhR4qrQresWFQ0cOHDnzp33339/bGysi4tLp06d7rrrLiOPtbe337hx4x133DF58uT58+ffcccdISEhBQUFaWlpW7ZsGTx48Nq1a/VXuXjx4qRJk8aOHevq6tqxY0fZhNiioUOHxsfHr1+//tZbb33hhRdiYmKqq6svXLjw+eefb9myRTYFsd6ECRNGjhz5559/Tpw4ccmSJX5+fnv37l22bFlYWJj023T06NGEkJdfftnNzW348OHXr1//4IMP/vjjD09PT2kr2d/fv1OnTklJSXPnzu3Vq5darRZD/bbbbtuyZcu8efPefvvt3r17Z2RkvPbaa5WVlUa+VtDOubu7f/LJJ1OnTo2NjV20aNGIESOCgoJyc3MvXLiwadOm6dOnizNXDBgwYODAgRMmTOjcubObm1tqaury5csJIVOmTBHPEx4e7ufn9/vvvz/xxBPR0dGOjo5Dhgzp1asX29redtttv//++7Rp09asWdO1a9e0tLQVK1bIcp7E2qpUqvXr16tUqrCwMDs7uwkTJgQFBT311FM7d+78+eefR44c+fjjj0dHR2s0moyMjN9+++2nn34y6V9NAAuzs7Nbv3792LFjH3rooaeffnrChAmenp5Xrlz58ccf+/Xr1+TCKOHh4eHh4UlJSfPmzZszZ45arf71119ffvnlyMhIcZnDVhBT419//XVxATOO46ZOnaofbNqzZ0/xW4+0rQEAilFwWilj1NXVRUZGyurs7e39v//9r/HO33zzDSHE3d1dP2O2nn4FJtnjTz75JKGnT8vIyBg1apQ+UUm2ApPs8F9++YUQMn/+fOmDhw8fbvxd2LFjxy+++EK/T25ubmxsrL39P/8MGFiBSavVvvjii9JVowghQUFBRUVFBl634uLiUaNG6fdXqVSrV69uvALT6tWrpSlZHTt2PHLkSFhYmIODg/RsiYmJ4q1/kbgCk06nkw3a69Wrl/iPb69evQzUDUDvl19+aTweOjIy8ueffxZ3GDNmjCzzT61Wr1y5kud5/Un27t0rzZE3vALTm2++Ka2AmNg7cOBAWcViY2MJIfrl2erq6mTz2gwdOjQxMZEQcuedd0oP/PjjjwMDA/W76dePqKiomDVrlj7k9c9F/wkDYM327t0rm0xGrVZv2rRJ3Np4WtBjx45JA8He3n716tXPP/88IWTr1q363cQVmBpfrsmJS1evXi2d5VA2RbG4uqGHh0fjBgBYP074N13UmmVnZ589e7agoMDR0bFTp04xMTGylFjR5s2bH3300fj4+MZTqNTX11+9etXV1VW2lu7169fL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hw4daq7WoWUr/Mtf/rJ48WJ1p28UIwbtQQz6QAxqxGDb64AxmJeX169fv8LCwvj4eE3T7rjjjptvvnnBggX2rdUtySigxIkTJzIzMz0eT3l5+ZQpU6655pqlS5eqXhTQgRCDgA2+/e1v33XXXQ899NDJkyeHDBly8ODBPn362LkAklGgWdOmTdu6dWt6evqpU6duuummP//5zwkJCaoXBXQgxCBgg927d0+dOjU9PT03N3f+/PkLFy60eQEko4Av+fn5Fy9e7NGjRysvIQLQMsQgYIPa2tqjR492795dSaCRjAIAAEAZN91nFAAAAO0MySgAAACUIRkFAACAMm5KRs+dO3fVRh1t6sKFC3l5eQ0NDTbvV4mampqcnJyioiLVC4FDEYNtjRiEb8RgWyMGlXBHMlpXV/f9739/2LBhY8eOHT9+fEVFhQ073bt3b//+/b/1rW/deuutffr02bJliw07bbR///5OnTrdd999tu3xtddeS09PnzRp0qBBg55//nnb9gtXIAZtQAzCB2LQBsSgMoYbrFix4vrrr6+qqqqvr58wYcKTTz5pw06PHj26fft27+Pf/e53aWlpuq7bsF/DMOrq6kaNGjV58uSZMxvDeyQAAAeCSURBVGfas8dPPvkkKSlp7969hmE0NDQUFhbas1+4BTHY1ohB+EYMtjViUCF3HBldtWrV/fffHxUVFRoaOmfOnFWrVtmw04EDB44ZM8b7eNKkSQUFBZcvX7Zhv5qmPf300xMmTBg6dKg9u9M0benSpXPmzBkyZEh1dXVISAj384MFMdjWiEH4Rgy2NWJQIXcko6dPn87IyPA+zszMzM3NtXkBf/rTn77zne9ERUXZsK+jR4+uXr360UcftWFf5p0WFBRkZmb27dt39OjRJ0+etHPvcD5i0IadEoPwgRi0YafEoCruSEYrKioaAyA6Orq6urq+vt62vb/zzjsrVqxYtmyZDfvSdX327NnPPvtsZGSkDbtrVFRUtH379l27dp07d2748OHZ2dl27h3ORwy2NWIQvhGDbY0YVChM9QICkpKSUlJS4n1cXFycnJwcFmbTyjds2DBnzpz3338/MzPTht298cYbxcXFOTk5OTk5e/fuLS4uXrVq1T333NPW+01NTb399tu9TZ+zs7NvuOGGhoaG0NDQtt4v3IIYbOv9EoPwjRhs6/0Sgwq548jo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", + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "p0 = plot(synthetic_data, synthetic_data.ts[2]; clims=(-5, 5), cmap = :bluesreds, aspect_ratio=:equal)\n", "title!(\"synthetic data\")\n", @@ -273,7 +3684,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, "metadata": {}, "outputs": [], "source": [ @@ -285,19 +3696,1651 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.428504 seconds (125 allocations: 175.672 MiB, 3.93% gc time)\n" + ] + }, + { + "data": { + "text/plain": [ + "KFState{Float64, Vector{Float64}, Matrix{Float64}}([0.5388081729455987, -0.004385730236686142, 0.34304419311483914, -0.004413078078857277, 0.175550067896574, -0.004420575633069053, 0.06896477748386687, -0.004410186181883772, 0.05808421823686416, -0.004382906962226614 … 28.062273897390877, -0.001919603264716894, 26.95590567803678, -0.0017878056455683546, 25.80547534178913, -0.0016632627409222547, 24.730671879379745, -0.001545838696558359, 23.748113010418827, -0.001435281436984811], [-529.662723790638 -7.571452655665726e-6 … -0.0052885475528653934 -2.4778463017959043e-6; 0.0 5.097132238177488 … 4.24618207911948e-5 -3.2488176833264963e-7; … ; 0.0 0.0 … -470.4242064556343 -6.568382907174583e-5; 0.0 0.0 … 0.0 5.0971310369744005])" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# do the KF correction\n", - "state_2_2 = stgpkf_correct(problem, state_2_1, measure_pts, measure_ys, measure_Σ)" + "@time state_2_2 = stgpkf_correct(problem, state_2_1, measure_pts, measure_ys, measure_Σ)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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fNg+cajVal977bVWbc7Op59+qkz4pcLCwjFjxrzzzjvnz58/f/78f//7XwUaBd7IkiVLsrKysrOzT58+rdVq586dq0CjAQEBixYtKi4uzs7OfuaZZ8aPH6+Y9w+r1Tpp0qTrr79emeYIIdu2bZs+ffqmTZuysrIKCgruv/9+xZoGXgFssLWBDaqI9w1Gly1bNmnSJJ1O5+/vP3HixGXLlrVqczfeeKM9aLufn9+wYcPOnj3bqs0RQvLz8//zn/+88847rd0QIeSrr7666qqr0tPTTSYTISQqKkqBRoE3smzZsokTJ/r7++t0ukmTJrW23dlJTU0dMmSI/XjUqFGFhYV1dXUKtEsIeeedd66//vqrrrpKmeYIIfPnz580aVLv3r1NJpNWq4VPTcAAG2xtYIMq4n2D0ZycnJSUFPtxSkpKTk6OMu3W1dWtWLHipptuau2GHnvssTfeeEOZKCPHjh0LDg7u06dPt27dkpOTf/nlFwUaBd5ITk5Oly5d7McpKSlnzpxRuAOLFy8eNmyYv7+/Am0dP3585cqVL730kgJtSRstLCxMSUlJSkoaPHjw6dOnlWwdeD6wQQUahQ2qhZcNRq1Wq8lkchhDQEBAZWWlAu2Kojh58uS4uLiMjIxWbWjp0qVWq/WOO+5o1VYclJSUrF+/funSpefPn//Xv/5177331tbWKtM08C6qq6uldmcymaxWq2Ktf/PNN59++ulHH32kQFuCIDzyyCNz5szx8/NToDkHJSUlO3bs2L17d35+ft++fVv7rwZ4HbDB1gY2qCJeNhjV6/URERFlZWX2ZGlpaWxsbGs3KoriE088kZWVtWbNGq22db+xZ555pm/fvgsWLFi8eDEhZMmSJa069RsTE3PNNdf06NGDEDJ+/Piamppjx461XnPAe4mOjpbaXWRkpF6vV6bpn376adKkST/++KNjSaRVWb58eWlpaVZW1oIFC/bt23fq1Cll1kNjYmLuvvvusLAwjUaTkZGxffv2diJeBi4CG2xtYIMq4mWDUUJI7969d+7caT/euXNn7969W7vF5557bufOnd99950CoqI77rgjPz9/7969Bw4cIIQcOHCgvLy89Zrr06ePY2rZZDLV19cHBQW1XnPAe7nqqqv++OMP+7Eydmdn48aNEyZM+Prrr/v27atMi3Fxcddcc83evXv37t178eLF0tLSQ4cOKdCu1BgrKioCAgJ0Op0C7QJvATbY2sAG1UT0NtatWxcTE7N+/fo1a9aEhITs2rWrVZt74403goKCFixYsHLlypUrV27YsKFVm3NQVFRECCkoKGjVVmpqauLi4ubMmbN///4HH3xwyJAhNputVVsEXsoff/wREhKyZs2a9evXx8bGfvvttwo0+ueffwYEBDz55JMr/6a6ulqBdh288MILdvmwAhw4cCAyMnL16tW7d+8ePHjw1KlTlWkXeAuwwdYGNqgiCk3yc2TMmDEVFRX//ve/fXx8vvzyy/79+7dqc+Hh4ePGjduzZ4892bFjR2U8Tfj5+WVkZLT2VvGAgIBff/115syZa9eu7dev3/fff9/a+xCAlzJgwIAlS5Z8+OGHFotl1qxZt956qwKNWiyW8ePH19XVbdy40f7OsGHDlPF6Zqd///4OyUhr06tXr2XLls2bN6+2tvbOO+988sknlWkXeAuwwdYGNqgiGlEpn2EAAAAAAAAwYBoMAAAAAACoBgajAAAAAABANTAYBQAAAAAAqoHBKAAAAAAAUA0MRgEAAAAAgGpgMAoAAAAAAFQDg1EAAAAAAKAaGIwCAAAAAADVwGAUAAAAAACoBgajAAAAAABANTAYBQAAAAAAqoHBKAAAAAAAUA0MRhXFarVOnz79rbfecrwjCMKLL7746quviqKoYscAaCfABgFQF9ggaIhe7Q60L/R6/YABA9LT02NiYh5++GFCyDvvvPPOO+/8/PPPGo1G7d4B0PaBDQKgLrBB0BANHkSUZ/LkyYsWLdq5c6fJZEpLS3v++ef/9a9/qd0pANoRsEEA1AU2CKRgMKoCdXV1gwYNqq+vr6qq6tKly6ZNm3T/374dqjQbx2EYFkVkGHYAqysmWVk12N0h7KxE8AxWzUZhUyyCwbqwYF+y2EQ++2743uuKb/qVB25e+J+c1EfBgNggtGyQ38Ro4+3t7fLy8vz8/OPjYzKZ1OfA4NggtGyQHx4wNe7v709PT/f7/ePjY30LDJENQssG+eHPaODh4WGxWNzd3a3X69Vq9fLycnFxUR8FA2KD0LJBfhOjh7bdbmez2fX19Wq12u/38/n8+Pj4+fl5NBrVp8Eg2CC0bJB/iNGD+vr6urq6+vz8fH19HY/HR0dH7+/v8/l8uVze3t7W18H/zwahZYP8JUYParfbPT09zWaz6XT683Gz2Wy325ubm7Ozs/A2GAIbhJYN8pcYBQAg4zU9AAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAABkxCgBARowCAJARowAAZMQoAAAZMQoAQEaMAgCQEaMAAGTEKAAAGTEKAEBGjAIAkBGjAABkxCgAAJlvXVF81s8kYvwAAAAASUVORK5CYII=", + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "p0 = plot(synthetic_data, synthetic_data.ts[2]; clims=(-5, 5), cmap = :bluesreds, aspect_ratio=:equal)\n", "title!(\"synthetic data\")\n", @@ -468,16 +5511,20 @@ } ], "metadata": { + "@webio": { + "lastCommId": null, + "lastKernelId": null + }, "kernelspec": { - "display_name": "Julia 1.10.2", + "display_name": "Julia (4 threads) 1.11.2", "language": "julia", - "name": "julia-1.10" + "name": "julia-_4-threads_-1.11" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.10.2" + "version": "1.11.2" } }, "nbformat": 4, diff --git a/examples/tmp.gif b/examples/tmp.gif index 0c68ca1..d43416b 100644 Binary files a/examples/tmp.gif and b/examples/tmp.gif differ diff --git a/ext/CudaExt/CudaExt.jl b/ext/CudaExt/CudaExt.jl new file mode 100644 index 0000000..686dc19 --- /dev/null +++ b/ext/CudaExt/CudaExt.jl @@ -0,0 +1,149 @@ +module CudaExt + +using SpatiotemporalGPs + +using Adapt, CUDA +using LinearAlgebra, StaticArrays, Kronecker +import SpecialFunctions +import Interpolations + +STGPKF = SpatiotemporalGPs.STGPKF +KF = STGPKF.KF +AbstractKernel = STGPKF.AbstractKernel +KroneckerIdentityProduct = STGPKF.KroneckerIdentityProduct + + +include("mul_utils.jl") +include("cuda_kron.jl") + + +function SpatiotemporalGPs.CudaSTGPKFProblem(pts, ks::KS, kt::KT, ΔT::F) where {F, KS<: AbstractKernel{F}, KT <: AbstractKernel{F}} + @assert length(pts)>0 "The grid points must be non-empty." + + # throw a warning if F != Float32 + F == Float32 || + @warn "Using CUDASTGPKFProblem with non-Float32 types may lead to performance issues. Consider using Float32." + + ss_model = cuda_state_space_model(kt, ΔT) + + # cost at problem creation + K_gg = kernel_matrix(ks, pts) # is a Symmetric matrix + sqrt_K_gg = Symmetric(sqrt(K_gg)) + inv_sqrt_K_gg = Symmetric(inv(sqrt_K_gg)) # might need to be smarter here about how to do inverse - maybe force chol first? + + # convert to CuArrays and Float32 + cu_sqrt_K_gg = adapt(CuArray, sqrt_K_gg) + cu_inv_sqrt_K_gg = adapt(CuArray, inv_sqrt_K_gg) + + return CudaSTGPKFProblem(pts, ks, kt, ΔT, ss_model, cu_sqrt_K_gg, cu_inv_sqrt_K_gg) +end + +#cuda version +function SpatiotemporalGPs.stgpkf_initialize(problem::CudaSTGPKFProblem{F}) where {F} + + grid_pts = problem.pts + spatial_kernel = problem.ks + temporal_kernel = problem.kt + sampling_period = problem.ΔT + + # number of grid points + Ng = length(grid_pts) + + # number of states in the state space model + nk = STGPKF.ss_dims(temporal_kernel) + + # create the initial state + x0 = zeros(F, nk * Ng) # everything starts at 0 + + # create the covariance matrix + P0 = STGPKF.initial_covariance(temporal_kernel) + Σ0 = collect(I(Ng) ⊗ P0) + + # convert to CuArrays + cu_x0 = adapt(CuArray, x0) + cu_Σ0 = adapt(CuArray, Σ0) + + return KFState(; μ = cu_x0, Σ = cu_Σ0) +end + + +function cuda_state_space_model(kt::AbstractKernel{F}, ΔT::F) where {F} + # create the state space model for the temporal kernel + + # construct on CPU + dss= STGPKF.state_space_model(kt, ΔT) + + # now convert to CuArrays (maintains type) + Φ = CuArray(dss.Φ) + W = CuArray(dss.W) + C = CuArray(dss.C) + + return STGPKF.DiscreteTimeStateSpaceModel(Φ, W, C, ΔT) +end + +function SpatiotemporalGPs.stgpkf_correct(prob::CudaSTGPKFProblem{F}, + state::KFState, + pts::VP, + ys::VF2, + Σm::MF2) where { + P, F, F2, VP <: AbstractVector{P}, VF2 <: AbstractVector{F2}, MF2 <: AbstractMatrix{F2}} + + # get the number of grid points + Ng = length(prob.pts) + Nm = length(pts) + + # check the passed in prob and state are compatible dimensions + STGPKF.checkdims(prob, state) + + # check that the measurements are of compatible dimensions + @assert length(ys)==Nm "The number of points and measurements must match." + @assert size(Σm)==(Nm, Nm) "The measurement noise matrix must be of size (Nm, Nm)." + # @assert isposdef(Σm) "Σm must be positive definite. remember to check `issymmetric(Σm)` is true." + + # construct the spatial kernel matrices # TODO: CUDA-ify + K_mm = CuArray{F}(STGPKF.kernel_matrix(prob.ks, pts)) + K_mg = CuArray{F}(STGPKF.kernel_matrix(prob.ks, pts, prob.pts)) + + # measurement matrix for a single grid point + C = prob.ss_model.C + + # construct the measurement matrix for the full state + L = K_mg * prob.inv_sqrt_K_gg + H = L * (I(Ng) ⊗ C) + + # construct the noise matrix + V = CuArray{F}(Σm) + K_mm - (L * L') + + + # do the update + new_state = KF.correct(state, CuVector{F}(ys), CuArray{F}(H), V) + + return new_state +end + +function KF.qrr( + A::Transpose{F, C}, + B::STGPKF.KroneckerIdentityProduct{F, UpperTriangular{F, C}}) where {F, C <: CuArray{F}} + + # println("im at KF.qrr on 134 with types $(typeof(A)) and $(typeof(B))") + + A_dense = copy(A) # force the transpose to be evaluated + # println("A_dense: $(typeof(A_dense))") + B_dense = make_dense(B) + # println("B_dense: $(typeof(B_dense))") + return KF.qrr(A_dense, B_dense) +end + +function make_dense(K::KroneckerIdentityProduct{F, C}) where {F, C <: AbstractMatrix{F}} + # println("converting K::KroneckerIdentityProduct to CuArray at 141") + # materialize the KroneckerIdentityProduct as a CuArray + n, m = size(K) + K_dense = CuArray{F}(undef, (n, m)) + I_dense = CuArray{F}(I(m)) + mul!(K_dense, K, I_dense) # materialize the KroneckerIdentityProduct + # collect!(K_dense, K) # materialize the KroneckerIdentityProduct + return K_dense +end + + +end \ No newline at end of file diff --git a/ext/CudaExt/cuda_kron.jl b/ext/CudaExt/cuda_kron.jl new file mode 100644 index 0000000..e111d47 --- /dev/null +++ b/ext/CudaExt/cuda_kron.jl @@ -0,0 +1,18 @@ +GeneralizedKroneckerProduct = Kronecker.GeneralizedKroneckerProduct + +# provide a way to allocate cuda arrays if the v is a cuda vector +function Base.:*(K::GeneralizedKroneckerProduct, v::CuVector) + return mul!(CuVector{promote_type(eltype(v), eltype(K))}(undef, first(size(K))), K, v) +end + +# provide a way to allocate cuda arrays if the M is a cuda matrix +function Base.:*(K::GeneralizedKroneckerProduct, M::CuMatrix) + return mul!(CuMatrix{promote_type(eltype(M), eltype(K))}(undef, size(K, 1), size(M, 2)), K, M) +end + + +function Base.:*(v::CuMatrix, K::GeneralizedKroneckerProduct) + out = CuMatrix{promote_type(eltype(v), eltype(K))}(undef, last(size(K)), first(size(v))) + # need to use copy instead of collect to keep the CuArray type + return transpose(mul!(out, transpose(K), copy(transpose(v)))) +end \ No newline at end of file diff --git a/ext/CudaExt/mul_utils.jl b/ext/CudaExt/mul_utils.jl new file mode 100644 index 0000000..c031b1c --- /dev/null +++ b/ext/CudaExt/mul_utils.jl @@ -0,0 +1,21 @@ + +# provide a overload for A * B' that works with CUDA +function LinearAlgebra.mul!(C::TC, + A::UpperTriangular{F, TC}, + B::Adjoint{F, TC}) where {F, TC <: CuMatrix{F}} + + # force the copy when running with adjoint + return mul!(C, A, copy(B) ) +end + + + +function LinearAlgebra.mul!(C::TC, A::Matrix{F}, B::Symmetric{F, TC}) where {F, TC <: CuArray{F}} + # SO SHITTY! + cA = CuArray{F}(A) + n = size(B, 1) + cB = CuArray{F}(I(n)) * B + return mul!(C, cA, cB) +end + + diff --git a/src/kernels.jl b/src/kernels.jl index 860fe57..d8457bf 100644 --- a/src/kernels.jl +++ b/src/kernels.jl @@ -33,6 +33,14 @@ function dims(SS::DiscreteTimeStateSpaceModel) return size(SS.Φ, 1) end +""" + ss_dims(kernel) +Returns the number of states in the state space model for the given kernel. +""" +ss_dims(k::Matern12) = 1 +ss_dims(k::Matern32) = 2 +ss_dims(k::Matern52) = 3 + # define the kernel functions function (k::SqExp)(x, y) d = norm(x - y) @@ -57,9 +65,9 @@ end function kernel_matrix( kernel::KK, X::VPX -) where {PX, VPX <: AbstractVector{PX}, KK <: AbstractKernel} +) where {F, PX, VPX <: AbstractVector{PX}, KK <: AbstractKernel{F}} NX = length(X) - K = Array{Float64, 2}(undef, NX, NX) + K = Array{F, 2}(undef, NX, NX) # only compute the upper triangle for i in 1:NX, j in i:NX K[i, j] = kernel(X[i], X[j]) @@ -79,10 +87,11 @@ function kernel_matrix( X::VPX, Y::VPY ) where { - PX, PY, VPX <: AbstractVector{PX}, VPY <: AbstractVector{PY}, KK <: AbstractKernel} + F, + PX, PY, VPX <: AbstractVector{PX}, VPY <: AbstractVector{PY}, KK <: AbstractKernel{F}} NX = length(X) NY = length(Y) - K = Array{Float64, 2}(undef, NX, NY) + K = Array{F, 2}(undef, NX, NY) for i in 1:NX, j in 1:NY K[i, j] = kernel(X[i], Y[j]) end @@ -93,9 +102,10 @@ end function state_space_model(kernel::Matern12{F}) where {F} λ = kernel.λ σ = sqrt(kernel.σsq) - A = @SMatrix [-λ] - B = @SMatrix [one(F)] - C = @SMatrix [σ * sqrt(2λ)] + + A = SMatrix{1,1,F,1}(-λ) + B = SMatrix{1,1,F,1}(1) + C = SMatrix{1,1,F,1}(σ * sqrt(2λ)) SS = ContinuousTimeStateSpaceModel(A, B, C) @@ -103,13 +113,17 @@ function state_space_model(kernel::Matern12{F}) where {F} end function state_space_model(kernel::Matern32{F}) where {F} + λ = kernel.λ σ = sqrt(kernel.σsq) - A = @SMatrix [[zero(F);; one(F)]; [-3 * λ^2;; -2 * sqrt(3) * λ]] - B = @SMatrix [[zero(F);;]; [one(F);;]] - C = @SMatrix [σ * sqrt(12 * sqrt(3)) * λ^(3 / 2);; zero(F)] + + # when creating static arrays, need to be explicit about the type, and provide elements in column-major order + A = SMatrix{2,2,F,4}(0, -3*λ^2, 1, -2*sqrt(3)*λ) + B = SMatrix{2,1,F,2}(0,1) + C = SMatrix{1, 2, F, 2}(σ * sqrt(12 * sqrt(3)) * λ^(3 / 2), 0) SS = ContinuousTimeStateSpaceModel(A, B, C) + return SS end @@ -130,12 +144,12 @@ function state_space_model(kernel::Matern52{F}) where {F} C = @SMatrix [[sqrt(400 * sqrt(5) / 3) * σ * λ^(5 / 2);; z;; z];] - SS = ContinuousTimeStateSpaceModel(A, B, C) + SS = ContinuousTimeStateSpaceModel(F.(A), F.(B), F.(C)) return SS end # get the discrete time state-space models -function state_space_model(kernel::Matern12, T) +function state_space_model(kernel::Matern12{F}, T) where {F} σ = sqrt(kernel.σsq) λ = kernel.λ @@ -143,12 +157,12 @@ function state_space_model(kernel::Matern12, T) W = @SMatrix [[-((-1 + exp(-2 * T * λ)) / (2 * λ));;];] C = @SMatrix [[σ * sqrt(2 * λ);;];] - SS = DiscreteTimeStateSpaceModel(Φ, W, C, T) + SS = DiscreteTimeStateSpaceModel(F.(Φ), F.(W), F.(C), F(T)) return SS end -function state_space_model(kernel::Matern32, T) +function state_space_model(kernel::Matern32{F}, T) where {F} σ = sqrt(kernel.σsq) λ = kernel.λ @@ -167,12 +181,12 @@ function state_space_model(kernel::Matern32, T) C = @SMatrix [[2 * 3^(3 / 4) * λ^(3 / 2) * σ;; 0];] - SS = DiscreteTimeStateSpaceModel(Φ, W, C, T) + SS = DiscreteTimeStateSpaceModel(F.(Φ), F.(W), F.(C), F(T)) return SS end -function state_space_model(kernel::Matern52, T) +function state_space_model(kernel::Matern52{F}, T) where {F} σ = sqrt(kernel.σsq) λ = kernel.λ @@ -229,24 +243,27 @@ function state_space_model(kernel::Matern52, T) C = @SMatrix [[(20 * 5^(1 / 4) * λ^(5 / 2) * σ) / sqrt(3);; 0;; 0];] - SS = DiscreteTimeStateSpaceModel(Φ, W, C, T) + SS = DiscreteTimeStateSpaceModel(F.(Φ), F.(W), F.(C), F(T)) return SS end # get the initial covariance matrix -function initial_covariance(kernel::Matern12) +function initial_covariance(kernel::Matern12{F}) where {F} λ = kernel.λ - return @SMatrix [[1 / (2 * λ);;];] + P = @SMatrix [[1 / (2 * λ);;];] + return F.(P) end -function initial_covariance(kernel::Matern32) +function initial_covariance(kernel::Matern32{F}) where {F} λ = kernel.λ - return @SMatrix [[1 / (12 * sqrt(3) * λ^3);; 0]; + P = @SMatrix [[1 / (12 * sqrt(3) * λ^3);; 0]; [0;; 1 / (4 * sqrt(3) * λ)]] + + return F.(P) end -function initial_covariance(kernel::Matern52) +function initial_covariance(kernel::Matern52{F}) where {F} λ = kernel.λ Σ11 = 3 / (400 * sqrt(5) * λ^5) Σ12 = 0 @@ -262,5 +279,5 @@ function initial_covariance(kernel::Matern52) [Σ21;; Σ22;; Σ23]; [Σ31;; Σ32;; Σ33]] - return Σ + return F.(Σ) end diff --git a/src/kron.jl b/src/kron.jl new file mode 100644 index 0000000..8bfbc39 --- /dev/null +++ b/src/kron.jl @@ -0,0 +1,107 @@ +# some small fast utilities for the kronecker product + +""" + KroneckerIdentityProduct(B, N) + +Represents the Kronecker product (I(N) ⊗ B) without forming the product. +""" +struct KroneckerIdentityProduct{T, TB} <: AbstractKroneckerProduct{T} + B::TB + N::Int + function KroneckerIdentityProduct(B::TB, N::Int) where {TB <: AbstractMatrix} + @assert N > 0 + return new{eltype(B), TB}(B, N) + end +end + +function Kronecker.getmatrices(K::KroneckerIdentityProduct) + return (I(K.N), K.B) +end + +function Kronecker.kronecker(A::Diagonal{Bool}, B::AbstractMatrix) + # A is a diagonal matrix with boolean values + # this is a special case where we can avoid forming the Kronecker product + return KroneckerIdentityProduct(B, size(A, 1)) +end + +function Base.adjoint(K::KroneckerIdentityProduct) + # adjoint of (I(N) ⊗ B) is (I(N) ⊗ B') + # do a copy to force the adjoint to be evaluated + return KroneckerIdentityProduct(copy(adjoint(K.B)), K.N) +end + +function Base.transpose(K::KroneckerIdentityProduct) + # transpose of (I(N) ⊗ B) is (I(N) ⊗ B') + # do a copy to force the transpose to be evaluated + return KroneckerIdentityProduct(copy(transpose(K.B)), K.N) +end + +""" + kron_I_B_mm!(Y, N, B, X) + +In-place matrix version: + Y := (I(N) ⊗ B) * X + +- B :: m×q +- X :: (q*N)×K (K right-hand sides) +- Y :: (m*N)×K +Works on Array and CuArray. +""" +function kron_I_B_mm!(Y::AbstractMatrix, N::Int, B::AbstractMatrix, X::AbstractMatrix) + m, q = size(B) + K = size(X,2) + @assert N * q == size(X,1) + @assert size(Y,1) == m*N && size(Y,2) == K + + # Fuse the N blocks: (qN × K) → (q × (N*K)), multiply, then reshape back + Xr = reshape(X, q, N*K) + Yr = reshape(Y, m, N*K) + mul!(Yr, B, Xr) + return Y +end + + +""" + kron_I_B_mv!(y, B, x) + +In-place version: y := (I(N) ⊗ B) * x +y :: length m*N +""" +function kron_I_B_mv!(y::AbstractVector, N::Int, B::AbstractMatrix, x::AbstractVector) + m, q = size(B) + @assert N * q == length(x) + @assert length(y) == m * N + X = reshape(x, q, N) + Y = reshape(y, m, N) + mul!(Y, B, X) + return y +end + + +function LinearAlgebra.mul!(y::AbstractVector, K::KroneckerIdentityProduct, x::AbstractVector) + kron_I_B_mv!(y, K.N, K.B, x) + return y +end + +function LinearAlgebra.mul!(Y::AbstractMatrix, K::KroneckerIdentityProduct, X::AbstractMatrix) + kron_I_B_mm!(Y, K.N, K.B, X) + return Y +end + +function Base.:*(M::UpperTriangular{F, C}, K::KroneckerIdentityProduct) where {F, C <: AbstractMatrix{F}} + # force it to become a normal matrix (sad - we loose the triangular nature of the output) + return C(M) * K +end +function Base.:*(M::LowerTriangular{F, C}, K::KroneckerIdentityProduct) where {F, C <: AbstractMatrix{F}} + # force it to become a normal matrix (sad - we loose the triangular nature of the output) + return C(M) * K +end + + + +function KF.chol_sqrt(K::KroneckerIdentityProduct) + # chol_sqrt = cholesky(K).U + # and cholesky(I ⊗ B).U = I ⊗ (chol(B).U) + # println("im here at chol_sqrt 147") + return KroneckerIdentityProduct(cholesky(K.B).U, K.N) +end \ No newline at end of file diff --git a/src/stgpkf.jl b/src/stgpkf.jl index 8ea2276..48a48e2 100644 --- a/src/stgpkf.jl +++ b/src/stgpkf.jl @@ -1,14 +1,14 @@ module STGPKF -using LinearAlgebra -using StaticArrays +using LinearAlgebra, StaticArrays using Kronecker import SpecialFunctions import Interpolations # this module creates a spatiotemporal GP Kalman Filter + export Matern, SquaredExponential export kernel_matrix, state_space_model -export STGPKFProblem +export STGPKFProblem, CudaSTGPKFProblem export stgpkf_initialize, stgpkf_predict, stgpkf_correct export generate_spatiotemporal_process @@ -17,6 +17,7 @@ KF = KalmanFilter KFState = KF.KFState include("types.jl") +include("kron.jl") include("kernels.jl") include("plotting.jl") include("synthetic.jl") @@ -46,7 +47,7 @@ end checkdims(prob, state) checks that the dimensions of the state and the problem match """ -function checkdims(prob::STGPKFProblem, state::KFState) +function checkdims(prob::AbstractSTGPKFProblem, state::KFState) Ng = length(prob.pts) nk = dims(prob.ss_model) nx = length(state) @@ -58,10 +59,10 @@ end returns the states of the Kalman Filter for all grid points, in a Vector{SVector{F}} format. The outer vector has same length as `problem.pts`. """ -function get_states(problem::STGPKFProblem, state::KFState) +function get_states(problem::AbstractSTGPKFProblem, state::KFState) nk = dims(problem.ss_model) Ng = length(problem.pts) - μ = KF.get_μ(state) + μ = Vector(KF.get_μ(state)) # force copy to CPU x = [SVector{nk}(μ[((i - 1) * nk + 1):(i * nk)]) for i in 1:Ng] return x end @@ -71,10 +72,10 @@ end returns the marginal states of the Kalman Filter for all grid points, in a Vector{KFState} format. The outer vector has same length as `problem.pts`. """ -function get_marginal_states(problem::STGPKFProblem, state::KFState) +function get_marginal_states(problem::AbstractSTGPKFProblem, state::KFState) nk = dims(problem.ss_model) Ng = length(problem.pts) - μ = KF.get_μ(state) + μ = Vector(KF.get_μ(state)) Σ = Matrix(KF.get_Σ(state)) xs = [SVector{nk}(μ[((i - 1) * nk + 1):(i * nk)]) for i in 1:Ng] Σs = [SMatrix{nk, nk}(Σ[((i - 1) * nk + 1):(i * nk), ((i - 1) * nk + 1):(i * nk)]) @@ -89,7 +90,7 @@ end returns the estimate of the Kalman Filter for all grid points, in a Vector{F} format. The outer vector has same length as `problem.pts`. """ -function get_estimate(problem::STGPKFProblem, state::KFState) +function get_estimate(problem::AbstractSTGPKFProblem, state::KFState) Ng = length(problem.pts) C = problem.ss_model.C # spatially uncorrelated components @@ -105,7 +106,7 @@ end returns the kalman filter's covariance of the estimated spatiotemporal field at all grid points, in a Vector{F} format. The vector has same length as `problem.pts`. """ -function get_estimate_covariance(problem::STGPKFProblem, state::KFState) +function get_estimate_covariance(problem::AbstractSTGPKFProblem, state::KFState) Ng = length(problem.pts) C = problem.ss_model.C # L = problem.sqrt_K_gg * (I(Ng) ⊗ C) @@ -149,7 +150,7 @@ end returns the standard deviation of the estimated spatiotemporal field at all grid points, in a Vector{F} format. The vector has same length as `problem.pts`. """ -function get_estimate_std(problem::STGPKFProblem, state::KFState) +function get_estimate_std(problem::AbstractSTGPKFProblem, state::KFState) # slow method # Σ = get_estimate_covariance(problem, state) @@ -176,7 +177,7 @@ end returns the clarity of the estimated spatiotemporal field at all grid points, in a Vector{F} format. The vector has same length as `problem.pts`. """ -function get_estimate_clarity(problem::STGPKFProblem, state::KFState) +function get_estimate_clarity(problem::AbstractSTGPKFProblem, state::KFState) σ = get_estimate_std(problem, state) return σ_to_clarity.(σ) @@ -187,14 +188,14 @@ end returns the percentile-% quantile of the estimated spatiotemporal field at all grid points, in a Vector{F} format. The vector has same length as `problem.pts`. """ -function get_estimate_percentile(problem::STGPKFProblem, state::KFState, percentile) +function get_estimate_percentile(problem::AbstractSTGPKFProblem, state::KFState, percentile) est = get_estimate(problem, state) σs = get_estimate_std(problem, state) return [quantile(μ, σ, percentile) for (μ, σ) in zip(est, σs)] end function spatial_interpolate( - problem::STGPKFProblem, state::KFState, pts::VP) where {P, VP <: AbstractVector{P}} + problem::AbstractSTGPKFProblem, state::KFState, pts::VP) where {P, VP <: AbstractVector{P}} K_mg = kernel_matrix(problem.ks, pts, problem.pts) C = problem.ss_model.C @@ -208,29 +209,24 @@ end stgpkf_initialize(problem) returns a `KFState` that represents the initial state of the Kalman Filter for all grid points """ -function stgpkf_initialize(problem::STGPKFProblem) +function stgpkf_initialize(problem::STGPKFProblem{F}) where {F} grid_pts = problem.pts spatial_kernel = problem.ks temporal_kernel = problem.kt sampling_period = problem.ΔT - # create the state-space model - SS = state_space_model(temporal_kernel, sampling_period) - # number of grid points Ng = length(grid_pts) + # number of states in the state space model - nk = dims(SS) + nk = ss_dims(temporal_kernel) # create the initial state - x0 = zeros(nk * Ng) # everything starts at 0 + x0 = zeros(F, nk * Ng) # everything starts at 0 # create the covariance matrix P0 = initial_covariance(temporal_kernel) - - # Σ0 = kron(1.0 * I(Ng), P0) - # Σ0 = I(Ng) ⊗ P0 - Σ0 = (1.0 * I(Ng)) ⊗ P0 + Σ0 = I(Ng) ⊗ P0 return KFState(μ = x0, Σ = Σ0) end @@ -241,12 +237,12 @@ end predicts the next state of the Kalman Filter for all grid points """ -function stgpkf_predict(prob::STGPKFProblem, state::KFState) +function stgpkf_predict(prob::AbstractSTGPKFProblem, state::KFState) checkdims(prob, state) Ng = length(prob.pts) A = I(Ng) ⊗ prob.ss_model.Φ - W = I(Ng) ⊗ prob.ss_model.W + W = I(Ng) ⊗ prob.ss_model.W new_state = KF.predict(state, A, W) @@ -259,12 +255,11 @@ end corrects the state of the Kalman Filter given a single point measurement at ``pt`` with value ``y`` and measurement noise standard deviation ``σ_m``. """ function stgpkf_correct( - prob::STGPKFProblem{P, F}, state::KFState, pt::P, y::F, σ_m::F) where {P, F} + prob::AbstractSTGPKFProblem{F, P}, state::KFState, pt::P, y::F2, σ_m::F2) where {F <: Real, P, F2 <: Real} vec_pts = [pt] - vec_ys = @SVector [y] - mat_Σm = @SMatrix [[σ_m^2;;];] + vec_ys = SVector{1, F}(y) + mat_Σm = SMatrix{1, 1, F}(σ_m^2) return stgpkf_correct(prob, state, vec_pts, vec_ys, mat_Σm) - return new_state end """ @@ -272,7 +267,7 @@ end corrects the state of the Kalman Filter given multiple point measurements at ``pts`` with values ``ys`` and measurement noise covariance matrix ``Σm``. """ -function stgpkf_correct(prob::STGPKFProblem{P, F}, +function stgpkf_correct(prob::AbstractSTGPKFProblem, state::KFState, pts::VP, ys::VF, @@ -303,7 +298,7 @@ function stgpkf_correct(prob::STGPKFProblem{P, F}, H = L * (I(Ng) ⊗ C) # construct the noise matrix - V = Symmetric(Σm) + Symmetric(K_mm) - Symmetric(L * L') + V = Symmetric(Σm + K_mm - L * L') # do the update new_state = KF.correct(state, ys, H, V) diff --git a/src/types.jl b/src/types.jl index 5b7a5fa..91e2f1a 100644 --- a/src/types.jl +++ b/src/types.jl @@ -1,24 +1,24 @@ -abstract type AbstractKernel end -abstract type AbstractMaternKernel <: AbstractKernel end +abstract type AbstractKernel{F} end +abstract type AbstractMaternKernel{F} <: AbstractKernel{F} end -struct SqExp{F} <: AbstractKernel +struct SqExp{F} <: AbstractKernel{F} σsq::F λ::F end # structs to hold hyperparameters -struct Matern12{F} <: AbstractMaternKernel +struct Matern12{F} <: AbstractMaternKernel{F} σsq::F λ::F end -struct Matern32{F} <: AbstractMaternKernel +struct Matern32{F} <: AbstractMaternKernel{F} σsq::F λ::F end -struct Matern52{F} <: AbstractMaternKernel +struct Matern52{F} <: AbstractMaternKernel{F} σsq::F λ::F end @@ -38,16 +38,39 @@ struct DiscreteTimeStateSpaceModel{MΦ, MW, MC, F} <: AbstractStateSpaceModel dt::F end +abstract type AbstractSTGPKFProblem{F, P} end + + struct STGPKFProblem{ + F, P, + VP <: AbstractVector{P}, + KS <: AbstractKernel{F}, + KT <: AbstractKernel{F}, + DTSS <: DiscreteTimeStateSpaceModel, + M1 <: AbstractMatrix{F}, + M2 <: AbstractMatrix{F} +} <: AbstractSTGPKFProblem{F, P} + pts::VP # grid points + ks::KS # spatial kernel + kt::KT # temporal kernel + ΔT::F # sampling period + ss_model::DTSS # state space model (discrete time) (for the temporal kernel) + sqrt_K_gg::M1 + inv_sqrt_K_gg::M2 # inverse of the square root of the spatial kernel matrix +end + +# create a similar struct for the Cuda version +struct CudaSTGPKFProblem{ F, + P, VP <: AbstractVector{P}, - KS <: AbstractKernel, - KT <: AbstractKernel, + KS <: AbstractKernel{F}, + KT <: AbstractKernel{F}, DTSS <: DiscreteTimeStateSpaceModel, M1 <: AbstractMatrix{F}, M2 <: AbstractMatrix{F} -} +} <: AbstractSTGPKFProblem{F, P} pts::VP # grid points ks::KS # spatial kernel kt::KT # temporal kernel diff --git a/test/Manifest.toml b/test/Manifest.toml deleted file mode 100644 index f96a78a..0000000 --- a/test/Manifest.toml +++ /dev/null @@ -1,106 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.10.2" -manifest_format = "2.0" -project_hash = "b418e8fdc671f400dac1e688699d216d1ba0f0a3" - -[[deps.Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" - -[[deps.Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[deps.CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "1.1.0+0" - -[[deps.Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[deps.Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[deps.LinearAlgebra]] -deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[deps.Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[deps.Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[deps.OpenBLAS_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] -uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.23+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.Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[deps.Random]] -deps = ["SHA"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" -version = "0.7.0" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[deps.StaticArrays]] -deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] -git-tree-sha1 = "eeafab08ae20c62c44c8399ccb9354a04b80db50" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.9.7" - - [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.TOML]] -deps = ["Dates"] -uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" -version = "1.0.3" - -[[deps.Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[deps.Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[deps.libblastrampoline_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.8.0+1" diff --git a/test/Project.toml b/test/Project.toml deleted file mode 100644 index 095ead7..0000000 --- a/test/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/runtests.jl b/test/runtests.jl index e8242ee..c34c2d9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,9 +3,16 @@ using SpatiotemporalGPs using Test using LinearAlgebra using StaticArrays +using CUDA @testset "SpatiotemporalGPs.jl" begin end include("tests/kf.jl") include("tests/kernels.jl") include("tests/stgpkf.jl") + +if CUDA.functional() + include("tests/cuda_kron.jl") + include("tests/cuda_stgpkf.jl") +end + diff --git a/test/tests/cuda_kron.jl b/test/tests/cuda_kron.jl new file mode 100644 index 0000000..4c1b6a7 --- /dev/null +++ b/test/tests/cuda_kron.jl @@ -0,0 +1,90 @@ + + +using Test +using LinearAlgebra +using StaticArrays +using CUDA +using SpatiotemporalGPs +using Kronecker + +@assert CUDA.functional() "CUDA is not functional on this system. Skipping CUDA kron tests." + +@testset "Kron test" begin + + n = 3 + N = 10 + A = randn(n, n) + b = randn(n * N) + In = I(N) + K = In ⊗ A + + # @assert typeof(K) <: STGPKF.KroneckerIdentityProduct + + # check against julia's kron + @test K * b ≈ kron(In, A) * b + + + # now check matrix multiplication + B = randn(n * N, N) + @test K * B ≈ kron(In, A) * B + + # test adjoint + Kt = K' + @test Kt * b ≈ kron(In, A') * b + @test Kt * B ≈ kron(In, A') * B + + +end + + +@testset "CUDA Kron test" begin + + # same as above but for CUDA + + n = 3 + N = 10 + A = randn(n, n) + cu_A = cu(A) + In = I(N) + + b = randn(n * N) + cu_b = cu(b) + + # create the cuda version of the product + K = In ⊗ cu_A + + # @test typeof(K) <: STGPKF.KroneckerIdentityProduct + + # check against julia's kron + @test collect(K * cu_b) ≈ collect(kron(In, A) * b) + + # now check matrix multiplication + B = randn(n * N, N) + cu_B = cu(B) + @test collect(K * cu_B) ≈ collect(kron(In, A) * B) + +end + +# test adjoint products +@testset "CUDA Kron adjoint test" begin + + n = 3 + N = 10 + A = randn(n, n) + cu_A = cu(A) + In = I(N) + + # create the cuda version of the product + K = In ⊗ cu_A + + # test adjoint + Kt = K' + + # test adjoint product + M = randn(n * N, n * N) + cu_M = cu(M) + @test collect(Kt * cu_M) ≈ collect(kron(In, A') * M) + @test collect(cu_M * Kt) ≈ collect(M * kron(In, A')) + + +end diff --git a/test/tests/cuda_stgpkf.jl b/test/tests/cuda_stgpkf.jl new file mode 100644 index 0000000..2f2fefd --- /dev/null +++ b/test/tests/cuda_stgpkf.jl @@ -0,0 +1,121 @@ + + +using Test +using LinearAlgebra +using StaticArrays +using CUDA +using SpatiotemporalGPs + +@assert CUDA.functional() "CUDA is not functional on this system. Skipping CUDA kron tests." + +function cuda_create_problem(kt_order, xs, ys, F) + + # create grid points + pts = vec([(@SVector [x, y]) for x in xs, y in ys]) + + # create temporal kernel + σt = F(2.1) + lt = F(3.1) + kt = Matern(kt_order - 1 / 2, σt, lt) + + # create spatial kernel + σs = F(1.1) + ls = F(2.1) + ks = Matern(3 / 2, σs, ls) + + # create the problem + ΔT = F(0.1) + prob = CudaSTGPKFProblem(pts, ks, kt, ΔT) + + return prob +end + +@testset "CUDA STGPKF" for F in (Float32, Float64), kt_order in 1:3 + + @testset "CUDA STGPKF - create" begin + xs = 0.0:1.0:5.0 + ys = 0.0:1.0:3.0 + prob = cuda_create_problem(kt_order, xs, ys, F) + + @test length(prob.pts) == length(xs) * length(ys) + @test size(prob.ss_model.Φ) == (kt_order, kt_order) + @test typeof(prob.sqrt_K_gg) <: Symmetric{F, M} where {M <: CuArray{F, 2}} + end + + + + @testset "CUDA STGPKF - initialize" begin + xs = 0.0:1.0:5.0 + ys = 0.0:1.0:3.0 + prob = cuda_create_problem(kt_order, xs, ys, F) + + # initialize + state_0_0 = stgpkf_initialize(prob) + + @test length(state_0_0.μ) == length(prob.pts) * STGPKF.dims(prob.ss_model) + @test isnothing(STGPKF.checkdims(prob, state_0_0)) + mu = state_0_0.μ + Sigma = get_Σ(state_0_0) + + @test typeof(mu) <: CuArray{F, 1} + @test typeof(Sigma) <: Cholesky{F, M} where {M <: CuArray{F, 2}} + + end + + @testset "STGPKF - predict correct" begin + xs = F.(0.0:1.0:5.0) + ys = F.(0.0:1.0:3.0) + prob = cuda_create_problem(kt_order, xs, ys, F) + + Ng = length(prob.pts) + nk = STGPKF.dims(prob.ss_model) + Nstate = Ng * nk + + # initialize + state_0_0 = stgpkf_initialize(prob) + + # predict + state_1_0 = stgpkf_predict(prob, state_0_0) + @test length(state_1_0.μ) == Nstate + + # the very first prediction should NOT change the state or the covariance + @test state_1_0.μ≈state_0_0.μ atol=1e-4 + @test Matrix(get_Σ(state_1_0))≈Matrix(get_Σ(state_0_0)) atol=1e-4 + + # correct + pt = SVector{2, F}(maximum(xs) * rand(), maximum(ys) * rand()) # random point + y = randn() # random measurement + σm = 0.1 # measurement noise + state_1_1 = stgpkf_correct(prob, state_1_0, pt, y, σm) + @test length(state_1_1.μ) == Nstate + # check that the states are changed + @test state_1_1.μ != state_1_0.μ + @test state_1_1.U != state_1_0.U + # @show typeof(state_1_1.μ) + # @show typeof(state_1_1.U) + + + # predict again + state_2_1 = stgpkf_predict(prob, state_1_1) + @test length(state_2_1.μ) == Nstate + # check that the states are changed + @test state_2_1.μ != state_1_1.μ + @test state_2_1.U != state_1_1.U + + # correct again, but this time with multiple measurements + N_measure = 10 + pts = [(@SVector [maximum(xs) * rand(), maximum(ys) * rand()]) for i in 1:N_measure] # random points + ys = randn(N_measure) # random measurement + Σm = rand_posdef(N_measure) + + state_2_2 = stgpkf_correct(prob, state_2_1, pts, ys, Σm) + + # check dimensions + @test length(state_2_2.μ) == Nstate + + # check that the states are changed + @test state_2_2.μ != state_2_1.μ + @test state_2_2.U != state_2_1.U + end + +end \ No newline at end of file diff --git a/test/tests/kernels.jl b/test/tests/kernels.jl index f23c409..dd2d002 100644 --- a/test/tests/kernels.jl +++ b/test/tests/kernels.jl @@ -21,6 +21,7 @@ using StaticArrays @test k52.λ ≈ 1 / l end + @testset "Kernels - kernel_matrix" for order in 1:3 σ = 5.0 l = 3.0 @@ -167,3 +168,64 @@ end @test dss.C≈H_true atol=1e-4 @test dss.dt ≈ T end + +# add a test for float32 version of the kernels +@testset "Kernels - create Float32" begin + σ = Float32(5.0) + l = Float32(3.0) + k12 = STGPKF.Matern(1 / 2, σ, l) + k32 = STGPKF.Matern(3 / 2, σ, l) + k52 = STGPKF.Matern(5 / 2, σ, l) + + @test k12.σsq ≈ σ^2 + @test k12.λ ≈ 1 / l + @test typeof(k12.σsq) == Float32 + @test typeof(k12.λ) == Float32 + @test typeof(k12.σsq) == Float32 + @test typeof(k12.λ) == Float32 + @test typeof(k12.σsq) == Float32 + @test typeof(k12.λ) == Float32 + + # now create a kernel matrix and check its type + x = [@SVector randn(2) for i in 1:10] + y = [@SVector randn(2) for i in 1:10] + Kxx = STGPKF.kernel_matrix(k12, x) + Kxy = STGPKF.kernel_matrix(k12, x, y) + @test typeof(Kxx) <: AbstractMatrix{Float32} + @test typeof(Kxy) <: AbstractMatrix{Float32} + + + # create the state space model and check its type + ss_12 = STGPKF.state_space_model(k12) + ss_32 = STGPKF.state_space_model(k32) + ss_52 = STGPKF.state_space_model(k52) + + @test typeof(ss_12.A) <: AbstractMatrix{Float32} + @test typeof(ss_12.B) <: AbstractMatrix{Float32} + @test typeof(ss_32.A) <: AbstractMatrix{Float32} + @test typeof(ss_32.B) <: AbstractMatrix{Float32} + @test typeof(ss_52.A) <: AbstractMatrix{Float32} + @test typeof(ss_52.B) <: AbstractMatrix{Float32} + + # create the discrete state space model and check its type + T = Float32(0.1) + dss_12 = STGPKF.state_space_model(k12, T) + dss_32 = STGPKF.state_space_model(k32, T) + dss_52 = STGPKF.state_space_model(k52, T) + + @test typeof(dss_12.Φ) <: AbstractMatrix{Float32} + @test typeof(dss_12.W) <: AbstractMatrix{Float32} + @test typeof(dss_12.C) <: AbstractMatrix{Float32} + @test typeof(dss_12.dt) == Float32 + + @test typeof(dss_32.Φ) <: AbstractMatrix{Float32} + @test typeof(dss_32.W) <: AbstractMatrix{Float32} + @test typeof(dss_32.C) <: AbstractMatrix{Float32} + @test typeof(dss_32.dt) == Float32 + + @test typeof(dss_52.Φ) <: AbstractMatrix{Float32} + @test typeof(dss_52.W) <: AbstractMatrix{Float32} + @test typeof(dss_52.C) <: AbstractMatrix{Float32} + @test typeof(dss_52.dt) == Float32 + +end \ No newline at end of file