diff --git a/Cargo.lock b/Cargo.lock index 4fbc288..0b4a8d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bincode" @@ -28,85 +28,73 @@ dependencies = [ [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" dependencies = [ "serde", ] [[package]] name = "bitflags" -version = "1.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "crossbeam-channel" -version = "0.5.6" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "either" -version = "1.8.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -114,37 +102,34 @@ dependencies = [ ] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "heck" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "indoc" -version = "1.0.7" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -152,36 +137,28 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" -dependencies = [ - "rawpointer", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ "autocfg", + "rawpointer", ] [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] name = "nalgebra" -version = "0.32.2" +version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d47bba83f9e2006d117a9a33af1524e655516b8919caac694427a6fb1e511" +checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" dependencies = [ "approx", "matrixmultiply", @@ -196,13 +173,13 @@ dependencies = [ [[package]] name = "nalgebra-macros" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -218,11 +195,26 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + [[package]] name = "num-complex" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", "serde", @@ -230,54 +222,42 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] -[[package]] -name = "num_cpus" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "numpy" -version = "0.18.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b0fee4571867d318651c24f4a570c3f18408cf95f16ccb576b3ce85496a46e" +checksum = "ec170733ca37175f5d75a5bea5911d6ff45d2cd52849ce98b685394e4f2f37f4" dependencies = [ "libc", "nalgebra", - "ndarray", + "ndarray 0.15.6", "num-complex", "num-integer", "num-traits", @@ -287,24 +267,24 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "ordered-float" -version = "3.6.0" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13a384337e997e6860ffbaa83708b2ef329fd8c54cb67a5f64d421e0f943254f" +checksum = "4a91171844676f8c7990ce64959210cd2eaef32c2612c50f9fae9f8aaa6065a6" dependencies = [ "num-traits", ] [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -312,22 +292,37 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-targets", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "portable-atomic" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" + +[[package]] +name = "portable-atomic-util" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdd8420072e66d54a407b3316991fe946ce3ab1083a7f575b2463866624704d" +dependencies = [ + "portable-atomic", +] [[package]] name = "ppca" @@ -336,7 +331,7 @@ dependencies = [ "approx", "bit-vec", "nalgebra", - "ndarray", + "ndarray 0.16.1", "ordered-float", "rand", "rand_distr", @@ -361,30 +356,34 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" -version = "0.18.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b1ac5b3731ba34fdaa9785f8d74d17448cd18f30cf19e0c7e7b1fdb5272109" +checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" dependencies = [ "cfg-if", "indoc", "libc", - "memoffset 0.8.0", + "memoffset", "parking_lot", + "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -393,9 +392,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.18.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cb946f5ac61bb61a5014924910d936ebd2b23b705f7a4a3c40b05c720b079a3" +checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" dependencies = [ "once_cell", "target-lexicon", @@ -403,9 +402,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.18.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4d7c5337821916ea2a1d21d1092e8443cf34879e53a0ac653fbb98f44ff65c" +checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" dependencies = [ "libc", "pyo3-build-config", @@ -413,32 +412,34 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.18.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d39c55dab3fc5a4b25bbd1ac10a2da452c4aca13bb450f22818a002e29648d" +checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "pyo3-macros-backend" -version = "0.18.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97daff08a4c48320587b5224cc98d609e3c27b6d437315bd40b605c98eeb5918" +checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" dependencies = [ + "heck", "proc-macro2", + "pyo3-build-config", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -491,9 +492,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -501,21 +502,19 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags", ] @@ -528,37 +527,37 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "safe_arch" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" dependencies = [ "bytemuck", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn", ] [[package]] @@ -576,26 +575,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -604,27 +592,27 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unindent" -version = "0.1.10" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ee9362deb4a96cef4d437d1ad49cffc9b9e92d202b6995674e928ce684f112" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" [[package]] name = "wasi" @@ -634,32 +622,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wide" -version = "0.7.8" +version = "0.7.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b689b6c49d6549434bf944e6b0f39238cf63693cb7a147e9d887507fffa3b223" +checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" dependencies = [ "bytemuck", "safe_arch", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -668,42 +648,69 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 7094549..f95b24f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ppca_rs" -version = "0.5.1" +version = "0.5.2" edition = "2021" publish = false @@ -14,10 +14,10 @@ crate-type = ["staticlib"] [dependencies] ppca = { path = "./ppca" } -pyo3 = { version = "0.18.3", features = ["extension-module"] } -numpy = { version = "0.18.0", features = ["nalgebra"] } +pyo3 = { version = "0.21.2", features = ["extension-module"] } +numpy = { version = "0.21.0", features = ["nalgebra"] } bincode = "1.3.3" rayon = "1.7.0" -nalgebra = "0.32.2" +nalgebra = "0.32.6" rand = "0.8.5" rand_distr = "0.4.3" diff --git a/ppca/Cargo.toml b/ppca/Cargo.toml index 4937fa3..b888597 100644 --- a/ppca/Cargo.toml +++ b/ppca/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ppca" -version = "0.5.0" +version = "0.5.2" edition = "2021" authors = ["Pedro Bittencourt Arruda "] description = "Rust implementation of the Probabilistic Principal Component Analysis model" @@ -22,12 +22,12 @@ categories = ["algorithms", "data-structures", "mathematics"] [dependencies] approx = "0.5.1" -bit-vec = { version = "0.6.3", features = ["serde"] } -nalgebra = { version = "0.32.2", features = ["serde-serialize"] } +bit-vec = { version = "0.8.0", features = ["serde"] } +nalgebra = { version = "0.32.6", features = ["serde-serialize"] } rand = "0.8.5" rand_distr = "0.4.3" rayon = "1.7.0" -ndarray = "0.15.6" +ndarray = "0.16.1" serde = { version = "1.0.160", features = ["rc"] } serde_derive = "1.0.160" -ordered-float = "3.6.0" +ordered-float = "4.2.2" diff --git a/ppca/src/dataset.rs b/ppca/src/dataset.rs index 68b1fd9..e0f8a15 100644 --- a/ppca/src/dataset.rs +++ b/ppca/src/dataset.rs @@ -193,7 +193,7 @@ impl Dataset { /// Lists the dimensions which as masked in __all__ samples in this dataset. pub fn empty_dimensions(&self) -> Vec { let Some(n_dimensions) = self.data.first().map(|sample| sample.mask().0.len()) else { - return vec![] + return vec![]; }; let new_mask = || BitVec::from_elem(n_dimensions, false); let poormans_or = |mut this: BitVec, other: &BitVec| { diff --git a/ppca/src/output_covariance.rs b/ppca/src/output_covariance.rs index ebd5868..be7399c 100644 --- a/ppca/src/output_covariance.rs +++ b/ppca/src/output_covariance.rs @@ -1,6 +1,7 @@ use nalgebra::{DMatrix, DVector}; use serde_derive::{Deserialize, Serialize}; use std::borrow::Cow; +use std::sync::OnceLock; use crate::utils::Mask; @@ -21,6 +22,18 @@ pub(crate) struct OutputCovariance<'a> { pub(crate) isotropic_noise: f64, /// The matrix mapping hidden state to output state, denoted as `C`. pub(crate) transform: Cow<'a, DMatrix>, + #[serde(default)] + #[serde(skip_serializing)] + #[serde(skip_deserializing)] + inner_product: OnceLock>, + #[serde(default)] + #[serde(skip_serializing)] + #[serde(skip_deserializing)] + inner_matrix: OnceLock>, + #[serde(default)] + #[serde(skip_serializing)] + #[serde(skip_deserializing)] + inner_inverse: OnceLock>, } impl<'a> OutputCovariance<'a> { @@ -31,6 +44,9 @@ impl<'a> OutputCovariance<'a> { OutputCovariance { isotropic_noise, transform: Cow::Owned(transform), + inner_product: OnceLock::new(), + inner_matrix: OnceLock::new(), + inner_inverse: OnceLock::new(), } } @@ -54,21 +70,34 @@ impl<'a> OutputCovariance<'a> { // + &*self.transform * self.transform.transpose() // } - pub(crate) fn inner_product(&self) -> DMatrix { + fn do_inner_product(&self) -> DMatrix { self.transform.transpose() * &*self.transform } - pub(crate) fn inner_matrix(&self) -> DMatrix { - DMatrix::identity(self.state_size(), self.state_size()) * self.isotropic_noise.powi(2) - + self.inner_product() + fn inner_product(&self) -> &DMatrix { + self.inner_product.get_or_init(|| self.do_inner_product()) } - pub(crate) fn inner_inverse(&self) -> DMatrix { + fn do_inner_matrix(&self) -> DMatrix { + DMatrix::identity(self.state_size(), self.state_size()) + + self.inner_product() / self.isotropic_noise.powi(2) + } + + fn inner_matrix(&self) -> &DMatrix { + self.inner_matrix.get_or_init(|| self.do_inner_matrix()) + } + + fn do_inner_inverse(&self) -> DMatrix { self.inner_matrix() + .clone() .try_inverse() .expect("inner matrix is always invertible") } + fn inner_inverse(&self) -> &DMatrix { + self.inner_inverse.get_or_init(|| self.do_inner_inverse()) + } + /// Calculates the linear transformation that estimates the hidden state from the /// observation. /// @@ -86,18 +115,21 @@ impl<'a> OutputCovariance<'a> { /// ``` /// C^T/sigma^2 - C^T*C/sigma^2*(I + C^T*C/sigma^2)^-1*C^T/sigma^2 /// ``` - /// Which can be calculated in `O(output_length * state_length^3)`. + /// Which can be calculated in `O(output_length * state_length^3)`. This can be futher simplified to + /// ``` + /// (I - C^T*C/sigma^2*(I + C^T*C/sigma^2)^-1) * C^T/sigma^2 + /// = ((I + C^T*C/sigma^2) - C^T*C/sigma^2) * (I + C^T*C/sigma^2)^-1 * C^T/sigma^2 + /// = (I + C^T*C/sigma^2)^-1 * C^T/sigma^2 + /// ``` + /// Which retains the same complexity, but uses fewer operations. pub(crate) fn estimator_transform(&self) -> DMatrix { - (self.transform.transpose() - - self.inner_product() * self.inner_inverse() * self.transform.transpose()) - / self.isotropic_noise.powi(2) + self.inner_inverse() * self.transform.transpose() / self.isotropic_noise.powi(2) } /// The covariance of the estimator that estimates hidden state from the observation. /// See `OutputCovariance.estimator_transform` for the explanation on the derivation. pub(crate) fn estimator_covariance(&self) -> DMatrix { - DMatrix::identity(self.state_size(), self.state_size()) - - self.estimator_transform() * &*self.transform + self.inner_inverse().clone() } /// Calculates the log of the determinant of the output covariance matrix form masked @@ -105,29 +137,19 @@ impl<'a> OutputCovariance<'a> { /// ``` /// det(I * sigma^2 + C * C^T) = det(I + C^T * C / sigma^2) * det(I * sigma^2) /// ``` - /// This can be simplified to - /// ``` - /// det(I * sigma^2 + C * C^T) = det(I * sigma^2 + C^T * C) - /// * sigma^(2 * (output_size - state_size)) - /// ``` /// The first `det` on the right side is the determinant of /// `OutputCovariance.inner_matrix`. pub(crate) fn covariance_log_det(&self) -> f64 { - // NOTE: not always `output_size > state_size`. self.inner_matrix().determinant().ln() - + self.isotropic_noise.ln() - * 2.0 - * (self.output_size() as f64 - self.state_size() as f64) + + self.isotropic_noise.ln() * 2.0 * (self.output_size() as f64) } pub(crate) fn masked(&self, mask: &Mask) -> OutputCovariance<'static> { assert_eq!(mask.0.len(), self.output_size()); - OutputCovariance { - isotropic_noise: self.isotropic_noise, - transform: Cow::Owned(DMatrix::from_rows( - &mask.filter(self.transform.row_iter()).collect::>(), - )), - } + OutputCovariance::new_owned( + self.isotropic_noise, + DMatrix::from_rows(&mask.filter(self.transform.row_iter()).collect::>()), + ) } pub(crate) fn quadratic_form(&self, x: &DVector) -> f64 { @@ -135,9 +157,9 @@ impl<'a> OutputCovariance<'a> { let transpose_transformed = self.transform.transpose() * x; (norm_squared - // this is a scalar. - (transpose_transformed.transpose() * self.inner_inverse() * transpose_transformed) - [(0, 0)]) + [(0, 0)] + / self.isotropic_noise.powi(2)) / self.isotropic_noise.powi(2) } } diff --git a/ppca/src/ppca_model.rs b/ppca/src/ppca_model.rs index 12b2d1b..5d22d3a 100644 --- a/ppca/src/ppca_model.rs +++ b/ppca/src/ppca_model.rs @@ -5,7 +5,6 @@ use rand::Rng; use rand_distr::Bernoulli; use rayon::prelude::*; use serde_derive::{Deserialize, Serialize}; -use std::borrow::Cow; use std::sync::Arc; use crate::dataset::{Dataset, MaskedSample}; @@ -61,10 +60,7 @@ impl PPCAModel { } PPCAModel(Arc::new(PPCAModelInner { - output_covariance: OutputCovariance { - isotropic_noise: 1.0, - transform: Cow::Owned(rand_transform), - }, + output_covariance: OutputCovariance::new_owned(1.0, rand_transform), mean: DVector::zeros(output_size), })) } @@ -384,10 +380,10 @@ impl PPCAModel { } PPCAModel(Arc::new(PPCAModelInner { - output_covariance: OutputCovariance { - transform: Cow::Owned(new_transform), - isotropic_noise: isotropic_noise_sq.sqrt(), - }, + output_covariance: OutputCovariance::new_owned( + isotropic_noise_sq.sqrt(), + new_transform, + ), mean: new_mean, })) } diff --git a/src/python_bindings.rs b/src/python_bindings.rs index 186cfea..a04e9a6 100644 --- a/src/python_bindings.rs +++ b/src/python_bindings.rs @@ -1,5 +1,8 @@ use nalgebra::DMatrix; -use numpy::{PyArray1, PyArray2, PyReadonlyArray1, PyReadonlyArray2, ToPyArray}; +use numpy::{ + PyArray1, PyArray2, PyArrayMethods, PyReadonlyArray1, PyReadonlyArray2, PyUntypedArrayMethods, + ToPyArray, +}; use pyo3::{prelude::*, types::PyBytes}; use rand_distr::Distribution; use rayon::prelude::*; @@ -13,7 +16,7 @@ use crate::utils::{to_nalgebra, to_nalgebra_vector}; /// This module is implemented in Rust. #[pymodule] -pub fn ppca_rs(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn ppca_rs(_py: Python<'_>, m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -64,21 +67,21 @@ impl DatasetWrapper { } #[staticmethod] - fn load(bytes: &PyBytes) -> PyResult { + fn load(bytes: &Bound) -> PyResult { Ok(DatasetWrapper( bincode::deserialize(bytes.as_bytes()) .map_err(|err| pyo3::exceptions::PyException::new_err(err.to_string()))?, )) } - fn dump<'a>(&self, py: Python<'a>) -> &'a PyBytes { - PyBytes::new( + fn dump<'a>(&self, py: Python<'a>) -> Bound<'a, PyBytes> { + PyBytes::new_bound( py, &bincode::serialize(&self.0).expect("can always serialize PPCA model"), ) } - fn numpy(&self, py: Python) -> Py> { + fn numpy<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray2> { let rows = py.allow_threads(|| { self.0 .data @@ -88,7 +91,7 @@ impl DatasetWrapper { }); let matrix = DMatrix::from_columns(&rows).transpose(); - matrix.to_pyarray(py).to_owned() + matrix.to_pyarray_bound(py) } fn __len__(&self) -> usize { @@ -103,8 +106,8 @@ impl DatasetWrapper { self.0.empty_dimensions() } - fn weights(&self, py: Python<'_>) -> Py> { - self.0.weights.to_pyarray(py).to_owned() + fn weights<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray1> { + self.0.weights.to_pyarray_bound(py) } fn chunks(slf: Py, py: Python, chunks: usize) -> DatasetChunks { @@ -208,9 +211,9 @@ struct InferredMaskedBatch { #[pymethods] impl InferredMaskedBatch { - fn states(&self, py: Python) -> Py> { + fn states<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray2> { if self.data.len() == 0 { - return DMatrix::::zeros(0, 0).to_pyarray(py).to_owned(); + return DMatrix::::zeros(0, 0).to_pyarray_bound(py); } let rows = py.allow_threads(|| { @@ -222,14 +225,14 @@ impl InferredMaskedBatch { .collect::>() }); let matrix = DMatrix::from_row_slice(self.data.len(), self.data[0].state().len(), &rows); - matrix.to_pyarray(py).to_owned() + matrix.to_pyarray_bound(py) } - fn covariances(&self, py: Python) -> Vec>> { + fn covariances<'a>(&self, py: Python<'a>) -> Vec>> { // No par iter for you because Python is not Sync. self.data .iter() - .map(|inferred| inferred.covariance().to_pyarray(py).to_owned()) + .map(|inferred| inferred.covariance().to_pyarray_bound(py)) .collect() } @@ -266,16 +269,15 @@ impl InferredMaskedBatch { DatasetWrapper(outputs) } - fn smoothed_covariances(&self, py: Python, ppca: &PPCAModelWrapper) -> Vec>> { + fn smoothed_covariances<'a>( + &self, + py: Python<'a>, + ppca: &PPCAModelWrapper, + ) -> Vec>> { // No par iter for you because Python is not Sync. self.data .iter() - .map(|inferred| { - inferred - .smoothed_covariance(&ppca.0) - .to_pyarray(py) - .to_owned() - }) + .map(|inferred| inferred.smoothed_covariance(&ppca.0).to_pyarray_bound(py)) .collect() } @@ -292,12 +294,12 @@ impl InferredMaskedBatch { DatasetWrapper(output_covariances_diagonal) } - fn extrapolated_covariances( + fn extrapolated_covariances<'a>( &self, - py: Python, + py: Python<'a>, ppca: &PPCAModelWrapper, dataset: &DatasetWrapper, - ) -> Vec>> { + ) -> Vec>> { // No par iter for you because Python is not Sync. self.data .iter() @@ -305,8 +307,7 @@ impl InferredMaskedBatch { .map(|(inferred, sample)| { inferred .extrapolated_covariance(&ppca.0, sample) - .to_pyarray(py) - .to_owned() + .to_pyarray_bound(py) }) .collect() } @@ -386,15 +387,15 @@ impl PPCAModelWrapper { } #[staticmethod] - fn load(bytes: &PyBytes) -> PyResult { + fn load(bytes: Bound) -> PyResult { Ok(PPCAModelWrapper( bincode::deserialize(bytes.as_bytes()) .map_err(|err| pyo3::exceptions::PyException::new_err(err.to_string()))?, )) } - fn dump<'a>(&self, py: Python<'a>) -> &'a PyBytes { - PyBytes::new( + fn dump<'a>(&self, py: Python<'a>) -> Bound<'a, PyBytes> { + PyBytes::new_bound( py, &bincode::serialize(&self.0).expect("can always serialize PPCA model"), ) @@ -416,18 +417,17 @@ impl PPCAModelWrapper { } #[getter] - fn singular_values(&self, py: Python<'_>) -> Py> { + fn singular_values<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray1> { self.0 .singular_values() - .to_pyarray(py) + .to_pyarray_bound(py) .reshape((self.0.state_size(),)) .expect("resizing is valid") - .to_owned() } #[getter] - fn transform(&self, py: Python<'_>) -> Py> { - self.0.transform().to_pyarray(py).to_owned() + fn transform<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray2> { + self.0.transform().to_pyarray_bound(py) } #[getter] @@ -436,14 +436,13 @@ impl PPCAModelWrapper { } #[getter] - fn mean(&self, py: Python<'_>) -> Py> { + fn mean<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray1> { self.0 .mean() .transpose() - .to_pyarray(py) + .to_pyarray_bound(py) .reshape((self.0.mean().len(),)) .expect("resizing is valid") - .to_owned() } #[staticmethod] @@ -467,12 +466,11 @@ impl PPCAModelWrapper { py.allow_threads(|| self.0.llk(&dataset.0)) } - fn llks(&self, py: Python<'_>, dataset: &DatasetWrapper) -> Py> { + fn llks<'a>(&self, py: Python<'a>, dataset: &DatasetWrapper) -> Bound<'a, PyArray1> { let llks = py.allow_threads(|| self.0.llks(&dataset.0)); - llks.to_pyarray(py) + llks.to_pyarray_bound(py) .reshape(llks.len()) .expect("can reshape") - .to_owned() } fn sample(&self, py: Python<'_>, dataset_size: usize, mask_prob: f64) -> DatasetWrapper { @@ -511,7 +509,7 @@ impl PPCAModelWrapper { } pub fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { - match state.extract::<&PyBytes>(py) { + match state.extract::>(py) { Ok(s) => { self.0 = PPCAModelWrapper::load(s)?.0; Ok(()) @@ -524,10 +522,10 @@ impl PPCAModelWrapper { Ok(self.dump(py).to_object(py)) } - pub fn __getnewargs__( + pub fn __getnewargs__<'a>( &self, - py: Python<'_>, - ) -> PyResult<(f64, Py>, Py>)> { + py: Python<'a>, + ) -> PyResult<(f64, Bound<'a, PyArray2>, Bound<'a, PyArray1>)> { Ok((self.isotropic_noise(), self.transform(py), self.mean(py))) } } @@ -569,15 +567,15 @@ impl PPCAMixWrapper { } #[staticmethod] - fn load(bytes: &PyBytes) -> PyResult { + fn load(bytes: Bound) -> PyResult { Ok(PPCAMixWrapper( bincode::deserialize(bytes.as_bytes()) .map_err(|err| pyo3::exceptions::PyException::new_err(err.to_string()))?, )) } - fn dump<'a>(&self, py: Python<'a>) -> &'a PyBytes { - PyBytes::new( + fn dump<'a>(&self, py: Python<'a>) -> Bound<'a, PyBytes> { + PyBytes::new_bound( py, &bincode::serialize(&self.0).expect("can always serialize PPCA model"), ) @@ -609,33 +607,30 @@ impl PPCAMixWrapper { } #[getter] - fn log_weights(&self, py: Python) -> Py> { + fn log_weights<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray1> { self.0 .log_weights() .clone() - .to_pyarray(py) + .to_pyarray_bound(py) .reshape(self.0.log_weights().len()) .expect("can reshape") - .to_owned() } #[getter] - fn weights(&self, py: Python) -> Py> { + fn weights<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray1> { self.0 .weights() .clone() - .to_pyarray(py) + .to_pyarray_bound(py) .reshape(self.0.log_weights().len()) .expect("can reshape") - .to_owned() } - pub fn llks(&self, py: Python, dataset: &DatasetWrapper) -> Py> { + pub fn llks<'a>(&self, py: Python<'a>, dataset: &DatasetWrapper) -> Bound<'a, PyArray1> { let llks = py.allow_threads(|| self.0.llks(&dataset.0)); - llks.to_pyarray(py) + llks.to_pyarray_bound(py) .reshape(llks.len()) .expect("can reshape") - .to_owned() } pub fn llk(&self, py: Python, dataset: &DatasetWrapper) -> f64 { @@ -651,10 +646,13 @@ impl PPCAMixWrapper { DatasetWrapper(py.allow_threads(|| self.0.sample(dataset_size, mask_probability))) } - pub fn infer_cluster(&self, py: Python, dataset: &DatasetWrapper) -> Py> { + fn infer_cluster<'a>( + &self, + py: Python<'a>, + dataset: &DatasetWrapper, + ) -> Bound<'a, PyArray2> { py.allow_threads(|| self.0.infer_cluster(&dataset.0)) - .to_pyarray(py) - .to_owned() + .to_pyarray_bound(py) } pub fn infer(&self, py: Python<'_>, dataset: &DatasetWrapper) -> InferredMaskedMixBatch { @@ -689,7 +687,7 @@ impl PPCAMixWrapper { } pub fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { - match state.extract::<&PyBytes>(py) { + match state.extract::>(py) { Ok(s) => { self.0 = PPCAMixWrapper::load(s)?.0; Ok(()) @@ -702,10 +700,10 @@ impl PPCAMixWrapper { Ok(self.dump(py).to_object(py)) } - pub fn __getnewargs__( + pub fn __getnewargs__<'a>( &self, - py: Python<'_>, - ) -> PyResult<(Vec, Py>)> { + py: Python<'a>, + ) -> PyResult<(Vec, Bound<'a, PyArray1>)> { Ok((self.models(), self.log_weights(py))) } } @@ -718,9 +716,9 @@ struct InferredMaskedMixBatch { #[pymethods] impl InferredMaskedMixBatch { - fn log_posteriors(&self, py: Python) -> Py> { + fn log_posteriors<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray2> { if self.data.len() == 0 { - return DMatrix::::zeros(0, 0).to_pyarray(py).to_owned(); + return DMatrix::::zeros(0, 0).to_pyarray_bound(py); } let rows = py.allow_threads(|| { @@ -731,12 +729,12 @@ impl InferredMaskedMixBatch { }); let matrix = DMatrix::from_row_slice(self.data.len(), self.data[0].log_posterior().len(), &rows); - matrix.to_pyarray(py).to_owned() + matrix.to_pyarray_bound(py) } - fn posteriors(&self, py: Python) -> Py> { + fn posteriors<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray2> { if self.data.len() == 0 { - return DMatrix::::zeros(0, 0).to_pyarray(py).to_owned(); + return DMatrix::::zeros(0, 0).to_pyarray_bound(py); } let rows = py.allow_threads(|| { @@ -747,12 +745,12 @@ impl InferredMaskedMixBatch { }); let matrix = DMatrix::from_row_slice(self.data.len(), self.data[0].log_posterior().len(), &rows); - matrix.to_pyarray(py).to_owned() + matrix.to_pyarray_bound(py) } - fn states(&self, py: Python) -> Py> { + fn states<'a>(&self, py: Python<'a>) -> Bound<'a, PyArray2> { if self.data.len() == 0 { - return DMatrix::::zeros(0, 0).to_pyarray(py).to_owned(); + return DMatrix::::zeros(0, 0).to_pyarray_bound(py); } let rows = py.allow_threads(|| { @@ -762,14 +760,14 @@ impl InferredMaskedMixBatch { .collect::>() }); let matrix = DMatrix::from_row_slice(self.data.len(), self.data[0].state().len(), &rows); - matrix.to_pyarray(py).to_owned() + matrix.to_pyarray_bound(py) } - fn covariances(&self, py: Python) -> Vec>> { + fn covariances<'a>(&self, py: Python<'a>) -> Vec>> { // No par iter for you because Python is not Sync. self.data .iter() - .map(|inferred| inferred.covariance().to_pyarray(py).to_owned()) + .map(|inferred| inferred.covariance().to_pyarray_bound(py)) .collect() } @@ -806,16 +804,15 @@ impl InferredMaskedMixBatch { DatasetWrapper(outputs) } - fn smoothed_covariances(&self, py: Python, ppca: &PPCAMixWrapper) -> Vec>> { + fn smoothed_covariances<'a>( + &self, + py: Python<'a>, + ppca: &PPCAMixWrapper, + ) -> Vec>> { // No par iter for you because Python is not Sync. self.data .iter() - .map(|inferred| { - inferred - .smoothed_covariance(&ppca.0) - .to_pyarray(py) - .to_owned() - }) + .map(|inferred| inferred.smoothed_covariance(&ppca.0).to_pyarray_bound(py)) .collect() } @@ -832,12 +829,12 @@ impl InferredMaskedMixBatch { DatasetWrapper(output_covariances_diagonal) } - fn extrapolated_covariances( + fn extrapolated_covariances<'a>( &self, - py: Python, + py: Python<'a>, ppca: &PPCAMixWrapper, dataset: &DatasetWrapper, - ) -> Vec>> { + ) -> Vec>> { // No par iter for you because Python is not Sync. self.data .iter() @@ -845,8 +842,7 @@ impl InferredMaskedMixBatch { .map(|(inferred, sample)| { inferred .extrapolated_covariance(&ppca.0, sample) - .to_pyarray(py) - .to_owned() + .to_pyarray_bound(py) }) .collect() } diff --git a/src/utils.rs b/src/utils.rs index 3da59d1..8c719fa 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,14 +1,14 @@ use nalgebra::{DMatrix, DVector}; -use numpy::PyArray2; +use numpy::{PyArray2, PyArrayMethods}; use pyo3::{Py, Python}; pub(crate) fn to_nalgebra(py: Python, x: Py>) -> DMatrix { - let array = x.as_ref(py).to_owned_array(); + let array = x.bind(py).to_owned_array(); DMatrix::from_fn(array.nrows(), array.ncols(), |i, j| array[[i, j]]) } pub(crate) fn to_nalgebra_vector(py: Python, x: Py>) -> DVector { - let array = x.as_ref(py).to_owned_array(); + let array = x.bind(py).to_owned_array(); if array.nrows() == 1 { DVector::from_fn(array.ncols(), |i, _| array[[0, i]]) } else if array.ncols() == 1 {