├── .JuliaFormatter.toml ├── .gitignore ├── CITATION.bib ├── CITATION.cff ├── LICENSE ├── LocalPreferences.toml ├── Manifest.toml ├── Project.toml ├── README.md ├── create_sysimage.jl ├── environment.yml ├── src ├── ControlNeuralODE.jl ├── auxiliaries.jl ├── collocation │ └── classic │ │ ├── bioreactor.jl │ │ ├── semibatch_reactor.jl │ │ └── van_der_pol.jl ├── controlODE.jl ├── interpolation.jl ├── loading.jl ├── nn.jl ├── optimizers.jl ├── penalties.jl ├── plotting.jl ├── scripts │ ├── batch_reactor.jl │ ├── bioreactor.jl │ ├── semibatch_reactor.jl │ └── van_der_pol.jl ├── simulators.jl ├── systems │ ├── batch_reactor.jl │ ├── bioreactor.jl │ ├── semibatch_reactor.jl │ └── van_der_pol.jl └── training.jl └── sysimage_tracing.jl /.JuliaFormatter.toml: -------------------------------------------------------------------------------- 1 | style = "blue" 2 | pipe_to_function_call = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # PackageCompiler images 2 | *.so 3 | 4 | # data 5 | *.csv 6 | *.txt 7 | *.json 8 | *.bson 9 | data/ 10 | 11 | # images 12 | *.pdf 13 | *.svg 14 | *.png 15 | 16 | # profiling 17 | statprof*/ 18 | 19 | # autogenerated 20 | __pycache__/ 21 | .vscode/ 22 | 23 | # work-in-progress 24 | temp/ 25 | 26 | # plots 27 | plots/ 28 | -------------------------------------------------------------------------------- /CITATION.bib: -------------------------------------------------------------------------------- 1 | @article{sandoval2022NODEpolicies, 2 | title = {Neural ODEs as Feedback Policies for Nonlinear Optimal Control}, 3 | author = {Sandoval, Ilya Orson and Petsagkourakis, Panagiotis and del Rio-Chanona, Ehecatl Antonio}, 4 | date = {2022}, 5 | pubstate = {submitted}, 6 | note = {submitted}, 7 | } -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite the associated publication (submitted)." 3 | authors: 4 | - family-names: "Sandoval" 5 | given-names: "Ilya Orson" 6 | orcid: "https://orcid.org/0000-0001-9648-5265" 7 | - family-names: "Petsagkourakis" 8 | given-names: "Panagiotis" 9 | orcid: "https://orcid.org/0000-0002-2024-3371" 10 | - family-names: "del Rio-Chanona" 11 | given-names: "Ehecatl Antonio" 12 | orcid: "https://orcid.org/0000-0003-0274-2852" 13 | title: "Neural ODEs as Feedback Policies for Nonlinear Optimal Control" 14 | version: juliacon2021 15 | license: "MIT" 16 | date-released: 2021-07-04 17 | url: "https://github.com/IlyaOrson/control_neuralode/tree/juliacon2021" 18 | preferred-citation: 19 | type: article 20 | title: "Neural ODEs as Feedback Policies for Nonlinear Optimal Control" 21 | authors: 22 | - family-names: "Sandoval" 23 | given-names: "Ilya Orson" 24 | - family-names: "Petsagkourakis" 25 | given-names: "Panagiotis" 26 | - family-names: "del Rio-Chanona" 27 | given-names: "Ehecatl Antonio" 28 | year: 2022 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ilya Orson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LocalPreferences.toml: -------------------------------------------------------------------------------- 1 | [CPUSummary] 2 | hwloc = false 3 | -------------------------------------------------------------------------------- /Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | julia_version = "1.8.0" 4 | manifest_format = "2.0" 5 | project_hash = "0719a27ccffa28e1bc217681c237daa1e244f3d0" 6 | 7 | [[deps.ASL_jll]] 8 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 9 | git-tree-sha1 = "6252039f98492252f9e47c312c8ffda0e3b9e78d" 10 | uuid = "ae81ac8f-d209-56e5-92de-9978fef736f9" 11 | version = "0.1.3+0" 12 | 13 | [[deps.AbstractAlgebra]] 14 | deps = ["GroupsCore", "InteractiveUtils", "LinearAlgebra", "MacroTools", "Markdown", "Random", "RandomExtensions", "SparseArrays", "Test"] 15 | git-tree-sha1 = "4a502c003026ecdcac4b100cfc1d14f63eccede7" 16 | uuid = "c3fe647b-3220-5bb0-a1ea-a7954cac585d" 17 | version = "0.27.3" 18 | 19 | [[deps.AbstractFFTs]] 20 | deps = ["ChainRulesCore", "LinearAlgebra"] 21 | git-tree-sha1 = "69f7020bd72f069c219b5e8c236c1fa90d2cb409" 22 | uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" 23 | version = "1.2.1" 24 | 25 | [[deps.AbstractTrees]] 26 | git-tree-sha1 = "5c0b629df8a5566a06f5fef5100b53ea56e465a0" 27 | uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" 28 | version = "0.4.2" 29 | 30 | [[deps.Accessors]] 31 | deps = ["Compat", "CompositionsBase", "ConstructionBase", "Dates", "InverseFunctions", "LinearAlgebra", "MacroTools", "Requires", "Test"] 32 | git-tree-sha1 = "8557017cfc7b58baea05a43ed35538857e6d35b4" 33 | uuid = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" 34 | version = "0.1.19" 35 | 36 | [[deps.Adapt]] 37 | deps = ["LinearAlgebra"] 38 | git-tree-sha1 = "195c5505521008abea5aee4f96930717958eac6f" 39 | uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" 40 | version = "3.4.0" 41 | 42 | [[deps.ArgCheck]] 43 | git-tree-sha1 = "a3a402a35a2f7e0b87828ccabbd5ebfbebe356b4" 44 | uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197" 45 | version = "2.3.0" 46 | 47 | [[deps.ArgTools]] 48 | uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" 49 | version = "1.1.1" 50 | 51 | [[deps.ArnoldiMethod]] 52 | deps = ["LinearAlgebra", "Random", "StaticArrays"] 53 | git-tree-sha1 = "62e51b39331de8911e4a7ff6f5aaf38a5f4cc0ae" 54 | uuid = "ec485272-7323-5ecc-a04f-4719b315124d" 55 | version = "0.2.0" 56 | 57 | [[deps.ArrayInterface]] 58 | deps = ["ArrayInterfaceCore", "Compat", "IfElse", "LinearAlgebra", "Static"] 59 | git-tree-sha1 = "0582b5976fc76523f77056e888e454f0f7732596" 60 | uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" 61 | version = "6.0.22" 62 | 63 | [[deps.ArrayInterfaceCore]] 64 | deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] 65 | git-tree-sha1 = "40debc9f72d0511e12d817c7ca06a721b6423ba3" 66 | uuid = "30b0a656-2188-435a-8636-2ec0e6a096e2" 67 | version = "0.1.17" 68 | 69 | [[deps.ArrayInterfaceGPUArrays]] 70 | deps = ["Adapt", "ArrayInterfaceCore", "GPUArraysCore", "LinearAlgebra"] 71 | git-tree-sha1 = "febba7add2873aecc0b6620b55969e73ec875bce" 72 | uuid = "6ba088a2-8465-4c0a-af30-387133b534db" 73 | version = "0.2.1" 74 | 75 | [[deps.ArrayInterfaceOffsetArrays]] 76 | deps = ["ArrayInterface", "OffsetArrays", "Static"] 77 | git-tree-sha1 = "c49f6bad95a30defff7c637731f00934c7289c50" 78 | uuid = "015c0d05-e682-4f19-8f0a-679ce4c54826" 79 | version = "0.1.6" 80 | 81 | [[deps.ArrayInterfaceStaticArrays]] 82 | deps = ["Adapt", "ArrayInterface", "ArrayInterfaceStaticArraysCore", "LinearAlgebra", "Static", "StaticArrays"] 83 | git-tree-sha1 = "efb000a9f643f018d5154e56814e338b5746c560" 84 | uuid = "b0d46f97-bff5-4637-a19a-dd75974142cd" 85 | version = "0.1.4" 86 | 87 | [[deps.ArrayInterfaceStaticArraysCore]] 88 | deps = ["Adapt", "ArrayInterfaceCore", "LinearAlgebra", "StaticArraysCore"] 89 | git-tree-sha1 = "a1e2cf6ced6505cbad2490532388683f1e88c3ed" 90 | uuid = "dd5226c6-a4d4-4bc7-8575-46859f9c95b9" 91 | version = "0.1.0" 92 | 93 | [[deps.ArrayInterfaceTracker]] 94 | deps = ["ArrayInterfaceCore", "Tracker"] 95 | git-tree-sha1 = "9600e1ef98f7067dc91c22c0759c60580a0320dd" 96 | uuid = "a2b0951a-f94f-4742-8780-617792921f9b" 97 | version = "0.1.1" 98 | 99 | [[deps.ArrayLayouts]] 100 | deps = ["FillArrays", "LinearAlgebra", "SparseArrays"] 101 | git-tree-sha1 = "ac5cc6021f32a272ee572dd2a325049a1fa0d034" 102 | uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" 103 | version = "0.8.11" 104 | 105 | [[deps.Artifacts]] 106 | uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" 107 | 108 | [[deps.AutoHashEquals]] 109 | git-tree-sha1 = "45bb6705d93be619b81451bb2006b7ee5d4e4453" 110 | uuid = "15f4f7f2-30c1-5605-9d31-71845cf9641f" 111 | version = "0.2.0" 112 | 113 | [[deps.BFloat16s]] 114 | deps = ["LinearAlgebra", "Printf", "Random", "Test"] 115 | git-tree-sha1 = "a598ecb0d717092b5539dbbe890c98bac842b072" 116 | uuid = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" 117 | version = "0.2.0" 118 | 119 | [[deps.BandedMatrices]] 120 | deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "Random", "SparseArrays"] 121 | git-tree-sha1 = "d8da9afb97ad4a1a06650db11c8b72d9dd2f1ace" 122 | uuid = "aae01518-5342-5314-be14-df237901396f" 123 | version = "0.17.5" 124 | 125 | [[deps.BangBang]] 126 | deps = ["Compat", "ConstructionBase", "Future", "InitialValues", "LinearAlgebra", "Requires", "Setfield", "Tables", "ZygoteRules"] 127 | git-tree-sha1 = "b15a6bc52594f5e4a3b825858d1089618871bf9d" 128 | uuid = "198e06fe-97b7-11e9-32a5-e1d131e6ad66" 129 | version = "0.3.36" 130 | 131 | [[deps.Base64]] 132 | uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" 133 | 134 | [[deps.Baselet]] 135 | git-tree-sha1 = "aebf55e6d7795e02ca500a689d326ac979aaf89e" 136 | uuid = "9718e550-a3fa-408a-8086-8db961cd8217" 137 | version = "0.1.1" 138 | 139 | [[deps.BenchmarkTools]] 140 | deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] 141 | git-tree-sha1 = "4c10eee4af024676200bc7752e536f858c6b8f93" 142 | uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" 143 | version = "1.3.1" 144 | 145 | [[deps.Bijections]] 146 | git-tree-sha1 = "fe4f8c5ee7f76f2198d5c2a06d3961c249cce7bd" 147 | uuid = "e2ed5e7c-b2de-5872-ae92-c73ca462fb04" 148 | version = "0.1.4" 149 | 150 | [[deps.BitTwiddlingConvenienceFunctions]] 151 | deps = ["Static"] 152 | git-tree-sha1 = "eaee37f76339077f86679787a71990c4e465477f" 153 | uuid = "62783981-4cbd-42fc-bca8-16325de8dc4b" 154 | version = "0.1.4" 155 | 156 | [[deps.BlockArrays]] 157 | deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra"] 158 | git-tree-sha1 = "0c0dd27be59bc76a3da6243d8172aeedd6420037" 159 | uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" 160 | version = "0.16.20" 161 | 162 | [[deps.BlockBandedMatrices]] 163 | deps = ["ArrayLayouts", "BandedMatrices", "BlockArrays", "FillArrays", "LinearAlgebra", "MatrixFactorizations", "SparseArrays", "Statistics"] 164 | git-tree-sha1 = "e43b59446b2c10024f6b64e82e359997e7adb26b" 165 | uuid = "ffab5731-97b5-5995-9138-79e8c1846df0" 166 | version = "0.11.9" 167 | 168 | [[deps.Bzip2_jll]] 169 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 170 | git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" 171 | uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" 172 | version = "1.0.8+0" 173 | 174 | [[deps.CEnum]] 175 | git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" 176 | uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" 177 | version = "0.4.2" 178 | 179 | [[deps.CPUSummary]] 180 | deps = ["CpuId", "IfElse", "Static"] 181 | git-tree-sha1 = "8a43595f7b3f7d6dd1e07ad9b94081e1975df4af" 182 | uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" 183 | version = "0.1.25" 184 | 185 | [[deps.CUDA]] 186 | deps = ["AbstractFFTs", "Adapt", "BFloat16s", "CEnum", "CompilerSupportLibraries_jll", "ExprTools", "GPUArrays", "GPUCompiler", "LLVM", "LazyArtifacts", "Libdl", "LinearAlgebra", "Logging", "Printf", "Random", "Random123", "RandomNumbers", "Reexport", "Requires", "SparseArrays", "SpecialFunctions", "TimerOutputs"] 187 | git-tree-sha1 = "49549e2c28ffb9cc77b3689dc10e46e6271e9452" 188 | uuid = "052768ef-5323-5732-b1bb-66c8b64840ba" 189 | version = "3.12.0" 190 | 191 | [[deps.Calculus]] 192 | deps = ["LinearAlgebra"] 193 | git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" 194 | uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" 195 | version = "0.5.1" 196 | 197 | [[deps.Cassette]] 198 | git-tree-sha1 = "063b2e77c5537a548c5bf2f44161f1d3e1ab3227" 199 | uuid = "7057c7e9-c182-5462-911a-8362d720325c" 200 | version = "0.3.10" 201 | 202 | [[deps.ChainRules]] 203 | deps = ["Adapt", "ChainRulesCore", "Compat", "Distributed", "GPUArraysCore", "IrrationalConstants", "LinearAlgebra", "Random", "RealDot", "SparseArrays", "Statistics", "StructArrays"] 204 | git-tree-sha1 = "b97807637619f6ef2b519b46bde368f758734bc3" 205 | uuid = "082447d4-558c-5d27-93f4-14fc19e9eca2" 206 | version = "1.44.4" 207 | 208 | [[deps.ChainRulesCore]] 209 | deps = ["Compat", "LinearAlgebra", "SparseArrays"] 210 | git-tree-sha1 = "80ca332f6dcb2508adba68f22f551adb2d00a624" 211 | uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" 212 | version = "1.15.3" 213 | 214 | [[deps.ChangesOfVariables]] 215 | deps = ["ChainRulesCore", "LinearAlgebra", "Test"] 216 | git-tree-sha1 = "38f7a08f19d8810338d4f5085211c7dfa5d5bdd8" 217 | uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" 218 | version = "0.1.4" 219 | 220 | [[deps.CloseOpenIntervals]] 221 | deps = ["ArrayInterface", "Static"] 222 | git-tree-sha1 = "5522c338564580adf5d58d91e43a55db0fa5fb39" 223 | uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9" 224 | version = "0.1.10" 225 | 226 | [[deps.CodecBzip2]] 227 | deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] 228 | git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7" 229 | uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" 230 | version = "0.7.2" 231 | 232 | [[deps.CodecZlib]] 233 | deps = ["TranscodingStreams", "Zlib_jll"] 234 | git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" 235 | uuid = "944b1d66-785c-5afd-91f1-9de20f533193" 236 | version = "0.7.0" 237 | 238 | [[deps.ColorSchemes]] 239 | deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Random"] 240 | git-tree-sha1 = "1fd869cc3875b57347f7027521f561cf46d1fcd8" 241 | uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" 242 | version = "3.19.0" 243 | 244 | [[deps.ColorTypes]] 245 | deps = ["FixedPointNumbers", "Random"] 246 | git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" 247 | uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 248 | version = "0.11.4" 249 | 250 | [[deps.ColorVectorSpace]] 251 | deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] 252 | git-tree-sha1 = "d08c20eef1f2cbc6e60fd3612ac4340b89fea322" 253 | uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" 254 | version = "0.9.9" 255 | 256 | [[deps.Colors]] 257 | deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] 258 | git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" 259 | uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" 260 | version = "0.12.8" 261 | 262 | [[deps.Combinatorics]] 263 | git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860" 264 | uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" 265 | version = "1.0.2" 266 | 267 | [[deps.CommonSolve]] 268 | git-tree-sha1 = "332a332c97c7071600984b3c31d9067e1a4e6e25" 269 | uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" 270 | version = "0.2.1" 271 | 272 | [[deps.CommonSubexpressions]] 273 | deps = ["MacroTools", "Test"] 274 | git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" 275 | uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" 276 | version = "0.3.0" 277 | 278 | [[deps.Compat]] 279 | deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] 280 | git-tree-sha1 = "78bee250c6826e1cf805a88b7f1e86025275d208" 281 | uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" 282 | version = "3.46.0" 283 | 284 | [[deps.CompilerSupportLibraries_jll]] 285 | deps = ["Artifacts", "Libdl"] 286 | uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" 287 | version = "0.5.2+0" 288 | 289 | [[deps.ComponentArrays]] 290 | deps = ["ArrayInterface", "ChainRulesCore", "LinearAlgebra", "Requires"] 291 | git-tree-sha1 = "1667973b9a342f0b2e790f9a172af2412cbc182b" 292 | uuid = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" 293 | version = "0.13.2" 294 | 295 | [[deps.CompositeTypes]] 296 | git-tree-sha1 = "d5b014b216dc891e81fea299638e4c10c657b582" 297 | uuid = "b152e2b5-7a66-4b01-a709-34e65c35f657" 298 | version = "0.1.2" 299 | 300 | [[deps.CompositionsBase]] 301 | git-tree-sha1 = "455419f7e328a1a2493cabc6428d79e951349769" 302 | uuid = "a33af91c-f02d-484b-be07-31d278c5ca2b" 303 | version = "0.1.1" 304 | 305 | [[deps.Conda]] 306 | deps = ["Downloads", "JSON", "VersionParsing"] 307 | git-tree-sha1 = "6e47d11ea2776bc5627421d59cdcc1296c058071" 308 | uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" 309 | version = "1.7.0" 310 | 311 | [[deps.Configurations]] 312 | deps = ["ExproniconLite", "OrderedCollections", "TOML"] 313 | git-tree-sha1 = "62a7c76dbad02fdfdaa53608104edf760938c4ca" 314 | uuid = "5218b696-f38b-4ac9-8b61-a12ec717816d" 315 | version = "0.17.4" 316 | 317 | [[deps.ConsoleProgressMonitor]] 318 | deps = ["Logging", "ProgressMeter"] 319 | git-tree-sha1 = "3ab7b2136722890b9af903859afcf457fa3059e8" 320 | uuid = "88cd18e8-d9cc-4ea6-8889-5259c0d15c8b" 321 | version = "0.1.2" 322 | 323 | [[deps.ConstructionBase]] 324 | deps = ["LinearAlgebra"] 325 | git-tree-sha1 = "fb21ddd70a051d882a1686a5a550990bbe371a95" 326 | uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" 327 | version = "1.4.1" 328 | 329 | [[deps.ContextVariablesX]] 330 | deps = ["Compat", "Logging", "UUIDs"] 331 | git-tree-sha1 = "8ccaa8c655bc1b83d2da4d569c9b28254ababd6e" 332 | uuid = "6add18c4-b38d-439d-96f6-d6bc489c04c5" 333 | version = "0.1.2" 334 | 335 | [[deps.Contour]] 336 | git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781" 337 | uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" 338 | version = "0.6.2" 339 | 340 | [[deps.CpuId]] 341 | deps = ["Markdown"] 342 | git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" 343 | uuid = "adafc99b-e345-5852-983c-f28acb93d879" 344 | version = "0.3.1" 345 | 346 | [[deps.Crayons]] 347 | git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" 348 | uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" 349 | version = "4.1.1" 350 | 351 | [[deps.DataAPI]] 352 | git-tree-sha1 = "fb5f5316dd3fd4c5e7c30a24d50643b73e37cd40" 353 | uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" 354 | version = "1.10.0" 355 | 356 | [[deps.DataInterpolations]] 357 | deps = ["ChainRulesCore", "LinearAlgebra", "Optim", "RecipesBase", "RecursiveArrayTools", "Reexport", "RegularizationTools", "Symbolics"] 358 | git-tree-sha1 = "cd5e1d85ca89521b7df86eb343bb129799d92b15" 359 | uuid = "82cc6244-b520-54b8-b5a6-8a565e85f1d0" 360 | version = "3.10.1" 361 | 362 | [[deps.DataStructures]] 363 | deps = ["Compat", "InteractiveUtils", "OrderedCollections"] 364 | git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" 365 | uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 366 | version = "0.18.13" 367 | 368 | [[deps.DataValueInterfaces]] 369 | git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" 370 | uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" 371 | version = "1.0.0" 372 | 373 | [[deps.Dates]] 374 | deps = ["Printf"] 375 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 376 | 377 | [[deps.DefineSingletons]] 378 | git-tree-sha1 = "0fba8b706d0178b4dc7fd44a96a92382c9065c2c" 379 | uuid = "244e2a9f-e319-4986-a169-4d1fe445cd52" 380 | version = "0.1.2" 381 | 382 | [[deps.DelimitedFiles]] 383 | deps = ["Mmap"] 384 | uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" 385 | 386 | [[deps.DensityInterface]] 387 | deps = ["InverseFunctions", "Test"] 388 | git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b" 389 | uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" 390 | version = "0.4.0" 391 | 392 | [[deps.DiffEqBase]] 393 | deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "Static", "StaticArrays", "Statistics", "ZygoteRules"] 394 | git-tree-sha1 = "4d5f6b613cad84aecdc482e66c0c229c0460954f" 395 | uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" 396 | version = "6.98.1" 397 | 398 | [[deps.DiffEqCallbacks]] 399 | deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "Markdown", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] 400 | git-tree-sha1 = "f8cc1ad62a87988225a07524ef84c7df7264c232" 401 | uuid = "459566f4-90b8-5000-8ac3-15dfb0a30def" 402 | version = "2.24.1" 403 | 404 | [[deps.DiffEqFlux]] 405 | deps = ["Adapt", "Cassette", "ChainRulesCore", "ConsoleProgressMonitor", "DataInterpolations", "DiffEqBase", "DiffResults", "Distributions", "DistributionsAD", "Flux", "ForwardDiff", "LinearAlgebra", "Logging", "LoggingExtras", "Lux", "NNlib", "Optim", "Optimization", "OptimizationFlux", "OptimizationOptimJL", "OptimizationPolyalgorithms", "Printf", "ProgressLogging", "Random", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "SciMLSensitivity", "StaticArrays", "TerminalLoggers", "Zygote", "ZygoteRules"] 406 | git-tree-sha1 = "11d536a7a92e780623c92c36811552e21c89abb7" 407 | uuid = "aae7a2af-3d4f-5e19-a356-7da93b79d9d0" 408 | version = "1.52.0" 409 | 410 | [[deps.DiffEqNoiseProcess]] 411 | deps = ["DiffEqBase", "Distributions", "GPUArraysCore", "LinearAlgebra", "Markdown", "Optim", "PoissonRandom", "QuadGK", "Random", "Random123", "RandomNumbers", "RecipesBase", "RecursiveArrayTools", "ResettableStacks", "SciMLBase", "StaticArrays", "Statistics"] 412 | git-tree-sha1 = "70590eb0a968cb0a801945c4c26dacca162bbbd3" 413 | uuid = "77a26b50-5914-5dd7-bc55-306e6241c503" 414 | version = "5.12.3" 415 | 416 | [[deps.DiffEqOperators]] 417 | deps = ["BandedMatrices", "BlockBandedMatrices", "DiffEqBase", "DomainSets", "ForwardDiff", "LazyArrays", "LazyBandedMatrices", "LinearAlgebra", "LoopVectorization", "NNlib", "NonlinearSolve", "Requires", "RuntimeGeneratedFunctions", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "SuiteSparse"] 418 | git-tree-sha1 = "403d101caee42ba504f2ee74ae6e8413b765605b" 419 | uuid = "9fdde737-9c7f-55bf-ade8-46b3f136cc48" 420 | version = "4.43.1" 421 | 422 | [[deps.DiffResults]] 423 | deps = ["StaticArrays"] 424 | git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805" 425 | uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" 426 | version = "1.0.3" 427 | 428 | [[deps.DiffRules]] 429 | deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] 430 | git-tree-sha1 = "992a23afdb109d0d2f8802a30cf5ae4b1fe7ea68" 431 | uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" 432 | version = "1.11.1" 433 | 434 | [[deps.Distances]] 435 | deps = ["LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI"] 436 | git-tree-sha1 = "3258d0659f812acde79e8a74b11f17ac06d0ca04" 437 | uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" 438 | version = "0.10.7" 439 | 440 | [[deps.Distributed]] 441 | deps = ["Random", "Serialization", "Sockets"] 442 | uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" 443 | 444 | [[deps.Distributions]] 445 | deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] 446 | git-tree-sha1 = "334a5896c1534bb1aa7aa2a642d30ba7707357ef" 447 | uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" 448 | version = "0.25.68" 449 | 450 | [[deps.DistributionsAD]] 451 | deps = ["Adapt", "ChainRules", "ChainRulesCore", "Compat", "DiffRules", "Distributions", "FillArrays", "LinearAlgebra", "NaNMath", "PDMats", "Random", "Requires", "SpecialFunctions", "StaticArrays", "StatsBase", "StatsFuns", "ZygoteRules"] 452 | git-tree-sha1 = "74dd5dac82812af7041ae322584d5c2181dead5c" 453 | uuid = "ced4e74d-a319-5a8a-b0ac-84af2272839c" 454 | version = "0.6.42" 455 | 456 | [[deps.DocStringExtensions]] 457 | deps = ["LibGit2"] 458 | git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" 459 | uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" 460 | version = "0.8.6" 461 | 462 | [[deps.DomainSets]] 463 | deps = ["CompositeTypes", "IntervalSets", "LinearAlgebra", "Random", "StaticArrays", "Statistics"] 464 | git-tree-sha1 = "dc45fbbe91d6d17a8e187abad39fb45963d97388" 465 | uuid = "5b8099bc-c8ec-5219-889f-1d9e522a28bf" 466 | version = "0.5.13" 467 | 468 | [[deps.Downloads]] 469 | deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] 470 | uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" 471 | version = "1.6.0" 472 | 473 | [[deps.DualNumbers]] 474 | deps = ["Calculus", "NaNMath", "SpecialFunctions"] 475 | git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" 476 | uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" 477 | version = "0.6.8" 478 | 479 | [[deps.DynamicPolynomials]] 480 | deps = ["DataStructures", "Future", "LinearAlgebra", "MultivariatePolynomials", "MutableArithmetics", "Pkg", "Reexport", "Test"] 481 | git-tree-sha1 = "d0fa82f39c2a5cdb3ee385ad52bc05c42cb4b9f0" 482 | uuid = "7c1d4256-1411-5781-91ec-d7bc3513ac07" 483 | version = "0.4.5" 484 | 485 | [[deps.EarCut_jll]] 486 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 487 | git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d" 488 | uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" 489 | version = "2.2.3+0" 490 | 491 | [[deps.EllipsisNotation]] 492 | deps = ["ArrayInterface"] 493 | git-tree-sha1 = "03b753748fd193a7f2730c02d880da27c5a24508" 494 | uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" 495 | version = "1.6.0" 496 | 497 | [[deps.Enzyme]] 498 | deps = ["Adapt", "CEnum", "Enzyme_jll", "GPUCompiler", "LLVM", "Libdl", "LinearAlgebra", "ObjectFile", "Printf", "Random"] 499 | git-tree-sha1 = "8ab9eb44fbcfc9161b3f81be7814a7618f2a3460" 500 | uuid = "7da242da-08ed-463a-9acd-ee780be4f1d9" 501 | version = "0.10.4" 502 | 503 | [[deps.Enzyme_jll]] 504 | deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg", "TOML"] 505 | git-tree-sha1 = "722aa3b554e883118e0e3111629ec40e176cee2c" 506 | uuid = "7cc45869-7501-5eee-bdea-0790c847d4ef" 507 | version = "0.0.33+0" 508 | 509 | [[deps.ExponentialUtilities]] 510 | deps = ["ArrayInterfaceCore", "GPUArraysCore", "GenericSchur", "LinearAlgebra", "Printf", "SparseArrays", "libblastrampoline_jll"] 511 | git-tree-sha1 = "b40c9037e1a33990466bc5d224ced34b34eebdb0" 512 | uuid = "d4d017d3-3776-5f7e-afef-a10c40355c18" 513 | version = "1.18.0" 514 | 515 | [[deps.ExprTools]] 516 | git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" 517 | uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" 518 | version = "0.1.8" 519 | 520 | [[deps.ExproniconLite]] 521 | git-tree-sha1 = "07b85b02d910f90dde6b383484c5ee6c0f169fa3" 522 | uuid = "55351af7-c7e9-48d6-89ff-24e801d99491" 523 | version = "0.7.0" 524 | 525 | [[deps.Extents]] 526 | git-tree-sha1 = "5e1e4c53fa39afe63a7d356e30452249365fba99" 527 | uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910" 528 | version = "0.1.1" 529 | 530 | [[deps.FLoops]] 531 | deps = ["BangBang", "Compat", "FLoopsBase", "InitialValues", "JuliaVariables", "MLStyle", "Serialization", "Setfield", "Transducers"] 532 | git-tree-sha1 = "4391d3ed58db9dc5a9883b23a0578316b4798b1f" 533 | uuid = "cc61a311-1640-44b5-9fba-1b764f453329" 534 | version = "0.2.0" 535 | 536 | [[deps.FLoopsBase]] 537 | deps = ["ContextVariablesX"] 538 | git-tree-sha1 = "656f7a6859be8673bf1f35da5670246b923964f7" 539 | uuid = "b9860ae5-e623-471e-878b-f6a53c775ea6" 540 | version = "0.1.1" 541 | 542 | [[deps.FastBroadcast]] 543 | deps = ["ArrayInterface", "ArrayInterfaceCore", "LinearAlgebra", "Polyester", "Static", "StrideArraysCore"] 544 | git-tree-sha1 = "21cdeff41e5a1822c2acd7fc7934c5f450588e00" 545 | uuid = "7034ab61-46d4-4ed7-9d0f-46aef9175898" 546 | version = "0.2.1" 547 | 548 | [[deps.FastClosures]] 549 | git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" 550 | uuid = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" 551 | version = "0.3.2" 552 | 553 | [[deps.FastGaussQuadrature]] 554 | deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"] 555 | git-tree-sha1 = "58d83dd5a78a36205bdfddb82b1bb67682e64487" 556 | uuid = "442a2c76-b920-505d-bb47-c5924d526838" 557 | version = "0.4.9" 558 | 559 | [[deps.FastLapackInterface]] 560 | deps = ["LinearAlgebra"] 561 | git-tree-sha1 = "25ff6094a718c5dd0996c04d9e52eb2def86c4e3" 562 | uuid = "29a986be-02c6-4525-aec4-84b980013641" 563 | version = "1.2.5" 564 | 565 | [[deps.FileIO]] 566 | deps = ["Pkg", "Requires", "UUIDs"] 567 | git-tree-sha1 = "94f5101b96d2d968ace56f7f2db19d0a5f592e28" 568 | uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" 569 | version = "1.15.0" 570 | 571 | [[deps.FileWatching]] 572 | uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" 573 | 574 | [[deps.FillArrays]] 575 | deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] 576 | git-tree-sha1 = "246621d23d1f43e3b9c368bf3b72b2331a27c286" 577 | uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" 578 | version = "0.13.2" 579 | 580 | [[deps.FiniteDiff]] 581 | deps = ["ArrayInterfaceCore", "LinearAlgebra", "Requires", "Setfield", "SparseArrays", "StaticArrays"] 582 | git-tree-sha1 = "5a2cff9b6b77b33b89f3d97a4d367747adce647e" 583 | uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" 584 | version = "2.15.0" 585 | 586 | [[deps.FixedPointNumbers]] 587 | deps = ["Statistics"] 588 | git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" 589 | uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" 590 | version = "0.8.4" 591 | 592 | [[deps.Flux]] 593 | deps = ["Adapt", "ArrayInterface", "CUDA", "ChainRulesCore", "Functors", "LinearAlgebra", "MLUtils", "MacroTools", "NNlib", "NNlibCUDA", "Optimisers", "ProgressLogging", "Random", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "Test", "Zygote"] 594 | git-tree-sha1 = "9b5419ad6f043ac2b52f1b7f9a8ecb8762231214" 595 | uuid = "587475ba-b771-5e3f-ad9e-33799f191a9c" 596 | version = "0.13.5" 597 | 598 | [[deps.FoldsThreads]] 599 | deps = ["Accessors", "FunctionWrappers", "InitialValues", "SplittablesBase", "Transducers"] 600 | git-tree-sha1 = "eb8e1989b9028f7e0985b4268dabe94682249025" 601 | uuid = "9c68100b-dfe1-47cf-94c8-95104e173443" 602 | version = "0.1.1" 603 | 604 | [[deps.Formatting]] 605 | deps = ["Printf"] 606 | git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" 607 | uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" 608 | version = "0.4.2" 609 | 610 | [[deps.ForwardDiff]] 611 | deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] 612 | git-tree-sha1 = "187198a4ed8ccd7b5d99c41b69c679269ea2b2d4" 613 | uuid = "f6369f11-7733-5829-9624-2563aa707210" 614 | version = "0.10.32" 615 | 616 | [[deps.FreeType]] 617 | deps = ["CEnum", "FreeType2_jll"] 618 | git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4" 619 | uuid = "b38be410-82b0-50bf-ab77-7b57e271db43" 620 | version = "4.0.0" 621 | 622 | [[deps.FreeType2_jll]] 623 | deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] 624 | git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" 625 | uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" 626 | version = "2.10.4+0" 627 | 628 | [[deps.FreeTypeAbstraction]] 629 | deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics"] 630 | git-tree-sha1 = "38a92e40157100e796690421e34a11c107205c86" 631 | uuid = "663a7486-cb36-511b-a19d-713bb74d65c9" 632 | version = "0.10.0" 633 | 634 | [[deps.FunctionWrappers]] 635 | git-tree-sha1 = "241552bc2209f0fa068b6415b1942cc0aa486bcc" 636 | uuid = "069b7b12-0de2-55c6-9aab-29f3d0a68a2e" 637 | version = "1.1.2" 638 | 639 | [[deps.FunctionWrappersWrappers]] 640 | deps = ["FunctionWrappers"] 641 | git-tree-sha1 = "2da4f223fbc4328b389bcce5f3e93dbe71678590" 642 | uuid = "77dc65aa-8811-40c2-897b-53d922fa7daf" 643 | version = "0.1.0" 644 | 645 | [[deps.Functors]] 646 | deps = ["LinearAlgebra"] 647 | git-tree-sha1 = "a2657dd0f3e8a61dbe70fc7c122038bd33790af5" 648 | uuid = "d9f16b24-f501-4c13-a1f2-28368ffc5196" 649 | version = "0.3.0" 650 | 651 | [[deps.Future]] 652 | deps = ["Random"] 653 | uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" 654 | 655 | [[deps.GPUArrays]] 656 | deps = ["Adapt", "GPUArraysCore", "LLVM", "LinearAlgebra", "Printf", "Random", "Reexport", "Serialization", "Statistics"] 657 | git-tree-sha1 = "45d7deaf05cbb44116ba785d147c518ab46352d7" 658 | uuid = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7" 659 | version = "8.5.0" 660 | 661 | [[deps.GPUArraysCore]] 662 | deps = ["Adapt"] 663 | git-tree-sha1 = "6872f5ec8fd1a38880f027a26739d42dcda6691f" 664 | uuid = "46192b85-c4d5-4398-a991-12ede77f4527" 665 | version = "0.1.2" 666 | 667 | [[deps.GPUCompiler]] 668 | deps = ["ExprTools", "InteractiveUtils", "LLVM", "Libdl", "Logging", "TimerOutputs", "UUIDs"] 669 | git-tree-sha1 = "122d7bcc92abf94cf1a86281ad7a4d0e838ab9e0" 670 | uuid = "61eb1bfa-7361-4325-ad38-22787b887f55" 671 | version = "0.16.3" 672 | 673 | [[deps.GarishPrint]] 674 | deps = ["Configurations", "Preferences"] 675 | git-tree-sha1 = "41136d24cc02c4d7c2b8c8982823fedac66d0a45" 676 | uuid = "b0ab02a7-8576-43f7-aa76-eaa7c3897c54" 677 | version = "0.5.1" 678 | 679 | [[deps.GenericSchur]] 680 | deps = ["LinearAlgebra", "Printf"] 681 | git-tree-sha1 = "fb69b2a645fa69ba5f474af09221b9308b160ce6" 682 | uuid = "c145ed77-6b09-5dd9-b285-bf645a82121e" 683 | version = "0.5.3" 684 | 685 | [[deps.GeoInterface]] 686 | deps = ["Extents"] 687 | git-tree-sha1 = "fb28b5dc239d0174d7297310ef7b84a11804dfab" 688 | uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" 689 | version = "1.0.1" 690 | 691 | [[deps.GeometryBasics]] 692 | deps = ["EarCut_jll", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] 693 | git-tree-sha1 = "a7a97895780dab1085a97769316aa348830dc991" 694 | uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" 695 | version = "0.4.3" 696 | 697 | [[deps.Graphs]] 698 | deps = ["ArnoldiMethod", "Compat", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] 699 | git-tree-sha1 = "a6d30bdc378d340912f48abf01281aab68c0dec8" 700 | uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" 701 | version = "1.7.2" 702 | 703 | [[deps.Groebner]] 704 | deps = ["AbstractAlgebra", "Combinatorics", "Logging", "MultivariatePolynomials", "Primes", "Random"] 705 | git-tree-sha1 = "144cd8158cce5b36614b9c95b8afab6911bd469b" 706 | uuid = "0b43b601-686d-58a3-8a1c-6623616c7cd4" 707 | version = "0.2.10" 708 | 709 | [[deps.GroupsCore]] 710 | deps = ["Markdown", "Random"] 711 | git-tree-sha1 = "9e1a5e9f3b81ad6a5c613d181664a0efc6fe6dd7" 712 | uuid = "d5909c97-4eac-4ecc-a3dc-fdd0858a4120" 713 | version = "0.4.0" 714 | 715 | [[deps.HostCPUFeatures]] 716 | deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"] 717 | git-tree-sha1 = "b7b88a4716ac33fe31d6556c02fc60017594343c" 718 | uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0" 719 | version = "0.1.8" 720 | 721 | [[deps.HypergeometricFunctions]] 722 | deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions", "Test"] 723 | git-tree-sha1 = "709d864e3ed6e3545230601f94e11ebc65994641" 724 | uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" 725 | version = "0.3.11" 726 | 727 | [[deps.IRTools]] 728 | deps = ["InteractiveUtils", "MacroTools", "Test"] 729 | git-tree-sha1 = "af14a478780ca78d5eb9908b263023096c2b9d64" 730 | uuid = "7869d1d1-7146-5819-86e3-90919afe41df" 731 | version = "0.4.6" 732 | 733 | [[deps.IfElse]] 734 | git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" 735 | uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" 736 | version = "0.1.1" 737 | 738 | [[deps.InfiniteOpt]] 739 | deps = ["AbstractTrees", "DataStructures", "Distributions", "FastGaussQuadrature", "JuMP", "LeftChildRightSiblingTrees", "LinearAlgebra", "MutableArithmetics", "Reexport", "SpecialFunctions"] 740 | git-tree-sha1 = "18477825f601679d8a32aed6c0c5190991bcedbd" 741 | uuid = "20393b10-9daf-11e9-18c9-8db751c92c57" 742 | version = "0.5.6" 743 | 744 | [[deps.Inflate]] 745 | git-tree-sha1 = "5cd07aab533df5170988219191dfad0519391428" 746 | uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" 747 | version = "0.1.3" 748 | 749 | [[deps.InitialValues]] 750 | git-tree-sha1 = "4da0f88e9a39111c2fa3add390ab15f3a44f3ca3" 751 | uuid = "22cec73e-a1b8-11e9-2c92-598750a2cf9c" 752 | version = "0.3.1" 753 | 754 | [[deps.IntegerMathUtils]] 755 | git-tree-sha1 = "f366daebdfb079fd1fe4e3d560f99a0c892e15bc" 756 | uuid = "18e54dd8-cb9d-406c-a71d-865a43cbb235" 757 | version = "0.1.0" 758 | 759 | [[deps.InteractiveUtils]] 760 | deps = ["Markdown"] 761 | uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" 762 | 763 | [[deps.IntervalSets]] 764 | deps = ["Dates", "Random", "Statistics"] 765 | git-tree-sha1 = "076bb0da51a8c8d1229936a1af7bdfacd65037e1" 766 | uuid = "8197267c-284f-5f27-9208-e0e47529a953" 767 | version = "0.7.2" 768 | 769 | [[deps.InverseFunctions]] 770 | deps = ["Test"] 771 | git-tree-sha1 = "b3364212fb5d870f724876ffcd34dd8ec6d98918" 772 | uuid = "3587e190-3f89-42d0-90ee-14403ec27112" 773 | version = "0.1.7" 774 | 775 | [[deps.Ipopt]] 776 | deps = ["Ipopt_jll", "MathOptInterface"] 777 | git-tree-sha1 = "6d4c0cec91619b7c44ed9d4f9d021ce053019e15" 778 | uuid = "b6b21f68-93f8-5de0-b562-5493be1d77c9" 779 | version = "1.0.4" 780 | 781 | [[deps.Ipopt_jll]] 782 | deps = ["ASL_jll", "Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "MUMPS_seq_jll", "OpenBLAS32_jll", "Pkg"] 783 | git-tree-sha1 = "e3e202237d93f18856b6ff1016166b0f172a49a8" 784 | uuid = "9cc047cb-c261-5740-88fc-0cf96f7bdcc7" 785 | version = "300.1400.400+0" 786 | 787 | [[deps.IrrationalConstants]] 788 | git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" 789 | uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" 790 | version = "0.1.1" 791 | 792 | [[deps.IterTools]] 793 | git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" 794 | uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" 795 | version = "1.4.0" 796 | 797 | [[deps.IterativeSolvers]] 798 | deps = ["LinearAlgebra", "Printf", "Random", "RecipesBase", "SparseArrays"] 799 | git-tree-sha1 = "1169632f425f79429f245113b775a0e3d121457c" 800 | uuid = "42fd0dbc-a981-5370-80f2-aaf504508153" 801 | version = "0.9.2" 802 | 803 | [[deps.IteratorInterfaceExtensions]] 804 | git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" 805 | uuid = "82899510-4779-5014-852e-03e436cf321d" 806 | version = "1.0.0" 807 | 808 | [[deps.JLLWrappers]] 809 | deps = ["Preferences"] 810 | git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" 811 | uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" 812 | version = "1.4.1" 813 | 814 | [[deps.JSON]] 815 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 816 | git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" 817 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 818 | version = "0.21.3" 819 | 820 | [[deps.JSON3]] 821 | deps = ["Dates", "Mmap", "Parsers", "StructTypes", "UUIDs"] 822 | git-tree-sha1 = "fd6f0cae36f42525567108a42c1c674af2ac620d" 823 | uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" 824 | version = "1.9.5" 825 | 826 | [[deps.JuMP]] 827 | deps = ["LinearAlgebra", "MathOptInterface", "MutableArithmetics", "OrderedCollections", "Printf", "SparseArrays"] 828 | git-tree-sha1 = "81e17aab8447b7af79ee4f5e0450922991969dd2" 829 | uuid = "4076af6c-e467-56ae-b986-b466b2749572" 830 | version = "1.2.1" 831 | 832 | [[deps.JuliaVariables]] 833 | deps = ["MLStyle", "NameResolution"] 834 | git-tree-sha1 = "49fb3cb53362ddadb4415e9b73926d6b40709e70" 835 | uuid = "b14d175d-62b4-44ba-8fb7-3064adc8c3ec" 836 | version = "0.2.4" 837 | 838 | [[deps.JumpProcesses]] 839 | deps = ["ArrayInterfaceCore", "DataStructures", "DiffEqBase", "DocStringExtensions", "FunctionWrappers", "Graphs", "LinearAlgebra", "Markdown", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "StaticArrays", "TreeViews", "UnPack"] 840 | git-tree-sha1 = "5a6e6c522e8a7b39b24be8eebcc13cc7885c6f2c" 841 | uuid = "ccbc3e58-028d-4f4c-8cd5-9ae44345cda5" 842 | version = "9.2.0" 843 | 844 | [[deps.KLU]] 845 | deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse_jll"] 846 | git-tree-sha1 = "cae5e3dfd89b209e01bcd65b3a25e74462c67ee0" 847 | uuid = "ef3ab10e-7fda-4108-b977-705223b18434" 848 | version = "0.3.0" 849 | 850 | [[deps.Krylov]] 851 | deps = ["LinearAlgebra", "Printf", "SparseArrays"] 852 | git-tree-sha1 = "a2327039e1c84615e22d662adb3df113caf44b70" 853 | uuid = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7" 854 | version = "0.8.3" 855 | 856 | [[deps.KrylovKit]] 857 | deps = ["LinearAlgebra", "Printf"] 858 | git-tree-sha1 = "49b0c1dd5c292870577b8f58c51072bd558febb9" 859 | uuid = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" 860 | version = "0.5.4" 861 | 862 | [[deps.LBFGSB]] 863 | deps = ["L_BFGS_B_jll"] 864 | git-tree-sha1 = "e2e6f53ee20605d0ea2be473480b7480bd5091b5" 865 | uuid = "5be7bae1-8223-5378-bac3-9e7378a2f6e6" 866 | version = "0.4.1" 867 | 868 | [[deps.LLVM]] 869 | deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Printf", "Unicode"] 870 | git-tree-sha1 = "e7e9184b0bf0158ac4e4aa9daf00041b5909bf1a" 871 | uuid = "929cbde3-209d-540e-8aea-75f648917ca0" 872 | version = "4.14.0" 873 | 874 | [[deps.LLVMExtra_jll]] 875 | deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg", "TOML"] 876 | git-tree-sha1 = "771bfe376249626d3ca12bcd58ba243d3f961576" 877 | uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab" 878 | version = "0.0.16+0" 879 | 880 | [[deps.L_BFGS_B_jll]] 881 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 882 | git-tree-sha1 = "77feda930ed3f04b2b0fbb5bea89e69d3677c6b0" 883 | uuid = "81d17ec3-03a1-5e46-b53e-bddc35a13473" 884 | version = "3.0.1+0" 885 | 886 | [[deps.LaTeXStrings]] 887 | git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" 888 | uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 889 | version = "1.3.0" 890 | 891 | [[deps.LabelledArrays]] 892 | deps = ["ArrayInterfaceCore", "ArrayInterfaceStaticArrays", "ChainRulesCore", "ForwardDiff", "LinearAlgebra", "MacroTools", "PreallocationTools", "RecursiveArrayTools", "StaticArrays"] 893 | git-tree-sha1 = "3926535a04c12fb986028a4a86bf5a0a3cf88b91" 894 | uuid = "2ee39098-c373-598a-b85f-a56591580800" 895 | version = "1.12.0" 896 | 897 | [[deps.Latexify]] 898 | deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] 899 | git-tree-sha1 = "1a43be956d433b5d0321197150c2f94e16c0aaa0" 900 | uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" 901 | version = "0.15.16" 902 | 903 | [[deps.LayoutPointers]] 904 | deps = ["ArrayInterface", "ArrayInterfaceOffsetArrays", "ArrayInterfaceStaticArrays", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static"] 905 | git-tree-sha1 = "b67e749fb35530979839e7b4b606a97105fe4f1c" 906 | uuid = "10f19ff3-798f-405d-979b-55457f8fc047" 907 | version = "0.1.10" 908 | 909 | [[deps.Lazy]] 910 | deps = ["MacroTools"] 911 | git-tree-sha1 = "1370f8202dac30758f3c345f9909b97f53d87d3f" 912 | uuid = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0" 913 | version = "0.15.1" 914 | 915 | [[deps.LazyArrays]] 916 | deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "MacroTools", "MatrixFactorizations", "SparseArrays", "StaticArrays"] 917 | git-tree-sha1 = "d9a962fac652cc6b0224622b18199f0ed46d316a" 918 | uuid = "5078a376-72f3-5289-bfd5-ec5146d43c02" 919 | version = "0.22.11" 920 | 921 | [[deps.LazyArtifacts]] 922 | deps = ["Artifacts", "Pkg"] 923 | uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" 924 | 925 | [[deps.LazyBandedMatrices]] 926 | deps = ["ArrayLayouts", "BandedMatrices", "BlockArrays", "BlockBandedMatrices", "FillArrays", "LazyArrays", "LinearAlgebra", "MatrixFactorizations", "SparseArrays", "StaticArrays"] 927 | git-tree-sha1 = "034d371419140f14a986ab7325d11f90f30b0c6d" 928 | uuid = "d7e5e226-e90b-4449-9968-0f923699bf6f" 929 | version = "0.7.17" 930 | 931 | [[deps.LazyGrids]] 932 | deps = ["Statistics"] 933 | git-tree-sha1 = "6067a4741e854999dab2b116094ab8391f480a3b" 934 | uuid = "7031d0ef-c40d-4431-b2f8-61a8d2f650db" 935 | version = "0.4.0" 936 | 937 | [[deps.LazyModules]] 938 | git-tree-sha1 = "a560dd966b386ac9ae60bdd3a3d3a326062d3c3e" 939 | uuid = "8cdb02fc-e678-4876-92c5-9defec4f444e" 940 | version = "0.3.1" 941 | 942 | [[deps.LeastSquaresOptim]] 943 | deps = ["FiniteDiff", "ForwardDiff", "LinearAlgebra", "Optim", "Printf", "SparseArrays", "Statistics", "SuiteSparse"] 944 | git-tree-sha1 = "06ea4a7c438f434dc0dc8d03c72e61ee0bf3629d" 945 | uuid = "0fc2ff8b-aaa3-5acd-a817-1944a5e08891" 946 | version = "0.8.3" 947 | 948 | [[deps.LeftChildRightSiblingTrees]] 949 | deps = ["AbstractTrees"] 950 | git-tree-sha1 = "fb6803dafae4a5d62ea5cab204b1e657d9737e7f" 951 | uuid = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e" 952 | version = "0.2.0" 953 | 954 | [[deps.LevyArea]] 955 | deps = ["LinearAlgebra", "Random", "SpecialFunctions"] 956 | git-tree-sha1 = "56513a09b8e0ae6485f34401ea9e2f31357958ec" 957 | uuid = "2d8b4e74-eb68-11e8-0fb9-d5eb67b50637" 958 | version = "1.0.0" 959 | 960 | [[deps.LibCURL]] 961 | deps = ["LibCURL_jll", "MozillaCACerts_jll"] 962 | uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" 963 | version = "0.6.3" 964 | 965 | [[deps.LibCURL_jll]] 966 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] 967 | uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" 968 | version = "7.84.0+0" 969 | 970 | [[deps.LibGit2]] 971 | deps = ["Base64", "NetworkOptions", "Printf", "SHA"] 972 | uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" 973 | 974 | [[deps.LibSSH2_jll]] 975 | deps = ["Artifacts", "Libdl", "MbedTLS_jll"] 976 | uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" 977 | version = "1.10.2+0" 978 | 979 | [[deps.Libdl]] 980 | uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 981 | 982 | [[deps.LineSearches]] 983 | deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] 984 | git-tree-sha1 = "7bbea35cec17305fc70a0e5b4641477dc0789d9d" 985 | uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" 986 | version = "7.2.0" 987 | 988 | [[deps.LinearAlgebra]] 989 | deps = ["Libdl", "libblastrampoline_jll"] 990 | uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 991 | 992 | [[deps.LinearSolve]] 993 | deps = ["ArrayInterfaceCore", "DocStringExtensions", "FastLapackInterface", "GPUArraysCore", "IterativeSolvers", "KLU", "Krylov", "KrylovKit", "LinearAlgebra", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "SparseArrays", "SuiteSparse", "UnPack"] 994 | git-tree-sha1 = "c48c190442b22c94499a446b8b452f16d04a258c" 995 | uuid = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" 996 | version = "1.23.3" 997 | 998 | [[deps.LogExpFunctions]] 999 | deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] 1000 | git-tree-sha1 = "94d9c52ca447e23eac0c0f074effbcd38830deb5" 1001 | uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" 1002 | version = "0.3.18" 1003 | 1004 | [[deps.Logging]] 1005 | uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" 1006 | 1007 | [[deps.LoggingExtras]] 1008 | deps = ["Dates", "Logging"] 1009 | git-tree-sha1 = "5d4d2d9904227b8bd66386c1138cf4d5ffa826bf" 1010 | uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" 1011 | version = "0.4.9" 1012 | 1013 | [[deps.LoopVectorization]] 1014 | deps = ["ArrayInterface", "ArrayInterfaceCore", "ArrayInterfaceOffsetArrays", "ArrayInterfaceStaticArrays", "CPUSummary", "ChainRulesCore", "CloseOpenIntervals", "DocStringExtensions", "ForwardDiff", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "SIMDDualNumbers", "SIMDTypes", "SLEEFPirates", "SnoopPrecompile", "SpecialFunctions", "Static", "ThreadingUtilities", "UnPack", "VectorizationBase"] 1015 | git-tree-sha1 = "60613258cc56b6c7c909f3e960e8b3b4e86dc2f2" 1016 | uuid = "bdcacae8-1622-11e9-2a5c-532679323890" 1017 | version = "0.12.124" 1018 | 1019 | [[deps.Lux]] 1020 | deps = ["Adapt", "CUDA", "ChainRulesCore", "ComponentArrays", "FillArrays", "Functors", "LinearAlgebra", "Markdown", "NNlib", "NNlibCUDA", "Optimisers", "Random", "Requires", "Setfield", "SparseArrays", "Statistics", "Zygote"] 1021 | git-tree-sha1 = "fc941ff74d639f31c0acc7110d061ee59aa0004c" 1022 | uuid = "b2108857-7c20-44ae-9111-449ecde12c47" 1023 | version = "0.4.17" 1024 | 1025 | [[deps.METIS_jll]] 1026 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1027 | git-tree-sha1 = "1d31872bb9c5e7ec1f618e8c4a56c8b0d9bddc7e" 1028 | uuid = "d00139f3-1899-568f-a2f0-47f597d42d70" 1029 | version = "5.1.1+0" 1030 | 1031 | [[deps.MLStyle]] 1032 | git-tree-sha1 = "c4f433356372cc8838da59e3608be4b0c4c2c280" 1033 | uuid = "d8e11817-5142-5d16-987a-aa16d5891078" 1034 | version = "0.4.13" 1035 | 1036 | [[deps.MLUtils]] 1037 | deps = ["ChainRulesCore", "DelimitedFiles", "FLoops", "FoldsThreads", "Random", "ShowCases", "Statistics", "StatsBase", "Transducers"] 1038 | git-tree-sha1 = "7fd41b7edef1d58062a75c2f129e839a8d168fe9" 1039 | uuid = "f1d291b0-491e-4a28-83b9-f70985020b54" 1040 | version = "0.2.10" 1041 | 1042 | [[deps.MUMPS_seq_jll]] 1043 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "METIS_jll", "OpenBLAS32_jll", "Pkg"] 1044 | git-tree-sha1 = "29de2841fa5aefe615dea179fcde48bb87b58f57" 1045 | uuid = "d7ed1dd3-d0ae-5e8e-bfb4-87a502085b8d" 1046 | version = "5.4.1+0" 1047 | 1048 | [[deps.MacroTools]] 1049 | deps = ["Markdown", "Random"] 1050 | git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" 1051 | uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" 1052 | version = "0.5.9" 1053 | 1054 | [[deps.ManualMemory]] 1055 | git-tree-sha1 = "bcaef4fc7a0cfe2cba636d84cda54b5e4e4ca3cd" 1056 | uuid = "d125e4d3-2237-4719-b19c-fa641b8a4667" 1057 | version = "0.1.8" 1058 | 1059 | [[deps.MarchingCubes]] 1060 | deps = ["StaticArrays"] 1061 | git-tree-sha1 = "3bf4baa9df7d1367168ebf60ed02b0379ea91099" 1062 | uuid = "299715c1-40a9-479a-aaf9-4a633d36f717" 1063 | version = "0.1.3" 1064 | 1065 | [[deps.Markdown]] 1066 | deps = ["Base64"] 1067 | uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" 1068 | 1069 | [[deps.MathOptInterface]] 1070 | deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] 1071 | git-tree-sha1 = "b79f525737702ff2a3f2005a0823e3518ce8b04c" 1072 | uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" 1073 | version = "1.7.0" 1074 | 1075 | [[deps.MathProgBase]] 1076 | deps = ["LinearAlgebra", "SparseArrays"] 1077 | git-tree-sha1 = "9abbe463a1e9fc507f12a69e7f29346c2cdc472c" 1078 | uuid = "fdba3010-5040-5b88-9595-932c9decdf73" 1079 | version = "0.7.8" 1080 | 1081 | [[deps.MatrixFactorizations]] 1082 | deps = ["ArrayLayouts", "LinearAlgebra", "Printf", "Random"] 1083 | git-tree-sha1 = "2320f1e1d87c98693df7fd30c2adcfca923f42da" 1084 | uuid = "a3b82374-2e81-5b9e-98ce-41277c0e4c87" 1085 | version = "0.9.2" 1086 | 1087 | [[deps.MbedTLS_jll]] 1088 | deps = ["Artifacts", "Libdl"] 1089 | uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" 1090 | version = "2.28.0+0" 1091 | 1092 | [[deps.Memoize]] 1093 | deps = ["MacroTools"] 1094 | git-tree-sha1 = "2b1dfcba103de714d31c033b5dacc2e4a12c7caa" 1095 | uuid = "c03570c3-d221-55d1-a50c-7939bbd78826" 1096 | version = "0.4.4" 1097 | 1098 | [[deps.Metatheory]] 1099 | deps = ["AutoHashEquals", "DataStructures", "Dates", "DocStringExtensions", "Parameters", "Reexport", "TermInterface", "ThreadsX", "TimerOutputs"] 1100 | git-tree-sha1 = "a160e323d3684889e6026914576f1f4288de131d" 1101 | uuid = "e9d8d322-4543-424a-9be4-0cc815abe26c" 1102 | version = "1.3.4" 1103 | 1104 | [[deps.MicroCollections]] 1105 | deps = ["BangBang", "InitialValues", "Setfield"] 1106 | git-tree-sha1 = "6bb7786e4f24d44b4e29df03c69add1b63d88f01" 1107 | uuid = "128add7d-3638-4c79-886c-908ea0c25c34" 1108 | version = "0.1.2" 1109 | 1110 | [[deps.Missings]] 1111 | deps = ["DataAPI"] 1112 | git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" 1113 | uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" 1114 | version = "1.0.2" 1115 | 1116 | [[deps.Mmap]] 1117 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 1118 | 1119 | [[deps.MozillaCACerts_jll]] 1120 | uuid = "14a3606d-f60d-562e-9121-12d972cd8159" 1121 | version = "2022.2.1" 1122 | 1123 | [[deps.MuladdMacro]] 1124 | git-tree-sha1 = "c6190f9a7fc5d9d5915ab29f2134421b12d24a68" 1125 | uuid = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" 1126 | version = "0.2.2" 1127 | 1128 | [[deps.MultivariatePolynomials]] 1129 | deps = ["ChainRulesCore", "DataStructures", "LinearAlgebra", "MutableArithmetics"] 1130 | git-tree-sha1 = "393fc4d82a73c6fe0e2963dd7c882b09257be537" 1131 | uuid = "102ac46a-7ee4-5c85-9060-abc95bfdeaa3" 1132 | version = "0.4.6" 1133 | 1134 | [[deps.MutableArithmetics]] 1135 | deps = ["LinearAlgebra", "SparseArrays", "Test"] 1136 | git-tree-sha1 = "4e675d6e9ec02061800d6cfb695812becbd03cdf" 1137 | uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" 1138 | version = "1.0.4" 1139 | 1140 | [[deps.NLSolversBase]] 1141 | deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] 1142 | git-tree-sha1 = "50310f934e55e5ca3912fb941dec199b49ca9b68" 1143 | uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" 1144 | version = "7.8.2" 1145 | 1146 | [[deps.NLopt]] 1147 | deps = ["MathOptInterface", "MathProgBase", "NLopt_jll"] 1148 | git-tree-sha1 = "5a7e32c569200a8a03c3d55d286254b0321cd262" 1149 | uuid = "76087f3c-5699-56af-9a33-bf431cd00edd" 1150 | version = "0.6.5" 1151 | 1152 | [[deps.NLopt_jll]] 1153 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1154 | git-tree-sha1 = "9b1f15a08f9d00cdb2761dcfa6f453f5d0d6f973" 1155 | uuid = "079eb43e-fd8e-5478-9966-2cf3e3edb778" 1156 | version = "2.7.1+0" 1157 | 1158 | [[deps.NLsolve]] 1159 | deps = ["Distances", "LineSearches", "LinearAlgebra", "NLSolversBase", "Printf", "Reexport"] 1160 | git-tree-sha1 = "019f12e9a1a7880459d0173c182e6a99365d7ac1" 1161 | uuid = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" 1162 | version = "4.5.1" 1163 | 1164 | [[deps.NNlib]] 1165 | deps = ["Adapt", "ChainRulesCore", "LinearAlgebra", "Pkg", "Requires", "Statistics"] 1166 | git-tree-sha1 = "415108fd88d6f55cedf7ee940c7d4b01fad85421" 1167 | uuid = "872c559c-99b0-510c-b3b7-b6c96a88d5cd" 1168 | version = "0.8.9" 1169 | 1170 | [[deps.NNlibCUDA]] 1171 | deps = ["Adapt", "CUDA", "LinearAlgebra", "NNlib", "Random", "Statistics"] 1172 | git-tree-sha1 = "4429261364c5ea5b7308aecaa10e803ace101631" 1173 | uuid = "a00861dc-f156-4864-bf3c-e6376f28a68d" 1174 | version = "0.2.4" 1175 | 1176 | [[deps.NaNMath]] 1177 | deps = ["OpenLibm_jll"] 1178 | git-tree-sha1 = "a7c3d1da1189a1c2fe843a3bfa04d18d20eb3211" 1179 | uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" 1180 | version = "1.0.1" 1181 | 1182 | [[deps.NameResolution]] 1183 | deps = ["PrettyPrint"] 1184 | git-tree-sha1 = "1a0fa0e9613f46c9b8c11eee38ebb4f590013c5e" 1185 | uuid = "71a1bf82-56d0-4bbc-8a3c-48b961074391" 1186 | version = "0.1.5" 1187 | 1188 | [[deps.NetworkOptions]] 1189 | uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" 1190 | version = "1.2.0" 1191 | 1192 | [[deps.NonlinearSolve]] 1193 | deps = ["ArrayInterfaceCore", "FiniteDiff", "ForwardDiff", "IterativeSolvers", "LinearAlgebra", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "StaticArrays", "UnPack"] 1194 | git-tree-sha1 = "a754a21521c0ab48d37f44bbac1eefd1387bdcfc" 1195 | uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" 1196 | version = "0.3.22" 1197 | 1198 | [[deps.ObjectFile]] 1199 | deps = ["Reexport", "StructIO"] 1200 | git-tree-sha1 = "55ce61d43409b1fb0279d1781bf3b0f22c83ab3b" 1201 | uuid = "d8793406-e978-5875-9003-1fc021f44a92" 1202 | version = "0.3.7" 1203 | 1204 | [[deps.OffsetArrays]] 1205 | deps = ["Adapt"] 1206 | git-tree-sha1 = "1ea784113a6aa054c5ebd95945fa5e52c2f378e7" 1207 | uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" 1208 | version = "1.12.7" 1209 | 1210 | [[deps.OpenBLAS32_jll]] 1211 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 1212 | git-tree-sha1 = "9c6c2ed4b7acd2137b878eb96c68e63b76199d0f" 1213 | uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" 1214 | version = "0.3.17+0" 1215 | 1216 | [[deps.OpenBLAS_jll]] 1217 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] 1218 | uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" 1219 | version = "0.3.20+0" 1220 | 1221 | [[deps.OpenLibm_jll]] 1222 | deps = ["Artifacts", "Libdl"] 1223 | uuid = "05823500-19ac-5b8b-9628-191a04bc5112" 1224 | version = "0.8.1+0" 1225 | 1226 | [[deps.OpenSpecFun_jll]] 1227 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 1228 | git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" 1229 | uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" 1230 | version = "0.5.5+0" 1231 | 1232 | [[deps.Optim]] 1233 | deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] 1234 | git-tree-sha1 = "ad8de074ed5dad13e87d76c467a82e5eff9c693a" 1235 | uuid = "429524aa-4258-5aef-a3af-852621145aeb" 1236 | version = "1.7.2" 1237 | 1238 | [[deps.Optimisers]] 1239 | deps = ["ChainRulesCore", "Functors", "LinearAlgebra", "Random", "Statistics"] 1240 | git-tree-sha1 = "1ef34738708e3f31994b52693286dabcb3d29f6b" 1241 | uuid = "3bd65402-5787-11e9-1adc-39752487f4e2" 1242 | version = "0.2.9" 1243 | 1244 | [[deps.Optimization]] 1245 | deps = ["ArrayInterfaceCore", "ConsoleProgressMonitor", "DiffResults", "DocStringExtensions", "Logging", "LoggingExtras", "Pkg", "Printf", "ProgressLogging", "Reexport", "Requires", "SciMLBase", "SparseArrays", "TerminalLoggers"] 1246 | git-tree-sha1 = "f2dbe632d3aad1fb1e5ee7dbbeb4896aabb39da1" 1247 | uuid = "7f7a1694-90dd-40f0-9382-eb1efda571ba" 1248 | version = "3.8.2" 1249 | 1250 | [[deps.OptimizationFlux]] 1251 | deps = ["Flux", "Optimization", "Printf", "ProgressLogging", "Reexport"] 1252 | git-tree-sha1 = "a2eb4ec758a38ce82ace42b806d341ac0457b604" 1253 | uuid = "253f991c-a7b2-45f8-8852-8b9a9df78a86" 1254 | version = "0.1.0" 1255 | 1256 | [[deps.OptimizationOptimJL]] 1257 | deps = ["Optim", "Optimization", "Reexport", "SparseArrays"] 1258 | git-tree-sha1 = "76ac41f9e82ba98a600d8a380532adef76b27e15" 1259 | uuid = "36348300-93cb-4f02-beb5-3c3902f8871e" 1260 | version = "0.1.2" 1261 | 1262 | [[deps.OptimizationOptimisers]] 1263 | deps = ["Optimisers", "Optimization", "Printf", "ProgressLogging", "Reexport"] 1264 | git-tree-sha1 = "e2f152fc4adc9a634ca6ec00de2f2500d8642789" 1265 | uuid = "42dfb2eb-d2b4-4451-abcd-913932933ac1" 1266 | version = "0.1.0" 1267 | 1268 | [[deps.OptimizationPolyalgorithms]] 1269 | deps = ["Optimization", "OptimizationOptimJL", "OptimizationOptimisers"] 1270 | git-tree-sha1 = "b4a77f60effaa6d3ce7de3c1d5635ba242acfa6f" 1271 | uuid = "500b13db-7e66-49ce-bda4-eed966be6282" 1272 | version = "0.1.0" 1273 | 1274 | [[deps.OrderedCollections]] 1275 | git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" 1276 | uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 1277 | version = "1.4.1" 1278 | 1279 | [[deps.OrdinaryDiffEq]] 1280 | deps = ["Adapt", "ArrayInterface", "ArrayInterfaceGPUArrays", "ArrayInterfaceStaticArrays", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "FunctionWrappersWrappers", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SciMLBase", "SnoopPrecompile", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] 1281 | git-tree-sha1 = "61d8e295c33ed44dca9ca37fd7e825fd7a5a43cd" 1282 | uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" 1283 | version = "6.24.0" 1284 | 1285 | [[deps.PDMats]] 1286 | deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] 1287 | git-tree-sha1 = "cf494dca75a69712a72b80bc48f59dcf3dea63ec" 1288 | uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" 1289 | version = "0.11.16" 1290 | 1291 | [[deps.Parameters]] 1292 | deps = ["OrderedCollections", "UnPack"] 1293 | git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" 1294 | uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" 1295 | version = "0.12.3" 1296 | 1297 | [[deps.Parsers]] 1298 | deps = ["Dates"] 1299 | git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" 1300 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 1301 | version = "2.3.2" 1302 | 1303 | [[deps.Pkg]] 1304 | deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] 1305 | uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 1306 | version = "1.8.0" 1307 | 1308 | [[deps.PoissonRandom]] 1309 | deps = ["Random"] 1310 | git-tree-sha1 = "9ac1bb7c15c39620685a3a7babc0651f5c64c35b" 1311 | uuid = "e409e4f3-bfea-5376-8464-e040bb5c01ab" 1312 | version = "0.4.1" 1313 | 1314 | [[deps.Polyester]] 1315 | deps = ["ArrayInterface", "BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "ManualMemory", "PolyesterWeave", "Requires", "Static", "StrideArraysCore", "ThreadingUtilities"] 1316 | git-tree-sha1 = "94e20822bd7427b1b1b843a3980003f5d5e8696b" 1317 | uuid = "f517fe37-dbe3-4b94-8317-1923a5111588" 1318 | version = "0.6.14" 1319 | 1320 | [[deps.PolyesterWeave]] 1321 | deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] 1322 | git-tree-sha1 = "233feae14c07cca6b95080f77a7d332612603f6a" 1323 | uuid = "1d0040c9-8b98-4ee7-8388-3f51789ca0ad" 1324 | version = "0.1.9" 1325 | 1326 | [[deps.PositiveFactorizations]] 1327 | deps = ["LinearAlgebra"] 1328 | git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" 1329 | uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" 1330 | version = "0.2.4" 1331 | 1332 | [[deps.PreallocationTools]] 1333 | deps = ["Adapt", "ArrayInterfaceCore", "ForwardDiff", "ReverseDiff"] 1334 | git-tree-sha1 = "5c076a409ec8d2a86d3685a7e4fed330cd489889" 1335 | uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46" 1336 | version = "0.4.2" 1337 | 1338 | [[deps.Preferences]] 1339 | deps = ["TOML"] 1340 | git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" 1341 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 1342 | version = "1.3.0" 1343 | 1344 | [[deps.PrettyPrint]] 1345 | git-tree-sha1 = "632eb4abab3449ab30c5e1afaa874f0b98b586e4" 1346 | uuid = "8162dcfd-2161-5ef2-ae6c-7681170c5f98" 1347 | version = "0.2.0" 1348 | 1349 | [[deps.Primes]] 1350 | deps = ["IntegerMathUtils"] 1351 | git-tree-sha1 = "311a2aa90a64076ea0fac2ad7492e914e6feeb81" 1352 | uuid = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae" 1353 | version = "0.5.3" 1354 | 1355 | [[deps.Printf]] 1356 | deps = ["Unicode"] 1357 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 1358 | 1359 | [[deps.Profile]] 1360 | deps = ["Printf"] 1361 | uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" 1362 | 1363 | [[deps.ProgressLogging]] 1364 | deps = ["Logging", "SHA", "UUIDs"] 1365 | git-tree-sha1 = "80d919dee55b9c50e8d9e2da5eeafff3fe58b539" 1366 | uuid = "33c8b6b6-d38a-422a-b730-caa89a2f386c" 1367 | version = "0.1.4" 1368 | 1369 | [[deps.ProgressMeter]] 1370 | deps = ["Distributed", "Printf"] 1371 | git-tree-sha1 = "d7a7aef8f8f2d537104f170139553b14dfe39fe9" 1372 | uuid = "92933f4c-e287-5a05-a399-4b506db050ca" 1373 | version = "1.7.2" 1374 | 1375 | [[deps.PyCall]] 1376 | deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] 1377 | git-tree-sha1 = "53b8b07b721b77144a0fbbbc2675222ebf40a02d" 1378 | uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" 1379 | version = "1.94.1" 1380 | 1381 | [[deps.PyPlot]] 1382 | deps = ["Colors", "LaTeXStrings", "PyCall", "Sockets", "Test", "VersionParsing"] 1383 | git-tree-sha1 = "f9d953684d4d21e947cb6d642db18853d43cb027" 1384 | uuid = "d330b81b-6aea-500a-939a-2ce795aea3ee" 1385 | version = "2.11.0" 1386 | 1387 | [[deps.QuadGK]] 1388 | deps = ["DataStructures", "LinearAlgebra"] 1389 | git-tree-sha1 = "78aadffb3efd2155af139781b8a8df1ef279ea39" 1390 | uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" 1391 | version = "2.4.2" 1392 | 1393 | [[deps.REPL]] 1394 | deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] 1395 | uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" 1396 | 1397 | [[deps.Random]] 1398 | deps = ["SHA", "Serialization"] 1399 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 1400 | 1401 | [[deps.Random123]] 1402 | deps = ["Random", "RandomNumbers"] 1403 | git-tree-sha1 = "7a1a306b72cfa60634f03a911405f4e64d1b718b" 1404 | uuid = "74087812-796a-5b5d-8853-05524746bad3" 1405 | version = "1.6.0" 1406 | 1407 | [[deps.RandomExtensions]] 1408 | deps = ["Random", "SparseArrays"] 1409 | git-tree-sha1 = "062986376ce6d394b23d5d90f01d81426113a3c9" 1410 | uuid = "fb686558-2515-59ef-acaa-46db3789a887" 1411 | version = "0.4.3" 1412 | 1413 | [[deps.RandomNumbers]] 1414 | deps = ["Random", "Requires"] 1415 | git-tree-sha1 = "043da614cc7e95c703498a491e2c21f58a2b8111" 1416 | uuid = "e6cf234a-135c-5ec9-84dd-332b85af5143" 1417 | version = "1.5.3" 1418 | 1419 | [[deps.RealDot]] 1420 | deps = ["LinearAlgebra"] 1421 | git-tree-sha1 = "9f0a1b71baaf7650f4fa8a1d168c7fb6ee41f0c9" 1422 | uuid = "c1ae055f-0cd5-4b69-90a6-9a35b1a98df9" 1423 | version = "0.1.0" 1424 | 1425 | [[deps.RecipesBase]] 1426 | git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d" 1427 | uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" 1428 | version = "1.2.1" 1429 | 1430 | [[deps.RecursiveArrayTools]] 1431 | deps = ["Adapt", "ArrayInterfaceCore", "ArrayInterfaceStaticArraysCore", "ChainRulesCore", "DocStringExtensions", "FillArrays", "GPUArraysCore", "IteratorInterfaceExtensions", "LinearAlgebra", "RecipesBase", "StaticArraysCore", "Statistics", "Tables", "ZygoteRules"] 1432 | git-tree-sha1 = "3004608dc42101a944e44c1c68b599fa7c669080" 1433 | uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" 1434 | version = "2.32.0" 1435 | 1436 | [[deps.RecursiveFactorization]] 1437 | deps = ["LinearAlgebra", "LoopVectorization", "Polyester", "StrideArraysCore", "TriangularSolve"] 1438 | git-tree-sha1 = "3ee71214057e29a8466f5d70cfe745236aa1d9d7" 1439 | uuid = "f2c3362d-daeb-58d1-803e-2bc74f2840b4" 1440 | version = "0.2.11" 1441 | 1442 | [[deps.Reexport]] 1443 | git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" 1444 | uuid = "189a3867-3050-52da-a836-e630ba90ab69" 1445 | version = "1.2.2" 1446 | 1447 | [[deps.Referenceables]] 1448 | deps = ["Adapt"] 1449 | git-tree-sha1 = "e681d3bfa49cd46c3c161505caddf20f0e62aaa9" 1450 | uuid = "42d2dcc6-99eb-4e98-b66c-637b7d73030e" 1451 | version = "0.1.2" 1452 | 1453 | [[deps.RegularizationTools]] 1454 | deps = ["Calculus", "Lazy", "LeastSquaresOptim", "LinearAlgebra", "MLStyle", "Memoize", "Optim", "Random", "Underscores"] 1455 | git-tree-sha1 = "d445316cca15281a4b36b63c520123baa256a545" 1456 | uuid = "29dad682-9a27-4bc3-9c72-016788665182" 1457 | version = "0.6.0" 1458 | 1459 | [[deps.Requires]] 1460 | deps = ["UUIDs"] 1461 | git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" 1462 | uuid = "ae029012-a4dd-5104-9daa-d747884805df" 1463 | version = "1.3.0" 1464 | 1465 | [[deps.ResettableStacks]] 1466 | deps = ["StaticArrays"] 1467 | git-tree-sha1 = "256eeeec186fa7f26f2801732774ccf277f05db9" 1468 | uuid = "ae5879a3-cd67-5da8-be7f-38c6eb64a37b" 1469 | version = "1.1.1" 1470 | 1471 | [[deps.ReverseDiff]] 1472 | deps = ["ChainRulesCore", "DiffResults", "DiffRules", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "LogExpFunctions", "MacroTools", "NaNMath", "Random", "SpecialFunctions", "StaticArrays", "Statistics"] 1473 | git-tree-sha1 = "b8e2eb3d8e1530acb73d8949eab3cedb1d43f840" 1474 | uuid = "37e2e3b7-166d-5795-8a7a-e32c996b4267" 1475 | version = "1.14.1" 1476 | 1477 | [[deps.Rmath]] 1478 | deps = ["Random", "Rmath_jll"] 1479 | git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f" 1480 | uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" 1481 | version = "0.7.0" 1482 | 1483 | [[deps.Rmath_jll]] 1484 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1485 | git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7" 1486 | uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" 1487 | version = "0.3.0+0" 1488 | 1489 | [[deps.RuntimeGeneratedFunctions]] 1490 | deps = ["ExprTools", "SHA", "Serialization"] 1491 | git-tree-sha1 = "cdc1e4278e91a6ad530770ebb327f9ed83cf10c4" 1492 | uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" 1493 | version = "0.5.3" 1494 | 1495 | [[deps.SHA]] 1496 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 1497 | version = "0.7.0" 1498 | 1499 | [[deps.SIMDDualNumbers]] 1500 | deps = ["ForwardDiff", "IfElse", "SLEEFPirates", "VectorizationBase"] 1501 | git-tree-sha1 = "dd4195d308df24f33fb10dde7c22103ba88887fa" 1502 | uuid = "3cdde19b-5bb0-4aaf-8931-af3e248e098b" 1503 | version = "0.1.1" 1504 | 1505 | [[deps.SIMDTypes]] 1506 | git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" 1507 | uuid = "94e857df-77ce-4151-89e5-788b33177be4" 1508 | version = "0.1.0" 1509 | 1510 | [[deps.SLEEFPirates]] 1511 | deps = ["IfElse", "Static", "VectorizationBase"] 1512 | git-tree-sha1 = "7ee0e13ac7cd77f2c0e93bff8c40c45f05c77a5a" 1513 | uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" 1514 | version = "0.6.33" 1515 | 1516 | [[deps.SciMLBase]] 1517 | deps = ["ArrayInterfaceCore", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "FunctionWrappersWrappers", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "RecipesBase", "RecursiveArrayTools", "StaticArraysCore", "Statistics", "Tables"] 1518 | git-tree-sha1 = "21d62a28bb9938f58f444312d4a20dca1930831d" 1519 | uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" 1520 | version = "1.51.1" 1521 | 1522 | [[deps.SciMLSensitivity]] 1523 | deps = ["Adapt", "ArrayInterfaceCore", "ArrayInterfaceTracker", "Cassette", "ChainRulesCore", "DiffEqBase", "DiffEqCallbacks", "DiffEqNoiseProcess", "DiffEqOperators", "DiffRules", "Distributions", "EllipsisNotation", "Enzyme", "FiniteDiff", "ForwardDiff", "FunctionWrappersWrappers", "GPUArraysCore", "LinearAlgebra", "LinearSolve", "Markdown", "OrdinaryDiffEq", "Parameters", "PreallocationTools", "QuadGK", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "ReverseDiff", "SciMLBase", "StaticArrays", "Statistics", "StochasticDiffEq", "Tracker", "Zygote", "ZygoteRules"] 1524 | git-tree-sha1 = "27d829fc34318817e40c2e65cda010f774f44152" 1525 | uuid = "1ed8b502-d754-442c-8d5d-10ac956f44a1" 1526 | version = "7.6.2" 1527 | 1528 | [[deps.Serialization]] 1529 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 1530 | 1531 | [[deps.Setfield]] 1532 | deps = ["ConstructionBase", "Future", "MacroTools", "Requires"] 1533 | git-tree-sha1 = "38d88503f695eb0301479bc9b0d4320b378bafe5" 1534 | uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" 1535 | version = "0.8.2" 1536 | 1537 | [[deps.SharedArrays]] 1538 | deps = ["Distributed", "Mmap", "Random", "Serialization"] 1539 | uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" 1540 | 1541 | [[deps.ShowCases]] 1542 | git-tree-sha1 = "7f534ad62ab2bd48591bdeac81994ea8c445e4a5" 1543 | uuid = "605ecd9f-84a6-4c9e-81e2-4798472b76a3" 1544 | version = "0.1.0" 1545 | 1546 | [[deps.SimpleTraits]] 1547 | deps = ["InteractiveUtils", "MacroTools"] 1548 | git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" 1549 | uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" 1550 | version = "0.9.4" 1551 | 1552 | [[deps.SnoopPrecompile]] 1553 | git-tree-sha1 = "f604441450a3c0569830946e5b33b78c928e1a85" 1554 | uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" 1555 | version = "1.0.1" 1556 | 1557 | [[deps.Sockets]] 1558 | uuid = "6462fe0b-24de-5631-8697-dd941f90decc" 1559 | 1560 | [[deps.SortingAlgorithms]] 1561 | deps = ["DataStructures"] 1562 | git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" 1563 | uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" 1564 | version = "1.0.1" 1565 | 1566 | [[deps.SparseArrays]] 1567 | deps = ["LinearAlgebra", "Random"] 1568 | uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 1569 | 1570 | [[deps.SparseDiffTools]] 1571 | deps = ["Adapt", "ArrayInterfaceCore", "ArrayInterfaceStaticArrays", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays", "VertexSafeGraphs"] 1572 | git-tree-sha1 = "5fb8ba9180f467885e87a2c99cae178b67934be1" 1573 | uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804" 1574 | version = "1.26.2" 1575 | 1576 | [[deps.SpecialFunctions]] 1577 | deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] 1578 | git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d" 1579 | uuid = "276daf66-3868-5448-9aa4-cd146d93841b" 1580 | version = "2.1.7" 1581 | 1582 | [[deps.SplittablesBase]] 1583 | deps = ["Setfield", "Test"] 1584 | git-tree-sha1 = "39c9f91521de844bad65049efd4f9223e7ed43f9" 1585 | uuid = "171d559e-b47b-412a-8079-5efa626c420e" 1586 | version = "0.1.14" 1587 | 1588 | [[deps.Static]] 1589 | deps = ["IfElse"] 1590 | git-tree-sha1 = "f94f9d627ba3f91e41a815b9f9f977d729e2e06f" 1591 | uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" 1592 | version = "0.7.6" 1593 | 1594 | [[deps.StaticArrays]] 1595 | deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] 1596 | git-tree-sha1 = "dfec37b90740e3b9aa5dc2613892a3fc155c3b42" 1597 | uuid = "90137ffa-7385-5640-81b9-e52037218182" 1598 | version = "1.5.6" 1599 | 1600 | [[deps.StaticArraysCore]] 1601 | git-tree-sha1 = "ec2bd695e905a3c755b33026954b119ea17f2d22" 1602 | uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" 1603 | version = "1.3.0" 1604 | 1605 | [[deps.Statistics]] 1606 | deps = ["LinearAlgebra", "SparseArrays"] 1607 | uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 1608 | 1609 | [[deps.StatsAPI]] 1610 | deps = ["LinearAlgebra"] 1611 | git-tree-sha1 = "f9af7f195fb13589dd2e2d57fdb401717d2eb1f6" 1612 | uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" 1613 | version = "1.5.0" 1614 | 1615 | [[deps.StatsBase]] 1616 | deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] 1617 | git-tree-sha1 = "d1bf48bfcc554a3761a133fe3a9bb01488e06916" 1618 | uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" 1619 | version = "0.33.21" 1620 | 1621 | [[deps.StatsFuns]] 1622 | deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] 1623 | git-tree-sha1 = "5783b877201a82fc0014cbf381e7e6eb130473a4" 1624 | uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" 1625 | version = "1.0.1" 1626 | 1627 | [[deps.StochasticDiffEq]] 1628 | deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "JumpProcesses", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] 1629 | git-tree-sha1 = "47648a908783ddbd124cf3deb3eb0d18b7cffcce" 1630 | uuid = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" 1631 | version = "6.53.0" 1632 | 1633 | [[deps.StrideArraysCore]] 1634 | deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "SIMDTypes", "Static", "ThreadingUtilities"] 1635 | git-tree-sha1 = "ac730bd978bf35f9fe45daa0bd1f51e493e97eb4" 1636 | uuid = "7792a7ef-975c-4747-a70f-980b88e8d1da" 1637 | version = "0.3.15" 1638 | 1639 | [[deps.StructArrays]] 1640 | deps = ["Adapt", "DataAPI", "StaticArraysCore", "Tables"] 1641 | git-tree-sha1 = "8c6ac65ec9ab781af05b08ff305ddc727c25f680" 1642 | uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" 1643 | version = "0.6.12" 1644 | 1645 | [[deps.StructIO]] 1646 | deps = ["Test"] 1647 | git-tree-sha1 = "010dc73c7146869c042b49adcdb6bf528c12e859" 1648 | uuid = "53d494c1-5632-5724-8f4c-31dff12d585f" 1649 | version = "0.3.0" 1650 | 1651 | [[deps.StructTypes]] 1652 | deps = ["Dates", "UUIDs"] 1653 | git-tree-sha1 = "79aa7175f0149ba2fe22b96a271f4024429de02d" 1654 | uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" 1655 | version = "1.9.0" 1656 | 1657 | [[deps.SuiteSparse]] 1658 | deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] 1659 | uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" 1660 | 1661 | [[deps.SuiteSparse_jll]] 1662 | deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"] 1663 | uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" 1664 | version = "5.10.1+0" 1665 | 1666 | [[deps.Suppressor]] 1667 | git-tree-sha1 = "c6ed566db2fe3931292865b966d6d140b7ef32a9" 1668 | uuid = "fd094767-a336-5f1f-9728-57cf17d0bbfb" 1669 | version = "0.2.1" 1670 | 1671 | [[deps.SymbolicUtils]] 1672 | deps = ["AbstractTrees", "Bijections", "ChainRulesCore", "Combinatorics", "ConstructionBase", "DataStructures", "DocStringExtensions", "DynamicPolynomials", "IfElse", "LabelledArrays", "LinearAlgebra", "Metatheory", "MultivariatePolynomials", "NaNMath", "Setfield", "SparseArrays", "SpecialFunctions", "StaticArrays", "TermInterface", "TimerOutputs"] 1673 | git-tree-sha1 = "027b43d312f6d52187bb16c2d4f0588ddb8c4bb2" 1674 | uuid = "d1185830-fcd6-423d-90d6-eec64667417b" 1675 | version = "0.19.11" 1676 | 1677 | [[deps.Symbolics]] 1678 | deps = ["ArrayInterfaceCore", "ConstructionBase", "DataStructures", "DiffRules", "Distributions", "DocStringExtensions", "DomainSets", "Groebner", "IfElse", "Latexify", "Libdl", "LinearAlgebra", "MacroTools", "Markdown", "Metatheory", "NaNMath", "RecipesBase", "Reexport", "Requires", "RuntimeGeneratedFunctions", "SciMLBase", "Setfield", "SparseArrays", "SpecialFunctions", "StaticArrays", "SymbolicUtils", "TermInterface", "TreeViews"] 1679 | git-tree-sha1 = "873596ee5c98f913bcb2cbb2dc779d815c5aeb86" 1680 | uuid = "0c5d862f-8b57-4792-8d23-62f2024744c7" 1681 | version = "4.10.4" 1682 | 1683 | [[deps.TOML]] 1684 | deps = ["Dates"] 1685 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 1686 | version = "1.0.0" 1687 | 1688 | [[deps.TableTraits]] 1689 | deps = ["IteratorInterfaceExtensions"] 1690 | git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" 1691 | uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" 1692 | version = "1.0.1" 1693 | 1694 | [[deps.Tables]] 1695 | deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] 1696 | git-tree-sha1 = "5ce79ce186cc678bbb5c5681ca3379d1ddae11a1" 1697 | uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" 1698 | version = "1.7.0" 1699 | 1700 | [[deps.Tar]] 1701 | deps = ["ArgTools", "SHA"] 1702 | uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" 1703 | version = "1.10.0" 1704 | 1705 | [[deps.TensorCore]] 1706 | deps = ["LinearAlgebra"] 1707 | git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" 1708 | uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" 1709 | version = "0.1.1" 1710 | 1711 | [[deps.TermInterface]] 1712 | git-tree-sha1 = "7aa601f12708243987b88d1b453541a75e3d8c7a" 1713 | uuid = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c" 1714 | version = "0.2.3" 1715 | 1716 | [[deps.TerminalLoggers]] 1717 | deps = ["Logging", "Printf"] 1718 | git-tree-sha1 = "987a3ebb20307530775f4def7eb9109cfa881748" 1719 | uuid = "5d786b92-1e48-4d6f-9151-6b4477ca9bed" 1720 | version = "0.1.0" 1721 | 1722 | [[deps.Test]] 1723 | deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] 1724 | uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 1725 | 1726 | [[deps.ThreadingUtilities]] 1727 | deps = ["ManualMemory"] 1728 | git-tree-sha1 = "f8629df51cab659d70d2e5618a430b4d3f37f2c3" 1729 | uuid = "8290d209-cae3-49c0-8002-c8c24d57dab5" 1730 | version = "0.5.0" 1731 | 1732 | [[deps.ThreadsX]] 1733 | deps = ["ArgCheck", "BangBang", "ConstructionBase", "InitialValues", "MicroCollections", "Referenceables", "Setfield", "SplittablesBase", "Transducers"] 1734 | git-tree-sha1 = "d223de97c948636a4f34d1f84d92fd7602dc555b" 1735 | uuid = "ac1d9e8a-700a-412c-b207-f0111f4b6c0d" 1736 | version = "0.1.10" 1737 | 1738 | [[deps.TimerOutputs]] 1739 | deps = ["ExprTools", "Printf"] 1740 | git-tree-sha1 = "9dfcb767e17b0849d6aaf85997c98a5aea292513" 1741 | uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" 1742 | version = "0.5.21" 1743 | 1744 | [[deps.Tracker]] 1745 | deps = ["Adapt", "DiffRules", "ForwardDiff", "Functors", "LinearAlgebra", "LogExpFunctions", "MacroTools", "NNlib", "NaNMath", "Optimisers", "Printf", "Random", "Requires", "SpecialFunctions", "Statistics"] 1746 | git-tree-sha1 = "2006952bef6c330fcec7605f27281e9d45d0743a" 1747 | uuid = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" 1748 | version = "0.2.21" 1749 | 1750 | [[deps.TranscodingStreams]] 1751 | deps = ["Random", "Test"] 1752 | git-tree-sha1 = "ed5d390c7addb70e90fd1eb783dcb9897922cbfa" 1753 | uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" 1754 | version = "0.9.8" 1755 | 1756 | [[deps.Transducers]] 1757 | deps = ["Adapt", "ArgCheck", "BangBang", "Baselet", "CompositionsBase", "DefineSingletons", "Distributed", "InitialValues", "Logging", "Markdown", "MicroCollections", "Requires", "Setfield", "SplittablesBase", "Tables"] 1758 | git-tree-sha1 = "c76399a3bbe6f5a88faa33c8f8a65aa631d95013" 1759 | uuid = "28d57a85-8fef-5791-bfe6-a80928e7c999" 1760 | version = "0.4.73" 1761 | 1762 | [[deps.TreeViews]] 1763 | deps = ["Test"] 1764 | git-tree-sha1 = "8d0d7a3fe2f30d6a7f833a5f19f7c7a5b396eae6" 1765 | uuid = "a2a6695c-b41b-5b7d-aed9-dbfdeacea5d7" 1766 | version = "0.3.0" 1767 | 1768 | [[deps.TriangularSolve]] 1769 | deps = ["CloseOpenIntervals", "IfElse", "LayoutPointers", "LinearAlgebra", "LoopVectorization", "Polyester", "SnoopPrecompile", "Static", "VectorizationBase"] 1770 | git-tree-sha1 = "8987cf4a0f8d6c375e4ab1438a048e0a185151e4" 1771 | uuid = "d5829a12-d9aa-46ab-831f-fb7c9ab06edf" 1772 | version = "0.1.13" 1773 | 1774 | [[deps.UUIDs]] 1775 | deps = ["Random", "SHA"] 1776 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 1777 | 1778 | [[deps.UnPack]] 1779 | git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" 1780 | uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" 1781 | version = "1.0.2" 1782 | 1783 | [[deps.Underscores]] 1784 | git-tree-sha1 = "6e6de5a5e7116dcff8effc99f6f55230c61f6862" 1785 | uuid = "d9a01c3f-67ce-4d8c-9b55-35f6e4050bb1" 1786 | version = "3.0.0" 1787 | 1788 | [[deps.Unicode]] 1789 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 1790 | 1791 | [[deps.UnicodePlots]] 1792 | deps = ["ColorSchemes", "ColorTypes", "Contour", "Crayons", "Dates", "FileIO", "FreeTypeAbstraction", "LazyModules", "LinearAlgebra", "MarchingCubes", "NaNMath", "Printf", "SparseArrays", "StaticArrays", "StatsBase", "Unitful"] 1793 | git-tree-sha1 = "5b931e95bf691e13ae25c1bdeda71b89169064ce" 1794 | uuid = "b8865327-cd53-5732-bb35-84acbb429228" 1795 | version = "3.0.5" 1796 | 1797 | [[deps.Unitful]] 1798 | deps = ["ConstructionBase", "Dates", "LinearAlgebra", "Random"] 1799 | git-tree-sha1 = "b649200e887a487468b71821e2644382699f1b0f" 1800 | uuid = "1986cc42-f94f-5a68-af5c-568840ba703d" 1801 | version = "1.11.0" 1802 | 1803 | [[deps.VectorizationBase]] 1804 | deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static"] 1805 | git-tree-sha1 = "a0b74e8247f30420ba25c8fcfc1c69cb84ff8cff" 1806 | uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" 1807 | version = "0.21.46" 1808 | 1809 | [[deps.VersionParsing]] 1810 | git-tree-sha1 = "58d6e80b4ee071f5efd07fda82cb9fbe17200868" 1811 | uuid = "81def892-9a0e-5fdd-b105-ffc91e053289" 1812 | version = "1.3.0" 1813 | 1814 | [[deps.VertexSafeGraphs]] 1815 | deps = ["Graphs"] 1816 | git-tree-sha1 = "8351f8d73d7e880bfc042a8b6922684ebeafb35c" 1817 | uuid = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f" 1818 | version = "0.2.0" 1819 | 1820 | [[deps.Zlib_jll]] 1821 | deps = ["Libdl"] 1822 | uuid = "83775a58-1f1d-513f-b197-d71354ab007a" 1823 | version = "1.2.12+3" 1824 | 1825 | [[deps.Zygote]] 1826 | deps = ["AbstractFFTs", "ChainRules", "ChainRulesCore", "DiffRules", "Distributed", "FillArrays", "ForwardDiff", "GPUArrays", "GPUArraysCore", "IRTools", "InteractiveUtils", "LinearAlgebra", "LogExpFunctions", "MacroTools", "NaNMath", "Random", "Requires", "SparseArrays", "SpecialFunctions", "Statistics", "ZygoteRules"] 1827 | git-tree-sha1 = "b02f2f7feda60d40aa7c24291ee865b50b33c9bc" 1828 | uuid = "e88e6eb3-aa80-5325-afca-941959d7151f" 1829 | version = "0.6.45" 1830 | 1831 | [[deps.ZygoteRules]] 1832 | deps = ["MacroTools"] 1833 | git-tree-sha1 = "8c1a8e4dfacb1fd631745552c8db35d0deb09ea0" 1834 | uuid = "700de1a5-db45-46bc-99cf-38207098b444" 1835 | version = "0.2.2" 1836 | 1837 | [[deps.libblastrampoline_jll]] 1838 | deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] 1839 | uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" 1840 | version = "5.1.1+0" 1841 | 1842 | [[deps.nghttp2_jll]] 1843 | deps = ["Artifacts", "Libdl"] 1844 | uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" 1845 | version = "1.48.0+0" 1846 | 1847 | [[deps.p7zip_jll]] 1848 | deps = ["Artifacts", "Libdl"] 1849 | uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" 1850 | version = "17.4.0+0" 1851 | -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | name = "ControlNeuralODE" 2 | uuid = "43796e44-9168-426f-8631-80c2c8cc7fef" 3 | authors = ["Ilya Orson Sandoval "] 4 | version = "0.1.0" 5 | 6 | [deps] 7 | ArgCheck = "dce04be8-c92d-5529-be00-80e4d2c0e197" 8 | CommonSolve = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" 9 | DataInterpolations = "82cc6244-b520-54b8-b5a6-8a565e85f1d0" 10 | DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 11 | Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" 12 | DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" 13 | DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" 14 | DiffEqFlux = "aae7a2af-3d4f-5e19-a356-7da93b79d9d0" 15 | Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" 16 | FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" 17 | Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" 18 | Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0" 19 | ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" 20 | GarishPrint = "b0ab02a7-8576-43f7-aa76-eaa7c3897c54" 21 | InfiniteOpt = "20393b10-9daf-11e9-18c9-8db751c92c57" 22 | Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" 23 | JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" 24 | LBFGSB = "5be7bae1-8223-5378-bac3-9e7378a2f6e6" 25 | LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 26 | LazyGrids = "7031d0ef-c40d-4431-b2f8-61a8d2f650db" 27 | LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" 28 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 29 | MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" 30 | NLopt = "76087f3c-5699-56af-9a33-bf431cd00edd" 31 | NNlib = "872c559c-99b0-510c-b3b7-b6c96a88d5cd" 32 | Optim = "429524aa-4258-5aef-a3af-852621145aeb" 33 | OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" 34 | ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" 35 | PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" 36 | QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" 37 | ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" 38 | SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" 39 | SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" 40 | Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 41 | Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 42 | Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" 43 | TerminalLoggers = "5d786b92-1e48-4d6f-9151-6b4477ca9bed" 44 | UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" 45 | Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" 46 | 47 | [compat] 48 | julia = "1.8" 49 | 50 | [extras] 51 | CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Feedback Control Policies with Neural ODEs 2 | 3 | This code showcases how a state-feedback neural policy, as commonly used in reinforcement 4 | learning, may be used similarly in an optimal control problem while enforcing state and control constraints. 5 | 6 | ## Constrained Van der Pol problem 7 | $$\begin{equation} 8 | \begin{aligned} 9 | \min_{\theta} \quad & J = \int_0^5 x_1^2 + x_2^2 + u^2 \,dt, \\ 10 | & \\ 11 | \textrm{s.t.} \quad & \dot x_1(t) = x_1(1-x_2^2) - x_2 + u, \\ 12 | & \dot x_2(t) = x_1, \\ 13 | & u(t) = \pi_\theta^2(x_1, x_2) \\ 14 | & \\ 15 | & x(t_0) = (0, 1), \\ 16 | & \\ 17 | & x_1(t) + 0.4 \geq 0, \\ 18 | & -0.3 \leq u(t) \leq 1, \\ 19 | \end{aligned} 20 | \end{equation}$$ 21 | 22 | ### Phase Space with embedded policy (before and after optimization) 23 | 24 | ![vdp_initial](https://github.com/IlyaOrson/control_neuralode/assets/12092488/1cbe6b23-71bd-4f5d-8f5a-7090ab4b4cd8) 25 | ![vdp_constrained](https://github.com/IlyaOrson/control_neuralode/assets/12092488/3d86f7a7-3b92-4495-9940-7dbc4813037d) 26 | 27 | ## JuliaCon 2021 28 | The main ideas where presented in [this talk](https://www.youtube.com/watch?v=omS3ZngEygw) of JuliaCon2021. 29 | 30 | [![Watch the video](https://img.youtube.com/vi/omS3ZngEygw/maxresdefault.jpg)](https://www.youtube.com/watch?v=omS3ZngEygw) 31 | 32 | ## Running the study cases 33 | This code requires Julia 1.7. 34 | 35 | Reproduce the environment with the required dependencies: 36 | ```julia 37 | julia> using Pkg; Pkg.activate(;temp=true) 38 | julia> Pkg.add(url="https://github.com/IlyaOrson/ControlNeuralODE.jl") 39 | ``` 40 | 41 | Run the test cases: 42 | 43 | ```julia 44 | julia> using ControlNeuralODE: van_der_pol, bioreactor, batch_reactor, semibatch_reactor 45 | julia> van_der_pol(store_results=true) 46 | ``` 47 | 48 | This will generate plots while the optimization runs and store result data in `data/`. 49 | 50 | ## Methodology (Control Vector Iteration for the Neural Policy parameters) 51 | By substituting the control function of the problem by the output of the policy, the 52 | weights of the controller become the new unconstrained controls of the system. 53 | The problem becomes a parameter estimation problem where the Neural ODE adjoint method may be used 54 | to backpropagate sensitivities with respect to functional cost. 55 | 56 | This method was originally called the _Kelley-Bryson_ gradient procedure (developed in the 60s); 57 | which is historically interesting due to being one of the earliest uses of backpropagation. 58 | Its continuous time extension is known as _Control Vector Iteration_ (CVI) in the optimal control 59 | literature, where it shares the not so great reputation of indirect methods. 60 | 61 | Its modern implementation depends crucially on automatic differentiation to avoid the manual 62 | derivations; one of the features that made the original versions unattractive. 63 | This is where `DiffEqFlux.jl` and similar software shine. See the publication for a clear explanation of the technical details. 64 | 65 | # Acknowledgements 66 | The idea was inspired heavily by the trebuchet demo of Flux and the differentiable control 67 | example of [DiffEqFlux](https://github.com/SciML/DiffEqFlux.jl). A similar idea was contrasted with reinforcement learning in [this work](https://github.com/samuela/ctpg). Chris Rackauckas advise was very useful. 68 | 69 | ## Citation 70 | 71 | If you find this work helpful please consider citing the following paper: 72 | ```bibtex 73 | @misc{https://doi.org/10.48550/arxiv.2210.11245, 74 | doi = {10.48550/ARXIV.2210.11245}, 75 | url = {https://arxiv.org/abs/2210.11245}, 76 | author = {Sandoval, Ilya Orson and Petsagkourakis, Panagiotis and del Rio-Chanona, Ehecatl Antonio}, 77 | keywords = {Optimization and Control (math.OC), Artificial Intelligence (cs.AI), Systems and Control (eess.SY), FOS: Mathematics, FOS: Mathematics, FOS: Computer and information sciences, FOS: Computer and information sciences, FOS: Electrical engineering, electronic engineering, information engineering, FOS: Electrical engineering, electronic engineering, information engineering}, 78 | title = {Neural ODEs as Feedback Policies for Nonlinear Optimal Control}, 79 | publisher = {arXiv}, 80 | year = {2022}, 81 | copyright = {arXiv.org perpetual, non-exclusive license} 82 | } 83 | ``` 84 | -------------------------------------------------------------------------------- /create_sysimage.jl: -------------------------------------------------------------------------------- 1 | # run without startup file 2 | # julia --startup-file=no create_sysimage.jl 3 | 4 | using Pkg 5 | using PackageCompiler: create_sysimage 6 | 7 | Pkg.activate(".") 8 | deps = [pair.second for pair in Pkg.dependencies()] 9 | direct_deps = filter(p -> p.is_direct_dep, deps) 10 | pkg_name_version = [(x.name, x.version) for x in direct_deps] 11 | pkg_list = [Symbol(x.name) for x in direct_deps] 12 | 13 | create_sysimage( 14 | # pkg_list; 15 | ["OrdinaryDiffEq", "Enzyme", "ReverseDiff", "PyPlot", "Zygote", "SciMLSensitivity", "UnicodePlots", "DiffEqFlux", "InfiniteOpt"]; 16 | sysimage_path="cnode.so", 17 | precompile_execution_file="sysimage_tracing.jl", 18 | ) 19 | 20 | # how to use sysimage to execute examples & activate current project: 21 | # julia --sysimage cnode.so --project=. 22 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: do-mpc 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - appdirs=1.4.4=py_0 7 | - attrs=20.3.0=pyhd3eb1b0_0 8 | - backcall=0.2.0=pyhd3eb1b0_0 9 | - black=19.10b0=py_0 10 | - blas=1.0=mkl 11 | - ca-certificates=2021.4.13=haa95532_1 12 | - certifi=2020.12.5=py39haa95532_0 13 | - click=7.1.2=pyhd3eb1b0_0 14 | - colorama=0.4.4=pyhd3eb1b0_0 15 | - cycler=0.10.0=py39haa95532_0 16 | - decorator=5.0.6=pyhd3eb1b0_0 17 | - freetype=2.10.4=hd328e21_0 18 | - icc_rt=2019.0.0=h0cc432a_1 19 | - icu=58.2=ha925a31_3 20 | - intel-openmp=2021.2.0=haa95532_616 21 | - ipopt=3.13.4=hf6be2e5_0 22 | - ipython=7.22.0=py39hd4e2768_0 23 | - ipython_genutils=0.2.0=pyhd3eb1b0_1 24 | - jedi=0.17.2=py39haa95532_1 25 | - jpeg=9b=hb83a4c4_2 26 | - kiwisolver=1.3.1=py39hd77b12b_0 27 | - libblas=3.9.0=1_h8933c1f_netlib 28 | - libcblas=3.9.0=5_hd5c7e75_netlib 29 | - libflang=5.0.0=h6538335_20180525 30 | - liblapack=3.9.0=5_hd5c7e75_netlib 31 | - libpng=1.6.37=h2a8f88b_0 32 | - libtiff=4.2.0=he0120a3_0 33 | - llvm-meta=5.0.0=0 34 | - lz4-c=1.9.3=h2bbff1b_0 35 | - m2w64-gcc-libgfortran=5.3.0=6 36 | - m2w64-gcc-libs=5.3.0=7 37 | - m2w64-gcc-libs-core=5.3.0=7 38 | - m2w64-gmp=6.1.0=2 39 | - m2w64-libwinpthread-git=5.0.0.4634.697f757=2 40 | - matplotlib=3.3.4=py39haa95532_0 41 | - matplotlib-base=3.3.4=py39h49ac443_0 42 | - metis=5.1.0=ha925a31_1006 43 | - mkl=2021.2.0=haa95532_296 44 | - mkl-service=2.3.0=py39h2bbff1b_1 45 | - mkl_fft=1.3.0=py39h277e83a_2 46 | - mkl_random=1.2.1=py39hf11a4ad_2 47 | - msys2-conda-epoch=20160418=1 48 | - mumps-seq=5.2.1=hb3f9cae_10 49 | - mypy_extensions=0.4.1=py39haa95532_0 50 | - numpy=1.20.1=py39h34a8a5c_0 51 | - numpy-base=1.20.1=py39haf7ebc8_0 52 | - olefile=0.46=py_0 53 | - openmp=5.0.0=vc14_1 54 | - openssl=1.1.1k=h2bbff1b_0 55 | - parso=0.7.0=py_0 56 | - pathspec=0.7.0=py_0 57 | - pickleshare=0.7.5=pyhd3eb1b0_1003 58 | - pillow=8.2.0=py39h4fa10fc_0 59 | - pip=21.0.1=py39haa95532_0 60 | - prompt-toolkit=3.0.17=pyh06a4308_0 61 | - pygments=2.8.1=pyhd3eb1b0_0 62 | - pyparsing=2.4.7=pyhd3eb1b0_0 63 | - pyqt=5.9.2=py39hd77b12b_6 64 | - python=3.9.4=h6244533_0 65 | - python-dateutil=2.8.1=pyhd3eb1b0_0 66 | - python_abi=3.9=1_cp39 67 | - qt=5.9.7=vc14h73c81de_0 68 | - regex=2021.4.4=py39h2bbff1b_0 69 | - scipy=1.6.2=py39h66253e8_1 70 | - setuptools=52.0.0=py39haa95532_0 71 | - sip=4.19.13=py39hd77b12b_0 72 | - six=1.15.0=py39haa95532_0 73 | - sqlite=3.35.4=h2bbff1b_0 74 | - tk=8.6.10=he774522_0 75 | - toml=0.10.2=pyhd3eb1b0_0 76 | - tornado=6.1=py39h2bbff1b_0 77 | - traitlets=5.0.5=pyhd3eb1b0_0 78 | - typed-ast=1.4.2=py39h2bbff1b_1 79 | - typing_extensions=3.7.4.3=pyha847dfd_0 80 | - tzdata=2020f=h52ac0ba_0 81 | - vc=14.2=h21ff451_1 82 | - vs2015_runtime=14.27.29016=h5e58377_2 83 | - wcwidth=0.2.5=py_0 84 | - wheel=0.36.2=pyhd3eb1b0_0 85 | - wincertstore=0.2=py39h2bbff1b_0 86 | - xz=5.2.5=h62dcd97_0 87 | - zlib=1.2.11=h62dcd97_4 88 | - zstd=1.4.5=ha9fde0e_0 89 | - pip: 90 | - casadi==3.5.5 91 | - do-mpc==4.1.1 92 | prefix: C:\Users\ilyao\miniconda3\envs\do-mpc 93 | -------------------------------------------------------------------------------- /src/ControlNeuralODE.jl: -------------------------------------------------------------------------------- 1 | module ControlNeuralODE 2 | 3 | using Base: @kwdef, ifelse 4 | using Base.Filesystem: mkpath 5 | using DelimitedFiles: readdlm, writedlm 6 | using LinearAlgebra: norm 7 | 8 | using Dates: now 9 | using DataStructures: SortedDict 10 | using GarishPrint: pprint 11 | using ArgCheck: @argcheck, @check 12 | using Formatting: format, sprintf1 13 | using Suppressor: @capture_out 14 | using ProgressMeter: ProgressMeter, Progress, ProgressUnknown 15 | # using ProgressLogging: @withprogress, @logprogress 16 | # using Infiltrator: @infiltrate 17 | using Statistics: mean, std 18 | using LineSearches: BackTracking 19 | using InfiniteOpt: 20 | InfiniteOpt, 21 | Infinite, 22 | InfiniteModel, 23 | OrthogonalCollocation, 24 | @infinite_parameter, 25 | @variable, 26 | @variables, 27 | @constraint, 28 | @constraints, 29 | @objective, 30 | integral, 31 | set_start_value_function, 32 | optimizer_with_attributes, 33 | optimizer_model, 34 | solution_summary, 35 | raw_status, 36 | termination_status, 37 | has_values, 38 | objective_value, 39 | supports, 40 | value, 41 | ∂ 42 | using Ipopt: Ipopt 43 | using NLopt: NLopt 44 | using LBFGSB: LBFGSB 45 | using Optim: Optim, LBFGS, BFGS 46 | using DataInterpolations: LinearInterpolation 47 | using ForwardDiff: ForwardDiff 48 | using ReverseDiff: ReverseDiff 49 | using Zygote: Zygote, pullback 50 | using Flux: Flux, glorot_uniform, sigmoid_fast, tanh_fast, ADAMW 51 | using SciMLBase: 52 | ODEProblem, 53 | DECallback, 54 | remake, 55 | AbstractODEAlgorithm, 56 | AbstractSensitivityAlgorithm, 57 | AbstractODEProblem 58 | using DiffEqCallbacks: FunctionCallingCallback 59 | using OrdinaryDiffEq: solve, AutoTsit5, Rodas4P, Rosenbrock23, Tsit5, QNDF, FBDF 60 | using SciMLSensitivity: 61 | # discrete forward 62 | ForwardDiffSensitivity, 63 | # discrete adjoint 64 | ReverseDiffAdjoint, 65 | TrackerAdjoint, 66 | ZygoteAdjoint, 67 | # continuous forward 68 | ForwardSensitivity, 69 | # continuous adjoint 70 | InterpolatingAdjoint, 71 | QuadratureAdjoint, 72 | BacksolveAdjoint, 73 | TrackerVJP, 74 | ZygoteVJP, 75 | EnzymeVJP, 76 | ReverseDiffVJP 77 | using DiffEqFlux: FastChain, FastDense, initial_params, FastLayer # sciml_train 78 | using UnicodePlots: lineplot, lineplot!, histogram 79 | using Serialization: serialize, deserialize 80 | using JSON3: JSON3 81 | 82 | using LazyGrids: ndgrid 83 | using PyPlot: plt, matplotlib, ColorMap, plot3D, scatter3D 84 | using LaTeXStrings: @L_str 85 | 86 | import CommonSolve: solve 87 | 88 | # scripts as functions 89 | export batch_reactor, bioreactor, semibatch_reactor, van_der_pol 90 | 91 | # NOTE : mark the variables that work as constants (avoid constants for Revise.jl) 92 | @show const INTEGRATOR = Tsit5() 93 | 94 | # https://diffeq.sciml.ai/stable/analysis/sensitivity/#Choosing-a-Sensitivity-Algorithm 95 | 96 | # Discrete sensitivity analysis 97 | # SENSEALG = ForwardSensitivity() 98 | # SENSEALG = ReverseDiffAdjoint() 99 | # SENSEALG = TrackerAdjoint() 100 | # SENSEALG = ZygoteAdjoint() 101 | 102 | # Continuous sensitivity analysis 103 | # SENSEALG = ForwardDiffSensitivity() 104 | const SENSEALG = QuadratureAdjoint(; autojacvec=ReverseDiffVJP()) 105 | # SENSEALG = QuadratureAdjoint(; autojacvec=ZygoteVJP()) 106 | # SENSEALG = QuadratureAdjoint(; autojacvec=TrackerVJP()) 107 | # SENSEALG = QuadratureAdjoint(; autojacvec=EnzymeVJP()) 108 | # SENSEALG = InterpolatingAdjoint(; autojacvec=ReverseDiffVJP(), checkpointing=true) 109 | # SENSEALG = InterpolatingAdjoint(; autojacvec=ZygoteVJP(), checkpointing=true) 110 | # SENSEALG = InterpolatingAdjoint(; autojacvec=TrackerVJP(), checkpointing=true) 111 | # SENSEALG = InterpolatingAdjoint(; autojacvec=EnzymeVJP(), checkpointing=true) 112 | @show SENSEALG 113 | 114 | include("auxiliaries.jl") 115 | include("controlODE.jl") 116 | include("nn.jl") 117 | include("penalties.jl") 118 | include("interpolation.jl") 119 | include("simulators.jl") 120 | include("optimizers.jl") 121 | include("training.jl") 122 | include("plotting.jl") 123 | include("loading.jl") 124 | 125 | # case studies 126 | include("systems/batch_reactor.jl") 127 | include("systems/van_der_pol.jl") 128 | include("systems/bioreactor.jl") 129 | include("systems/semibatch_reactor.jl") 130 | 131 | # classic collocation 132 | include("collocation/classic/van_der_pol.jl") 133 | include("collocation/classic/bioreactor.jl") 134 | include("collocation/classic/semibatch_reactor.jl") 135 | 136 | # training 137 | include("scripts/batch_reactor.jl") 138 | include("scripts/van_der_pol.jl") 139 | include("scripts/bioreactor.jl") 140 | include("scripts/semibatch_reactor.jl") 141 | 142 | end # module 143 | -------------------------------------------------------------------------------- /src/auxiliaries.jl: -------------------------------------------------------------------------------- 1 | find_array_param(arr::AbstractArray{T}) where {T} = T 2 | 3 | string_datetime() = replace(string(now()), (":" => "_")) 4 | 5 | function generate_data_subdir( 6 | callerfile; parent=dirname(@__DIR__), subdir=string_datetime() 7 | ) 8 | datadir = joinpath(parent, "data", basename(callerfile), subdir) 9 | @info "Generating data directory" datadir 10 | mkpath(datadir) 11 | return datadir 12 | end 13 | 14 | function local_grid(npoints::Integer, percentage::Real; scale=1.0f0, type=:centered) 15 | @argcheck zero(percentage) < percentage <= one(percentage) 16 | @argcheck type in (:centered, :negative, :positive) 17 | @argcheck !iszero(scale) 18 | width = percentage * scale * npoints 19 | if type == :centered 20 | translation = width / 2.0f0 21 | elseif type == :negative 22 | translation = width 23 | elseif type == :positive 24 | translation = 0.0f0 25 | end 26 | return [n * percentage * scale - translation for n in 0:(npoints - 1)] 27 | end 28 | 29 | function square_bounds(u0, arista) 30 | low_bounds = u0 .- repeat([arista / 2], length(u0)) 31 | high_bounds = u0 .+ repeat([arista / 2], length(u0)) 32 | bounds = [(l, h) for (l, h) in zip(low_bounds, high_bounds)] 33 | return bounds 34 | end 35 | 36 | function controller_shape(controller) 37 | # this method is brittle as any function inside the Chain 38 | # will not be identified, could be a problem if those change dimensions 39 | 40 | # Flux Layers have fields (:weight, :bias, :σ) 41 | # FastLayers have fields (:out, :in, :σ, :initial_params, :bias) 42 | dims_input = [l.in for l in controller.layers[1:end] if typeof(l) <: FastLayer] 43 | dims_output = [l.out for l in controller.layers[1:end] if typeof(l) <: FastLayer] 44 | return push!(dims_input, pop!(dims_output)) 45 | end 46 | 47 | function compose_layers(controller::FastChain, params, u0, L) 48 | @argcheck 1 <= L <= length(controller.layers) 49 | @argcheck length(initial_params(controller)) == length(params) 50 | index = 1 51 | x = u0 52 | for i in 1:L 53 | layer = controller.layers[i] 54 | if typeof(layer) <: FastLayer 55 | ip = initial_params(layer) 56 | s = length(ip) 57 | p = params[index:(index + s - 1)] 58 | index += s 59 | x = layer(x, p) 60 | else 61 | x = layer(x, params) 62 | end 63 | end 64 | return x 65 | end 66 | 67 | function scaled_sigmoids(control_ranges) 68 | return (x, p) -> [ 69 | (control_ranges[i][2] - control_ranges[i][1]) * sigmoid_fast(x[i]) + 70 | control_ranges[i][1] for i in eachindex(control_ranges) 71 | ] 72 | end 73 | 74 | function optimize_infopt!(infopt_model::InfiniteModel; verbose=false, solver_report=false) 75 | 76 | solver_output = @capture_out InfiniteOpt.optimize!(infopt_model) 77 | 78 | # list possible termination status: model |> termination_status |> typeof 79 | jump_model = optimizer_model(infopt_model) 80 | # OPTIMAL = 1, LOCALLY_SOLVED = 4 81 | if Int(termination_status(jump_model)) ∉ (1, 4) 82 | @error raw_status(jump_model) termination_status(jump_model) 83 | error("The collocation optimization failed.") 84 | else 85 | @info "Solver summary" solution_summary(jump_model; verbose) 86 | # @info "Objective value" objective_value(infopt_model) 87 | solver_report && @info "Solver report" solver_output 88 | end 89 | return infopt_model 90 | end 91 | 92 | # TODO: save explicit model https://jump.dev/JuMP.jl/stable/manual/models/ 93 | function extract_infopt_results(model; time=:t, state=:x, control=:c, param=:p) 94 | @argcheck has_values(model) 95 | 96 | model_keys = keys(model.obj_dict) 97 | 98 | times = supports(model[time]) 99 | states = hcat(value.(model[state])...) |> permutedims 100 | 101 | results = (; times=times, states=states) 102 | 103 | if control in model_keys 104 | controls = hcat(value.(model[control])...) |> permutedims 105 | results = merge(results, (; controls=controls)) 106 | end 107 | if param in model_keys 108 | params = hcat(value.(model[param])...) |> permutedims 109 | results = merge(results, (; params=params)) 110 | end 111 | return results 112 | end 113 | -------------------------------------------------------------------------------- /src/collocation/classic/bioreactor.jl: -------------------------------------------------------------------------------- 1 | function bioreactor_collocation( 2 | u0, 3 | tspan; 4 | num_supports::Integer=25, 5 | nodes_per_element::Integer=2, 6 | constrain_states::Bool=false, 7 | verbose=false, 8 | ) 9 | t0, tf = tspan 10 | optimizer = optimizer_with_attributes( 11 | Ipopt.Optimizer, 12 | "print_level" => 2, 13 | ) 14 | model = InfiniteModel(optimizer) 15 | method = OrthogonalCollocation(nodes_per_element) 16 | @infinite_parameter( 17 | model, 18 | t in [t0, tf], 19 | num_supports = num_supports, 20 | derivative_method = method 21 | ) 22 | 23 | @variables( 24 | model, 25 | begin 26 | # state variables 27 | x[1:3], Infinite(t) 28 | # control variables 29 | c[1:2], Infinite(t) 30 | end 31 | ) 32 | 33 | # fixed parameters 34 | (; u_m, u_d, K_N, Y_NX, k_m, k_d, k_s, k_i, k_sq, k_iq, K_Np) = BioReactor() 35 | 36 | # initial conditions 37 | @constraint(model, [i = 1:3], x[i](0) == u0[i]) 38 | 39 | # control range 40 | @constraints( 41 | model, 42 | begin 43 | 80 <= c[1] <= 180 44 | 0 <= c[2] <= 20 45 | end 46 | ) 47 | 48 | if constrain_states 49 | @constraints( 50 | model, 51 | begin 52 | x[2](tf - 1e-2) >= 250 53 | x[2] <= 400 54 | # 1.1e-2 * x[1] - x[3] <= 1.0e-2 55 | end 56 | ) 57 | end 58 | 59 | # dynamic equations 60 | @constraints( 61 | model, 62 | begin 63 | ∂(x[1], t) == 64 | u_m * 65 | (c[1] / (c[1] + k_s + c[1]^2.0 / k_i)) * 66 | x[1] * 67 | (x[2] / (x[2] + K_N)) - u_d * x[1] 68 | ∂(x[2], t) == 69 | -Y_NX * 70 | u_m * 71 | (c[1] / (c[1] + k_s + c[1]^2.0 / k_i)) * 72 | x[1] * 73 | (x[2] / (x[2] + K_N)) + c[2] 74 | ∂(x[3], t) == 75 | k_m * (c[1] / (c[1] + k_sq + c[1]^2.0 / k_iq)) * x[1] - 76 | k_d * (x[3] / (x[2] + K_Np)) 77 | end 78 | ) 79 | 80 | @objective(model, Max, x[3](tf)) 81 | 82 | optimize_infopt!(model; verbose) 83 | 84 | jump_model = optimizer_model(model) 85 | solution_summary(jump_model; verbose=false) 86 | 87 | return model 88 | end 89 | -------------------------------------------------------------------------------- /src/collocation/classic/semibatch_reactor.jl: -------------------------------------------------------------------------------- 1 | function semibatch_reactor_collocation( 2 | u0, 3 | tspan; 4 | num_supports::Integer=20, 5 | nodes_per_element::Integer=3, 6 | constrain_states::Bool=false, 7 | verbose=false, 8 | ) 9 | optimizer = optimizer_with_attributes( 10 | Ipopt.Optimizer, 11 | "print_level" => 2, 12 | ) 13 | model = InfiniteModel(optimizer) 14 | method = OrthogonalCollocation(nodes_per_element) 15 | 16 | # control constraints 17 | # F = volumetric flow rate 18 | # V = exchanger temperature 19 | # F = 240 & V = 298 in Fogler's book 20 | # F ∈ (0, 250) & V ∈ (200, 500) in Bradford 2017 21 | control_ranges = [(100.0f0, 700.0f0), (0.0f0, 400.0f0)] 22 | 23 | # state constraints 24 | # T ∈ (0, 420] 25 | # Vol ∈ (0, 200] 26 | T_up = 380.0f0 27 | V_up = 200.0f0 28 | 29 | t0, tf = tspan 30 | @infinite_parameter( 31 | model, t in [t0, tf], num_supports = num_supports, derivative_method = method 32 | ) 33 | 34 | @variables( 35 | model, 36 | begin 37 | # state variables 38 | x[1:5], Infinite(t) 39 | # control variables 40 | c[1:2], Infinite(t) 41 | end 42 | ) 43 | 44 | # tricks to make IPOPT work... 45 | almost_zero = 1.0f-3 46 | close_to_infinity = 1.0f3 47 | 48 | set_start_value_function(x[1], t -> 0.5f0) 49 | set_start_value_function(x[2], t -> 0.5f0) 50 | set_start_value_function(x[3], t -> 0.5f0) 51 | set_start_value_function(x[4], t -> 2.0f2) 52 | set_start_value_function(x[5], t -> 1.0f2) 53 | 54 | set_start_value_function(c[1], t -> 2.0f2) 55 | set_start_value_function(c[2], t -> 1.0f2) 56 | 57 | @constraints( 58 | model, 59 | begin 60 | almost_zero <= x[1] <= close_to_infinity 61 | almost_zero <= x[2] <= close_to_infinity 62 | almost_zero <= x[3] <= close_to_infinity 63 | almost_zero <= x[4] <= close_to_infinity 64 | almost_zero <= x[5] <= close_to_infinity 65 | end 66 | ) 67 | 68 | # fixed_parameters 69 | (; CpA, CpB, CpC, CpH2SO4, N0H2S04, T0, CA0, HRA, HRB, E1A, E2B, A1, A2, UA, Tr1, Tr2) = SemibatchReactor() 70 | 71 | # initial_conditions 72 | @constraints( 73 | model, 74 | begin 75 | x[1](0) == u0[1] 76 | x[2](0) == u0[2] + almost_zero 77 | x[3](0) == u0[3] + almost_zero 78 | end 79 | ) 80 | 81 | # control_constraints 82 | @constraints( 83 | model, 84 | begin 85 | control_ranges[1][1] <= c[1] <= control_ranges[1][2] 86 | control_ranges[2][1] <= c[2] <= control_ranges[2][2] 87 | end 88 | ) 89 | 90 | if constrain_states 91 | # state_constraints 92 | @constraints( 93 | model, 94 | begin 95 | x[4] <= T_up 96 | x[5] <= V_up 97 | end 98 | ) 99 | end 100 | 101 | # dynamic_constraints 102 | @constraints( 103 | model, 104 | begin 105 | ∂(x[1], t) == 106 | -(A1 * exp(E1A * ((1.0f0 / Tr1) - (1.0f0 / x[4]))) * x[1]) + 107 | (CA0 - x[1]) * c[1] / x[5] 108 | ∂(x[2], t) == 109 | 0.5f0 * (A1 * exp(E1A * ((1.0f0 / Tr1) - (1.0f0 / x[4]))) * x[1]) - 110 | (A2 * exp(E2B * ((1.0f0 / Tr2) - (1.0f0 / x[4]))) * x[2]) - 111 | x[2] * c[1] / x[5] 112 | ∂(x[3], t) == 113 | 3.0f0 * (A2 * exp(E2B * ((1.0f0 / Tr2) - (1.0f0 / x[4]))) * x[2]) - 114 | x[3] * c[1] / x[5] 115 | ∂(x[4], t) == 116 | ( 117 | UA * (c[2] - x[4]) - CA0 * c[1] * CpA * (x[4] - T0) + 118 | ( 119 | HRA * (-(A1 * exp(E1A * ((1.0f0 / Tr1) - (1.0f0 / x[4]))) * x[1])) + 120 | HRB * (-(A2 * exp(E2B * ((1.0f0 / Tr2) - (1.0f0 / x[4]))) * x[2])) 121 | ) * x[5] 122 | ) / ((x[1] * CpA + CpB * x[2] + CpC * x[3]) * x[5] + N0H2S04 * CpH2SO4) 123 | ∂(x[5], t) == c[1] 124 | end 125 | ) 126 | 127 | @objective(model, Max, x[2](tf)) 128 | 129 | optimize_infopt!(model; verbose) 130 | 131 | jump_model = optimizer_model(model) 132 | solution_summary(jump_model; verbose=false) 133 | 134 | return model 135 | end 136 | -------------------------------------------------------------------------------- /src/collocation/classic/van_der_pol.jl: -------------------------------------------------------------------------------- 1 | function van_der_pol_collocation( 2 | u0, 3 | tspan; 4 | num_supports::Integer=10, 5 | nodes_per_element::Integer=2, 6 | constrain_states::Bool=false, 7 | verbose=false, 8 | ) 9 | optimizer = optimizer_with_attributes( 10 | Ipopt.Optimizer, 11 | "print_level" => 2, 12 | ) 13 | model = InfiniteModel(optimizer) 14 | method = OrthogonalCollocation(nodes_per_element) 15 | @infinite_parameter( 16 | model, t in [tspan[1], tspan[2]], num_supports = num_supports, derivative_method = method 17 | ) 18 | 19 | @variables( 20 | model, 21 | begin # "start" sets the initial guess values 22 | # state variables 23 | x[1:2], Infinite(t) 24 | # control variables 25 | c[1], Infinite(t) 26 | end 27 | ) 28 | 29 | # initial conditions 30 | @constraint(model, [i = 1:2], x[i](0) == u0[i]) 31 | 32 | # control range 33 | @constraint(model, -0.3 <= c[1] <= 1.0) 34 | 35 | if constrain_states 36 | @constraint(model, -0.4 <= x[1]) 37 | end 38 | 39 | # dynamic equations 40 | @constraints( 41 | model, 42 | begin 43 | ∂(x[1], t) == (1 - x[2]^2) * x[1] - x[2] + c[1] 44 | ∂(x[2], t) == x[1] 45 | end 46 | ) 47 | 48 | @objective(model, Min, integral(x[1]^2 + x[2]^2 + c[1]^2, t)) 49 | 50 | optimize_infopt!(model; verbose) 51 | 52 | jump_model = optimizer_model(model) 53 | solution_summary(jump_model; verbose=false) 54 | 55 | return model 56 | end 57 | -------------------------------------------------------------------------------- /src/controlODE.jl: -------------------------------------------------------------------------------- 1 | struct ControlODE{uType<:Real,tType<:Real} 2 | controller 3 | system 4 | u0::AbstractVector{uType} 5 | tspan::Tuple{tType,tType} 6 | tsteps::AbstractVector{tType} 7 | integrator::AbstractODEAlgorithm 8 | sensealg::AbstractSensitivityAlgorithm 9 | prob::AbstractODEProblem 10 | inplace::Bool 11 | 12 | function ControlODE( 13 | controller, 14 | system, 15 | u0, 16 | tspan; 17 | tsteps::Union{Nothing,AbstractVector{<:Real}}=nothing, 18 | Δt::Union{Nothing,Real}=nothing, 19 | npoints::Union{Nothing,Real}=nothing, 20 | input::Symbol=:state, 21 | integrator=INTEGRATOR, 22 | sensealg=SENSEALG, 23 | ) 24 | # check tsteps construction 25 | if !isnothing(tsteps) 26 | @argcheck tspan[begin] == tsteps[begin] 27 | @argcheck tspan[end] == tsteps[end] 28 | elseif !isnothing(Δt) 29 | tsteps = range(tspan...; step=Δt) 30 | elseif !isnothing(npoints) 31 | tsteps = range(tspan...; length=npoints) 32 | else 33 | # @argcheck !isnothing(tsteps) || !isnothing(Δt) || !isnothing(npoints) 34 | throw( 35 | ArgumentError( 36 | "Either tsteps, Δt or npoints keyword must be provided. 37 | They follow that order of priority if several are given.", 38 | ), 39 | ) 40 | end 41 | 42 | # check domain types 43 | time_type = find_array_param(tsteps) 44 | space_type = find_array_param(u0) 45 | # control_type = find_array_param(controller(u0, initial_params(controller))) 46 | # @argcheck space_type == control_type 47 | 48 | # construct ODE problem 49 | @assert length(methods(system)) == 1 50 | # number of arguments for inplace form system (du, u, p, t, controller; input) 51 | local prob, inplace 52 | if methods(system)[1].nargs < 6 53 | inplace = false 54 | dudt(u, p, t) = system(u, p, t, controller; input) 55 | prob = ODEProblem(dudt, u0, tspan) 56 | else 57 | inplace = true 58 | dudt!(du, u, p, t) = system(du, u, p, t, controller; input) 59 | prob = ODEProblem(dudt!, u0, tspan) 60 | end 61 | return new{space_type,time_type}( 62 | controller, system, u0, tspan, tsteps, integrator, sensealg, prob, inplace 63 | ) 64 | end 65 | end 66 | 67 | # TODO follow recommended interface https://github.com/SciML/CommonSolve.jl 68 | function solve(code::ControlODE, params; kwargs...) 69 | return solve( 70 | code.prob, 71 | code.integrator; 72 | p=params, 73 | saveat=code.tsteps, # this should not be necessary 74 | sensealg=code.sensealg, 75 | abstol=1e-2, 76 | reltol=1e-3, 77 | kwargs..., 78 | ) 79 | end 80 | -------------------------------------------------------------------------------- /src/interpolation.jl: -------------------------------------------------------------------------------- 1 | function interpolant_controller(collocation; plot=nothing) 2 | 3 | num_controls = size(collocation.controls, 1) 4 | 5 | interpolations = [ 6 | LinearInterpolation(collocation.controls[i, :], collocation.times) for i in 1:num_controls 7 | # CubicSpline(collocation.controls[i, :], collocation.times) for i in 1:num_controls 8 | ] 9 | 10 | function control_profile(t, p) 11 | Zygote.ignore() do 12 | return [interpolations[i](t) for i in 1:num_controls] 13 | end 14 | end 15 | 16 | if !isnothing(plot) 17 | @argcheck plot in [:unicode, :pyplot] 18 | for c in 1:num_controls 19 | if plot == :unicode 20 | display( 21 | lineplot( 22 | t -> control_profile(t, nothing)[c], 23 | collocation.times[begin+1], 24 | collocation.times[end-1]; 25 | xlim=(collocation.times[begin], collocation.times[end]), 26 | title="Collocation result", 27 | ), 28 | ) 29 | else 30 | plot_collocation( 31 | collocation.controls[c, begin+1:end-1], interpolations[c], collocation.times 32 | ) 33 | end 34 | end 35 | end 36 | return control_profile 37 | end 38 | -------------------------------------------------------------------------------- /src/loading.jl: -------------------------------------------------------------------------------- 1 | const RESULTS_REGEX = r"iter_(\d+)" 2 | const WEIGHTS_EXT = ".jls" 3 | const METADATA_EXT = ".json" 4 | 5 | # this simple function centralizes the naming convention between saving and loading 6 | name_interpolation(iter) = "iter_$iter" 7 | 8 | function extract_name_value(filename; re=RESULTS_REGEX) 9 | matcher = match(re, filename) 10 | if isnothing(matcher) 11 | return nothing 12 | else 13 | @check length(matcher) == 1 "Pattern $re matched more than one number in $filename." 14 | iter_s = matcher.captures[begin] 15 | iter = parse(Int, iter_s) 16 | return iter 17 | end 18 | end 19 | 20 | function filter_matching_filepath(filepaths, re; extension=nothing) 21 | for filepath in filepaths 22 | relevant = !isnothing(extension) && endswith(filepath, extension) 23 | if relevant 24 | matcher = match(re, filepath) 25 | if !isnothing(matcher) 26 | # will only return the first match 27 | return filepath 28 | end 29 | end 30 | end 31 | end 32 | 33 | function extract_values_per_iter(dirpath) 34 | filepaths = readdir(dirpath; join=true, sort=true) 35 | if isempty(filepaths) 36 | error("The directory is empty.") 37 | end 38 | # iter_values_dict = SortedDict{Int, Dict}() 39 | iter_values_dict = SortedDict() 40 | 41 | 42 | for filepath in filepaths 43 | _, ext = splitext(filepath) 44 | ext !== METADATA_EXT && continue 45 | iter = extract_name_value(filepath) 46 | isnothing(iter) && continue 47 | open(filepath, "r") do io 48 | iter_values_dict[iter] = JSON3.read(io) 49 | end 50 | end 51 | return iter_values_dict 52 | end 53 | 54 | function load_penalization_round(dirpath, system; iter) # system = BioReactor(), VanDerPol() ... 55 | filepaths = readdir(dirpath; join=true, sort=true) 56 | 57 | name = name_interpolation(iter) 58 | filepath = filter_matching_filepath(filepaths, Regex(name); extension="params.jls") 59 | 60 | controlODE = ControlODE(system) 61 | weights = deserialize(filepath) 62 | 63 | return controlODE, weights 64 | end 65 | 66 | function plot_penalization_rounds( 67 | dirpath, 68 | system; 69 | state_var=nothing, 70 | control_var=nothing, 71 | timesteps=100, 72 | palette="Blues", # Purples, Blues, Greens, Oranges, Reds 73 | running_ref=nothing, 74 | final_ref=nothing, 75 | ref_color="orange", 76 | transparency=0.7, 77 | saveto=nothing, 78 | ) 79 | @argcheck !all(map(x -> isnothing(x), (state_var, control_var))) "Please specify either state_var or control_var." 80 | @argcheck !all(map(x -> !isnothing(x), (state_var, control_var))) "Please specify just one of state_var or control_var." 81 | 82 | iter_values_dict = extract_values_per_iter(dirpath) 83 | if isempty(iter_values_dict) 84 | @error "No files matched the expected pattern: $(RESULTS_REGEX)" 85 | return 86 | end 87 | # pprint(iter_values_dict) 88 | iters = collect(keys(iter_values_dict)) 89 | color_range = range(0.2, 1, length(iter_values_dict)) 90 | cmap = ColorMap(palette) 91 | cmap_range = ColorMap(palette)(color_range) 92 | fig, ax = plt.subplots() 93 | 94 | local times 95 | for (iter, meta) in iter_values_dict 96 | 97 | controlODE, weights = load_penalization_round(dirpath, system; iter) 98 | span = controlODE.tspan[end] - controlODE.tspan[begin] 99 | times, states, controls = run_simulation(controlODE, weights; saveat=span / timesteps) 100 | 101 | α = meta[:α] 102 | δ = meta[:δ] 103 | 104 | if !isnothing(state_var) 105 | ax.plot( 106 | times, 107 | states[state_var,:]; 108 | color=cmap_range[iter, :], 109 | label="α=$α δ=$δ", 110 | alpha=transparency, 111 | ) 112 | plt.ylabel("x_$state_var") 113 | elseif !isnothing(control_var) 114 | ax.plot( 115 | times, 116 | controls[control_var,:]; 117 | color=cmap_range[iter, :], 118 | label="α=$α δ=$δ", 119 | alpha=transparency, 120 | ) 121 | plt.ylabel("c_$control_var") 122 | end 123 | end 124 | final_time_gap = (times[end] - times[begin]) / 10 125 | !isnothing(running_ref) && plt.plot( 126 | (times[begin], times[end] - final_time_gap), 127 | (running_ref, running_ref); 128 | zorder=110, 129 | color=ref_color, 130 | alpha=transparency, 131 | ls="--", 132 | ) 133 | !isnothing(final_ref) && plt.plot( 134 | (times[end] - final_time_gap, times[end]), 135 | (running_ref, running_ref); 136 | zorder=110, 137 | color=ref_color, 138 | alpha=transparency, 139 | ls="--", 140 | ) 141 | # plt.legend(; fontsize="x-small", loc="center left", bbox_to_anchor=(1.02, 0.5)) 142 | 143 | norm = matplotlib.colors.Normalize(; vmin=iters[begin], vmax=iters[end]) 144 | fig.colorbar( 145 | matplotlib.cm.ScalarMappable(; norm=norm, cmap=cmap); 146 | # cax=ax, 147 | orientation="vertical", 148 | # label=L"\delta", 149 | label="iteration", 150 | ) 151 | plt.xlabel("time") 152 | plt.title("Constraint enforcement with Fiacco-McCormick iterations") 153 | 154 | !isnothing(saveto) && plt.savefig(saveto) 155 | return fig 156 | end 157 | -------------------------------------------------------------------------------- /src/nn.jl: -------------------------------------------------------------------------------- 1 | # A custom basic dense neural network for JuMP usage 2 | 3 | function dense(x, p, out_size, fun=identity) 4 | in_size = length(x) 5 | @argcheck length(p) == (in_size + 1) * out_size 6 | matrix = reshape(p[1:(out_size * in_size)], out_size, in_size) 7 | biases = p[(out_size * in_size + 1):end] # end = out_size * (in_size + 1) 8 | # @show size(matrix) size(biases) 9 | return fun.(matrix * x .+ biases) 10 | end 11 | 12 | function count_params(state_size, layers_sizes) 13 | in_size = state_size 14 | sum = 0 15 | for out_size in layers_sizes 16 | # @show in_size out_size 17 | sum += (in_size + 1) * out_size 18 | in_size = out_size 19 | end 20 | return sum 21 | end 22 | 23 | function chain(x, p, sizes, funs) 24 | @argcheck length(p) == count_params(length(x), sizes) 25 | state = x 26 | start_param = 1 27 | for (out_size, fun) in zip(sizes, funs) 28 | in_size = length(state) 29 | nparams_dense_layer = (in_size + 1) * out_size 30 | # @show start_param insize length(p[start_param : start_param + nparams_dense_layer - 1]) 31 | state = dense( 32 | state, p[start_param:(start_param + nparams_dense_layer - 1)], out_size, fun 33 | ) 34 | start_param += nparams_dense_layer 35 | end 36 | return state 37 | end 38 | 39 | function start_values_sampler( 40 | state_size, layers_sizes; factor=(in, out) -> 2 / (in + out) 41 | ) 42 | in_size = state_size 43 | total_params = count_params(state_size, layers_sizes) 44 | sample_array = zeros(total_params) 45 | start_param = 1 46 | for out_size in layers_sizes 47 | nparams_dense_layer = (in_size + 1) * out_size 48 | # Xavier initialization: variance = 2/(in+out) 49 | # factor = 2/(in_size + out_size) 50 | samples = factor(in_size, out_size)^2 * randn(nparams_dense_layer) 51 | sample_array[start_param:(start_param + nparams_dense_layer - 1)] = samples 52 | start_param += nparams_dense_layer 53 | in_size = out_size 54 | end 55 | return sample_array 56 | end 57 | -------------------------------------------------------------------------------- /src/optimizers.jl: -------------------------------------------------------------------------------- 1 | function optimize_flux( 2 | θ, 3 | loss; 4 | opt::Flux.Optimise.AbstractOptimiser=ADAMW(0.01, (0.9, 0.999), 1.0f-2), 5 | maxiters::Integer=1_000, 6 | x_tol::Union{Nothing,Real}=nothing, 7 | f_tol::Union{Nothing,Real}=nothing, 8 | g_tol::Union{Nothing,Real}=nothing, 9 | show_progressbar::Bool=true, 10 | noise_factor=1.0f-1, 11 | kwargs..., 12 | ) 13 | @argcheck isnothing(x_tol) || x_tol > zero(x_tol) 14 | @argcheck isnothing(f_tol) || f_tol > zero(f_tol) 15 | @argcheck isnothing(g_tol) || g_tol > zero(g_tol) 16 | 17 | params = copy(θ) 18 | params_ref = copy(θ) 19 | 20 | prog = Progress(maxiters; 21 | desc="Flux adaptive training. (x_tol=$x_tol, f_tol=$f_tol, g_tol=$g_tol, maxiters=$maxiters)", 22 | dt=0.2, 23 | enabled=show_progressbar, 24 | showspeed=true, 25 | offset=1, 26 | ) 27 | iter = 1 28 | while true 29 | local current_loss, back, gradient 30 | try 31 | # global current_loss, back, gradient 32 | # back is a function that computes the gradient 33 | current_loss, back = pullback(loss, params) 34 | 35 | # apply back() to the correct type of 1.0 to get the gradient of the loss. 36 | gradient = back(one(current_loss))[1] 37 | catch 38 | @warn "Unstable parameter region. Adding some noise to parameters." 39 | params += noise_factor * std(params) * randn(eltype(params), length(params)) 40 | iter += 1 41 | continue 42 | end 43 | 44 | # references 45 | copy!(params_ref, params) 46 | 47 | # optimizer opdate (modifies params) 48 | Flux.update!(opt, params, gradient) 49 | 50 | # finish metrics 51 | x_diff = sum(abs2, params_ref - params) 52 | f_diff = abs2(current_loss - loss(params)) 53 | g_norm = sum(abs2, gradient) 54 | 55 | # display 56 | current_values = [ 57 | (:iter, iter), 58 | (:loss, current_loss), 59 | (:x_diff, x_diff), 60 | (:f_diff, f_diff), 61 | (:g_norm, g_norm), 62 | ] 63 | ProgressMeter.next!(prog; showvalues=current_values) 64 | 65 | if !isnothing(x_tol) && x_diff < x_tol 66 | desc = "Space rate threshold reached: $x_diff < $x_tol tolerance" 67 | @debug desc 68 | # ProgressMeter.finish!(prog; desc) 69 | return params 70 | elseif !isnothing(f_tol) && f_diff < f_tol 71 | desc = "Objective rate threshold reached: $f_diff < $f_tol tolerance" 72 | @debug desc 73 | # ProgressMeter.finish!(prog; desc) 74 | return params 75 | elseif !isnothing(g_tol) && g_norm < g_tol 76 | desc = "Gradient norm threshold reached: $g_norm < $g_tol tolerance" 77 | @debug desc 78 | # ProgressMeter.finish!(prog; desc) 79 | return params 80 | elseif iter > maxiters 81 | desc = "Iteration bound reached: $iter > $maxiters tolerance" 82 | @debug desc 83 | # ProgressMeter.finish!(prog; desc) 84 | return params 85 | end 86 | iter += 1 87 | end 88 | end 89 | 90 | function optimize_lbfgsb(θ, loss, grad!) 91 | # LBFGSB 92 | # https://github.com/Gnimuc/LBFGSB.jl/blob/master/test/wrapper.jl 93 | params_size = length(θ) 94 | lbfgsb = LBFGSB.L_BFGS_B(params_size, 10) 95 | bounds = zeros(3, params_size) 96 | for i in 1:params_size 97 | bounds[1, i] = 2 # 0->unbounded, 1->only lower bound, 2-> both lower and upper bounds, 3->only upper bound 98 | bounds[2, i] = -1e1 99 | bounds[3, i] = 1e1 100 | end 101 | fout, xout = lbfgsb( 102 | loss, 103 | grad!, 104 | Float64.(θ), 105 | bounds; 106 | m=5, 107 | factr=1e7, 108 | pgtol=1e-5, 109 | iprint=-1, 110 | maxfun=1000, 111 | maxiter=100, 112 | ) 113 | return xout 114 | end 115 | 116 | function optimize_optim(θ, loss, grad!) 117 | # Optim 118 | # https://julianlsolvers.github.io/Optim.jl/stable/#user/config/ 119 | optim_options = Optim.Options(; 120 | store_trace=true, show_trace=false, extended_trace=false 121 | ) 122 | # optim_result = Optim.optimize(loss, grad!, θ, BFGS(), optim_options) 123 | optim_result = Optim.optimize(loss, grad!, θ, LBFGS(; linesearch=BackTracking()), optim_options) 124 | return optim_result.minimizer 125 | end 126 | 127 | function optimize_nlopt(θ, loss, grad!; algorithm=:LD_MMA, xtol_rel=1e-2) 128 | # gradient based algorithms available 129 | # https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/ 130 | reasonable_algs = [:LD_MMA, :LD_CCSAQ, :LD_SLSQP, :LD_LBFGS, :LD_TNEWTON_PRECOND_RESTART] 131 | @argcheck algorithm in reasonable_algs 132 | params_size=length(θ) 133 | opt = NLopt.Opt(algorithm, length(θ)) 134 | opt.lower_bounds = fill(-1e1, params_size) 135 | opt.upper_bounds = fill(1e1, params_size) 136 | opt.xtol_rel = xtol_rel 137 | 138 | function loss_grad(x, g) 139 | grad!(g, x) 140 | return loss(x) 141 | end 142 | opt.min_objective = loss_grad 143 | 144 | (minf, minx, ret) = NLopt.optimize(opt, θ) 145 | if ret ∈ [:FORCED_STOP, :ROUNDOFF_LIMITED, :OUT_OF_MEMORY, :INVALID_ARGS, :FAILURE] 146 | @error "Optimization failed with status $ret" 147 | return nothing 148 | else 149 | @info "Found minimum $minf after $(opt.numevals) iterations (returned $ret)." 150 | end 151 | return minx 152 | end 153 | 154 | function optimize_ipopt( 155 | θ, 156 | loss, 157 | grad!; 158 | maxiters::Int=1_000, 159 | tolerance::Float64=1e-2, 160 | verbosity::Union{Int, Nothing}=3 161 | ) 162 | # IPOPT 163 | # https://github.com/jump-dev/Ipopt.jl/blob/master/test/C_wrapper.jl 164 | eval_g(x, g) = g[:] = zero(x) 165 | eval_grad_f(x, g) = grad!(g, x) 166 | eval_jac_g(x, rows, cols, values) = return nothing 167 | # eval_h(x, rows, cols, obj_factor, lambda, values) = return nothing 168 | params_size=length(θ) 169 | x_lb = fill(-1e1, params_size) 170 | x_ub = fill(1e1, params_size) 171 | ipopt = Ipopt.CreateIpoptProblem( 172 | params_size, 173 | x_lb, 174 | x_ub, 175 | 0, 176 | Float64[], 177 | Float64[], 178 | 0, 179 | 0, 180 | loss, 181 | eval_g, 182 | eval_grad_f, 183 | eval_jac_g, 184 | nothing, 185 | ) 186 | ipopt.x = Float64.(θ) 187 | if !isnothing(verbosity) 188 | Ipopt.AddIpoptIntOption(ipopt, "print_level", verbosity) # default is 5 189 | end 190 | Ipopt.AddIpoptNumOption(ipopt, "tol", tolerance) 191 | Ipopt.AddIpoptIntOption(ipopt, "max_iter", maxiters) 192 | Ipopt.AddIpoptNumOption(ipopt, "acceptable_tol", 0.1*tolerance) # default is 1e-6 193 | Ipopt.AddIpoptIntOption(ipopt, "acceptable_iter", 5) # default is 15 194 | Ipopt.AddIpoptStrOption(ipopt, "check_derivatives_for_naninf", "yes") 195 | Ipopt.AddIpoptStrOption(ipopt, "print_info_string", "yes") 196 | Ipopt.AddIpoptStrOption(ipopt, "hessian_approximation", "limited-memory") 197 | Ipopt.AddIpoptStrOption(ipopt, "mu_strategy", "adaptive") 198 | # A (slow!) derivative test will be performed before the optimization. 199 | # The test is performed at the user provided starting point and marks derivative values that seem suspicious 200 | Ipopt.AddIpoptStrOption(ipopt, "derivative_test", "first-order") 201 | 202 | # https://github.com/jump-dev/Ipopt.jl/blob/master/src/MOI_wrapper.jl#L1261 203 | local solve_status 204 | optimizer_output = @capture_out begin 205 | solve_status = Ipopt.IpoptSolve(ipopt) 206 | end 207 | if isnothing(verbosity) 208 | # only first entry of logger gets formatted as a string 209 | @info "Ipopt report" status=Ipopt._STATUS_CODES[solve_status] 210 | elseif verbosity != 0 211 | @info "Ipopt report (verbosity=$(verbosity))\n" * optimizer_output 212 | end 213 | # @infiltrate !in(solve_status, [0, 1, -1, -3]) # debugging 214 | return ipopt.x # ipopt_minimizer 215 | end 216 | -------------------------------------------------------------------------------- /src/penalties.jl: -------------------------------------------------------------------------------- 1 | # Feller, C., & Ebenbauer, C. (2014). 2 | # Continuous-time linear MPC algorithms based on relaxed logarithmic barrier functions. 3 | # IFAC Proceedings Volumes, 47(3), 2481–2488. 4 | # https://doi.org/10.3182/20140824-6-ZA-1003.01022 5 | 6 | function quadratic_relaxation(z, δ) 7 | return one(typeof(z)) / 2 * (((z - 2δ) / δ)^2 - one(typeof(z))) - log(δ) 8 | end 9 | exponential_relaxation(z, δ) = exp(one(typeof(z)) - z / δ) - one(typeof(z)) - log(δ) 10 | function relaxed_log_barrier(z; δ=0.3f0) 11 | # return max(z > δ ? -log(z) : exponential_relaxation(z, δ), zero(typeof(z))) 12 | return z > δ ? -log(z) : exponential_relaxation(z, δ) 13 | end 14 | function relaxed_log_barrier(z, lower, upper; δ=(upper - lower) / convert(typeof(z), 2)) 15 | return relaxed_log_barrier(z - lower; δ) + relaxed_log_barrier(upper - z; δ) 16 | end 17 | 18 | indicator_function(z; δ) = min(z, zero(typeof(z))) 19 | quadratic_penalty(z; δ) = indicator_function(z; δ)^2 20 | -------------------------------------------------------------------------------- /src/plotting.jl: -------------------------------------------------------------------------------- 1 | let # avoid namespace pollution 2 | plt.ion() 3 | plt.style.use("seaborn-colorblind") # "ggplot" 4 | palette = plt.cm.Dark2.colors 5 | 6 | font = Dict(:family => "STIXGeneral", :size => 16) 7 | savefig = Dict(:dpi => 600, :bbox => "tight") 8 | lines = Dict(:linewidth => 4) 9 | figure = Dict(:figsize => (8, 5)) 10 | axes = Dict(:prop_cycle => matplotlib.cycler(; color=palette)) 11 | legend = Dict(:fontsize => "x-large") # medium for presentations, x-large for papers 12 | 13 | matplotlib.rc("font"; font...) 14 | matplotlib.rc("savefig"; savefig...) 15 | matplotlib.rc("lines"; lines...) 16 | matplotlib.rc("figure"; figure...) 17 | matplotlib.rc("axes"; axes...) 18 | matplotlib.rc("legend"; legend...) 19 | end 20 | 21 | function fun_plotter(fun, array; xlim=(0, 0)) 22 | output = map(fun, eachrow(array)...) 23 | return lineplot(output; title="Custom Function", name="fun", ylim=extrema(output), xlim) 24 | end 25 | 26 | # handy terminal plots 27 | function unicode_plotter(states, controls; only=nothing, vars=nothing, fun=nothing) 28 | @argcheck size(states, 2) == size(controls, 2) 29 | xlim = (0, size(states, 2)) 30 | if only == :states 31 | if !isnothing(fun) 32 | return fun_plotter(fun, states; xlim) 33 | end 34 | typeof(vars) <: Vector && (states = @view states[vars, :]) 35 | ylim = states |> extrema 36 | tag = isnothing(vars) ? "x1" : "x$(vars[1])" 37 | plt = lineplot( 38 | states[1, :]; title="State Evolution", name=tag, xlabel="step", ylim, xlim 39 | ) 40 | for (i, s) in enumerate(eachrow(states[2:end, :])) 41 | tag = isnothing(vars) ? "x$(i+1)" : "x$(vars[i+1])" 42 | lineplot!(plt, collect(s); name=tag) 43 | end 44 | elseif only == :controls 45 | if !isnothing(fun) 46 | return fun_plotter(fun, controls; xlim) 47 | end 48 | typeof(vars) <: Vector && (controls = @view controls[vars, :]) 49 | ylim = controls |> extrema 50 | tag = isnothing(vars) ? "c1" : "c$(vars[1])" 51 | plt = lineplot( 52 | controls[1, :]; title="Control Evolution", name=tag, xlabel="step", ylim, xlim 53 | ) 54 | for (i, s) in enumerate(eachrow(controls[2:end, :])) 55 | tag = isnothing(vars) ? "c$(i+1)" : "c$(vars[i+1])" 56 | lineplot!(plt, collect(s); name=tag) 57 | end 58 | else 59 | if !isnothing(fun) 60 | return fun_plotter(fun, hcat(states, controls); xlim) 61 | end 62 | ylim = Iterators.flatten((states, controls)) |> extrema 63 | plt = lineplot( 64 | states[1, :]; 65 | title="State and Control Evolution", 66 | name="x1", 67 | xlabel="step", 68 | ylim, 69 | xlim, 70 | ) 71 | for (i, s) in enumerate(eachrow(states[2:end, :])) 72 | lineplot!(plt, collect(s); name="x$(i+1)") 73 | end 74 | for (i, c) in enumerate(eachrow(controls)) 75 | lineplot!(plt, collect(c); name="c$i") 76 | end 77 | end 78 | return plt 79 | end 80 | 81 | function plot_simulation( 82 | controlODE, params; show=nothing, only=nothing, vars=nothing, fun=nothing, yrefs=nothing 83 | ) 84 | !isnothing(show) && @info show 85 | 86 | # TODO: use times in plotting? 87 | times, states, controls = run_simulation(controlODE, params) 88 | plt = unicode_plotter(states, controls; only, vars, fun) 89 | if !isnothing(yrefs) 90 | for yref in yrefs 91 | lineplot!(plt, x -> yref; name="$yref") 92 | end 93 | end 94 | display(plt) 95 | return false # if return true, then optimization stops 96 | end 97 | 98 | function histogram_weights_per_layer(controller::FastChain, params) 99 | @argcheck length(initial_params(controller)) == length(params) 100 | index = 1 101 | for i in 1:length(controller.layers) 102 | l = controller.layers[i] 103 | if typeof(l) <: FastLayer 104 | p = initial_params(l) 105 | s = length(p) 106 | lp = params[index:index + s - 1] 107 | h = histogram(lp; title="layer $(i-1)") 108 | display(h) 109 | index += s 110 | end 111 | end 112 | end 113 | function histogram_weights_per_layer(controlODE::ControlODE, params) 114 | histogram_weights_per_layer(controlODE.controller, params) 115 | end 116 | 117 | function plot_collocation(controls_collocation, interpol, tsteps) 118 | fig = plt.figure() 119 | finer_tsteps = range(tsteps[begin+1], tsteps[end-1]; length=1000) 120 | plt.plot(finer_tsteps, [interpol(t) for t in finer_tsteps]; label="interpolation") 121 | plt.plot(tsteps, controls_collocation, "xg"; label="collocation") 122 | plt.title("Control collocation") 123 | plt.xlabel("time") 124 | plt.legend() 125 | return fig 126 | end 127 | 128 | abstract type PhasePlotMarkers end 129 | 130 | @kwdef struct IntegrationPath <: PhasePlotMarkers 131 | points 132 | fmt = "m:" 133 | label = "Integration path" 134 | markersize = nothing 135 | linewidth = 6 136 | end 137 | 138 | @kwdef struct InitialMarkers <: PhasePlotMarkers 139 | points 140 | fmt = "bD" 141 | label = "Initial state" 142 | markersize = 12 143 | linewidth = nothing 144 | end 145 | 146 | @kwdef struct FinalMarkers <: PhasePlotMarkers 147 | points 148 | fmt = "r*" 149 | label = "Final state" 150 | markersize = 18 151 | linewidth = nothing 152 | end 153 | 154 | function states_markers(states_array) 155 | start_mark = InitialMarkers(; points=states_array[:, 1]) 156 | marker_path = IntegrationPath(; points=states_array) 157 | final_mark = FinalMarkers(; points=states_array[:, end]) 158 | # returned order is irrelevant 159 | return [marker_path, start_mark, final_mark] 160 | end 161 | 162 | @kwdef struct ShadeConf 163 | indicator::Function 164 | cmap = "gray" 165 | transparency = 1 166 | end 167 | 168 | @kwdef struct ConstRef 169 | val::Real 170 | direction::Symbol 171 | class::Symbol 172 | var::Integer 173 | linestyle = "--" 174 | color = "r" 175 | label = "Constraint" 176 | linewidth = 3 177 | min = 0 178 | max = 1 179 | function ConstRef( 180 | val, direction, class, var, linestyle, color, label, linewidth, min, max 181 | ) 182 | @argcheck direction in (:vertical, :horizontal) 183 | @argcheck class in (:state, :control) 184 | @argcheck 0 <= min < max <= 1 185 | return new(val, direction, class, var, linestyle, color, label, linewidth, min, max) 186 | end 187 | end 188 | 189 | @kwdef struct FuncRef 190 | fn::Function 191 | dom::Symbol 192 | class::Symbol 193 | var::Integer 194 | linestyle = "--" 195 | color = "r" 196 | label = "Constraint" 197 | linewidth = 3 198 | function FuncRef(fn, dom, class, var, linestyle, color, label, linewidth) 199 | @argcheck dom in (:space, :time) 200 | @argcheck class in (:state, :control) 201 | return new(fn, dom, class, var, linestyle, color, label, linewidth) 202 | end 203 | end 204 | 205 | function phase_portrait( 206 | controlODE, 207 | params, 208 | coord_lims; 209 | time=0.0f0, 210 | point_base=controlODE.prob.u0, 211 | points_per_dim=1000, 212 | projection=[1, 2], 213 | markers::Union{Nothing,AbstractVector{<:PhasePlotMarkers}}=nothing, 214 | start_points=nothing, 215 | start_points_x=nothing, 216 | start_points_y=nothing, 217 | title=nothing, 218 | shader=nothing, 219 | kwargs..., 220 | ) 221 | dimension = length(controlODE.prob.u0) 222 | 223 | @argcheck length(projection) == 2 224 | @argcheck all(ind in 1:dimension for ind in projection) 225 | @argcheck all(x -> isa(x, Tuple) && length(x) == 2, coord_lims) 226 | 227 | state_dtype = find_array_param(controlODE.prob.u0) 228 | function stream_interface(coords...) 229 | @argcheck length(coords) == dimension 230 | u = zeros(state_dtype, dimension) 231 | copyto!(u, coords) 232 | if controlODE.inplace 233 | # du = deepcopy(coords) 234 | du = zeros(state_dtype, dimension) 235 | controlODE.system(du, u, params, time, controlODE.controller) 236 | return du 237 | end 238 | return controlODE.system(u, params, time, controlODE.controller) 239 | end 240 | 241 | # evaluate system over each combination of coords in the specified ranges 242 | # NOTE: float64 is relevant for the conversion to pyplot due to inner 243 | # numerical checks of equidistant input in the streamplot function 244 | ranges = [range(Float64.(lims)...; length=points_per_dim) for lims in coord_lims] 245 | xpoints, ypoints = collect.(ranges[projection]) 246 | 247 | coord_arrays = Vector{Array{state_dtype}}(undef, dimension) 248 | for ind in 1:dimension 249 | if ind == projection[1] 250 | coord_arrays[ind] = xpoints 251 | elseif ind == projection[2] 252 | coord_arrays[ind] = ypoints 253 | else 254 | coord_arrays[ind] = [point_base[ind]] 255 | end 256 | end 257 | # NOTE: the transpose is required to get f.(a',b) instead of the default f.(a, b') 258 | # states_grid = stream_interface.(xpoints', ypoints) 259 | coord_grids = ndgrid(coord_arrays...) 260 | states_grid = stream_interface.(coord_grids...) 261 | 262 | disposable_dims = Tuple(filter(x -> x ∉ projection, 1:dimension)) 263 | filtered_states_grid = dropdims(states_grid; dims=disposable_dims) |> permutedims 264 | 265 | xphase, yphase = [getindex.(filtered_states_grid, dim) for dim in projection] 266 | 267 | magnitude = map((x, y) -> sqrt(sum(x^2 + y^2)), xphase, yphase) 268 | 269 | fig = plt.figure() 270 | # gs = GridSpec(nrows=3, ncols=2, height_ratios=[1, 1, 2]) 271 | 272 | if isnothing(start_points) && !isnothing(start_points_x) && !isnothing(start_points_y) 273 | @argcheck size(start_points_x) == size(start_points_y) 274 | start_grid_x, start_grid_y = ndgrid(start_points_x, start_points_y) 275 | start_points = hcat(reshape(start_grid_x, :, 1), reshape(start_grid_y, :, 1)) 276 | end 277 | 278 | # integration_direction = isnothing(start_points) ? "both" : "forward" 279 | ax = fig.add_subplot() 280 | strm = ax.streamplot( 281 | xpoints, 282 | ypoints, 283 | xphase, 284 | yphase; 285 | color=magnitude, 286 | linewidth=1.5, 287 | density=1.5, 288 | cmap="summer", 289 | kwargs..., 290 | ) 291 | if !isnothing(start_points) 292 | start_points = start_points[:, projection] 293 | ax.plot(start_points[:, 1], start_points[:, 2], "kX"; markersize=12) 294 | strm = ax.streamplot( 295 | xpoints, 296 | ypoints, 297 | xphase, 298 | yphase; 299 | color="darkorchid", 300 | linewidth=3, 301 | density=20, 302 | start_points, 303 | integration_direction="forward", 304 | kwargs..., 305 | ) 306 | end 307 | 308 | # displaying points (handles multiple points as horizontally concatenated) 309 | if !isnothing(markers) 310 | for plotconf in markers 311 | points_projected = plotconf.points[projection, :] 312 | ax.plot( 313 | points_projected[1, :], 314 | points_projected[2, :], 315 | plotconf.fmt; 316 | label=plotconf.label, 317 | markersize=plotconf.markersize, 318 | linewidth=plotconf.linewidth, 319 | ) 320 | end 321 | end 322 | 323 | xlims, ylims = coord_lims[projection] 324 | 325 | if !isnothing(shader) 326 | mask = 327 | dropdims(shader.indicator.(coord_grids...); dims=disposable_dims) |> permutedims 328 | ax.imshow( 329 | mask; 330 | extent=(xlims..., ylims...), 331 | alpha=shader.transparency, 332 | cmap=shader.cmap, 333 | aspect="auto", 334 | ) 335 | end 336 | 337 | ax.set(; xlim=xlims .+ (-0.05, 0.05), ylim=ylims .+ (-0.05, 0.05)) 338 | ax.set_xlabel("x") 339 | ax.set_ylabel("y") 340 | !isnothing(title) && ax.set_title(title) 341 | 342 | # fig.colorbar(strm.lines) 343 | ax.legend(labelspacing=1.2) 344 | 345 | # remove frame 346 | ax.spines["top"].set_visible(false) 347 | ax.spines["right"].set_visible(false) 348 | ax.spines["bottom"].set_visible(false) 349 | ax.spines["left"].set_visible(false) 350 | 351 | plt.tight_layout() 352 | 353 | return fig 354 | end 355 | 356 | function transparecy_scaler_abs(noise, perturbations; top=1, low=0.2) 357 | highest = maximum(abs, perturbations) 358 | amplitude = abs(noise) / highest 359 | return top - (top - low) * amplitude 360 | end 361 | 362 | function set_state_control_subplots( 363 | num_states, num_controls; annotation=nothing, refs=nothing 364 | ) 365 | if !isnothing(refs) 366 | @argcheck all(ref isa ConstRef for ref in refs) 367 | @argcheck all( 368 | ifelse(ref.class == :state, ref.var in 1:num_states, ref.var in 1:num_controls) 369 | for ref in refs 370 | ) BoundsError 371 | end 372 | 373 | fig_states, axs_states = plt.subplots( 374 | num_states; 375 | sharex="col", 376 | squeeze=false, 377 | # constrained_layout=true, # incompatible with subplots_adjust 378 | ) 379 | fig_controls, axs_controls = plt.subplots( 380 | num_controls; 381 | sharex="col", 382 | squeeze=false, 383 | # constrained_layout=true, # incompatible with subplots_adjust 384 | ) 385 | axs_states[1].set_title("States") 386 | axs_controls[1].set_title("Controls") 387 | axs_states[end].set_xlabel("time") 388 | axs_controls[end].set_xlabel("time") 389 | 390 | for s in 1:num_states 391 | axs_states[s].set_ylabel("state[$s]") 392 | end 393 | for c in 1:num_controls 394 | axs_controls[c].set_ylabel("control[$c]") 395 | end 396 | if !isnothing(refs) 397 | for r in refs 398 | ax = r.class == :state ? axs_states[r.var] : axs_controls[r.var] 399 | if r.direction == :vertical 400 | ax.axvline( 401 | r.val; 402 | ymin=r.min, 403 | ymax=r.max, 404 | label=r.label, 405 | linestyle=r.linestyle, 406 | color=r.color, 407 | ) 408 | elseif r.direction == :horizontal 409 | ax.axhline( 410 | r.val; 411 | xmin=r.min, 412 | xmax=r.max, 413 | label=r.label, 414 | linestyle=r.linestyle, 415 | color=r.color, 416 | ) 417 | end 418 | end 419 | end 420 | 421 | if !isnothing(annotation) 422 | fig_states.text(0, 0, string(annotation)) 423 | fig_controls.text(0, 0, string(annotation)) 424 | end 425 | 426 | return fig_states, axs_states, fig_controls, axs_controls 427 | end 428 | 429 | function plot_initial_perturbations(controlODE, θ, specs; refs=nothing, funcs=nothing, storedir=nothing) 430 | u0 = controlODE.u0 431 | state_size = size(u0, 1) 432 | control_size = size(controlODE.controller(u0, θ), 1) 433 | 434 | for spec in specs 435 | perturbations = local_grid( 436 | spec.samples, spec.percentage; scale=spec.scale, type=spec.type 437 | ) 438 | cmap = ColorMap("tab10") 439 | fig_states, axs_states, fig_controls, axs_controls = set_state_control_subplots( 440 | length(u0), length(controlODE.controller(u0, θ)); annotation=spec, refs 441 | ) 442 | 443 | for noise in perturbations 444 | noise_vec = zeros(typeof(noise), length(u0)) 445 | noise_vec[spec.variable] = noise 446 | 447 | perturbed_u0 = u0 + noise_vec 448 | controlODE = ControlODE( 449 | controlODE.controller, 450 | controlODE.system, 451 | perturbed_u0, 452 | controlODE.tspan; 453 | tsteps=controlODE.tsteps, 454 | integrator=controlODE.integrator, 455 | sensealg=controlODE.sensealg, 456 | ) 457 | 458 | times, states, controls = run_simulation(controlODE, θ) 459 | 460 | for s in 1:state_size 461 | axs_states[s].plot( 462 | times, 463 | states[s, :]; 464 | label="u0[$(spec.variable)] + " * format(noise; precision=2), 465 | alpha=transparecy_scaler_abs(noise, perturbations), 466 | c=cmap(s), 467 | ) 468 | end 469 | for c in 1:control_size 470 | axs_controls[c].plot( 471 | times, 472 | controls[c, :]; 473 | label="u0[$(spec.variable)] + " * format(noise; precision=2), 474 | alpha=transparecy_scaler_abs(noise, perturbations), 475 | c=cmap(c + size(states, 1)), 476 | ) 477 | end 478 | end 479 | legend_elements = [ 480 | matplotlib.patches.Patch(; 481 | facecolor="black", 482 | edgecolor="black", 483 | label=format(noise; precision=2), 484 | alpha=transparecy_scaler_abs(noise, perturbations), 485 | ) for noise in sort(perturbations) 486 | ] 487 | fig_legend_div = 0.8 488 | fig_states.subplots_adjust(; right=fig_legend_div) 489 | legend_states = fig_states.legend(; 490 | handles=legend_elements, 491 | bbox_to_anchor=(fig_legend_div, 0.5), 492 | loc="center left", 493 | # borderaxespad=0, 494 | title="Perturbation", 495 | ) 496 | fig_controls.subplots_adjust(; right=fig_legend_div) 497 | legend_controls = fig_controls.legend(; 498 | handles=legend_elements, 499 | bbox_to_anchor=(fig_legend_div, 0.5), 500 | loc="center left", 501 | # borderaxespad=0, 502 | title="Perturbation", 503 | ) 504 | 505 | if !isnothing(storedir) 506 | # tight_layout alternative that considers the legend (or other artists) 507 | # bbox_extra_artists must be an iterable 508 | filename = "u0_$(spec.variable)_" * sprintf1("%04d", tag) 509 | fig.savefig(joinpath(storedir, filename * "states_noise.pdf"), bbox_extra_artists=(legend_states,), bbox_inches="tight") 510 | fig.savefig(joinpath(storedir, filename * "controls_noise.pdf"), bbox_extra_artists=(legend_controls,), bbox_inches="tight") 511 | else 512 | fig_states.show() 513 | fig_controls.show() 514 | end 515 | end 516 | end 517 | 518 | function plot_initial_perturbations_collocation( 519 | controlODE, θ, specs, infopt_collocation; refs=nothing, funcs=nothing, storedir=nothing 520 | ) 521 | state_size = size(controlODE.u0, 1) 522 | control_size = size(controlODE.controller(controlODE.u0, θ), 1) 523 | 524 | u0 = controlODE.u0 525 | for spec in specs 526 | perturbations = local_grid( 527 | spec.samples, spec.percentage; scale=spec.scale, type=spec.type 528 | ) 529 | for (tag, noise) in enumerate(perturbations) 530 | cmap = ColorMap("tab20") 531 | fig_states, axs_states, fig_controls, axs_controls = set_state_control_subplots( 532 | length(controlODE.u0), 533 | length(controlODE.controller(controlODE.u0, θ)); 534 | annotation=spec, 535 | refs, 536 | ) 537 | 538 | noise_vec = zeros(typeof(noise), length(controlODE.u0)) 539 | noise_vec[spec.variable] = noise 540 | 541 | # perturbed prob = ODEProblem(dudt!, u0 + noise_vec, tspan, θ) 542 | perturbed_u0 = u0 + noise_vec 543 | controlODE = ControlODE( 544 | controlODE.controller, 545 | controlODE.system, 546 | perturbed_u0, 547 | controlODE.tspan; 548 | tsteps=controlODE.tsteps, 549 | integrator=controlODE.integrator, 550 | sensealg=controlODE.sensealg, 551 | ) 552 | 553 | times, states, controls = run_simulation(controlODE, θ) 554 | collocation = infopt_collocation( 555 | perturbed_u0, 556 | controlODE.tspan; 557 | num_supports=length(controlODE.tsteps), 558 | constrain_states=true, 559 | ) 560 | for s in 1:state_size 561 | axs_states[s].plot( 562 | times, 563 | states[s, :]; 564 | label="policy", 565 | # alpha=transparecy_scaler_abs(noise, perturbations), 566 | color=cmap(2s - 2), 567 | ) 568 | axs_states[s].plot( 569 | times, 570 | collocation.states[s, :]; 571 | label="collocation", 572 | marker="x", 573 | linestyle="None", 574 | # alpha=transparecy_scaler_abs(noise, perturbations), 575 | color=cmap(2s - 1), 576 | ) 577 | end 578 | for c in 1:control_size 579 | axs_controls[c].plot( 580 | times, 581 | controls[c, :]; 582 | label="policy", 583 | # alpha=transparecy_scaler_abs(noise, perturbations), 584 | color=cmap(2c - 2 + 2size(states, 1)), 585 | ) 586 | axs_controls[c].plot( 587 | times, 588 | collocation.controls[c, :]; 589 | label="collocation", 590 | marker="x", 591 | linestyle="None", 592 | # alpha=transparecy_scaler_abs(noise, perturbations), 593 | color=cmap(2c - 1 + 2size(states, 1)), 594 | ) 595 | end 596 | title = "u0[$(spec.variable)] + " * format(noise; precision=2) 597 | fig_states.suptitle(title) 598 | fig_controls.suptitle(title) 599 | 600 | legend_elements = [ 601 | matplotlib.lines.Line2D( 602 | [0], [0]; color="black", linewidth=3, label="policy" 603 | ), 604 | matplotlib.lines.Line2D( 605 | [0], 606 | [0]; 607 | color="black", 608 | marker="x", 609 | linestyle="None", 610 | linewidth=3, 611 | label="collocation", 612 | ), 613 | ] 614 | 615 | # fig_legend_div = 0.8 616 | # fig_states.subplots_adjust(; right=fig_legend_div) 617 | legend_states = fig_states.legend(; 618 | handles=legend_elements, 619 | # bbox_to_anchor=(fig_legend_div, 0.5), 620 | # loc="center left", 621 | ) 622 | # fig_controls.subplots_adjust(; right=fig_legend_div) 623 | legend_controls = fig_controls.legend(; 624 | handles=legend_elements, 625 | # bbox_to_anchor=(fig_legend_div, 0.5), 626 | # loc="center left", 627 | ) 628 | 629 | if !isnothing(storedir) 630 | # tight_layout alternative that considers the legend (or other artists) 631 | # bbox_extra_artists must be an iterable 632 | filename = "u0_$(spec.variable)_" * sprintf1("%04d", tag) 633 | fig_states.savefig( 634 | joinpath(storedir, filename * "_states.pdf"); 635 | bbox_extra_artists=(legend_states,), 636 | # bbox_inches="tight", # this adjusts filesize slighly... problematic for gifs 637 | ) 638 | fig_controls.savefig( 639 | joinpath(storedir, filename * "_controls.pdf"); 640 | bbox_extra_artists=(legend_controls,), 641 | # bbox_inches="tight", 642 | ) 643 | else 644 | fig_states.show() 645 | fig_controls.show() 646 | end 647 | end 648 | end 649 | end 650 | -------------------------------------------------------------------------------- /src/scripts/batch_reactor.jl: -------------------------------------------------------------------------------- 1 | function batch_reactor(; store_results::Bool=false) 2 | datadir = nothing 3 | if store_results 4 | datadir = generate_data_subdir(@__FILE__) 5 | end 6 | 7 | # define objective function to optimize 8 | function loss(controlODE, params) 9 | sol = solve(controlODE, params) 10 | return -Array(sol)[2, end] # second variable, last value, maximize 11 | end 12 | 13 | system = BatchReactor() 14 | controlODE = ControlODE(system) 15 | 16 | θ = initial_params(controlODE.controller) 17 | 18 | # variables for streamplots 19 | xlims, ylims = (0.0f0, 1.5f0), (0.0f0, 0.8f0) 20 | coord_lims = [xlims, ylims] 21 | # xwidth = xlims[end] - xlims[1] 22 | # ywidth = ylims[end] - ylims[1] 23 | # start_points_x = range(u0[1] - 1e-4, u0[1] - xwidth/5; length=3) 24 | # start_points_y = range(u0[2] + 1e-4, u0[2] + ywidth/5; length=3) 25 | 26 | _, states_raw, _ = run_simulation(controlODE, θ) 27 | phase_portrait( 28 | controlODE, 29 | θ, 30 | coord_lims; 31 | markers=states_markers(states_raw), 32 | # start_points_x, start_points_y, 33 | # start_points=reshape(u0 .+ (-1e-4, 0), 1, 2), 34 | title="Initial policy", 35 | ) 36 | 37 | # closures to comply with required interface 38 | loss(params) = loss(controlODE, params) 39 | function plotting_callback(params, loss) 40 | return plot_simulation(controlODE, params; only=:controls, show=loss) 41 | end 42 | 43 | @info "Training..." 44 | grad!(g, params) = g .= Zygote.gradient(loss, params)[1] 45 | θ = optimize_optim(θ, loss, grad!) 46 | 47 | store_simulation( 48 | "optimized", 49 | controlODE, 50 | θ; 51 | datadir, 52 | ) 53 | plot_simulation(controlODE, θ; only=:controls) 54 | 55 | _, states_raw, _ = run_simulation(controlODE, θ) 56 | phase_portrait( 57 | controlODE, 58 | θ, 59 | coord_lims; 60 | markers=states_markers(states_raw), 61 | # start_points_x, start_points_y, 62 | # start_points=reshape(u0 .+ (-1e-4, 0), 1, 2), 63 | title="Optimized policy", 64 | ) 65 | return 66 | end # script wrapper 67 | -------------------------------------------------------------------------------- /src/scripts/bioreactor.jl: -------------------------------------------------------------------------------- 1 | # Bradford, E., Imsland, L., Zhang, D., & del Rio Chanona, E. A. (2020). 2 | # Stochastic data-driven model predictive control using Gaussian processes. 3 | # Computers & Chemical Engineering, 139, 106844. 4 | 5 | # objective: maximize C_qc 6 | 7 | # state constraints 8 | # C_N(t) - 250 ≥ 0 t = T 9 | # C_N(t) − 400 ≤ 0 ∀t 10 | 11 | function bioreactor(; store_results::Bool=false) 12 | 13 | datadir = nothing 14 | if store_results 15 | datadir = generate_data_subdir(@__FILE__) 16 | end 17 | 18 | system = BioReactor() 19 | controlODE = ControlODE(system) 20 | 21 | function plot_state_constraints(θ) 22 | plot_simulation(controlODE, θ; only=:states, vars=[2], yrefs=[400, 250]) 23 | plot_simulation(controlODE, θ; only=:states, vars=[3]) 24 | end 25 | 26 | collocation_model = bioreactor_collocation( 27 | controlODE.u0, 28 | controlODE.tspan; 29 | constrain_states=true, 30 | ) 31 | collocation_results = extract_infopt_results(collocation_model) 32 | reference_controller = interpolant_controller(collocation_results; plot=:unicode) 33 | 34 | θ = initial_params(controlODE.controller) 35 | θ = preconditioner( 36 | controlODE, 37 | reference_controller; 38 | θ, 39 | x_tol=1e-4, 40 | # progressbar=true, 41 | ) 42 | 43 | plot_state_constraints(θ) 44 | plot_simulation(controlODE, θ; only=:controls, vars=[1]) 45 | plot_simulation(controlODE, θ; only=:controls, vars=[2]) 46 | store_simulation("precondition", controlODE, θ; datadir) 47 | 48 | function state_penalty_functional(solution_array; δ) 49 | # state constraints 50 | # C_N(t) - 250 ≥ 0 t = T 51 | # C_N(t) − 400 ≤ 0 ∀t 52 | C_N_over_running = map(y -> relaxed_log_barrier(400f0 - y; δ), solution_array[2, 1:end-1]) 53 | C_N_over_last = relaxed_log_barrier(solution_array[2, end] - 250f0; δ) 54 | 55 | # Δt = Float32(controlODE.tsteps.step) 56 | # return Δt * sum(C_N_over_running) + C_N_over_last 57 | return mean(C_N_over_running) + C_N_over_last 58 | end 59 | 60 | function losses(controlODE, params; α, δ, ρ) 61 | # integrate ODE system 62 | sol_raw = solve(controlODE, params) 63 | sol = Array(sol_raw) 64 | 65 | # https://diffeqflux.sciml.ai/dev/examples/divergence/ 66 | # Zygote.@ignore @infiltrate sol_raw.retcode != :Success 67 | Zygote.@ignore if sol_raw.t[end] != controlODE.tspan[end] 68 | return Inf 69 | end 70 | 71 | objective = -sol[3, end] # maximize C_qc 72 | 73 | state_penalty = α * state_penalty_functional(sol; δ) 74 | 75 | # # penalty on change of controls 76 | control_penalty = 0.0 77 | # for i in 1:(size(sol, 2) - 1) 78 | # prev = controller(sol[:, i], params) 79 | # post = controller(sol[:, i + 1], params) 80 | # for j in 1:length(prev) 81 | # control_penalty += μ[j] * (prev[j] - post[j])^2 82 | # end 83 | # end 84 | 85 | regularization = ρ * sum(abs2, params) 86 | 87 | return (; objective, state_penalty, control_penalty, regularization) 88 | end 89 | 90 | ρ = 1f-3 91 | θ, barrier_progression = constrained_training( 92 | losses, 93 | controlODE, 94 | θ; 95 | ρ, 96 | show_progressbar=false, 97 | datadir, 98 | ) 99 | 100 | @info "Alpha progression" barrier_progression.α 101 | lineplot(log.(barrier_progression.α); title="Alpha progression") |> display 102 | 103 | @info "Delta progression" barrier_progression.δ 104 | lineplot(log.(barrier_progression.δ); title="Delta progression") |> display 105 | 106 | δ_final = barrier_progression.δ[end] 107 | α_final = barrier_progression.α[end] 108 | objective, state_penalty, control_penalty, regularization = losses( 109 | controlODE, θ; δ = δ_final, α = α_final, ρ 110 | ) 111 | final_loss = objective + state_penalty + control_penalty + regularization 112 | 113 | @info "Final states" 114 | plot_state_constraints(θ) 115 | 116 | @info "Final controls" 117 | plot_simulation(controlODE, θ; only=:controls, vars=[1]) 118 | plot_simulation(controlODE, θ; only=:controls, vars=[2]) 119 | 120 | @info "Final losses" objective state_penalty control_penalty regularization final_loss 121 | 122 | @info "Collocation comparison" 123 | collocation_model = bioreactor_collocation( 124 | controlODE.u0, 125 | controlODE.tspan; 126 | constrain_states=true, 127 | ) 128 | collocation_results = extract_infopt_results(collocation_model) 129 | interpolant_controller(collocation_results) 130 | 131 | @info "Collocation states" 132 | for states in eachrow(collocation_results.states) 133 | lineplot(states) |> display 134 | end 135 | 136 | @info "Collocation controls" 137 | for controls in eachrow(collocation_results.controls) 138 | lineplot(controls) |> display 139 | end 140 | 141 | # perturbation_specs = [ 142 | # (variable=1, type=:centered, scale=1.0f0, samples=3, percentage=5.0f-2) 143 | # (variable=2, type=:centered, scale=400.0f0, samples=3, percentage=5.0f-2) 144 | # (variable=3, type=:positive, scale=5.0f-1, samples=3, percentage=5.0f-2) 145 | # ] 146 | # plot_initial_perturbations(controlODE, θ, perturbation_specs) 147 | 148 | end # script wrapper 149 | -------------------------------------------------------------------------------- /src/scripts/semibatch_reactor.jl: -------------------------------------------------------------------------------- 1 | # Elements of Chemical Reaction Engineering 2 | # Fifth Edition 3 | # H. SCOTT FOGLER 4 | # Chapter 13: Unsteady-State Nonisothermal Reactor Design 5 | # Section 13.5: Nonisothermal Multiple Reactions 6 | # Example 13–5 Multiple Reactions in a Semibatch Reactor 7 | # p. 658 8 | 9 | function semibatch_reactor(; store_results::Bool=false) 10 | datadir = nothing 11 | if store_results 12 | datadir = generate_data_subdir(@__FILE__) 13 | end 14 | 15 | # state constraints 16 | # T ∈ (0, 420] 17 | # Vol ∈ (0, 200] 18 | T_up = 380.0f0 19 | V_up = 200.0f0 20 | 21 | system = SemibatchReactor() 22 | controlODE = ControlODE(system) 23 | 24 | # simulate the system with constant controls as in Fogler's 25 | # to reproduce his results and verify correctness 26 | fogler_ref = [240.0f0, 298.0f0] # reference values in Fogler 27 | fogler_timespan = (0.0f0, 1.5f0) 28 | fixed_controlODE = ControlODE((u, p) -> fogler_ref, system, controlODE.u0, fogler_timespan; Δt=1.5f-1) 29 | @info "Fogler's case: final time state" solve(fixed_controlODE, nothing).u[end] 30 | plot_simulation( 31 | fixed_controlODE, 32 | nothing; 33 | only=:states, 34 | vars=[1, 2, 3], 35 | ) 36 | plot_simulation( 37 | fixed_controlODE, 38 | nothing; 39 | only=:states, 40 | vars=[4, 5], 41 | ) 42 | 43 | collocation_model = semibatch_reactor_collocation( 44 | controlODE.u0, 45 | controlODE.tspan; 46 | num_supports=length(controlODE.tsteps), 47 | nodes_per_element=2, 48 | constrain_states=false, 49 | ) 50 | collocation_results = extract_infopt_results(collocation_model) 51 | 52 | reference_controller = interpolant_controller(collocation_results; plot=:unicode) 53 | 54 | θ = initial_params(controlODE.controller) 55 | θ = preconditioner( 56 | controlODE, 57 | reference_controller; 58 | θ, 59 | x_tol=nothing, 60 | f_tol=1.0f-3, 61 | maxiters=2_000, 62 | ) 63 | plot_simulation(controlODE, θ; only=:states) 64 | plot_simulation(controlODE, θ; only=:controls) 65 | store_simulation("precondition", controlODE, θ; datadir) 66 | 67 | # objective function splitted componenets to optimize 68 | function losses(controlODE, params; α, δ, ρ) 69 | 70 | # integrate ODE system 71 | sol_raw = solve(controlODE, params) 72 | sol_array = Array(sol_raw) 73 | 74 | # https://diffeqflux.sciml.ai/dev/examples/divergence/ 75 | # if sol_raw.retcode != :Success # avoid this with Zygote... 76 | Zygote.@ignore if sol_raw.t[end] != controlODE.tspan[end] 77 | return Inf 78 | end 79 | 80 | # running cost 81 | out_temp = map(x -> relaxed_log_barrier(T_up - x; δ), sol_array[4, 1:end]) 82 | out_vols = map(x -> relaxed_log_barrier(V_up - x; δ), sol_array[5, 1:end]) 83 | 84 | # terminal cost 85 | # L = - (100 x₁ - x₂) + penalty # Bradford 86 | objective = -sol_array[2, end] 87 | 88 | # integral penalty 89 | Δt = Float32(controlODE.tsteps.step) 90 | state_penalty = α * Δt * (sum(out_temp) + sum(out_vols)) 91 | control_penalty = 0.0f0 92 | regularization = ρ * sum(abs2, params) 93 | return (; objective, state_penalty, control_penalty, regularization) 94 | end 95 | 96 | # α: penalty coefficient 97 | # ρ: regularization coefficient 98 | # δ: barrier relaxation coefficient 99 | ρ = 1f-3 100 | θ, barrier_progression = constrained_training( 101 | losses, 102 | controlODE, 103 | θ; 104 | ρ, 105 | show_progressbar=false, 106 | datadir, 107 | ) 108 | @info "Alpha progression" barrier_progression.α 109 | lineplot(log.(barrier_progression.α); title="Alpha progression") |> display 110 | 111 | @info "Delta progression" barrier_progression.δ 112 | lineplot(log.(barrier_progression.δ); title="Delta progression") |> display 113 | 114 | δ_final = barrier_progression.δ[end] 115 | α_final = barrier_progression.α[end] 116 | objective, state_penalty, control_penalty, regularization = losses( 117 | controlODE, θ; δ = δ_final, α = α_final, ρ 118 | ) 119 | final_loss = objective + state_penalty + control_penalty + regularization 120 | 121 | @info "Final states" 122 | plot_simulation(controlODE, θ; only=:states, vars=[1, 2, 3]) 123 | plot_simulation( 124 | controlODE, θ; only=:states, vars=[4, 5], yrefs=[T_up, V_up] 125 | ) 126 | 127 | @info "Final controls" 128 | plot_simulation(controlODE, θ; only=:controls)# only=:states, vars=[1,2,3]) 129 | 130 | @info "Final losses" objective state_penalty control_penalty regularization final_loss 131 | 132 | @info "Collocation comparison" 133 | collocation_model = semibatch_reactor_collocation( 134 | controlODE.u0, 135 | controlODE.tspan; 136 | constrain_states=true, 137 | ) 138 | collocation_results = extract_infopt_results(collocation_model) 139 | interpolant_controller(collocation_results) 140 | 141 | @info "Collocation states" 142 | for states in eachrow(collocation_results.states) 143 | lineplot(states) |> display 144 | end 145 | 146 | @info "Collocation controls" 147 | for controls in eachrow(collocation_results.controls) 148 | lineplot(controls) |> display 149 | end 150 | 151 | end # function wrapper 152 | -------------------------------------------------------------------------------- /src/scripts/van_der_pol.jl: -------------------------------------------------------------------------------- 1 | # Vassiliadis, V. S., Sargent, R. W. H., & Pantelides, C. C. (1994). 2 | # Solution of a Class of Multistage Dynamic Optimization Problems. 2. Problems with Path Constraints. 3 | # Industrial & Engineering Chemistry Research, 33(9), 2123–2133. https://doi.org/10.1021/ie00033a015 4 | 5 | function van_der_pol(; store_results::Bool=false) 6 | datadir = nothing 7 | if store_results 8 | datadir = generate_data_subdir(@__FILE__) 9 | end 10 | 11 | system = VanDerPol() 12 | controlODE = ControlODE(system) 13 | 14 | θ = initial_params(controlODE.controller) 15 | 16 | _, states_raw, _ = run_simulation(controlODE, θ) 17 | phase_portrait( 18 | controlODE, 19 | θ, 20 | square_bounds(controlODE.u0, 7); 21 | projection=[1, 2], 22 | markers=states_markers(states_raw), 23 | title="Initial policy", 24 | ) 25 | 26 | collocation_model = van_der_pol_collocation( 27 | controlODE.u0, 28 | controlODE.tspan; 29 | num_supports=length(controlODE.tsteps), 30 | nodes_per_element=2, 31 | constrain_states=false, 32 | ) 33 | collocation_results = extract_infopt_results(collocation_model) 34 | reference_controller = interpolant_controller(collocation_results; plot=:unicode) 35 | 36 | θ = preconditioner( 37 | controlODE, 38 | reference_controller; 39 | θ, 40 | x_tol=1f-7, 41 | g_tol=1f-2, 42 | ) 43 | 44 | plot_simulation(controlODE, θ; only=:controls) 45 | store_simulation("precondition", controlODE, θ; datadir) 46 | 47 | _, states_raw, _ = run_simulation(controlODE, θ) 48 | phase_portrait( 49 | controlODE, 50 | θ, 51 | square_bounds(controlODE.u0, 4); 52 | projection=[1, 2], 53 | markers=states_markers(states_raw), 54 | title="Preconditioned policy", 55 | ) 56 | 57 | ### define objective function to optimize 58 | function loss(controlODE, params; kwargs...) 59 | sol = solve(controlODE, params) |> Array 60 | # return Array(sol)[3, end] # return last value of third variable ...to be minimized 61 | objective = 0.0f0 62 | for i in axes(sol, 2) 63 | s = sol[:, i] 64 | c = controlODE.controller(s, params) 65 | objective += s[1]^2 + s[2]^2 + c[1]^2 66 | end 67 | return objective 68 | end 69 | loss(params) = loss(controlODE, params) 70 | 71 | @info "Training..." 72 | grad!(g, params) = g .= Zygote.gradient(loss, params)[1] 73 | # θ = optimize_optim(θ, loss, grad!) 74 | θ = optimize_ipopt(θ, loss, grad!) 75 | 76 | _, states_raw, _ = run_simulation(controlODE, θ) 77 | phase_portrait( 78 | controlODE, 79 | θ, 80 | square_bounds(controlODE.u0, 4); 81 | projection=[1, 2], 82 | markers=states_markers(states_raw), 83 | title="Optimized policy", 84 | ) 85 | 86 | store_simulation( 87 | "unconstrained", 88 | controlODE, 89 | θ; 90 | datadir, 91 | metadata=Dict(:loss => loss(θ), :constraint => "none"), 92 | ) 93 | 94 | ### now add state constraint x1(t) > -0.4 with 95 | function losses(controlODE, params; α, δ, ρ) 96 | # integrate ODE system 97 | Δt = Float32(controlODE.tsteps.step) 98 | sol = solve(controlODE, params) |> Array 99 | objective = 0.0f0 100 | control_penalty = 0.0f0 101 | for i in axes(sol, 2) 102 | s = sol[:, i] 103 | c = controlODE.controller(s, params) 104 | objective += s[1]^2 + s[2]^2 105 | control_penalty += c[1]^2 106 | end 107 | objective *= Δt 108 | control_penalty *= Δt 109 | 110 | # fault = min.(sol[1, 1:end] .+ 0.4f0, 0.0f0) 111 | state_fault = map(x -> relaxed_log_barrier(x - -0.4f0; δ), sol[1, 1:end-1]) 112 | # penalty = α * sum(fault .^ 2) # quadratic penalty 113 | state_penalty = Δt * α * sum(state_fault) 114 | regularization = ρ * sum(abs2, params) 115 | return (; objective, state_penalty, control_penalty, regularization) 116 | end 117 | 118 | @info "Enforcing constraints..." 119 | ρ = 0f0 120 | θ, barrier_progression = constrained_training( 121 | losses, 122 | controlODE, 123 | θ; 124 | ρ, 125 | show_progressbar=false, 126 | datadir, 127 | ) 128 | 129 | @info "Alpha progression" barrier_progression.α 130 | lineplot(log.(barrier_progression.α); title="Alpha progression") |> display 131 | 132 | @info "Delta progression" barrier_progression.δ 133 | lineplot(log.(barrier_progression.δ); title="Delta progression") |> display 134 | 135 | α_final = barrier_progression.α[end] 136 | δ_final = barrier_progression.δ[end] 137 | 138 | # penalty_loss(result.minimizer, constrained_prob, tsteps; α=penalty_coefficients[end]) 139 | plot_simulation(controlODE, θ; only=:controls) 140 | 141 | objective, state_penalty, control_penalty, regularization = losses(controlODE, θ; α=α_final, δ=δ_final, ρ) 142 | store_simulation( 143 | "constrained", 144 | controlODE, 145 | θ; 146 | datadir, 147 | metadata=Dict( 148 | # :loss => penalty_loss(controlODE, θ; α=α0, δ), 149 | # :constraint => "quadratic x2(t) > -0.4", 150 | :objective => objective, 151 | :state_penalty => state_penalty, 152 | :control_penalty => control_penalty, 153 | :regularization => regularization, 154 | ), 155 | ) 156 | 157 | _, states_opt, _ = run_simulation(controlODE, θ) 158 | function indicator(coords...) 159 | if coords[1] > -0.4 160 | return true 161 | end 162 | return false 163 | end 164 | shader = ShadeConf(; indicator) 165 | phase_portrait( 166 | controlODE, 167 | θ, 168 | square_bounds(controlODE.u0, 4); 169 | shader, 170 | projection=[1, 2], 171 | markers=states_markers(states_opt), 172 | title="Optimized policy with constraints", 173 | ) 174 | 175 | # u0 = [0f0, 1f0] 176 | # perturbation_specs = [ 177 | # (variable=1, type=:positive, scale=1.0f0, samples=3, percentage=1.0f-1) 178 | # (variable=2, type=:negative, scale=1.0f0, samples=3, percentage=1.0f-1) 179 | # # (variable=3, type=:positive, scale=20.0f0, samples=8, percentage=2.0f-2) 180 | # ] 181 | # constraint_spec = ConstRef(; val=-0.4, direction=:horizontal, class=:state, var=1) 182 | 183 | # plot_initial_perturbations_collocation( 184 | # controlODE, 185 | # θ, 186 | # perturbation_specs, 187 | # van_der_pol_collocation; 188 | # refs=[constraint_spec], 189 | # storedir=datadir, 190 | # ) 191 | return 192 | end 193 | -------------------------------------------------------------------------------- /src/simulators.jl: -------------------------------------------------------------------------------- 1 | function run_simulation( 2 | controlODE::ControlODE, 3 | params; 4 | control_input=:state, 5 | noise::Union{Nothing,Real}=nothing, 6 | vars::Union{Nothing,AbstractArray{<:Integer}}=nothing, 7 | callback::Union{Nothing,DECallback}=nothing, 8 | kwargs..., 9 | ) 10 | if !isnothing(noise) && !isnothing(vars) 11 | if !isnothing(callback) 12 | @warn "Supplied callback will be replaced by a noise callback." 13 | end 14 | @argcheck noise > zero(noise) 15 | @argcheck all(var in eachindex(controlODE.u0) for var in vars) 16 | 17 | function noiser(u, t, integrator) 18 | for var in vars 19 | u[var] += noise 20 | end 21 | end 22 | callback = FunctionCallingCallback( 23 | noiser; 24 | # funcat=tsteps, 25 | func_everystep=true, 26 | ) 27 | end 28 | 29 | # integrate with given parameters 30 | solution = solve(controlODE, params; callback, kwargs...) 31 | 32 | # construct arrays with the same type used by the integrator 33 | elements_type = eltype(solution.t) 34 | states = Array(solution) 35 | total_steps = size(states, 2) 36 | # state_dimension = size(states, 1) 37 | 38 | # regenerate controls from controlODE.controller 39 | if control_input == :state 40 | control_dimension = length(controlODE.controller(solution.u[begin], params)) 41 | controls = zeros(elements_type, control_dimension, total_steps) 42 | for (step, state) in enumerate(solution.u) 43 | controls[:, step] = controlODE.controller(state, params) 44 | end 45 | elseif control_input == :time 46 | control_dimension = length(controlODE.controller(solution.t[begin], params)) 47 | controls = zeros(elements_type, control_dimension, total_steps) 48 | for (step, time) in enumerate(solution.t) 49 | controls[:, step] = controlODE.controller(time, params) 50 | end 51 | else 52 | @check control_input in [:state, :time] 53 | end 54 | 55 | return solution.t, states, controls 56 | end 57 | 58 | # TODO: use DrWatson jl 59 | function store_simulation( 60 | filename::Union{Nothing,String}, 61 | controlODE::ControlODE, 62 | params::AbstractVector{<:Real}; 63 | metadata::Union{Nothing,Dict}=nothing, 64 | datadir::Union{Nothing,String}=nothing, 65 | ) 66 | if isnothing(datadir) || isnothing(filename) 67 | @info "Results not stored due to missing filename/datadir." maxlog = 1 68 | return nothing 69 | end 70 | 71 | params_path = joinpath(datadir, filename * "_params.jls") 72 | serialize(params_path, params) 73 | 74 | # weights_path = joinpath(datadir, filename * "_nnweights.csv") 75 | # CSV.write(weights_path, Tables.table(params), writeheader=false) 76 | 77 | times, states, controls = run_simulation(controlODE, params) 78 | 79 | state_headers = ["x$i" for i in 1:size(states, 1)] 80 | control_headers = ["c$i" for i in 1:size(controls, 1)] 81 | 82 | header = vcat(["t"], state_headers, control_headers) 83 | data = hcat(times, permutedims(states), permutedims(controls)) 84 | 85 | filepath_csv = joinpath(datadir, filename * ".csv") 86 | 87 | # data_table = table(data; header) 88 | # CSV.write(filepath_csv, data_table) 89 | 90 | open(filepath_csv, "w") do io 91 | writedlm(io, vcat(permutedims(header), data), ',') 92 | end 93 | 94 | if !isnothing(metadata) 95 | open(joinpath(datadir, filename * "_meta.json"), "w") do f 96 | JSON3.pretty(f, metadata) 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /src/systems/batch_reactor.jl: -------------------------------------------------------------------------------- 1 | @kwdef struct BatchReactor 2 | α = 0.5f0 3 | β = 1.0f0 4 | γ = 1.0f0 5 | δ = 1.0f0 6 | end 7 | 8 | function (S::BatchReactor)(du, u, p, t, controller; input=:state) 9 | @argcheck input in (:state, :time) 10 | 11 | # fixed parameters 12 | (; α, β, γ, δ) = S 13 | 14 | y1, y2 = u 15 | 16 | # neural network outputs controls taken by the system 17 | if input == :state 18 | c1, c2 = controller(u, p) 19 | elseif input == :time 20 | c1, c2 = controller(t, p) 21 | end 22 | 23 | # dynamics of the controlled system 24 | y1_prime = -(c1 + α * c1^2) * y1 + δ * c2 25 | y2_prime = (β * c1 - γ * c2) * y1 26 | 27 | # update in-place 28 | @inbounds begin 29 | du[1] = y1_prime 30 | du[2] = y2_prime 31 | end 32 | return nothing 33 | end 34 | 35 | function ControlODE(system::BatchReactor) 36 | # initial conditions and timepoints 37 | t0 = 0.0f0 38 | tf = 1.0f0 39 | Δt = 1f-2 40 | tspan = (t0, tf) 41 | u0 = [1.0f0, 0.0f0] 42 | 43 | # weights initializer reference https://pytorch.org/docs/stable/nn.init.html 44 | controller = FastChain( 45 | FastDense(2, 12, tanh_fast), 46 | FastDense(12, 12, tanh_fast), 47 | FastDense(12, 2), 48 | (x, p) -> 5 * sigmoid_fast.(x), # controllers ∈ (0, 5) 49 | ) 50 | return ControlODE(controller, system, u0, tspan; Δt) 51 | end 52 | -------------------------------------------------------------------------------- /src/systems/bioreactor.jl: -------------------------------------------------------------------------------- 1 | # Bradford, E., Imsland, L., Zhang, D., & del Rio Chanona, E. A. (2020). 2 | # Stochastic data-driven model predictive control using Gaussian processes. 3 | # Computers & Chemical Engineering, 139, 106844. 4 | 5 | @kwdef struct BioReactor 6 | u_m=0.0572f0 7 | u_d=0.0f0 8 | K_N=393.1f0 9 | Y_NX=504.5f0 10 | k_m=0.00016f0 11 | k_d=0.281f0 12 | k_s=178.9f0 13 | k_i=447.1f0 14 | k_sq=23.51f0 15 | k_iq=800.0f0 16 | K_Np=16.89f0 17 | end 18 | 19 | function (S::BioReactor)(du, u, p, t, controller; input=:state) 20 | @argcheck input in (:state, :time) 21 | 22 | (; u_m, u_d, K_N, Y_NX, k_m, k_d, k_s, k_i, k_sq, k_iq, K_Np) = S 23 | 24 | C_X, C_N, C_qc = u 25 | 26 | if input == :state 27 | I, F_N = controller(u, p) 28 | elseif input == :time 29 | I, F_N = controller(t, p) 30 | end 31 | 32 | # auxiliary variables 33 | I_ksi = I / (I + k_s + I^2.0f0 / k_i) 34 | CN_KN = C_N / (C_N + K_N) 35 | 36 | I_kiq = I / (I + k_sq + I^2.0f0 / k_iq) 37 | Cqc_KNp = C_qc / (C_N + K_Np) 38 | 39 | # dynamics of the controlled system 40 | dC_X = u_m * I_ksi * C_X * CN_KN - u_d * C_X 41 | dC_N = -Y_NX * u_m * I_ksi * C_X * CN_KN + F_N 42 | dC_qc = k_m * I_kiq * C_X - k_d * Cqc_KNp 43 | 44 | # update in-place 45 | @inbounds begin 46 | du[1] = dC_X 47 | du[2] = dC_N 48 | du[3] = dC_qc 49 | end 50 | return nothing 51 | # return [dC_X, dC_N, dC_qc] 52 | end 53 | 54 | function ControlODE(system::BioReactor) 55 | # initial conditions and timepoints 56 | t0 = 0f0 57 | tf = 240.0f0 58 | Δt = 2f0 59 | tspan = (t0, tf) 60 | u0 = [1f0, 150f0, 0f0] # C_X₀, C_N₀, C_qc₀ 61 | control_constraints = [(80f0, 180f0), (0f0, 20f0)] 62 | 63 | # weights initializer reference https://pytorch.org/docs/stable/nn.init.html 64 | controller = FastChain( 65 | (x, p) -> [x[1], x[2] / 100f0, x[3] * 10f0], # input scaling 66 | FastDense(3, 8, tanh_fast; initW=(x, y) -> Float32(5 / 3) * glorot_uniform(x, y)), 67 | FastDense(8, 8, tanh_fast; initW=(x, y) -> Float32(5 / 3) * glorot_uniform(x, y)), 68 | FastDense(8, 2; initW=(x, y) -> glorot_uniform(x, y)), 69 | # I ∈ [120, 400] & F ∈ [0, 40] in Bradford 2020 70 | # (x, p) -> [280f0 * sigmoid(x[1]) + 120f0, 40f0 * sigmoid(x[2])], 71 | scaled_sigmoids(control_constraints), 72 | ) 73 | return ControlODE(controller, system, u0, tspan; Δt) 74 | end 75 | -------------------------------------------------------------------------------- /src/systems/semibatch_reactor.jl: -------------------------------------------------------------------------------- 1 | # Elements of Chemical Reaction Engineering 2 | # Fifth Edition 3 | # H. SCOTT FOGLER 4 | # Chapter 13: Unsteady-State Nonisothermal Reactor Design 5 | # Section 13.5: Nonisothermal Multiple Reactions 6 | # Example 13–5 Multiple Reactions in a Semibatch Reactor 7 | # p. 658 8 | 9 | @kwdef struct SemibatchReactor 10 | CpA=30.0f0 11 | CpB=60.0f0 12 | CpC=20.0f0 13 | CpH2SO4=35.0f0 14 | N0H2S04=100.0f0 15 | T0=305.0f0 16 | CA0=4.0f0 17 | HRA=-6500.0f0 18 | HRB=8000.0f0 19 | E1A=9500.0f0 / 1.987f0 20 | E2B=7000.0f0 / 1.987f0 21 | A1=1.25f0 22 | A2=0.08f0 23 | UA=35000.0f0 # 45000 Bradford value 24 | Tr1=320.0f0 # 420 Bradford value 25 | Tr2=290.0f0 # 400 Bradford value 26 | end 27 | 28 | function (S::SemibatchReactor)(du, u, p, t, controller; input=:state) 29 | @argcheck input in (:state, :time) 30 | 31 | (; CpA, CpB, CpC, CpH2SO4, N0H2S04, T0, CA0, HRA, HRB, E1A, E2B, A1, A2, UA, Tr1, Tr2) = S 32 | 33 | # neural network outputs controls taken by the system 34 | CA, CB, CC, T, Vol = u # states 35 | # controls 36 | if input == :state 37 | c_F, c_T = controller(u, p) 38 | elseif input == :time 39 | c_F, c_T = controller(t, p) 40 | end 41 | k1A = A1 * exp(E1A * ((1.0f0 / Tr1) - (1.0f0 / T))) 42 | k2B = A2 * exp(E2B * ((1.0f0 / Tr2) - (1.0f0 / T))) 43 | 44 | k1CA = k1A * CA 45 | k2CB = k2B * CB 46 | F_Vol = c_F / Vol 47 | 48 | ra = -k1CA 49 | rb = 0.5f0 * k1CA - k2CB 50 | rc = 3.0f0 * k2CB 51 | 52 | num = 53 | UA * (c_T - T) - CA0 * c_F * CpA * (T - T0) + 54 | (HRA * (-k1CA) + HRB * (-k2CB)) * Vol 55 | den = (CA * CpA + CpB * CB + CpC * CC) * Vol + N0H2S04 * CpH2SO4 56 | 57 | # dynamics of the controlled system 58 | dCA = ra + (CA0 - CA) * F_Vol 59 | dCB = rb - CB * F_Vol 60 | dCC = rc - CC * F_Vol 61 | dT = num / den 62 | dVol = c_F 63 | 64 | # update in-place 65 | @inbounds begin 66 | du[1] = dCA 67 | du[2] = dCB 68 | du[3] = dCC 69 | du[4] = dT 70 | du[5] = dVol 71 | end 72 | return nothing 73 | # return [dCA, dCB, dCC, dT, dVol] 74 | end 75 | 76 | function ControlODE(system::SemibatchReactor) 77 | # initial conditions and timepoints 78 | t0 = 0.0f0 79 | tf = 0.4f0 # Bradfoard uses 0.4 80 | Δt = 0.01f0 81 | tspan = (t0, tf) 82 | 83 | # state: CA, CB, CC, T, Vol 84 | u0 = [1.0f0, 0.0f0, 0.0f0, 290.0f0, 100.0f0] 85 | 86 | # control constraints 87 | # F = volumetric flow rate 88 | # V = exchanger temperature 89 | # F = 240 & V = 298 in Fogler's book 90 | # F ∈ (0, 250) & V ∈ (200, 500) in Bradford 2017 91 | control_ranges = [(100.0f0, 700.0f0), (0.0f0, 400.0f0)] 92 | 93 | controller = FastChain( 94 | (x, p) -> [x[1], x[2], x[3], x[4] / 1f2, x[5] / 1f2], 95 | FastDense(5, 16, tanh), 96 | FastDense(16, 16, tanh), 97 | # FastDense(16, 16, tanh), 98 | FastDense(16, 2), 99 | # (x, p) -> [240f0, 298f0], 100 | scaled_sigmoids(control_ranges), 101 | ) 102 | return ControlODE(controller, system, u0, tspan; Δt) 103 | end 104 | -------------------------------------------------------------------------------- /src/systems/van_der_pol.jl: -------------------------------------------------------------------------------- 1 | # Vassiliadis, V. S., Sargent, R. W. H., & Pantelides, C. C. (1994). 2 | # Solution of a Class of Multistage Dynamic Optimization Problems. 2. Problems with Path Constraints. 3 | # Industrial & Engineering Chemistry Research, 33(9), 2123–2133. https://doi.org/10.1021/ie00033a015 4 | 5 | @kwdef struct VanDerPol 6 | μ=1f0 7 | end 8 | 9 | function (S::VanDerPol)(du, u, p, t, controller; input=:state) 10 | @argcheck input in (:state, :time) 11 | 12 | # neural network outputs the controls taken by the system 13 | x1, x2 = u 14 | 15 | if input == :state 16 | c1 = controller(u, p)[1] # control based on state and parameters 17 | elseif input == :time 18 | c1 = controller(t, p)[1] # control based on time and parameters 19 | end 20 | 21 | # dynamics of the controlled system 22 | x1_prime = S.μ * (1 - x2^2) * x1 - x2 + c1 23 | x2_prime = x1 24 | 25 | # update in-place 26 | @inbounds begin 27 | du[1] = x1_prime 28 | du[2] = x2_prime 29 | end 30 | return nothing 31 | # return [x1_prime, x2_prime] 32 | end 33 | 34 | function ControlODE(system::VanDerPol) 35 | # initial conditions and timepoints 36 | t0 = 0.0f0 37 | tf = 5.0f0 38 | u0 = [0.0f0, 1.0f0] 39 | tspan = (t0, tf) 40 | Δt = 0.1f0 41 | 42 | # set arquitecture of neural network controller 43 | controller = FastChain( 44 | FastDense(2, 12, tanh_fast), 45 | FastDense(12, 12, tanh_fast), 46 | FastDense(12, 1), 47 | (x, p) -> (1.3f0 .* sigmoid_fast.(x)) .- 0.3f0, 48 | ) 49 | 50 | return ControlODE(controller, system, u0, tspan; Δt) 51 | end 52 | -------------------------------------------------------------------------------- /src/training.jl: -------------------------------------------------------------------------------- 1 | function preconditioner( 2 | controlODE, 3 | precondition; 4 | θ, 5 | ρ=nothing, 6 | saveat=(), 7 | progressbar=false, 8 | plot_final=true, 9 | integrator=INTEGRATOR, 10 | max_solver_iterations=10, # per step 11 | kwargs..., 12 | ) 13 | @info "Preconditioning..." 14 | 15 | prog = Progress( 16 | length(controlODE.tsteps[2:end]); 17 | desc="Pretraining in subintervals t ∈ $(controlODE.tspan)", 18 | dt=0.2, 19 | showspeed=true, 20 | enabled=progressbar, 21 | ) 22 | # skip spurious ends from collocation 23 | # @withprogress name="Pretraining in subintervals t ∈ $(controlODE.tspan)" begin 24 | for partial_time in controlODE.tsteps[2:(end - 1)] 25 | partial_tspan = (controlODE.tspan[1], partial_time) 26 | 27 | local fixed_prob 28 | if controlODE.inplace 29 | function fixed_dudt!(du, u, p, t) 30 | return controlODE.system(du, u, p, t, precondition; input=:time) 31 | end 32 | fixed_prob = ODEProblem(fixed_dudt!, controlODE.u0, partial_tspan) 33 | else 34 | fixed_dudt(u, p, t) = controlODE.system(u, p, t, precondition; input=:time) 35 | fixed_prob = ODEProblem(fixed_dudt, controlODE.u0, partial_tspan) 36 | end 37 | fixed_sol = solve(fixed_prob, integrator; saveat) 38 | 39 | # Zygote ignore anything unrelated to loss function 40 | function precondition_loss(params; plot=nothing) 41 | plot_arrays = Dict(:reference => [], :control => []) 42 | 43 | sum_squares = 0.0f0 44 | datapoints = length(fixed_sol.t) 45 | # for (time, state) in zip(fixed_sol.t, fixed_sol.u) # Zygote error 46 | for (i, state) in enumerate(eachcol(Array(fixed_sol))) 47 | reference = precondition(fixed_sol.t[i], nothing) # precondition(time, params) 48 | control = controlODE.controller(state, params) 49 | diff_square = (control - reference) .^ 2 50 | sum_squares += sum(diff_square) 51 | Zygote.ignore() do 52 | if !isnothing(plot) 53 | push!(plot_arrays[:reference], reference) 54 | push!(plot_arrays[:control], control) 55 | end 56 | end 57 | end 58 | Zygote.ignore() do 59 | if !isnothing(plot) 60 | @argcheck plot in [:unicode, :pyplot] 61 | reference = reduce(hcat, plot_arrays[:reference]) 62 | control = reduce(hcat, plot_arrays[:control]) 63 | 64 | if plot == :unicode 65 | for r in axes(reference, 1) 66 | p = lineplot(reference[r, :]; name="fixed") 67 | lineplot!(p, control[r, :]; name="neural") 68 | display(p) 69 | end 70 | elseif plot == :pyplot 71 | cmap = ColorMap("tab20") # binary comparisons 72 | nrows = size(reference, 1) 73 | rows = 1:nrows 74 | fig, axs = plt.subplots( 75 | nrows, 76 | 1; 77 | sharex="col", 78 | squeeze=false, 79 | constrained_layout=true, 80 | #tight_layout=false, 81 | ) 82 | for r in rows 83 | ax = axs[r, 1] 84 | ax.plot( 85 | fixed_sol.t, 86 | reference[r, :], 87 | "o"; 88 | label="fixed", 89 | color=cmap(2r - 2), 90 | ) 91 | ax.plot( 92 | fixed_sol.t, 93 | control[r, :]; 94 | label="neural", 95 | color=cmap(2r - 1), 96 | ) 97 | ax.legend() 98 | end 99 | fig.supxlabel("time") 100 | fig.suptitle("Preconditioning") 101 | fig.show() 102 | end 103 | end 104 | end 105 | mse = sum_squares/datapoints 106 | if isnothing(ρ) 107 | return mse 108 | else 109 | regularization = ρ * sum(abs2, params) 110 | return mse + regularization 111 | end 112 | end 113 | 114 | grad!(g, params) = g .= Zygote.gradient(precondition_loss, params)[1] 115 | # θ = optimize_flux(θ, precondition_loss; kwargs...) 116 | θ = optimize_ipopt(θ, precondition_loss, grad!; tolerance=1e-1, maxiters=max_solver_iterations, verbosity=3) 117 | 118 | ProgressMeter.next!(prog) 119 | @info "Progress $(100*partial_time/controlODE.tsteps[(end - 1)])%" partial_time final_time=controlODE.tsteps[(end - 1)] 120 | # @logprogress partial_time/controlODE.tsteps[(end - 1)] 121 | if partial_time == controlODE.tsteps[end] && plot_final 122 | precondition_loss(θ; plot=:pyplot) 123 | end 124 | end 125 | # end # @withprogress 126 | return θ 127 | end 128 | 129 | function increase_by_percentage(x, per) 130 | @argcheck 0 < per 131 | return (1f0 + 1f-2 * per) * x 132 | end 133 | 134 | function decrease_by_percentage(x, per) 135 | @argcheck 0 < per < 100 136 | return (1f0 - 1f-2 * per) * x 137 | end 138 | 139 | function evaluate_barrier( 140 | losses, 141 | controlODE, 142 | θ; 143 | α, 144 | δ, 145 | ρ, 146 | penalty_ratio_upper_bound=1f1, 147 | penalty_ratio_lower_bound=1f-1, 148 | verbose=false, 149 | ) 150 | objective, state_penalty, control_penalty, regularization = losses(controlODE, θ; α, δ, ρ) 151 | if isinf(state_penalty) 152 | return :inf 153 | end 154 | state_penalty_size = abs(state_penalty) 155 | other_penalties_size = abs(objective) 156 | # other_penalties_size = max(abs(objective), abs(control_penalty), abs(regularization)) 157 | state_penalty_ratio = state_penalty_size / other_penalties_size 158 | verbose && @info "Penalty ratios" α δ objective state_penalty state_penalty_ratio 159 | if state_penalty_ratio > penalty_ratio_upper_bound 160 | return :overtight 161 | elseif state_penalty_ratio < penalty_ratio_lower_bound 162 | return :overlax 163 | else 164 | return :reasonable 165 | end 166 | end 167 | 168 | function tune_barrier( 169 | losses, 170 | controlODE, 171 | θ; 172 | α, 173 | ρ, 174 | δ, 175 | δ_percentage_change=10f0, 176 | α_percentage_change=50f0, 177 | max_iters=10, 178 | increase_alpha=true, 179 | verbose=false, 180 | ) 181 | previous_evaluation = :reasonable 182 | counter=0 183 | 184 | # @withprogress name="Tuning barrier parameters" begin 185 | while counter < max_iters 186 | counter+=1 187 | 188 | evaluation = evaluate_barrier(losses, controlODE, θ; α, δ, ρ, verbose) 189 | @info "Barrier tuning" counter evaluation 190 | # increase_alpha && counter == 1 && evaluation == :overtight && @infiltrate 191 | if evaluation == :overlax 192 | δ = decrease_by_percentage(δ, δ_percentage_change) 193 | 194 | elseif evaluation in [:overtight, :inf] 195 | δ = increase_by_percentage(δ, δ_percentage_change) 196 | # @infiltrate counter == max_iters 197 | 198 | elseif evaluation == :reasonable 199 | if previous_evaluation in [:overtight, :inf] 200 | if increase_alpha 201 | α = increase_by_percentage(α, α_percentage_change) 202 | end 203 | else 204 | δ = decrease_by_percentage(δ, δ_percentage_change) 205 | end 206 | return α, δ 207 | else 208 | @check evaluation in [:inf, :overtight, :overlax, :reasonable] 209 | end 210 | 211 | previous_evaluation = evaluation 212 | # @logprogress counter/max_iters 213 | end 214 | # end # @withprogress 215 | return α, δ 216 | end 217 | 218 | # avoid closures over barrier parameters with a callable struct 219 | # https://discourse.julialang.org/t/function-factories-or-callable-structs/52987 220 | # https://discourse.julialang.org/t/why-is-closure-slower-than-handmade-callable-struct/80361 221 | struct BarrierLosses{T<:Real} 222 | losses::Function 223 | controlODE::ControlODE 224 | α::T 225 | δ::T 226 | ρ::T 227 | end 228 | 229 | function (l::BarrierLosses)(params) 230 | l.losses(l.controlODE, params; α=l.α, δ=l.δ, ρ=l.ρ) 231 | end 232 | 233 | function constrained_training( 234 | losses, 235 | controlODE, 236 | θ; 237 | ρ, 238 | α0=1f-3, 239 | δ0=1f1, 240 | max_solver_iterations=10, # per step 241 | max_barrier_iterations=100, 242 | max_α = 1e3 * α0, 243 | min_δ = 1e-2 * δ0, 244 | max_δ = 1e4 * δ0, 245 | show_progressbar=false, 246 | datadir=nothing, 247 | metadata=Dict(), # metadata is added to this dict always 248 | ) 249 | @info "Training with constraints..." 250 | 251 | prog = Progress(max_barrier_iterations; 252 | desc="Fiacco-McCormick barrier iterations", 253 | dt=0.2, 254 | enabled=show_progressbar, 255 | showspeed=true, 256 | ) 257 | 258 | α, δ = tune_barrier( 259 | losses, 260 | controlODE, 261 | θ; 262 | ρ, 263 | α=α0, 264 | δ=δ0, 265 | max_iters=100, 266 | increase_alpha=false, 267 | ) 268 | 269 | α_progression = [α] 270 | δ_progression = [δ] 271 | barrier_iteration = 0 272 | # @withprogress name="Fiacco-McCormick barrier iterations" begin 273 | while barrier_iteration < max_barrier_iterations 274 | barrier_iteration += 1 275 | 276 | # @infiltrate any(isinf, (α, δ, ρ)) 277 | 278 | # for debugging convenience 279 | # callable struct to avoid a closure 280 | lost = BarrierLosses(losses, controlODE, α, δ, ρ) 281 | # lost(params) = losses(controlODE, params; α, δ, ρ) 282 | # objective_grad = norm(Zygote.gradient(x -> lost(x)[1], θ)[1]) 283 | # @info "Objective grad" objective_grad 284 | state_penalty_grad_norm = norm(Zygote.gradient(x -> lost(x)[2], θ)[1]) 285 | @info "State penalty grad norm" state_penalty_grad_norm / norm(θ) 286 | # regularization_grad = norm(Zygote.gradient(x -> lost(x)[4], θ)[1]) 287 | # @info "Regularization grad" regularization_grad 288 | 289 | # comply with optimization interface using closures 290 | loss(params) = sum(lost(params)) 291 | # loss(params) = sum(losses(controlODE, params; α, δ, ρ)) 292 | function grad(params) 293 | try 294 | return Zygote.gradient(loss, params)[1] 295 | catch e 296 | if isa(e, DomainError) 297 | return zeros(eltype(params), length(params)) 298 | else 299 | # @infiltrate 300 | rethrow(e) 301 | end 302 | end 303 | end 304 | grad!(g, params) = g .= grad(params) 305 | 306 | local minimizer 307 | let trials = 5, iters = max_solver_iterations 308 | for trial in 1:trials 309 | try 310 | minimizer = optimize_ipopt(θ, loss, grad!; maxiters=iters) 311 | # minimizer = optimize_lbfgsb(θ, loss, grad!) 312 | # minimizer = optimize_optim(θ, loss, grad!) 313 | break 314 | catch 315 | trial == trials && error("Optimization failed!") 316 | # not the smartest workaround... 317 | @error "Optimization failed! Retrying with less iterations and added noise... ($trial / $trials)" 318 | θ += 1.0f-1 * std(θ) * randn(eltype(θ), length(θ)) 319 | iters = iters ÷ 2 320 | end 321 | end 322 | end 323 | 324 | objective, state_penalty, control_penalty, regularization = lost(minimizer) 325 | 326 | local_metadata = Dict( 327 | :iter => barrier_iteration, 328 | :δ => δ, 329 | :α => α, 330 | :ρ => ρ, 331 | :objective => objective, 332 | :state_penalty => state_penalty, 333 | :control_penalty => control_penalty, 334 | :regularization_cost => regularization, 335 | :initial_condition => controlODE.u0, 336 | :tspan => controlODE.tspan, 337 | ) 338 | 339 | !show_progressbar && @info "Barrier iterations" local_metadata 340 | ProgressMeter.next!(prog; showvalues=[(el.first, el.second) for el in local_metadata]) 341 | # @logprogress barrier_iteration/max_barrier_iterations 342 | 343 | metadata = merge(metadata, local_metadata) 344 | name = name_interpolation(barrier_iteration) 345 | store_simulation(name, controlODE, θ; metadata, datadir) 346 | 347 | tuned_α, tuned_δ = tune_barrier( 348 | losses, 349 | controlODE, 350 | minimizer; 351 | α, 352 | ρ, 353 | δ, 354 | increase_alpha=true, 355 | ) 356 | if tuned_α > α 357 | prev_losses = losses(controlODE, minimizer; α, δ, ρ) 358 | tuned_losses = losses(controlODE, minimizer; α=tuned_α, δ=tuned_δ, ρ) 359 | @info "Increased alpha" α δ tuned_α tuned_δ prev_losses sum(prev_losses) tuned_losses sum(tuned_losses) 360 | end 361 | if (min_δ > tuned_δ > max_δ) || (tuned_α > max_α) 362 | @info "Barrier parameter reached bounds." min_δ tuned_δ max_δ tuned_α max_α 363 | θ = minimizer 364 | break 365 | end 366 | 367 | α, δ = tuned_α, tuned_δ 368 | push!(α_progression, α) 369 | push!(δ_progression, δ) 370 | 371 | θ = minimizer 372 | end 373 | # end # @withprogress 374 | ProgressMeter.finish!(prog) 375 | barriers_progression = (; α=α_progression, δ=δ_progression) 376 | return θ, barriers_progression 377 | end 378 | -------------------------------------------------------------------------------- /sysimage_tracing.jl: -------------------------------------------------------------------------------- 1 | using ControlNeuralODE: van_der_pol 2 | 3 | van_der_pol() 4 | --------------------------------------------------------------------------------