From a03fedcc222f2b43cc60bf1d0cfc3d873c20e8f0 Mon Sep 17 00:00:00 2001 From: BeGeiger Date: Wed, 3 Jan 2024 06:57:39 -0500 Subject: [PATCH 1/5] update dependencies --- poetry.lock | 148 +++++++++++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 65 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7214f96..a94baf8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -701,70 +701,88 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] [[package]] name = "pillow" -version = "10.1.0" +version = "10.2.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, - {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, - {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, - {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, - {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, - {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, - {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, - {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, + {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, + {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, + {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, + {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, + {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, + {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, + {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, + {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, + {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, + {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, + {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, + {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, + {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, + {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, + {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, + {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, ] [package.extras] docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "platformdirs" @@ -867,13 +885,13 @@ testing = ["covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytes [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -1062,17 +1080,17 @@ test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeo [[package]] name = "seaborn" -version = "0.13.0" +version = "0.13.1" description = "Statistical data visualization" optional = false python-versions = ">=3.8" files = [ - {file = "seaborn-0.13.0-py3-none-any.whl", hash = "sha256:70d740828c48de0f402bb17234e475eda687e3c65f4383ea25d0cc4728f7772e"}, - {file = "seaborn-0.13.0.tar.gz", hash = "sha256:0e76abd2ec291c655b516703c6a022f0fd5afed26c8e714e8baef48150f73598"}, + {file = "seaborn-0.13.1-py3-none-any.whl", hash = "sha256:6baa69b6d1169ae59037971491c450c0b73332b42bd4b23570b62a546bc61cb8"}, + {file = "seaborn-0.13.1.tar.gz", hash = "sha256:bfad65e9c5989e5e1897e61bdbd2f22e62455940ca76fd49eca3ed69345b9179"}, ] [package.dependencies] -matplotlib = ">=3.3,<3.6.1 || >3.6.1" +matplotlib = ">=3.4,<3.6.1 || >3.6.1" numpy = ">=1.20,<1.24.0 || >1.24.0" pandas = ">=1.2" @@ -1083,13 +1101,13 @@ stats = ["scipy (>=1.7)", "statsmodels (>=0.12)"] [[package]] name = "setuptools" -version = "69.0.2" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] From 7c5ac5db95eb8aa36b484259381482d0fdb67828 Mon Sep 17 00:00:00 2001 From: BeGeiger Date: Wed, 3 Jan 2024 06:57:53 -0500 Subject: [PATCH 2/5] improve doc --- src/salamander/nmf_framework/corrnmf.py | 36 ++++++++----------- src/salamander/nmf_framework/corrnmf_det.py | 10 +++--- src/salamander/nmf_framework/klnmf.py | 8 +++-- src/salamander/nmf_framework/nmf.py | 21 ++++++----- src/salamander/nmf_framework/signature_nmf.py | 19 ++++++---- 5 files changed, 46 insertions(+), 48 deletions(-) diff --git a/src/salamander/nmf_framework/corrnmf.py b/src/salamander/nmf_framework/corrnmf.py index 8c1aa0a..f0258f5 100644 --- a/src/salamander/nmf_framework/corrnmf.py +++ b/src/salamander/nmf_framework/corrnmf.py @@ -16,11 +16,10 @@ class CorrNMF(SignatureNMF): r""" The abstract class CorrNMF unifies the structure of deterministic and - stochastic correlated NMF (CorrNMF) with and without given signatures. - Both variants of CorrNMF have an identical generative model and objective function. - The model parameters are the sample biases \alpha, variance \sigma^2, - signature matrix W and the auxiliary parameters p. - The latent variables are the signature embeddings L and the sample embeddings U. + stochastic algorithms to fit the parameters of correlated NMF (CorrNMF). + + The model parameters are the signature and sample biases, the variance, and the + signature matrix. The latent variables are the signature and sample embeddings. Overview: @@ -48,12 +47,10 @@ class CorrNMF(SignatureNMF): update a single sample embedding u - fit: - Run CorrNMF for a given mutation count data. Every - fit method should also implement a version that allows fixing - arbitrary many a priori known signatures. + Run CorrNMF for a given mutation count data. - The following attributes are implemented in the abstract class CNMF: + The following attributes are implemented in CorrNMF: - signatures: pd.DataFrame The signature matrix including mutation type names and signature names @@ -73,10 +70,7 @@ class CorrNMF(SignatureNMF): The number of parameters fitted in CorrNMF - objective: str - "minimize" or "maximize". Whether the NMF algorithm maximizes - or minimizes the objective function. Some algorithms maximize a likelihood, - others minimize a distance. The distinction is useful for filtering NMF - runs based on the fitted objective function value. + "minimize" or "maximize". CorrNMF maximizes the objective function. - corr_signatures: pd.DataFrame The signature correlation matrix induced by the signature embeddings @@ -85,7 +79,7 @@ class CorrNMF(SignatureNMF): The sample correlation matrix induced by the sample embeddings - The following methods are implemented in the abstract class CorrNMF: + The following methods are implemented in CorrNMF: - objective_function: The evidence lower bound (ELBO) of the log-likelihood. @@ -103,12 +97,12 @@ class CorrNMF(SignatureNMF): Initialize all model parameters and latent variables depending on the initialization method chosen - - _get_embedding_annotations: - A helper function to concatenate signature and sample names + - _get_embedding_data: + A helper function for the embedding plot that returns the signature + and sample embeddings - - plot_embeddings: - Plot signature or sample embeddings in 2D using PCA, tSNE or UMAP. - The respective plotting functions are implemented in the plot.py module + - _get_default_embedding_annotations: + A helper function for the embedding plot that returns the signature names More specific docstrings are written for the respective attributes and methods. """ @@ -207,10 +201,8 @@ def _n_parameters(self): """ There are n_features * n_signatures parameters corresponding to the signature matrix, each embedding corresponds to dim_embeddings parameters, - and each signature & sample has a bias. + and each signature & sample has a real valued bias. Finally, the model variance is a single positive real number. - - Note: We do not include the number of auxiliary parameters p. """ n_parameters_signatures = self.n_features * self.n_signatures n_parameters_embeddings = self.dim_embeddings * ( diff --git a/src/salamander/nmf_framework/corrnmf_det.py b/src/salamander/nmf_framework/corrnmf_det.py index f45b185..2ad6a2b 100644 --- a/src/salamander/nmf_framework/corrnmf_det.py +++ b/src/salamander/nmf_framework/corrnmf_det.py @@ -20,17 +20,16 @@ class CorrNMFDet(CorrNMF): "Bayesian Nonnegative Matrix Factorization with Stochastic Variational Inference" by Paisley et al. - The following methods are implemented to match the structure - of the abstract class CorrNMF: + The following methods are implemented to match the structure of CorrNMF: - _update_alpha: - update the sample exposure biases \alpha + update the sample biases \alpha - _update_beta: update the signature biases \beta - _update_sigma_sq: - update the variance \sigma^2 assumed in the generative model + update the variance \sigma^2 - _update_W: update the signature matrix W @@ -47,8 +46,7 @@ class CorrNMFDet(CorrNMF): The following method is implemented to match the structure of SignatureNMF: - fit: - Perform CorrNMF for the given mutation count data or - for given signatures and mutation count data + Inference of the CorrNMF parameters for a given mutation count data """ def _update_alpha(self, given_sample_biases=None): diff --git a/src/salamander/nmf_framework/klnmf.py b/src/salamander/nmf_framework/klnmf.py index 57eabc1..0ce4fc1 100644 --- a/src/salamander/nmf_framework/klnmf.py +++ b/src/salamander/nmf_framework/klnmf.py @@ -11,9 +11,11 @@ class KLNMF(NMF): """ Decompose a mutation count matrix X into the product of a signature - matrix W and an exposure matrix H by minimizing the generalized - Kullback-Leibler (KL) divergence under the constraint of having - normalized signatures. + matrix W and an exposure matrix H by minimizing the weighted + generalized Kullback-Leibler (KL) divergence under the constraint of + having normalized signatures. + The implementation supports a sparstiy-inducing l_half penalty of the + exposures. Parameters ---------- diff --git a/src/salamander/nmf_framework/nmf.py b/src/salamander/nmf_framework/nmf.py index f5dc04d..b0c3d4a 100644 --- a/src/salamander/nmf_framework/nmf.py +++ b/src/salamander/nmf_framework/nmf.py @@ -69,7 +69,7 @@ class NMF(SignatureNMF): The exposure matrix including the signature names and sample names - _n_parameters: - The number of parameters fitted + The number of parameters of models with signature and exposure matrices - corr_signatures: pd.DataFrame The signature correlation matrix induced by their sample exposures @@ -80,18 +80,17 @@ class NMF(SignatureNMF): The following methods are implemented in the abstract class NMF: - - initialize: - Initialize all model parameters and latent variables depending on the - initialization method chosen + - _initialize: + Initialize all model parameters - - _get_embedding_annotations: - A helper function to get the sample names for the embedding plots + - _get_embedding_data: + A helper function for the embedding plot. Models with signature and + exposure matrices use the exposures as the lower-dimensional + representation of the samples - - plot_embeddings: - Plot signature or sample embeddings in 2D using PCA, tSNE or UMAP. - The respective plotting functions are implemented in the plot.py module. - - More details are explained in the respective attributes and methods. + - _get_default_embedding_annotations: + A helper function for the embedding plot. By default, no samples are + annotated """ def __init__( diff --git a/src/salamander/nmf_framework/signature_nmf.py b/src/salamander/nmf_framework/signature_nmf.py index 9a96158..54e13c5 100644 --- a/src/salamander/nmf_framework/signature_nmf.py +++ b/src/salamander/nmf_framework/signature_nmf.py @@ -73,8 +73,11 @@ class SignatureNMF(ABC): fit method should also implement a version that allows fixing arbitrary many a priori known signatures. - - plot_embeddings: - Plot the sample (and potentially the signature) embeddings in 2D. + - _get_embedding_data: + A helper function for the embedding plot + + - _get_default_embedding_annotations: + A helper function for the embedding plot The following attributes and methods are implemented in SignatureNMF: @@ -90,9 +93,11 @@ class SignatureNMF(ABC): - bic: float The value of the Bayesian Information Criterion (BIC) - - _setup_parameters_fitting: - Perform parameter checks and add the input mutation counts matrix - as an attributes + - _setup_data_parameters: + Perform parameter checks on the input data and add attributes + + - plot_history: + Plot the history of the objective function values after fitting the model - plot_signatures: Plot the signatures using the signatures_plot function implemented in @@ -102,7 +107,9 @@ class SignatureNMF(ABC): Plot the correlation of either the signatures or exposures using the corr_plot function implemented in the plot module - More specific docstrings are written for the respective attributes and methods. + - plot_embeddings: + Plot the sample (and potentially the signature) embeddings in 2D + using PCA, tSNE or UMAP """ def __init__( From 194f47b7e694a443fd6f0c1c78d21f1064d2f850 Mon Sep 17 00:00:00 2001 From: BeGeiger Date: Wed, 3 Jan 2024 06:58:38 -0500 Subject: [PATCH 3/5] improve order --- src/salamander/nmf_framework/corrnmf.py | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/salamander/nmf_framework/corrnmf.py b/src/salamander/nmf_framework/corrnmf.py index f0258f5..5c698aa 100644 --- a/src/salamander/nmf_framework/corrnmf.py +++ b/src/salamander/nmf_framework/corrnmf.py @@ -196,24 +196,6 @@ def exposures(self) -> pd.DataFrame: ) return exposures - @property - def _n_parameters(self): - """ - There are n_features * n_signatures parameters corresponding to - the signature matrix, each embedding corresponds to dim_embeddings parameters, - and each signature & sample has a real valued bias. - Finally, the model variance is a single positive real number. - """ - n_parameters_signatures = self.n_features * self.n_signatures - n_parameters_embeddings = self.dim_embeddings * ( - self.n_signatures + self.n_samples - ) - n_parameters_biases = self.n_samples + self.n_signatures - n_parameters_exposures = n_parameters_embeddings + n_parameters_biases - n_parameters = n_parameters_signatures + n_parameters_exposures + 1 - - return n_parameters - @property def reconstruction_error(self): return kl_divergence(self.X, self.W, self.exposures.values) @@ -282,6 +264,24 @@ def _surrogate_objective_function(self, penalize_sample_embeddings=True) -> floa def loglikelihood(self): return self.objective_function() + @property + def _n_parameters(self): + """ + There are n_features * n_signatures parameters corresponding to + the signature matrix, each embedding corresponds to dim_embeddings parameters, + and each signature & sample has a real valued bias. + Finally, the model variance is a single positive real number. + """ + n_parameters_signatures = self.n_features * self.n_signatures + n_parameters_embeddings = self.dim_embeddings * ( + self.n_signatures + self.n_samples + ) + n_parameters_biases = self.n_samples + self.n_signatures + n_parameters_exposures = n_parameters_embeddings + n_parameters_biases + n_parameters = n_parameters_signatures + n_parameters_exposures + 1 + + return n_parameters + @abstractmethod def _update_alpha(self): pass From 259d1b8a68c2648bf411150b577e08335d3b3063 Mon Sep 17 00:00:00 2001 From: BeGeiger Date: Wed, 3 Jan 2024 11:04:03 -0500 Subject: [PATCH 4/5] fix given parameters the model variance of CorrNMF models can now also be fixed during model training --- src/salamander/nmf_framework/corrnmf.py | 23 +++++++++++--- src/salamander/nmf_framework/corrnmf_det.py | 18 +++++++---- .../nmf_framework/multimodal_corrnmf.py | 30 ++++++++++++------- tests/test_corrnmf.py | 5 ++++ tests/test_multimodal_corrnmf.py | 10 ++++++- 5 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/salamander/nmf_framework/corrnmf.py b/src/salamander/nmf_framework/corrnmf.py index 5c698aa..f399f84 100644 --- a/src/salamander/nmf_framework/corrnmf.py +++ b/src/salamander/nmf_framework/corrnmf.py @@ -355,6 +355,7 @@ def _check_given_parameters( given_signature_embeddings, given_sample_biases, given_sample_embeddings, + given_variance, ): if given_signatures is not None: self._check_given_signatures(given_signatures) @@ -381,6 +382,11 @@ def _check_given_parameters( given_sample_embeddings, self.n_samples, "given_sample_embeddings" ) + if given_variance is not None: + type_checker("given_variance", given_variance, [float, int]) + if given_variance <= 0.0: + raise ValueError("The variance has to be a positive real number.") + def _initialize( self, given_signatures=None, @@ -388,11 +394,12 @@ def _initialize( given_signature_embeddings=None, given_sample_biases=None, given_sample_embeddings=None, + given_variance=None, init_kwargs=None, ): """ Initialize the signature matrix W, sample biases alpha, signature biases beta, - the squared variance, and the signature and sample embeddings. + the variance, and the signature and sample embeddings. The signatures or signature embeddings can also be provided by the user. Parameters @@ -417,6 +424,9 @@ def _initialize( given_sample_embeddings : np.ndarray, default=None A priori known sample embeddings of shape (dim_embeddings, n_samples). + given_variance : float, default=None + A priori known model variance of the embeddings. + init_kwargs : dict Any further keyword arguments to pass to the initialization method. This includes, for example, a possible 'seed' keyword argument @@ -428,6 +438,7 @@ def _initialize( given_signature_embeddings, given_sample_biases, given_sample_embeddings, + given_variance, ) if given_signatures is not None: @@ -439,7 +450,11 @@ def _initialize( self.W, _, self.signature_names = initialize( self.X, self.n_signatures, self.init_method, given_signatures, **init_kwargs ) - self.sigma_sq = 1.0 + + if given_variance is None: + self.sigma_sq = 1.0 + else: + self.sigma_sq = float(given_variance) if given_signature_biases is None: self.beta = np.zeros(self.n_signatures) @@ -449,7 +464,7 @@ def _initialize( if given_signature_embeddings is None: self.L = np.random.multivariate_normal( np.zeros(self.dim_embeddings), - np.identity(self.dim_embeddings), + self.sigma_sq * np.identity(self.dim_embeddings), size=self.n_signatures, ).T else: @@ -463,7 +478,7 @@ def _initialize( if given_sample_embeddings is None: self.U = np.random.multivariate_normal( np.zeros(self.dim_embeddings), - np.identity(self.dim_embeddings), + self.sigma_sq * np.identity(self.dim_embeddings), size=self.n_samples, ).T else: diff --git a/src/salamander/nmf_framework/corrnmf_det.py b/src/salamander/nmf_framework/corrnmf_det.py index 2ad6a2b..3eda6f9 100644 --- a/src/salamander/nmf_framework/corrnmf_det.py +++ b/src/salamander/nmf_framework/corrnmf_det.py @@ -59,10 +59,11 @@ def _update_beta(self, p, given_signature_biases=None): self.X, p, self.alpha, self.L, self.U ) - def _update_sigma_sq(self): - embeddings = np.concatenate([self.L, self.U], axis=1) - self.sigma_sq = np.mean(embeddings**2) - self.sigma_sq = np.clip(self.sigma_sq, EPSILON, None) + def _update_sigma_sq(self, given_variance=None): + if given_variance is None: + embeddings = np.concatenate([self.L, self.U], axis=1) + self.sigma_sq = np.mean(embeddings**2) + self.sigma_sq = np.clip(self.sigma_sq, EPSILON, None) def _update_W(self): self.W = update_W( @@ -191,6 +192,7 @@ def fit( given_signature_embeddings=None, given_sample_biases=None, given_sample_embeddings=None, + given_variance=None, init_kwargs=None, history=False, verbose=0, @@ -217,9 +219,12 @@ def fit( Known sample biases of shape (n_samples,) that will be fixed during model fitting. - given_sample_embeddings: np.ndarray, default=None + given_sample_embeddings : np.ndarray, default=None Known sample embeddings that will be fixed during model fitting. + given_variance : float, default=None + Known model variance that will be fixed during model fitting. + init_kwargs: dict Any further keywords arguments to be passed to the initialization method. This includes, for example, a possible 'seed' keyword argument @@ -244,6 +249,7 @@ def fit( given_signature_embeddings=given_signature_embeddings, given_sample_biases=given_sample_biases, given_sample_embeddings=given_sample_embeddings, + given_variance=given_variance, init_kwargs=init_kwargs, ) of_values = [self.objective_function()] @@ -260,7 +266,7 @@ def fit( p = self._update_p() self._update_beta(p, given_signature_biases) self._update_LU(p, given_signature_embeddings, given_sample_embeddings) - self._update_sigma_sq() + self._update_sigma_sq(given_variance) if self.n_given_signatures < self.n_signatures: self._update_W() diff --git a/src/salamander/nmf_framework/multimodal_corrnmf.py b/src/salamander/nmf_framework/multimodal_corrnmf.py index 3b90573..cdf2f56 100755 --- a/src/salamander/nmf_framework/multimodal_corrnmf.py +++ b/src/salamander/nmf_framework/multimodal_corrnmf.py @@ -187,14 +187,15 @@ def _update_betas(self, ps, given_signature_biases): for model, p, given_sig_biases in zip(self.models, ps, given_signature_biases): model._update_beta(p, given_sig_biases) - def _update_sigma_sq(self): - Ls = np.concatenate([model.L for model in self.models], axis=1) - embeddings = np.concatenate([Ls, self.models[0].U], axis=1) - sigma_sq = np.mean(embeddings**2) - sigma_sq = np.clip(sigma_sq, EPSILON, None) + def _update_sigma_sq(self, given_variance): + if given_variance is None: + Ls = np.concatenate([model.L for model in self.models], axis=1) + embeddings = np.concatenate([Ls, self.models[0].U], axis=1) + sigma_sq = np.mean(embeddings**2) + sigma_sq = np.clip(sigma_sq, EPSILON, None) - for model in self.models: - model.sigma_sq = sigma_sq + for model in self.models: + model.sigma_sq = sigma_sq def _update_Ws(self): for model in self.models: @@ -351,11 +352,17 @@ def _initialize( given_signature_embeddings=None, given_sample_biases=None, given_sample_embeddings=None, + given_variance=None, init_kwargs=None, ): if given_signatures is None: given_signatures = [None for _ in range(self.n_modalities)] + if given_variance is None: + variance = 1.0 + else: + variance = given_variance + if given_signature_biases is None: given_signature_biases = [None for _ in range(self.n_modalities)] @@ -368,7 +375,7 @@ def _initialize( if given_sample_embeddings is None: U = np.random.multivariate_normal( np.zeros(self.dim_embeddings), - np.identity(self.dim_embeddings), + variance * np.identity(self.dim_embeddings), size=self.n_samples, ).T else: @@ -395,6 +402,7 @@ def _initialize( given_signature_embeddings=given_sig_embs, given_sample_biases=given_sam_biases, given_sample_embeddings=U, + given_variance=variance, init_kwargs=init_kwargs, ) model.signature_names = np.concatenate( @@ -410,7 +418,6 @@ def _initialize( given_signature_biases, given_signature_embeddings, given_sample_biases, - given_sample_embeddings, ) def fit( @@ -421,6 +428,7 @@ def fit( given_signature_embeddings=None, given_sample_biases=None, given_sample_embeddings=None, + given_variance=None, init_kwargs=None, history=False, verbose=0, @@ -430,13 +438,13 @@ def fit( given_signature_biases, given_signature_embeddings, given_sample_biases, - given_sample_embeddings, ) = self._initialize( given_signatures=given_signatures, given_signature_biases=given_signature_biases, given_signature_embeddings=given_signature_embeddings, given_sample_biases=given_sample_biases, given_sample_embeddings=given_sample_embeddings, + given_variance=given_variance, init_kwargs=init_kwargs, ) of_values = [self.objective_function()] @@ -453,7 +461,7 @@ def fit( ps = self._update_ps() self._update_betas(ps, given_signature_biases) self._update_LsU(ps, given_signature_embeddings, given_sample_embeddings) - self._update_sigma_sq() + self._update_sigma_sq(given_variance) self._update_Ws() if n_iteration % self.conv_test_freq == 0: diff --git a/tests/test_corrnmf.py b/tests/test_corrnmf.py index 2dad2f4..481c9d7 100644 --- a/tests/test_corrnmf.py +++ b/tests/test_corrnmf.py @@ -214,3 +214,8 @@ def test_given_sample_embeddings(self, model, counts): ) model.fit(counts, given_sample_embeddings=given_sample_embeddings) assert np.allclose(given_sample_embeddings, model.U) + + def test_given_variance(self, model, counts): + given_variance = 3 + model.fit(counts, given_variance=given_variance) + assert np.allclose(given_variance, model.sigma_sq) diff --git a/tests/test_multimodal_corrnmf.py b/tests/test_multimodal_corrnmf.py index 6d08611..185a0d7 100644 --- a/tests/test_multimodal_corrnmf.py +++ b/tests/test_multimodal_corrnmf.py @@ -239,7 +239,8 @@ def test_update_U(self, multi_model_init, _auxs, U_updated): assert np.allclose(model.U, U_updated) def test_update_sigma_sq(self, multi_model_init, sigma_sq_updated): - multi_model_init._update_sigma_sq() + given_variance = None + multi_model_init._update_sigma_sq(given_variance) for model in multi_model_init.models: assert np.allclose(model.sigma_sq, sigma_sq_updated) @@ -313,3 +314,10 @@ def test_given_sample_embeddings(self, multi_model, counts): for model in multi_model.models: assert np.allclose(given_sample_embeddings, model.U) + + def test_given_variance(self, multi_model, counts): + given_variance = 3 + multi_model.fit(counts, given_variance=given_variance) + + for model in multi_model.models: + assert np.allclose(given_variance, model.sigma_sq) From d4bd71f4f50971d049cfd3085a8ab5d7e323757c Mon Sep 17 00:00:00 2001 From: BeGeiger Date: Wed, 3 Jan 2024 11:06:58 -0500 Subject: [PATCH 5/5] bump version --- CHANGELOG.md | 8 ++++++-- pyproject.toml | 2 +- src/salamander/__init__.py | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f67f4b..788e7a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- --- +## 0.3.2 - 2024-01 +### Fixed + - Support fixing the model variance of (multimodal) CorrNMF models during training + ## 0.3.1 - 2023-12 ### Fixed - Improve signature, history and embedding plots @@ -16,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Support a sample-weigted KL-divergence loss in KL-NMF - Support a sample-weighted sparsity regularization in KL-NMF - - Support fixing signature and sample biases in (multimodal) CorrNMF during inference + - Support fixing signature and sample biases of (multimodal) CorrNMF models during training ## 0.2.1 - 2023-10 ### Fixed @@ -25,7 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.2.0 - 2023-10 ### Added - - Support fixing arbitrary many a priori known signatures during inference + - Support fixing arbitrary many a priori known signatures during model training - Improved performance with just-in-time compiled update rules ## 0.1.0 - 2023-10 diff --git a/pyproject.toml b/pyproject.toml index 98a23a9..1872680 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "salamander-learn" -version = "0.3.1" +version = "0.3.2" description = "Salamander is a non-negative matrix factorization framework for signature analysis" license = "MIT" authors = ["Benedikt Geiger"] diff --git a/src/salamander/__init__.py b/src/salamander/__init__.py index 8198b35..59d4511 100644 --- a/src/salamander/__init__.py +++ b/src/salamander/__init__.py @@ -8,7 +8,7 @@ from .nmf_framework.mvnmf import MvNMF from .plot import set_salamander_style -__version__ = "0.3.1" +__version__ = "0.3.2" __all__ = ["CorrNMFDet", "KLNMF", "MvNMF", "MultimodalCorrNMF"]