diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index f8fdc4f..9afaad4 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -1,49 +1,29 @@
-# This is a basic workflow to help you get started with Actions
-
name: Check code style
-# Controls when the workflow will run
on:
- # Triggers the workflow on push or pull request events
[ push, pull_request ]
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
- # This workflow contains a single job called "Check_code_style"
Check_code_style:
-
- # The type of runner that the job will run on
- runs-on: ubuntu-latest
-
- # A strategy creates a build matrix for your jobs
+ runs-on: ubuntu-18.04
strategy:
-
- # You can define a matrix of different job configurations
matrix:
-
- # Each option you define in the matrix has a key and value
python-version: [ 3.8 ]
-
- # Steps represent a sequence of tasks that will be executed as part of the job
steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Set up Git repository
uses: actions/checkout@v2
- # Setup Python with version from matrix
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- # Install pre-commit
- name: Install pre-commit
run: |
python -m pip install pre-commit==2.15.0
pre-commit install
- # Run pre-commit on all the files in the repo
- name: Run pre-commit
run: |
pre-commit run --all-files --color always --verbose --show-diff-on-failure
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..ca13504
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,28 @@
+name: Test
+
+on: [ push, pull_request ]
+
+jobs:
+ tests:
+ runs-on: ubuntu-18.04
+ strategy:
+ matrix:
+ python-version: [ "3.8" ]
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install packages
+ run: |
+ python -m pip install --upgrade pip wheel setuptools
+ python -m pip install .
+ python -m pip install -r requirements/test.txt
+ python -m pip list
+
+ - name: Test Genegram
+ run: |
+ pytest -vv -s tests
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 74514e6..39591c6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -6,6 +6,6 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
- rev: 20.8b1
+ rev: 22.3.0
hooks:
- id: black
diff --git a/Pipfile b/Pipfile
deleted file mode 100644
index 051ba01..0000000
--- a/Pipfile
+++ /dev/null
@@ -1,18 +0,0 @@
-[[source]]
-url = "https://pypi.org/simple"
-verify_ssl = true
-name = "pypi"
-
-[packages]
-tensorflow = "*"
-pillow = "*"
-cfpq-data = "==2.0.0"
-pyformlang = "*"
-pygraphblas = "*"
-
-[dev-packages]
-pre-commit = "*"
-black = "*"
-
-[requires]
-python_version = "3.8"
diff --git a/Pipfile.lock b/Pipfile.lock
deleted file mode 100644
index 40887d2..0000000
--- a/Pipfile.lock
+++ /dev/null
@@ -1,1107 +0,0 @@
-{
- "_meta": {
- "hash": {
- "sha256": "64395db63eff600d49e3acc49e9108f8c1beb9d99924c83b5f235432b6ec5487"
- },
- "pipfile-spec": 6,
- "requires": {
- "python_version": "3.8"
- },
- "sources": [
- {
- "name": "pypi",
- "url": "https://pypi.org/simple",
- "verify_ssl": true
- }
- ]
- },
- "default": {
- "absl-py": {
- "hashes": [
- "sha256:84e6dcdc69c947d0c13e5457d056bd43cade4c2393dce00d684aedea77ddc2a3",
- "sha256:ac511215c01ee9ae47b19716599e8ccfa746f2e18de72bdf641b79b22afa27ea"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.0.0"
- },
- "astunparse": {
- "hashes": [
- "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872",
- "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"
- ],
- "version": "==1.6.3"
- },
- "cachetools": {
- "hashes": [
- "sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693",
- "sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1"
- ],
- "markers": "python_version ~= '3.5'",
- "version": "==4.2.4"
- },
- "certifi": {
- "hashes": [
- "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
- "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
- ],
- "version": "==2021.10.8"
- },
- "cffi": {
- "hashes": [
- "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3",
- "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2",
- "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636",
- "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20",
- "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728",
- "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27",
- "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66",
- "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443",
- "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0",
- "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7",
- "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39",
- "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605",
- "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a",
- "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37",
- "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029",
- "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139",
- "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc",
- "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df",
- "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14",
- "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880",
- "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2",
- "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a",
- "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e",
- "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474",
- "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024",
- "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8",
- "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0",
- "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e",
- "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a",
- "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e",
- "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032",
- "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6",
- "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e",
- "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b",
- "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e",
- "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954",
- "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962",
- "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c",
- "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4",
- "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55",
- "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962",
- "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023",
- "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c",
- "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6",
- "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8",
- "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382",
- "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7",
- "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc",
- "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997",
- "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"
- ],
- "version": "==1.15.0"
- },
- "cfpq-data": {
- "hashes": [
- "sha256:404e9f22244ecb92deec122f8d00210542b252723d07ed70617a7e7a2f4d88d0",
- "sha256:c655e34172fb9a851a4927d7ca24327807e24e283731624c956179c58ffc5483"
- ],
- "index": "pypi",
- "version": "==2.0.0"
- },
- "charset-normalizer": {
- "hashes": [
- "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0",
- "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"
- ],
- "markers": "python_version >= '3'",
- "version": "==2.0.7"
- },
- "contextvars": {
- "hashes": [
- "sha256:f38c908aaa59c14335eeea12abea5f443646216c4e29380d7bf34d2018e2c39e"
- ],
- "version": "==2.4"
- },
- "flatbuffers": {
- "hashes": [
- "sha256:12158ab0272375eab8db2d663ae97370c33f152b27801fa6024e1d6105fd4dd2",
- "sha256:3751954f0604580d3219ae49a85fafec9d85eec599c0b96226e1bc0b48e57474"
- ],
- "version": "==2.0"
- },
- "gast": {
- "hashes": [
- "sha256:40feb7b8b8434785585ab224d1568b857edb18297e5a3047f1ba012bc83b42c1",
- "sha256:b7adcdd5adbebf1adf17378da5ba3f543684dbec47b1cda1f3997e573cd542c4"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==0.4.0"
- },
- "google-auth": {
- "hashes": [
- "sha256:a348a50b027679cb7dae98043ac8dbcc1d7951f06d8387496071a1e05a2465c0",
- "sha256:d83570a664c10b97a1dc6f8df87e5fdfff012f48f62be131e449c20dfc32630e"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
- "version": "==2.3.3"
- },
- "google-auth-oauthlib": {
- "hashes": [
- "sha256:3f2a6e802eebbb6fb736a370fbf3b055edcb6b52878bf2f26330b5e041316c73",
- "sha256:a90a072f6993f2c327067bf65270046384cda5a8ecb20b94ea9a687f1f233a7a"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.4.6"
- },
- "google-pasta": {
- "hashes": [
- "sha256:4612951da876b1a10fe3960d7226f0c7682cf901e16ac06e473b267a5afa8954",
- "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed",
- "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e"
- ],
- "version": "==0.2.0"
- },
- "grpcio": {
- "hashes": [
- "sha256:0aa1af3e1480b6dd3092ee67c4b67b1ea88d638fcdc4d1a611ae11e311800b34",
- "sha256:0c075616d5e86fb65fd4784d5a87d6e5a1882d277dce5c33d9b67cfc71d79899",
- "sha256:133fb9a3cf4519543e4e41eb18b5dac0da26941aeabca8122dbcf3decbad2d21",
- "sha256:23a3f03e1d9ac429ff78d23d2ab07756d3728ee1a68b5f244d8435006608b6aa",
- "sha256:2a34c8979de10b04a44d2cad07d41d83643e65e49f84a05b1adf150aeb41c95f",
- "sha256:2eb8180a6d9e47fc865a4e92a2678f3202145021ef2c1bccf165fa5744f6ec95",
- "sha256:2f2ee78a6ae88d668ceda56fa4a18d8a38b34c2f2e1332083dd1da1a92870703",
- "sha256:31a47af7356fb5ed3120636dd75c5efb571ecf15737484119e31286687f0e52a",
- "sha256:3213dfe3abfc3fda7f30e86aa5967dce0c2eb4cc90a0504f95434091bf6b219a",
- "sha256:32b7ca83f1a6929217098aaaac89fc49879ae714c95501d40df41a0e7506164c",
- "sha256:3713e3918da6ae10812a64e75620a172f01af2ff0a1c99d6481c910e1d4a9053",
- "sha256:3b4b7c1ab18283eb64af5648d20eabef9237a2aec09e30a805f18adc9497258d",
- "sha256:3f0b70cf8632028714a8341b841b011a47900b1c163bf5fababb4ab3888c9b6c",
- "sha256:61aa02f4505c5bbbaeba80fef1bd6871d1aef05a8778a707ab91303ee0865ad0",
- "sha256:6ca497ccecaa8727f14c4ccc9ffb70a19c6413fe1d4650500c90a7febd662860",
- "sha256:71d9ed5a732a54b9c87764609f2fd2bc4ae72fa85e271038eb132ea723222209",
- "sha256:72d0bdc3605dc8f4187b302e1180643963896e3f2917a52becb51afb54448e3e",
- "sha256:734690b3f35468f8ed4003ec7622d2d47567f1881f5fcdca34f1e52551c2ef55",
- "sha256:740f5b21a7108a8c08bf522434752dc1d306274d47ca8b4d51af5588a16b6113",
- "sha256:766f1b943abc3e27842b72fba6e28fb9f57c9b84029fd7e91146e4c37034d937",
- "sha256:788154b32bf712e9711d001df024af5f7b2522117876c129bb27b9ad6e5461fb",
- "sha256:7a22a7378ea59ad1e6f2e79f9da6862eb9e1f6586253aee784d419a49e3f4bd9",
- "sha256:8487fb0649ebebc9c5dca1a6dc4eb7fddf701183426b3eefeb3584639d223d43",
- "sha256:8824b36e6b0e45fefe0b4eac5ad460830e0cbc856a0c794f711289b4b8933d53",
- "sha256:888d8519709652dd39415de5f79abd50257201b345dd4f40151feffc3dad3232",
- "sha256:9170b5d2082fc00c057c6ccd6b893033c1ade05717fcec1d63557c3bc7afdb1b",
- "sha256:9b751271b029432a526a4970dc9b70d93eb6f0963b6a841b574f780b72651969",
- "sha256:9d1be99f216b18f8a9dbdfbdbcc9a6caee504d0d27295fdbb5c8da35f5254a69",
- "sha256:9e403d07d77ed4495ad3c18994191525b11274693e72e464241c9139e2f9cd7c",
- "sha256:a3bb4302389b23f2006ecaaea5eb4a39cc80ea98d1964159e59c1c20ef39a483",
- "sha256:a5ac91db3c588296366554b2d91116fc3a9f05bae516cafae07220e1f05bfef7",
- "sha256:b1232c5efc8a9e4b7a13db235c51135412beb9e62e618a2a89dd0463edb3d929",
- "sha256:b8dd1b6456c6fb3681affe0f81dff4b3bc46f825fc05e086d64216545da9ad92",
- "sha256:c32c470e077b34a52e87e7de26644ad0f9e9ff89a785ff7e6466870869659e05",
- "sha256:c35b847bc6bd3c3a118a13277d91a772e7dd163ce7dd2791239f9941b6eaafe3",
- "sha256:c3a446b6a1f8077cc03d0d496fc1cecdd3d0b66860c0c5b65cc92d0549117840",
- "sha256:d1461672b2eaef9affb60a71014ebd2f789deea7c9acb1d4bd163de92dd8e044",
- "sha256:e156ea12adb7a7ca8d8280c9df850c15510b790c785fc26c9a3fb928cd221fd4",
- "sha256:ead9885b53777bed4b0694ff0baea9d2c519ff774b17b177bde43d73e2b4aa38",
- "sha256:ebbe9582ef06559a2358827a588ab4b92a2639517de8fe428288772820ab03b5",
- "sha256:f68aa98f5970eccb6c94456f3447a99916c42fbddae1971256bc4e7c40a6593b",
- "sha256:fc2eadfb5ec956c556c138fab0dfc1d2395c57ae0bfea047edae1976a26b250c",
- "sha256:fd11995e3402af0f838844194707da8b3235f1719bcac961493f0138f1325893",
- "sha256:fd570720871dc84d2adc8430ce287319c9238d1e2f70c140f9bc54c690fabd1b"
- ],
- "version": "==1.41.1"
- },
- "h5py": {
- "hashes": [
- "sha256:320f5810e058dcea73529dc98ae42263d34004bcc9209d7bf44eac5136716c3f",
- "sha256:3f9518c37a8b9cd067927a8cbc6fe96846d5d28c32e10baf49c8a1d012c9b0a6",
- "sha256:40fe8572511c317ec7598271b5dce9c25957cc373af733e53ea246bbf0244958",
- "sha256:77c7be4001ac7d3ed80477de5b6942501d782de1bbe4886597bdfec2a7ab821f",
- "sha256:834a53178fc558c9832081fd18bc22f6f2585edcc06c802adfa4afb07ff884b4",
- "sha256:c99329ebe346a73bd13bf3fc3d54ee9421f6ee00de6ea085c64a856a9acee7b3",
- "sha256:cdff848353e2d20d5f66535957595c79932851f51e496623a96186d02ba0cf30",
- "sha256:d15e1556ff9591b3f3d8c7b3b66085f3867e5500528663bf11c499ab71c9c6b6",
- "sha256:f75d7bdaba8d3537490b0f53adcd043991ada3597f88e772969172c45145a8f6",
- "sha256:fc763e707aa631fdc200878c7b5c13ea5b5d1f9772696871dcd6f0f5932fcd35"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.5.0"
- },
- "idna": {
- "hashes": [
- "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
- "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
- ],
- "markers": "python_version >= '3'",
- "version": "==3.3"
- },
- "immutables": {
- "hashes": [
- "sha256:0020aaa4010b136056c20a46ce53204e1407a9e4464246cb2cf95b90808d9161",
- "sha256:064001638ab5d36f6aa05b6101446f4a5793fb71e522bc81b8fc65a1894266ff",
- "sha256:0a396314b9024fa55bf83a27813fd76cf9f27dce51f53b0f19b51de035146251",
- "sha256:19bdede174847c2ef1292df0f23868ab3918b560febb09fcac6eec621bd4812b",
- "sha256:1de393f1b188740ca7b38f946f2bbc7edf3910d2048f03bbb8d01f17a038d67c",
- "sha256:2505d93395d3f8ae4223e21465994c3bc6952015a38dc4f03cb3e07a2b8d8325",
- "sha256:298a301f85f307b4c056a0825eb30f060e64d73605e783289f3df37dd762bab8",
- "sha256:29c9ed003eacb92e630ef200e31f47236c2139b39476894f7963b32bd39bafa3",
- "sha256:4a2a71678348fb95b13ca108d447f559a754c41b47bd1e7e4fb23974e735682d",
- "sha256:50793a44ba0d228ed8cad4d0925e00dfd62ea32f44ddee8854f8066447272d05",
- "sha256:511c93d8b1bbbf103ff3f1f120c5a68a9866ce03dea6ac406537f93ca9b19139",
- "sha256:734c269e82e5f307fb6e17945953b67659d1731e65309787b8f7ba267d1468f2",
- "sha256:798b095381eb42cf40db6876339e7bed84093e5868018a9e73d8e1f7ab4bb21e",
- "sha256:799621dcdcdcbb2516546a40123b87bf88de75fe7459f7bd8144f079ace6ec3e",
- "sha256:7a58825ff2254e2612c5a932174398a4ea8fbddd8a64a02c880cc32ee28b8820",
- "sha256:7bcf52aeb983bd803b7c6106eae1b2d9a0c7ab1241bc6b45e2174ba2b7283031",
- "sha256:9ccf4c0e3e2e3237012b516c74c49de8872ccdf9129739f7a0b9d7444a8c4862",
- "sha256:a307eb0984eb43e815dcacea3ac50c11d00a936ecf694c46991cd5a23bcb0ec0",
- "sha256:a454d5d3fee4b7cc627345791eb2ca4b27fa3bbb062ccf362ecaaa51679a07ed",
- "sha256:aa7bf572ae1e006104c584be70dc634849cf0dc62f42f4ee194774f97e7fd17d",
- "sha256:acbfa79d44228d96296279068441f980dc63dbed52522d9227ff9f4d96c6627e",
- "sha256:b651b61c1af6cda2ee201450f2ffe048a5959bc88e43e6c312f4c93e69c9e929",
- "sha256:b779617f5b94486bfd0f22162cd72eb5f2beb0214a14b75fdafb7b2c908ed0cb",
- "sha256:d59beef203a3765db72b1d0943547425c8318ecf7d64c451fd1e130b653c2fbb",
- "sha256:d67e86859598eed0d926562da33325dac7767b7b1eff84e232c22abea19f4360",
- "sha256:edd9f67671555af1eb99ad3c7550238487dd7ac0ac5205b40204ed61c9a922ac",
- "sha256:fcf678a3074613119385a02a07c469ec5130559f5ea843c85a0840c80b5b71c6"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.16"
- },
- "isodate": {
- "hashes": [
- "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8",
- "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81"
- ],
- "version": "==0.6.0"
- },
- "keras": {
- "hashes": [
- "sha256:0c33ae1f728064ca0d35dfba999e9c316f03623bf5688c82fb83cc74a80ea248"
- ],
- "version": "==2.7.0"
- },
- "keras-preprocessing": {
- "hashes": [
- "sha256:7b82029b130ff61cc99b55f3bd27427df4838576838c5b2f65940e4fcec99a7b",
- "sha256:add82567c50c8bc648c14195bf544a5ce7c1f76761536956c3d2978970179ef3"
- ],
- "version": "==1.1.2"
- },
- "lazy-property": {
- "hashes": [
- "sha256:3a1cd36949b323468731ba569e169415a609d5904d53fffe982055fbe67b1180",
- "sha256:907b3a9e653771f4d0bcafd0fbfcdac8aaade85b31ed7eccd1cbfe59c59b149f"
- ],
- "version": "==0.0.1"
- },
- "libclang": {
- "hashes": [
- "sha256:275126823c60ab5c9fae6a433cbb6a47e4d1b5f668a985fbd6065553dbc7efcc",
- "sha256:3b0585dbdc3f3b372340f1efe7c28bf4a5b658d2fb8dc0544a7ef0d2bef40618",
- "sha256:6df2f8a2cb75181e3c1e99e5dfca2fd44bb7f84ed12d5112541e03c10384f306",
- "sha256:b828cb52cf3f02fb0e0a8fddb9dece7e2ed006f8b4d54ee811cef0471d414367",
- "sha256:fadad3bf5fbab50c996eb151adc58c3a7cbee45a9135060c416be7b640372112"
- ],
- "version": "==12.0.0"
- },
- "llvmlite": {
- "hashes": [
- "sha256:14030a1c0f9aee0185db069163240c51d4e8a3eec0daf02468e057281dee612b",
- "sha256:15b8ac7a489e31b7d5c482193edaa44374e3c18e409bea494224e31eb60e38e5",
- "sha256:30431fe9a9b7b1c3585b71149cc11dc79b9d62dc86d3db15c3dcca33d274b5be",
- "sha256:447b01c25d18921c4179f2eccba218d7c82b65cfe3952b0d018d569945427bf9",
- "sha256:4616e17914fcc7c5bfb7d1014acbd4fca478949820e86218a29d9473d0aa221b",
- "sha256:4c1e91fd4ba2764161e9a05b6fff46a52d26170186bad99629777e8c7246f0ef",
- "sha256:57c1dae337863b497c141d40736041d4acb7769226b44fe05959fce3c3570d5d",
- "sha256:6392b870cd018ec0c645d6bbb918d6aa0eeca8c62674baaee30862d6b6865b15",
- "sha256:7449acca596f45e9e12b20c0b72d184f83025341cc2d44d7ccf5fe31356dcd08",
- "sha256:74b6c3d2eb8cef32a09e8fd7637d0d37628c74f4deedf9361e0c0ebecc239208",
- "sha256:794191922ac6414c55d66058eaba8b88a630c6e9f2cf0db7e8e661e74d71fa14",
- "sha256:995c1a2c8b6a11a7f2c66e52576de6a28292d37842d383aae5be7b965b56d10f",
- "sha256:ab00b7996e5ef795f59d95d3125850f3af28d19e43bdc08473947cb8045ce098",
- "sha256:b6466d6369051e5c083b15cf285c00595ddb7f828be1ebecb1dfb97f3fab0bff",
- "sha256:c92a209439fd0b8a41f6e2aba1d3afa260357028a29ed7db8c602c4d67c21540",
- "sha256:cf7d623d33d24df51adc4e9e9f5734df752330661793d1662425ad2e926cb2d4",
- "sha256:d31a3bd69894b31bbc68df00e0b37b0980a0cf025f9dbea9cdd37988230c33a3",
- "sha256:df1d1b162a426480b37d6c4adeddff49e2fb9f71b307c7facac67bdce4767746",
- "sha256:f9e84d683943c2f636b08db9b2d182d4b40b83e1a3e31e100af3bb9ed8d94bcd"
- ],
- "markers": "python_version < '3.10' and python_version >= '3.7'",
- "version": "==0.37.0"
- },
- "markdown": {
- "hashes": [
- "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49",
- "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.3.4"
- },
- "mmparse": {
- "hashes": [
- "sha256:8db89bde4ae8f85a297dcb6cc83830072f12d929fb2285266d01a0118bb99243"
- ],
- "version": "==0.6"
- },
- "networkx": {
- "hashes": [
- "sha256:2306f1950ce772c5a59a57f5486d59bb9cab98497c45fc49cbc45ac0dec119bb",
- "sha256:5fcb7004be69e8fbdf07dcb502efa5c77cadcaad6982164134eeb9721f826c2e"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==2.6.2"
- },
- "numba": {
- "hashes": [
- "sha256:0354df1fcfa9d9d8df3b63780fae408c8f23c474d71a4e929f4c5b44f2c9ce5a",
- "sha256:0f1c2c23c4e05cbed19f7a15710a25e71ab818ba7cd0bf66572bacd221721f22",
- "sha256:1380429f4a3f73440aae093a058713c780fdc14930b3070c883bc1737e8711b0",
- "sha256:5239bf413a9d3c7fad839400d5082032635511c3b7058e17835c7c4090f223ed",
- "sha256:5492ffa42425b7dc783e4376dfc07617c751d7d087d64fe8c2e7944038e35261",
- "sha256:606ebf5b0474d89f96a2e1354f0349e985c3897c2989b78e47b095d67434cf4c",
- "sha256:64451b4fd2437ebb7bbcff72133b28575cb8464eb3f10ccd88c70a3792e6de0a",
- "sha256:77479e79b6840e3eb5e0613bbdbb4be8f4b9c4130bafdf6ac39b9507ea742f15",
- "sha256:7da918aed4790a4ce6682061971e6248e7422dd5618dcac8054d4a47955182dc",
- "sha256:884ad2cdebb6f8bcc7b5ec70e56c9acdb8456482c49cea12273d34709dfc2c9c",
- "sha256:b385451355a9023c9611400c7c6d4088f5781ed11b104b5d690f0ad65b142860",
- "sha256:b657cece0b069cd4361a6d25aaae2e9e9df9e65abfa63f09345352fbb1069a11",
- "sha256:c2e877a33f6920365e96ad088023f786a4b1ce44a7e772763cc02c55f49614dd",
- "sha256:c36e50271146c3c33f10111488307a6aa75416aa53384709b037599426a967ea",
- "sha256:d0799e7e8640a31d9567a032a6e046d797356afb3e812e0a0f97e6e74ded7e35",
- "sha256:ec7033409e66158e9f2b83c22d887fda7949bf2ac652bbbdcbc006b590c37339",
- "sha256:ef4d27ee039007510c3de9c42fd6bb57051661ceeca4a9a6244b642a742632a0",
- "sha256:f9dfc803c864edcc2381219b800abf366793400aea55e26d4d5b7d953e14f43f",
- "sha256:fe4f0c881dbaac0c818dafc80e348edf8d8f1022278c368390ca20e92ed381cc"
- ],
- "markers": "python_version < '3.10' and python_version >= '3.7'",
- "version": "==0.54.1"
- },
- "numpy": {
- "hashes": [
- "sha256:1676b0a292dd3c99e49305a16d7a9f42a4ab60ec522eac0d3dd20cdf362ac010",
- "sha256:16f221035e8bd19b9dc9a57159e38d2dd060b48e93e1d843c49cb370b0f415fd",
- "sha256:43909c8bb289c382170e0282158a38cf306a8ad2ff6dfadc447e90f9961bef43",
- "sha256:4e465afc3b96dbc80cf4a5273e5e2b1e3451286361b4af70ce1adb2984d392f9",
- "sha256:55b745fca0a5ab738647d0e4db099bd0a23279c32b31a783ad2ccea729e632df",
- "sha256:5d050e1e4bc9ddb8656d7b4f414557720ddcca23a5b88dd7cff65e847864c400",
- "sha256:637d827248f447e63585ca3f4a7d2dfaa882e094df6cfa177cc9cf9cd6cdf6d2",
- "sha256:6690080810f77485667bfbff4f69d717c3be25e5b11bb2073e76bb3f578d99b4",
- "sha256:66fbc6fed94a13b9801fb70b96ff30605ab0a123e775a5e7a26938b717c5d71a",
- "sha256:67d44acb72c31a97a3d5d33d103ab06d8ac20770e1c5ad81bdb3f0c086a56cf6",
- "sha256:6ca2b85a5997dabc38301a22ee43c82adcb53ff660b89ee88dded6b33687e1d8",
- "sha256:6e51534e78d14b4a009a062641f465cfaba4fdcb046c3ac0b1f61dd97c861b1b",
- "sha256:70eb5808127284c4e5c9e836208e09d685a7978b6a216db85960b1a112eeace8",
- "sha256:830b044f4e64a76ba71448fce6e604c0fc47a0e54d8f6467be23749ac2cbd2fb",
- "sha256:8b7bb4b9280da3b2856cb1fc425932f46fba609819ee1c62256f61799e6a51d2",
- "sha256:a9c65473ebc342715cb2d7926ff1e202c26376c0dcaaee85a1fd4b8d8c1d3b2f",
- "sha256:c1c09247ccea742525bdb5f4b5ceeacb34f95731647fe55774aa36557dbb5fa4",
- "sha256:c5bf0e132acf7557fc9bb8ded8b53bbbbea8892f3c9a1738205878ca9434206a",
- "sha256:db250fd3e90117e0312b611574cd1b3f78bec046783195075cbd7ba9c3d73f16",
- "sha256:e515c9a93aebe27166ec9593411c58494fa98e5fcc219e47260d9ab8a1cc7f9f",
- "sha256:e55185e51b18d788e49fe8305fd73ef4470596b33fc2c1ceb304566b99c71a69",
- "sha256:ea9cff01e75a956dbee133fa8e5b68f2f92175233de2f88de3a682dd94deda65",
- "sha256:f1452578d0516283c87608a5a5548b0cdde15b99650efdfd85182102ef7a7c17",
- "sha256:f39a995e47cb8649673cfa0579fbdd1cdd33ea497d1728a6cb194d6252268e48"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==1.20.3"
- },
- "oauthlib": {
- "hashes": [
- "sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc",
- "sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.1.1"
- },
- "opt-einsum": {
- "hashes": [
- "sha256:2455e59e3947d3c275477df7f5205b30635e266fe6dc300e3d9f9646bfcea147",
- "sha256:59f6475f77bbc37dcf7cd748519c0ec60722e91e63ca114e68821c0c54a46549"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==3.3.0"
- },
- "pandas": {
- "hashes": [
- "sha256:003ba92db58b71a5f8add604a17a059f3068ef4e8c0c365b088468d0d64935fd",
- "sha256:10e10a2527db79af6e830c3d5842a4d60383b162885270f8cffc15abca4ba4a9",
- "sha256:22808afb8f96e2269dcc5b846decacb2f526dd0b47baebc63d913bf847317c8f",
- "sha256:2d1dc09c0013d8faa7474574d61b575f9af6257ab95c93dcf33a14fd8d2c1bab",
- "sha256:35c77609acd2e4d517da41bae0c11c70d31c87aae8dd1aabd2670906c6d2c143",
- "sha256:372d72a3d8a5f2dbaf566a5fa5fa7f230842ac80f29a931fb4b071502cf86b9a",
- "sha256:42493f8ae67918bf129869abea8204df899902287a7f5eaf596c8e54e0ac7ff4",
- "sha256:4acc28364863127bca1029fb72228e6f473bb50c32e77155e80b410e2068eeac",
- "sha256:5298a733e5bfbb761181fd4672c36d0c627320eb999c59c65156c6a90c7e1b4f",
- "sha256:5ba0aac1397e1d7b654fccf263a4798a9e84ef749866060d19e577e927d66e1b",
- "sha256:9707bdc1ea9639c886b4d3be6e2a45812c1ac0c2080f94c31b71c9fa35556f9b",
- "sha256:a2aa18d3f0b7d538e21932f637fbfe8518d085238b429e4790a35e1e44a96ffc",
- "sha256:a388960f979665b447f0847626e40f99af8cf191bce9dc571d716433130cb3a7",
- "sha256:a51528192755f7429c5bcc9e80832c517340317c861318fea9cea081b57c9afd",
- "sha256:b528e126c13816a4374e56b7b18bfe91f7a7f6576d1aadba5dee6a87a7f479ae",
- "sha256:c1aa4de4919358c5ef119f6377bc5964b3a7023c23e845d9db7d9016fa0c5b1c",
- "sha256:c2646458e1dce44df9f71a01dc65f7e8fa4307f29e5c0f2f92c97f47a5bf22f5",
- "sha256:c2f44425594ae85e119459bb5abb0748d76ef01d9c08583a667e3339e134218e",
- "sha256:d47750cf07dee6b55d8423471be70d627314277976ff2edd1381f02d52dbadf9",
- "sha256:d99d2350adb7b6c3f7f8f0e5dfb7d34ff8dd4bc0a53e62c445b7e43e163fce63",
- "sha256:dd324f8ee05925ee85de0ea3f0d66e1362e8c80799eb4eb04927d32335a3e44a",
- "sha256:eaca36a80acaacb8183930e2e5ad7f71539a66805d6204ea88736570b2876a7b",
- "sha256:f567e972dce3bbc3a8076e0b675273b4a9e8576ac629149cf8286ee13c259ae5",
- "sha256:fe48e4925455c964db914b958f6e7032d285848b7538a5e1b19aeb26ffaea3ec"
- ],
- "markers": "python_full_version >= '3.7.1'",
- "version": "==1.3.4"
- },
- "pillow": {
- "hashes": [
- "sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76",
- "sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585",
- "sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b",
- "sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8",
- "sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55",
- "sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc",
- "sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645",
- "sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff",
- "sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc",
- "sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b",
- "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6",
- "sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20",
- "sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e",
- "sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a",
- "sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779",
- "sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02",
- "sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39",
- "sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f",
- "sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a",
- "sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409",
- "sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c",
- "sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488",
- "sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b",
- "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d",
- "sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09",
- "sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b",
- "sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153",
- "sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9",
- "sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad",
- "sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df",
- "sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df",
- "sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed",
- "sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed",
- "sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698",
- "sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29",
- "sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649",
- "sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49",
- "sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b",
- "sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2",
- "sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a",
- "sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"
- ],
- "index": "pypi",
- "version": "==8.4.0"
- },
- "protobuf": {
- "hashes": [
- "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942",
- "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f",
- "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560",
- "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089",
- "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6",
- "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04",
- "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7",
- "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e",
- "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d",
- "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7",
- "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c",
- "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002",
- "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6",
- "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853",
- "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d",
- "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3",
- "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8",
- "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995",
- "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea",
- "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6",
- "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2",
- "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b",
- "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17",
- "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==3.19.1"
- },
- "pyasn1": {
- "hashes": [
- "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
- "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
- "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
- "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
- "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
- "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
- "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
- "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
- "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
- "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
- "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
- "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
- "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
- ],
- "version": "==0.4.8"
- },
- "pyasn1-modules": {
- "hashes": [
- "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
- "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
- "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
- "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
- "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
- "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
- "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
- "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
- "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
- "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
- "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
- "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
- "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
- ],
- "version": "==0.2.8"
- },
- "pycparser": {
- "hashes": [
- "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
- "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"
- ],
- "version": "==2.21"
- },
- "pydot": {
- "hashes": [
- "sha256:248081a39bcb56784deb018977e428605c1c758f10897a339fce1dd728ff007d",
- "sha256:66c98190c65b8d2e2382a441b4c0edfdb4f4c025ef9cb9874de478fb0793a451"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.4.2"
- },
- "pyformlang": {
- "hashes": [
- "sha256:ba8a1932ce93801a812881a0f718a8e96cc31e8fdd2df846f8fab27d63125f76",
- "sha256:d7b46a25ad73f5e2d1cf59145fb746de2b5168971e876400d773f3e2010ddcca"
- ],
- "index": "pypi",
- "version": "==0.1.26"
- },
- "pygraphblas": {
- "hashes": [
- "sha256:ecd763cf54394ca1d5e37474dcf36b8727ae001df3e3485180e0d94be81b858b"
- ],
- "index": "pypi",
- "version": "==5.1.8.0"
- },
- "pyparsing": {
- "hashes": [
- "sha256:4881e3d2979f27b41a3a2421b10be9cbfa7ce2baa6c7117952222f8bbea6650c",
- "sha256:9329d1c1b51f0f76371c4ded42c5ec4cc0be18456b22193e0570c2da98ed288b"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.0.5"
- },
- "python-dateutil": {
- "hashes": [
- "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
- "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==2.8.2"
- },
- "pytz": {
- "hashes": [
- "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c",
- "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"
- ],
- "version": "==2021.3"
- },
- "rdflib": {
- "hashes": [
- "sha256:7ce4d757eb26f4dd43205ec340d8c097f29e5adfe45d6ea20238c731dc679879",
- "sha256:bb24f0058070d5843503e15b37c597bc3858d328d11acd9476efad3aa62f555d"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==6.0.0"
- },
- "requests": {
- "hashes": [
- "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24",
- "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
- "version": "==2.26.0"
- },
- "requests-oauthlib": {
- "hashes": [
- "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
- "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
- "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
- ],
- "version": "==1.3.0"
- },
- "rsa": {
- "hashes": [
- "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2",
- "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==4.7.2"
- },
- "scipy": {
- "hashes": [
- "sha256:1437073f1d4664990879aa8f9547524764372e0fef84a077be4b19e82bba7a8d",
- "sha256:17fd991a275e4283453f89d404209aa92059ac68d76d804b4bc1716a3742e1b5",
- "sha256:1ea6233f5a365cb7945b4304bd06323ece3ece85d6a3fa8598d2f53e513467c9",
- "sha256:2d25272c03ee3c0fe5e0dff1bb7889280bb6c9e1766fa9c7bde81ad8a5f78694",
- "sha256:30bdda199667e74b50208a793eb1ba47a04e5e3fa16f5ff06c6f7969ae78e4da",
- "sha256:359b60a0cccd17723b9d5e329a5212a710e771a3ddde800e472fb93732756c46",
- "sha256:39f838ea5ce8da868785193d88d05cf5a6d5c390804ec99de29a28e1dcdd53e6",
- "sha256:4d175ba93e00d8eef8f7cd70d4d88a9106a86800c82ea03cf2268c36d6545483",
- "sha256:5273d832fb9cd5724ee0d335c16a903b923441107dd973d27fc4293075a9f4e3",
- "sha256:54951f51d731c832b1b8885e0a92e89f33d087de7e40d02078bf0d49c7cbdbb5",
- "sha256:74f518ce542533054695f743e4271cb8986b63f95bb51d70fcee4f3929cbff7d",
- "sha256:7b1d0f5f524518f1a86f288443528e4ff4a739c0966db663af4129b7ac7849f8",
- "sha256:82c5befebf54d799d77e5f0205c03030f57f69ba2541baa44d2e6ad138c28cd3",
- "sha256:8482c8e45857ab0a5446eb7460d2307a27cbbe659d6d2257820c6d6eb950fd0f",
- "sha256:87cf3964db0f1cce17aeed5bfc1b89a6b4b07dbfc48e50d21fa3549e00456803",
- "sha256:8b5726a0fedeaa6beb1095e4466998bdd1d1e960b28db9b5a16c89cbd7b2ebf1",
- "sha256:97eb573e361a73a553b915dc195c6f72a08249964b1a33f157f9659f3b6210d1",
- "sha256:a80eb01c43fd98257ec7a49ff5cec0edba32031b5f86503f55399a48cb2c5379",
- "sha256:cac71d5476a6f56b50459da21f6221707e0051ebd428b2137db32ef4a43bb15e",
- "sha256:d86abd1ddf421dea5e9cebfeb4de0d205b3dc04e78249afedba9c6c3b2227ff2",
- "sha256:dc2d1bf41294e63c7302bf499973ac0c7f73c93c01763db43055f6525234bf11",
- "sha256:e08b81fcd9bf98740b58dc6fdd7879e33a64dcb682201c1135f7d4a75216bb05",
- "sha256:e3efe7ef75dfe627b354ab0af0dbc918eadee97cc80ff1aabea6d3e01114ebdd",
- "sha256:fa2dbabaaecdb502641b0b3c00dec05fb475ae48655c66da16c9ed24eda1e711"
- ],
- "markers": "python_version < '3.11' and python_version >= '3.7'",
- "version": "==1.7.2"
- },
- "setuptools": {
- "hashes": [
- "sha256:a481fbc56b33f5d8f6b33dce41482e64c68b668be44ff42922903b03872590bf",
- "sha256:dae6b934a965c8a59d6d230d3867ec408bb95e73bd538ff77e71fedf1eaca729"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==58.5.3"
- },
- "six": {
- "hashes": [
- "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
- "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.16.0"
- },
- "ssgetpy": {
- "hashes": [
- "sha256:3860bce10bc4ee3cb5ed93c08388bafadfcaac24175a7c42fcbb187c033ddc0d",
- "sha256:bf298e173f1545d451877220b1912b2c94af79314e9c4812a5398a393c1010b5"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.0rc2"
- },
- "suitesparse-graphblas": {
- "hashes": [
- "sha256:129a4661501c4d8c00b2370180804669b832ca36ddd749617622295c40b7888c",
- "sha256:15810893b43217ee0299e2e3e11c1c194270b285d279e6dc8d1bda1a729a3f3e",
- "sha256:267f52bd75e16c09dd08524ee41868c9eb528f5de44e70a287734e4df6510f7e",
- "sha256:e07520e3cbb09de0b17235c5c02fc21fdfea62f602545116c14386ff6104d09a"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==5.1.10.1"
- },
- "tensorboard": {
- "hashes": [
- "sha256:239f78a4a8dff200ce585a030c787773a8c1184d5c159252f5f85bac4e3c3b38"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2.7.0"
- },
- "tensorboard-data-server": {
- "hashes": [
- "sha256:809fe9887682d35c1f7d1f54f0f40f98bb1f771b14265b453ca051e2ce58fca7",
- "sha256:d8237580755e58eff68d1f3abefb5b1e39ae5c8b127cc40920f9c4fb33f4b98a",
- "sha256:fa8cef9be4fcae2f2363c88176638baf2da19c5ec90addb49b1cde05c95c88ee"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.6.1"
- },
- "tensorboard-plugin-wit": {
- "hashes": [
- "sha256:2a80d1c551d741e99b2f197bb915d8a133e24adb8da1732b840041860f91183a"
- ],
- "version": "==1.8.0"
- },
- "tensorflow": {
- "hashes": [
- "sha256:12f19d6c7161ffef21e69a14e60aaaf47dc25bff133ac954839f1308262b29bf",
- "sha256:62db938367757c9fb54c56fa2fbbe3cd3bf05c046ee1da81667257fea554dc70",
- "sha256:7c7572de9f80547dcf3bcc2f94cd7d5dc14395d494c3b9d223e7b3e579a6b24f",
- "sha256:8f6066b1cbd33e47beb5a35df0f06c60d59d1e0b02ac420789b7679e8d879c70",
- "sha256:a4539796c4ff8e7a3baaa6337cea237e49ec8f56a9c45f618a9642b474c0c8bd",
- "sha256:ae17148d608a280c8d82d18404883367015e36cb1f4e02d34395d70a96912432",
- "sha256:be0a2e3460dacc4214eedd6484b11e50583cb790ed37c6872378100fcaff1090",
- "sha256:e24b83eecf70d0467adbd5c5507a4f1a448b6df8cc586471d3decce8c50dd25f",
- "sha256:eb653c85bdd00ca2dba6104b1a04c37eaffccec47e5357a0f57d7b9ee9a678c0"
- ],
- "index": "pypi",
- "version": "==2.7.0"
- },
- "tensorflow-estimator": {
- "hashes": [
- "sha256:325b5a224864379242b7b76c6987ca544239be82579d33e68ec7c2bda57abc9d"
- ],
- "version": "==2.7.0"
- },
- "tensorflow-io-gcs-filesystem": {
- "hashes": [
- "sha256:14b80d87c3876a1915d5b45ee46291c82f577113de88a852fa5918f0ac1ba949",
- "sha256:32b9f368486ffd748801e3d8602de1868334406ef47d63292f7fceee1f491d4d",
- "sha256:4345771944f1bbc4bd38ed35de9248b8cec10af78ce107c96f0a45bd20b152d5",
- "sha256:a4d2a30c3fb966f8d74ec41380ab2a101dad46aa73a3f0e9f8e5b1dee6bc4cf7",
- "sha256:ab3967679a360650609fef533c1fe9157f83264a542584a95407329b45dfd514",
- "sha256:c5de3d42baf0bf0c7fad173dcae2e93b79176f701b1083f28fa698bd507785ec",
- "sha256:def85b562e53d540c8ed620780b3a7f6c925a69bc4534014c29100bd4a014f9c",
- "sha256:fd002b7eb9d0e4d7c188825ce3f73be5a63c19eac67ef3441f5448d3b024405b",
- "sha256:ff734f70c80709263b633839f29edc15669f13fa213084ce4e85a3d0215ca7fd"
- ],
- "markers": "python_version < '3.10' and python_version >= '3.6'",
- "version": "==0.22.0"
- },
- "termcolor": {
- "hashes": [
- "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"
- ],
- "version": "==1.1.0"
- },
- "tqdm": {
- "hashes": [
- "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c",
- "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==4.62.3"
- },
- "typing-extensions": {
- "hashes": [
- "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
- "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
- "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
- ],
- "version": "==3.10.0.2"
- },
- "urllib3": {
- "hashes": [
- "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
- "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
- "version": "==1.26.7"
- },
- "werkzeug": {
- "hashes": [
- "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f",
- "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2.0.2"
- },
- "wheel": {
- "hashes": [
- "sha256:21014b2bd93c6d0034b6ba5d35e4eb284340e09d63c59aef6fc14b0f346146fd",
- "sha256:e2ef7239991699e3355d54f8e968a21bb940a1dbf34a4d226741e64462516fad"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==0.37.0"
- },
- "wrapt": {
- "hashes": [
- "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179",
- "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096",
- "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374",
- "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df",
- "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185",
- "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785",
- "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7",
- "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909",
- "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918",
- "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33",
- "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068",
- "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829",
- "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af",
- "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79",
- "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce",
- "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc",
- "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36",
- "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade",
- "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca",
- "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32",
- "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125",
- "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e",
- "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709",
- "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f",
- "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b",
- "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb",
- "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb",
- "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489",
- "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640",
- "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb",
- "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851",
- "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d",
- "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44",
- "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13",
- "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2",
- "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb",
- "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b",
- "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9",
- "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755",
- "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c",
- "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a",
- "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf",
- "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3",
- "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229",
- "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e",
- "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de",
- "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554",
- "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10",
- "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80",
- "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056",
- "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==1.13.3"
- }
- },
- "develop": {
- "backports.entry-points-selectable": {
- "hashes": [
- "sha256:7fceed9532a7aa2bd888654a7314f864a3c16a4e710b34a58cfc0f08114c663b",
- "sha256:914b21a479fde881635f7af5adc7f6e38d6b274be32269070c53b698c60d5386"
- ],
- "markers": "python_version >= '2.7'",
- "version": "==1.1.1"
- },
- "black": {
- "hashes": [
- "sha256:6eb7448da9143ee65b856a5f3676b7dda98ad9abe0f87fce8c59291f15e82a5b",
- "sha256:a9952229092e325fe5f3dae56d81f639b23f7131eb840781947e4b2886030f33"
- ],
- "index": "pypi",
- "version": "==21.10b0"
- },
- "cfgv": {
- "hashes": [
- "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426",
- "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==3.3.1"
- },
- "click": {
- "hashes": [
- "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3",
- "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==8.0.3"
- },
- "distlib": {
- "hashes": [
- "sha256:c8b54e8454e5bf6237cc84c20e8264c3e991e824ef27e8f1e81049867d861e31",
- "sha256:d982d0751ff6eaaab5e2ec8e691d949ee80eddf01a62eaa96ddb11531fe16b05"
- ],
- "version": "==0.3.3"
- },
- "filelock": {
- "hashes": [
- "sha256:7afc856f74fa7006a289fd10fa840e1eebd8bbff6bffb69c26c54a0512ea8cf8",
- "sha256:bb2a1c717df74c48a2d00ed625e5a66f8572a3a30baacb7657add1d7bac4097b"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.3.2"
- },
- "identify": {
- "hashes": [
- "sha256:6f0368ba0f21c199645a331beb7425d5374376e71bc149e9cb55e45cb45f832d",
- "sha256:ba945bddb4322394afcf3f703fa68eda08a6acc0f99d9573eb2be940aa7b9bba"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==2.3.5"
- },
- "mypy-extensions": {
- "hashes": [
- "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
- "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
- ],
- "version": "==0.4.3"
- },
- "nodeenv": {
- "hashes": [
- "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b",
- "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"
- ],
- "version": "==1.6.0"
- },
- "pathspec": {
- "hashes": [
- "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a",
- "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"
- ],
- "version": "==0.9.0"
- },
- "platformdirs": {
- "hashes": [
- "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2",
- "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2.4.0"
- },
- "pre-commit": {
- "hashes": [
- "sha256:3c25add78dbdfb6a28a651780d5c311ac40dd17f160eb3954a0c59da40a505a7",
- "sha256:a4ed01000afcb484d9eb8d504272e642c4c4099bbad3a6b27e519bd6a3e928a6"
- ],
- "index": "pypi",
- "version": "==2.15.0"
- },
- "pyyaml": {
- "hashes": [
- "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
- "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
- "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
- "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
- "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
- "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
- "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
- "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
- "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
- "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
- "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
- "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
- "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
- "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
- "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
- "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
- "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
- "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
- "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
- "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
- "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
- "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
- "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
- "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
- "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
- "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
- "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
- "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
- "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
- "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
- "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
- "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
- "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==6.0"
- },
- "regex": {
- "hashes": [
- "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f",
- "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc",
- "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4",
- "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4",
- "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8",
- "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f",
- "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a",
- "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef",
- "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f",
- "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc",
- "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50",
- "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d",
- "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d",
- "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733",
- "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36",
- "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345",
- "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0",
- "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12",
- "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646",
- "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667",
- "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244",
- "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29",
- "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec",
- "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf",
- "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4",
- "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449",
- "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a",
- "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d",
- "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb",
- "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e",
- "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83",
- "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e",
- "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a",
- "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94",
- "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc",
- "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e",
- "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965",
- "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0",
- "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36",
- "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec",
- "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23",
- "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7",
- "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe",
- "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6",
- "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b",
- "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb",
- "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b",
- "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30",
- "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"
- ],
- "version": "==2021.11.10"
- },
- "six": {
- "hashes": [
- "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
- "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.16.0"
- },
- "toml": {
- "hashes": [
- "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
- "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
- ],
- "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==0.10.2"
- },
- "tomli": {
- "hashes": [
- "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee",
- "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.2.2"
- },
- "typing-extensions": {
- "hashes": [
- "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
- "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
- "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
- ],
- "version": "==3.10.0.2"
- },
- "virtualenv": {
- "hashes": [
- "sha256:4b02e52a624336eece99c96e3ab7111f469c24ba226a53ec474e8e787b365814",
- "sha256:576d05b46eace16a9c348085f7d0dc8ef28713a2cabaa1cf0aea41e8f12c9218"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==20.10.0"
- }
- }
-}
diff --git a/README.md b/README.md
index 8c3c834..1c16e40 100644
--- a/README.md
+++ b/README.md
@@ -1,58 +1,131 @@
-[](https://github.com/JetBrains-Research/Genegram/actions/workflows/check_code_style.yml)
+[](https://github.com/JetBrains-Research/Genegram/actions/workflows/lint.yml)
+[](https://github.com/JetBrains-Research/Genegram/actions/workflows/test.yml)
---
-# Genegram
+
+# Genegram: RNA Secondary Structure Prediction by Combination of Formal Grammars and Neural Networks
## Description
-[comment]: <> (TODO)
+Command Line Tool for Predicting RNA Secondary Structure Connectivity Table
-## Install
+## FASTA format
-We use [`Pipenv`](https://pipenv.pypa.io/en/latest/) to manage dependencies.
+**⚠️ We use a slightly more strict FASTA format than the [standard](https://en.wikipedia.org/wiki/FASTA_format) ⚠️**
-### [Install Pipenv](https://pipenv.pypa.io/en/latest/#install-pipenv-today)
+### Our format
-```shell
-pip install --user pipenv
+```text
+>RNA description
+RNA sequence
+...
+>RNA description
+RNA sequence
```
-### Install Genegram (from sources)
+### Example
+
+```text
+>34551
+GGCCUCCAAGCUGUGCCUUGGGUGGCC
+>34552
+CCUCCCUUACAAGGAGG
+>34553
+GGAGUGGCCGAAAGGCAUCUCC
+>34735
+GGCUCUCAGUGAGCC
+```
-```shell
-git clone https://github.com/JetBrains-Research/Genegram
-cd Genegram
-pipenv install --ignore-pipfile
+## Requirements
+
+### Hardware
+
+* Genegram requires only a standard computer with around 16 GB RAM to support the in-memory operations for RNAs sequence length less than 500
+
+### OS
+
+* [`Ubuntu 18.04`](https://releases.ubuntu.com/18.04/)
+
+### Software
+
+* [`Python 3.8`](https://www.python.org/downloads/release/python-380/)
+* [`Virtualenv`](https://virtualenv.pypa.io/en/latest/installation/)
+* [`CUDA 11.2`](https://developer.nvidia.com/cuda-11.2.0-download-archive) *(Optional If using GPU)*
+* [`cuDNN 8.1`](https://developer.nvidia.com/cudnn) *(Optional If using GPU)*
+
+### Python packages
+
+```text
+tensorflow==2.7.0
+pygraphblas==4.2.2
+pyformlang==0.1.26
```
+## Installation
+
+### From PyPI
+
+To install **Gengram** from PyPI following commands can be used in terminal:
+
+1. `virtualenv -p python3.8 venv`
+2. `source ./venv/bin/activate`
+3. `pip install genegram`
+
+### From sources
+
+To install **Gengram** from sources following commands can be used in terminal:
+
+1. `git clone https://github.com/JetBrains-Research/Genegram.git`
+2. `cd Genegram`
+
+Either follow `virtualenv` column steps or `conda` column steps to create virtual environment
+and to install **Genegram** dependencies given in table below:
+
+| | virtualenv | conda |
+| --- |--------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| 3. | `virtualenv -p python3.8 venv` | `conda create -n venv python=3.8` |
+| 4. | `source ./venv/bin/activate` | `conda activate venv` |
+| 5. | To run Genegram on **CPU:**
`pip install tensorflow-cpu==2.7.0`
or
To run Genegram on **GPU:**
`pip install tensorflow-gpu==2.7.0` | To run Genegram on **CPU:**
`conda install tensorflow-cpu==2.7.0 --channel conda-forge`
or
To run Genegram on **GPU:**
`conda install tensorflow-gpu==2.7.0 --channel conda-forge` |
+| 6. | `pip install .` | `pip install .` |
+
## Usage
-Run the following command with arguments.
+After successfully installing the package, you have three options to use it:
-```bash
-python -m genegram
-```
+1. `python -m genegram `
+2. `genegram `
+3. ```Python
+ from genegram import process_fasta_group
+ process_fasta_group()
+ ```
-### **Arguments**
+### Arguments
Argument | Required | Description
:--- | :---: | :---
-i, --inp | True | Path to the [`FASTA`](http://genetics.bwh.harvard.edu/pph/FASTA.html) file
-o, --out | True | Path to the folder where the [`Connectivity Tables`](http://rna.urmc.rochester.edu/Text/File_Formats.html#CT) will be saved
-m, --model | False | Type of the model to be used: `main` -- The default model, the best on average `mps` -- Multiplet prediction model `pks` -- Pseudoknots prediction model
--l, --log | False | Type of the logging level to be used: `INFO` -- Confirmation that things are working as expected `WARNING` -- An indication that something unexpected happened, the software is still working as expected `ERROR` -- Due to a more serious problem, the software has not been able to perform some function `CRITICAL` -- A serious error, indicating that the program itself may be unable to continue running `DEBUG` -- Detailed information, typically of interest only when diagnosing problems
-## Code style
+## Examples
+
+If you have installed Genegram from sources, you can run the following example (in the Genegram folder)
+
+`genegram -i tests/data/seq.fasta -o EXAMPLE_FOLDER -m main`
+
+## Information for Developers
+
+### Code Style
We recommend you use a [pre-commit](https://pre-commit.com/#install) hook, which runs [black](https://github.com/psf/black) when you type git commit.
-### Install pre-commit
+#### Install pre-commit
```shell
pipenv install --dev
pre-commit install
```
-### Use pre-commit
+#### Use pre-commit
```shell
pre-commit run --all-files --color always --verbose
diff --git a/genegram/__init__.py b/genegram/__init__.py
index 1a925cb..9335c4d 100644
--- a/genegram/__init__.py
+++ b/genegram/__init__.py
@@ -1,6 +1,11 @@
+__version__ = "1.0.0"
+
import genegram.shared
from genegram.shared import *
+import genegram.utils
+from genegram.utils import *
+
import genegram.cfpq_pyalgo
from genegram.cfpq_pyalgo import *
@@ -9,3 +14,6 @@
import genegram.predict
from genegram.predict import *
+
+import genegram.main
+from genegram.main import *
diff --git a/genegram/__main__.py b/genegram/__main__.py
index 1f42c4f..9738b24 100644
--- a/genegram/__main__.py
+++ b/genegram/__main__.py
@@ -1,12 +1,11 @@
-import logging
+"""Genegram CLI"""
from argparse import ArgumentParser, RawTextHelpFormatter
from pathlib import Path
-from genegram.parsing import read_fasta
-from genegram.predict import rna_predict, setup_model, clear_session
-from genegram.shared import ROOT
+from genegram.main import process_fasta_group
-if __name__ == "__main__":
+
+def main():
parser = ArgumentParser(
description="Genegram", formatter_class=RawTextHelpFormatter
)
@@ -34,49 +33,15 @@
"\npks -- Pseudoknots prediction model"
),
)
- parser.add_argument(
- "-l",
- "--log",
- required=False,
- type=str,
- choices=["INFO", "WARNING", "ERROR", "CRITICAL", "DEBUG"],
- default="INFO",
- help=(
- "Type of the logging level to be used:"
- "\nINFO -- Confirmation that things are working as expected"
- "\nWARNING -- An indication that something unexpected happened, the software is still working as expected"
- "\nERROR -- Due to a more serious problem, the software has not been able to perform some function"
- "\nCRITICAL -- A serious error, indicating that the program itself may be unable to continue running"
- "\nDEBUG -- Detailed information, typically of interest only when diagnosing problems"
- ),
- )
args = parser.parse_args()
- logging.basicConfig(
- level=args.log,
- format="[%(asctime)s]>%(levelname)s>%(message)s",
- datefmt="%Y-%m-%d %H:%M:%S",
+ process_fasta_group(
+ fasta=Path(args.inp).resolve(),
+ out=Path(args.out).resolve(),
+ weights=args.model,
)
- logging.info(f"Parse {args=}")
-
- out = Path(args.out).resolve()
- if not out.exists():
- out.mkdir(parents=True, exist_ok=True)
- logging.info(f"Create {out} dir")
-
- model = setup_model(ROOT / "weights" / f"{args.model}.h5")
-
- for rna in read_fasta(Path(args.inp).resolve()):
- pred = rna_predict(rna, model)
- target_path = out / f"{rna.description}.ct"
-
- with open(target_path, "w") as fout:
- fout.write(pred.ct)
- logging.info(
- f"Save {rna=} secondary structure connectivity table to {target_path=}"
- )
-
- clear_session()
+if __name__ == "__main__":
+ main()
diff --git a/genegram/cfpq_pyalgo.py b/genegram/cfpq_pyalgo.py
index 674de45..700d86b 100644
--- a/genegram/cfpq_pyalgo.py
+++ b/genegram/cfpq_pyalgo.py
@@ -1,121 +1,238 @@
-from typing import AbstractSet, Iterable, Tuple
+"""The All-Pairs CFL-reachability module"""
+from collections import defaultdict
+from typing import Dict, List
-from cfpq_data import cnf_from_cfg
-from networkx import MultiDiGraph
-from pyformlang.cfg import CFG, Variable, Terminal
-from pygraphblas import Matrix, BOOL
+import pygraphblas as gb
+from pyformlang.cfg import CFG, Production, Variable, Terminal, Epsilon
__all__ = [
- "CNF",
- "BooleanMatrixGraph",
"all_pairs_reachability_matrix",
+ "WCNF",
+ "BooleanMatrixGraph",
]
-class CNF:
- def __init__(
- self,
- start_symbol: Variable,
- variables: AbstractSet[Variable],
- terminals: AbstractSet[Terminal],
- unary_productions: Iterable[Tuple[Variable, Terminal]],
- double_productions: Iterable[Tuple[Variable, Variable, Variable]],
- ):
- self.start_symbol = start_symbol
- self.variables = variables
- self.terminals = terminals
- self.unary_productions = unary_productions
- self.double_productions = double_productions
-
- @classmethod
- def from_cfg(cls, cfg: CFG):
- base_cnf = cnf_from_cfg(cfg)
-
- unary_productions = list()
- double_productions = list()
-
- for p in base_cnf.productions:
- if len(p.body) == 0:
- unary_productions.append((p.head, Terminal("$")))
- elif len(p.body) == 1:
- unary_productions.append((p.head, Terminal(p.body[0].value)))
- elif len(p.body) == 2:
- double_productions.append(
- (p.head, Variable(p.body[0].value), Variable(p.body[1].value))
- )
-
- cnf = CNF(
- base_cnf.start_symbol,
- base_cnf.variables,
- base_cnf.terminals,
- unary_productions,
- double_productions,
- )
-
- return cnf
-
- @classmethod
- def from_text(cls, text, start_symbol: Variable = Variable("S")):
- return CNF.from_cfg(CFG.from_text(text, start_symbol))
-
-
class BooleanMatrixGraph:
- def __init__(self, matrices_size: int):
- self.matrices_size = matrices_size
- self.matrices = dict()
-
- def __getitem__(self, item) -> Matrix:
- if item not in self.matrices:
- self.matrices[item] = Matrix.sparse(
- BOOL, self.matrices_size, self.matrices_size
+ """A Labeled Graph decomposed into Boolean Matrices"""
+
+ def __init__(self, number_of_nodes: int = 0):
+ self._matrices: Dict[str, gb.Matrix] = dict()
+ self._number_of_nodes: int = number_of_nodes
+
+ def __getitem__(self, label: str) -> gb.Matrix:
+ if label not in self._matrices:
+ self._matrices[label] = gb.Matrix.sparse(
+ typ=gb.BOOL,
+ nrows=self._number_of_nodes,
+ ncols=self._number_of_nodes,
)
- return self.matrices[item]
+ return self._matrices[label]
- def __setitem__(self, key, value):
- self.matrices[key] = value
-
- def __iter__(self):
- return self.matrices.__iter__()
+ def __setitem__(self, label: str, matrix: gb.Matrix) -> None:
+ self._matrices[label] = matrix
@property
- def labels(self):
- return list(self.matrices.keys())
-
- @classmethod
- def from_multidigraph(cls, g: MultiDiGraph):
- bmg = BooleanMatrixGraph(g.number_of_nodes())
+ def number_of_nodes(self) -> int:
+ """The number of nodes in the graph
+ Returns
+ -------
+ number_of_nodes: int
+ Number of nodes in the graph
+ """
+ return self._number_of_nodes
+
+ def add_edge(self, u: int, v: int, label: str) -> None:
+ """Add an edge between `u` and `v` with label `label`.
+ The nodes `u` and `v` will be automatically added if they are
+ not already in the graph.
+ Parameters
+ ----------
+ u: int
+ The tail of the edge
+ v: int
+ The head of the edge
+ label: str
+ The label of the edge
+ """
+ if max(u, v) > self._number_of_nodes - 1:
+ self._number_of_nodes = max(u, v) + 1
+ for key in self._matrices:
+ self._matrices[key].resize(self._number_of_nodes, self._number_of_nodes)
+
+ if label not in self._matrices:
+ self._matrices[label] = gb.Matrix.sparse(
+ typ=gb.BOOL, nrows=self._number_of_nodes, ncols=self._number_of_nodes
+ )
- for u, v, edge_labels in g.edges(data=True):
- bmg[Terminal(edge_labels["label"])][u, v] = 1
+ self._matrices[label][u, v] = True
+
+
+class WCNF:
+ """A Weak Chomsky Normal Form of Context-Free Grammar
+ in which products take the following form:
+ - A -> B C
+ - A -> a
+ - A -> epsilon
+ where `A`, `B` and `C` are variables; `a` is an arbitrary terminal
+ Also known as Weak Chomsky Normal Form
+
+ Parameters
+ ----------
+ cfg: CFG
+ Context-Free Grammar
+ """
+
+ def __init__(self, cfg: CFG):
+ self._cfg: CFG = cfg
+ self.start_variable: Variable = cfg.start_symbol
+
+ if not _is_in_wcnf(cfg):
+ cnf = cfg.to_normal_form()
+ else:
+ cnf = cfg
+
+ self.epsilon_productions: List[Production] = []
+ self.unary_productions: List[Production] = []
+ self.binary_productions: List[Production] = []
+
+ for production in self._cfg.productions:
+ if production.body in ([], Epsilon):
+ if production not in self.epsilon_productions:
+ self.epsilon_productions.append(production)
+
+ for production in cnf.productions:
+ if len(production.body) == 1:
+ if production not in self.unary_productions:
+ self.unary_productions.append(production)
+ elif len(production.body) == 2:
+ if production not in self.binary_productions:
+ self.binary_productions.append(production)
+
+ self.productions = (
+ self.epsilon_productions + self.unary_productions + self.binary_productions
+ )
- return bmg
+ self.variables: List[Variable] = []
+ self.terminals: List[Terminal] = []
- @classmethod
- def from_triples(cls, triples):
- number_of_nodes = max({max(u, v) for u, label, v in triples})
+ for production in self.productions:
+ if production.head not in self.variables:
+ self.variables.append(production.head)
- bmg = BooleanMatrixGraph(number_of_nodes + 1)
+ for term in production.body:
+ if isinstance(term, Terminal):
+ if term not in self.terminals:
+ self.terminals.append(term)
+ elif isinstance(term, Variable):
+ if term not in self.variables:
+ self.variables.append(term)
- for u, label, v in triples:
- bmg[Terminal(label)][u, v] = 1
+ def contains(self, word: str) -> bool:
+ """Gives the membership of a word to the grammar
- return bmg
+ Parameters
+ ----------
+ word : str
+ The word to check
+ Returns
+ ----------
+ contains : bool
+ Whether word if in the grammar's language or not
+ """
+ return self._cfg.contains(word)
-def all_pairs_reachability_matrix(graph: BooleanMatrixGraph, grammar: CNF):
- m = BooleanMatrixGraph(graph.matrices_size)
- for l, r in grammar.unary_productions:
- m[l] += graph[r]
+ @classmethod
+ def from_text(cls, text, start_symbol=Variable("S")):
+ """
+ Read a Weak Chomsky Normal Form Context-Free Grammar from a text.
+ The text contains one rule per line.
+ The structure of a production is:
+ head -> body1 | body2 | ... | bodyn
+ where | separates the bodies.
+ A variable (or non terminal) begins by a capital letter.
+ A terminal begins by a non-capital character
+ Terminals and Variables are separated by spaces.
+ An epsilon symbol can be represented by epsilon, $, ε, ϵ or Є.
+ If you want to have a variable name starting with a non-capital \
+ letter or a terminal starting with a capital letter, you can \
+ explicitly give the type of your symbol with "VAR:yourVariableName" \
+ or "TER:yourTerminalName" (with the quotation marks). For example:
+ S -> "TER:John" "VAR:d" a b
+
+ Parameters
+ ----------
+ text : str
+ The text of transform
+ start_symbol : str, optional
+ The start symbol, S by default
+
+ Returns
+ -------
+ wcnf : WCNF
+ A Weak Chomsky Normal Form Context-Free Grammar
+ """
+ return cls(CFG.from_text(text, start_symbol))
+
+
+def _is_in_wcnf(cfg: CFG) -> bool:
+ for production in cfg.productions:
+ if len(production.body) > 2:
+ return False
+ elif len(production.body) == 2:
+ if not (
+ isinstance(production.body[0], Variable)
+ and isinstance(production.body[1], Variable)
+ ):
+ return False
+ elif len(production.body) == 1:
+ if not isinstance(production.body[0], Terminal):
+ return False
+ return True
+
+
+def all_pairs_reachability_matrix(
+ graph: BooleanMatrixGraph, grammar: WCNF
+) -> gb.Matrix:
+ """Determines the pairs of vertices (`u`, `v`)
+ where there exists a path from `u` to `v`
+ in `graph` and its word is in the language of `grammar`
+
+ Parameters
+ ----------
+ graph: BooleanMatrixGraph
+ grammar: WCNF
+
+ Returns
+ -------
+ pairs: pygraphblas.Matrix
+ Reachability matrix
+ """
+ bmg = BooleanMatrixGraph(graph.number_of_nodes)
+
+ for production in grammar.unary_productions:
+ # production :: l -> r
+ l = production.head.value
+ r = production.body[0].value
+
+ bmg[l] += graph[r]
changed = True
+ nvals = defaultdict(int)
while changed:
changed = False
- for l, r1, r2 in grammar.double_productions:
- old_nnz = m[l].nvals
- m[l] += m[r1].mxm(m[r2], semiring=BOOL.ANY_PAIR)
- new_nnz = m[l].nvals
+ for production in grammar.binary_productions:
+ # production :: l -> r1 r2
+ l = production.head.value
+ r1 = production.body[0].value
+ r2 = production.body[1].value
+
+ bmg[l] += bmg[r1].mxm(bmg[r2], semiring=gb.BOOL.ANY_PAIR)
+
+ nnz = bmg[l].nvals
+
+ changed |= nvals[l] != nnz
- if old_nnz != new_nnz:
- changed = True
+ nvals[l] = nnz
- return m[grammar.start_symbol]
+ return bmg[grammar.start_variable.value]
diff --git a/genegram/grammar.txt b/genegram/grammar.txt
deleted file mode 100644
index 61a102b..0000000
--- a/genegram/grammar.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-S -> S1
-S0 -> Any_str | Any_str S1 S0
-S2 -> a S0 u | g S0 c | u S0 a | c S0 g
-S3 -> a S2 u | g S2 c | u S2 a | c S2 g
-S4 -> a S3 u | g S3 c | u S3 a | c S3 g
-S1 -> a S1 u | u S1 a | c S1 g | g S1 c | S4
-Any -> a | u | c | g
-Any_str -> Any
-Any_str -> Any Any
-Any_str -> Any Any Any
-Any_str -> Any Any Any Any
-Any_str -> Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
-Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
diff --git a/genegram/main.py b/genegram/main.py
new file mode 100644
index 0000000..78c40fd
--- /dev/null
+++ b/genegram/main.py
@@ -0,0 +1,107 @@
+"""FASTA processing module"""
+from pathlib import Path
+
+from genegram.parsing import (
+ read_fasta_group,
+ parse_rna_group,
+ read_fasta_single,
+ parse_rna_single,
+)
+from genegram.predict import setup_model, clear_session, predict
+from genegram.shared import ROOT
+from genegram.utils import binarize_image, create_connectivity_table, remove_multiplets
+
+__all__ = [
+ "process_fasta_single",
+ "process_fasta_group",
+]
+
+
+def process_fasta_single(
+ fasta: Path,
+ out: Path,
+ weights: str = "main",
+ bin_coeff: float = 0.6,
+) -> Path:
+ """Process Secondary Structure for each RNA from `fasta` file using single method
+
+ Parameters
+ ----------
+ fasta: Path
+ The path to FASTA input file
+ out:
+ The path where the resulting connectivity tables will be saved
+ weights:
+ Type of predictive model weights
+ bin_coeff:
+ Binarization coefficient
+
+ Returns
+ -------
+ out: Path
+ The path where the resulting connectivity tables will be saved
+ """
+ if not out.exists():
+ out.mkdir(parents=True, exist_ok=True)
+
+ model = setup_model(ROOT / "weights" / f"{weights}.h5")
+
+ for rna in read_fasta_single(fasta):
+ image = parse_rna_single(rna)
+ prediction = predict(image, model)
+ prediction_cleaned = remove_multiplets(prediction)
+ pred_bin = binarize_image(prediction_cleaned, bin_coeff)
+ ct = create_connectivity_table(pred_bin, *rna)
+
+ target_path = out / f"{rna.description}.ct"
+ with open(target_path, "w") as fout:
+ fout.write(ct)
+
+ clear_session()
+
+ return Path(out).resolve()
+
+
+def process_fasta_group(
+ fasta: Path,
+ out: Path,
+ weights: str = "main",
+ bin_coeff: float = 0.6,
+) -> Path:
+ """Process Secondary Structure for each RNA from `fasta` file using group method
+
+ Parameters
+ ----------
+ fasta: Path
+ The path to FASTA input file
+ out:
+ The path where the resulting connectivity tables will be saved
+ weights:
+ Type of predictive model weights
+ bin_coeff:
+ Binarization coefficient
+
+ Returns
+ -------
+ out: Path
+ The path where the resulting connectivity tables will be saved
+ """
+ if not out.exists():
+ out.mkdir(parents=True, exist_ok=True)
+
+ model = setup_model(ROOT / "weights" / f"{weights}.h5")
+
+ for rna_group in read_fasta_group(fasta):
+ for index, image in parse_rna_group(rna_group):
+ prediction = predict(image, model)
+ prediction_cleaned = remove_multiplets(prediction)
+ pred_bin = binarize_image(prediction_cleaned, bin_coeff)
+ ct = create_connectivity_table(pred_bin, *rna_group[index])
+
+ target_path = out / f"{rna_group[index].description}.ct"
+ with open(target_path, "w") as fout:
+ fout.write(ct)
+
+ clear_session()
+
+ return Path(out).resolve()
diff --git a/genegram/parsing.py b/genegram/parsing.py
index ab7a8c8..58d591b 100644
--- a/genegram/parsing.py
+++ b/genegram/parsing.py
@@ -1,71 +1,172 @@
-import logging
-from collections import namedtuple
+"""FASTA parsing module"""
from pathlib import Path
-from typing import Iterator
+from typing import List, Tuple
-from PIL import Image, ImageDraw
-from cfpq_data import cfg_from_txt
-from pyformlang.cfg import Terminal
+import numpy as np
-from genegram.cfpq_pyalgo import BooleanMatrixGraph, CNF, all_pairs_reachability_matrix
-from genegram.shared import ROOT
-
-GRAMMAR = CNF.from_cfg(cfg_from_txt(ROOT / "grammar.txt"))
-NUCLEOTIDE_TO_COLOR = {"a": 32, "c": 64, "g": 96, "u": 128}
-
-RNA = namedtuple("RNA", ["description", "sequence"])
+from genegram.cfpq_pyalgo import BooleanMatrixGraph, all_pairs_reachability_matrix
+from genegram.shared import GROUP_LEN, GRAMMAR, RNA, NUCLEOTIDE_TO_COLOR
__all__ = [
- "RNA",
- "read_fasta",
- "rna_to_img",
+ "read_fasta_single",
+ "read_fasta_group",
+ "parse_rna_single",
+ "parse_rna_group",
]
-def read_fasta(fasta: Path) -> Iterator[RNA]:
- logging.info(f"Read {fasta=}")
+def read_fasta_single(fasta: Path) -> List[RNA]:
+ """Read FASTA file from `fasta` path.
+ The FASTA file must be in the following format:
+ >`RNA description`
+ `RNA sequence`
+ >`RNA description`
+ `RNA sequence`
+ ...
+ >`RNA description`
+ `RNA sequence`
+
+ Parameters
+ ----------
+ fasta: Path
+ Path to the FASTA file
+
+ Returns
+ -------
+ rna: List[RNA]
+ RNA sequences from a FASTA file
+ """
with open(fasta, "r") as fin:
- while True:
- desc = fin.readline().strip()
+ data = fin.readlines()
+ return [
+ RNA(data[i].strip()[1:], data[i + 1].strip()) for i in range(0, len(data), 2)
+ ]
+
+
+def read_fasta_group(fasta: Path, limit: int = GROUP_LEN) -> List[List[RNA]]:
+ """Read FASTA file from `fasta` path.
+ The FASTA file must be in the following format:
+ >`RNA description`
+ `RNA sequence`
+ >`RNA description`
+ `RNA sequence`
+ ...
+ >`RNA description`
+ `RNA sequence`
+
+ Parameters
+ ----------
+ fasta: Path
+ Path to the FASTA file
+ limit: int
+ Limit on the total size of a group of RNA sequences
+
+ Returns
+ -------
+ rna: List[List[RNA]]
+ Grouped RNA sequences from a FASTA file
+ """
+ with open(fasta, "r") as fin:
+ data = fin.readlines()
+ result = []
+ cur_group = []
+ cur_len = 0
- # EOF
- if not desc:
- break
+ for i in range(0, len(data), 2):
+ rna = RNA(data[i].strip()[1:], data[i + 1].strip())
+ cur_group.append(rna)
+ cur_len += 1 + len(rna.sequence)
- seq = fin.readline().strip()
+ if abs(limit - cur_len) < abs(limit - (cur_len + 1 + len(rna.sequence))):
+ result.append(cur_group)
+ cur_group = []
+ cur_len = 0
- logging.debug(f"read_fasta():\n{desc=} \n{seq=}")
+ if cur_group:
+ result.append(cur_group)
- yield RNA(desc[1:], seq.lower())
+ return result
-def rna_to_img(rna: RNA) -> Image:
- logging.info(f"{rna=} to image")
+def parse_rna_single(rna: RNA) -> np.ndarray:
+ """Parse RNA `rna` with grammar `GRAMMAR`
- bmg = BooleanMatrixGraph(matrices_size=len(rna.sequence) + 1)
+ Parameters
+ ----------
+ rna: RNA
- for i, nucleotide in enumerate(rna.sequence):
- bmg[Terminal(nucleotide)][i, i + 1] = True
+ Returns
+ -------
+ image: np.ndarray
+ The result of parsing presented as an image
+ """
+ n = len(rna.sequence)
+ bmg = BooleanMatrixGraph(n + 1)
+ # in grammar, nucleotides must be lowercase
+ for i, nucleotide in enumerate(rna.sequence.lower()):
+ bmg[nucleotide][i, i + 1] = True
- reachabilities = all_pairs_reachability_matrix(
- graph=bmg,
- grammar=GRAMMAR,
- )
+ reachabilities = all_pairs_reachability_matrix(bmg, GRAMMAR)
- # create white&black 8-bit image
- img = Image.new(mode="L", size=(bmg.matrices_size - 1, bmg.matrices_size - 1))
- im_draw = ImageDraw.Draw(img)
+ image = np.zeros((n, n), dtype=np.uint8)
- # draw reachabilities
+ # draw pairings
I, J, _ = reachabilities.to_lists()
- for k, i in enumerate(I):
- j = J[k]
- im_draw.line(xy=[(j - 3, i + 2), (j - 1, i)], fill=255)
+ for i, j in zip(I, J):
+ image[i + 2, j - 3] = 255
+ image[i + 1, j - 2] = 255
+ image[i, j - 1] = 255
- # draw letters
+ # draw nucleotides
for i, nucleotide in enumerate(rna.sequence):
- im_draw.point(xy=(i, i), fill=NUCLEOTIDE_TO_COLOR[nucleotide])
+ image[i, i] = NUCLEOTIDE_TO_COLOR[nucleotide]
+
+ return image
+
+
+def parse_rna_group(rna_group: List[RNA]) -> List[Tuple[int, np.ndarray]]:
+ """Parse a group of RNA sequences `rna_group` with grammar `GRAMMAR`
+
+ Parameters
+ ----------
+ rna_group: List[RNA]
+ A group of RNA sequences
+
+ Returns
+ -------
+ index, image: Tuple[int, np.ndarray]
+ Iterator over the result of parsing
+ """
+ result = []
+ # in grammar, nucleotides must be lowercase
+ glued_rna = "$".join((seq.lower() for _, seq in rna_group))
+ bmg = BooleanMatrixGraph(len(glued_rna) + 1)
+ for i, nucleotide in enumerate(glued_rna):
+ bmg[nucleotide][i, i + 1] = True
+
+ reachabilities = all_pairs_reachability_matrix(bmg, GRAMMAR)
+
+ prefix = 0
+ for index, (desc, seq) in enumerate(rna_group):
+ n = len(seq)
+
+ # create white&black 8-bit image
+ image = np.zeros((n, n), dtype=np.uint8)
+
+ # draw pairings
+ I, J, _ = reachabilities[
+ prefix : (prefix + n), prefix : (prefix + n)
+ ].to_lists()
+ for i, j in zip(I, J):
+ image[i + 2, j - 3] = 255
+ image[i + 1, j - 2] = 255
+ image[i, j - 1] = 255
+
+ # draw nucleotides
+ for i, nucleotide in enumerate(seq):
+ image[i, i] = NUCLEOTIDE_TO_COLOR[nucleotide]
- logging.debug(f"rna_to_img():\n{bmg=} \n{reachabilities=} \n{img=}")
+ prefix += n + 1
+ result.append((index, image))
- return img
+ return result
diff --git a/genegram/predict.py b/genegram/predict.py
index b445c61..1fb7787 100644
--- a/genegram/predict.py
+++ b/genegram/predict.py
@@ -1,13 +1,6 @@
-import logging
-import os
-from collections import namedtuple
from pathlib import Path
import numpy as np
-
-# hide TensorFlow warnings
-os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
-
import tensorflow as tf
from keras import backend as K
from keras import regularizers
@@ -15,158 +8,17 @@
from keras.models import Model
from tensorflow.keras.layers import Layer
-from genegram.parsing import RNA, rna_to_img
-
__all__ = [
- "PredictionContext",
- "rna_predict",
- "img_predict",
- "img_binarize",
- "img_to_ct",
- "remove_multiplets",
+ "predict",
"setup_model",
"clear_session",
]
-PredictionContext = namedtuple(
- "PredictionContext",
- [
- "rna",
- "img_rna",
- "img_pred",
- "ct",
- ],
-)
-
def clear_session():
- logging.info("Clear TensorFlow session")
K.clear_session()
-def img_to_ct(img, meta, seq):
- logging.info(f"Create Connectivity Table for RNA({meta}, {seq})")
-
- size = len(img)
- ct = " " + str(size) + " " + meta + "\n"
- for i in range(size):
- pair = 0
- for j in range(size):
- if img[i][j] == 255 or img[j][i] == 255:
- pair = j + 1
- ct += (
- " "
- + str(i + 1)
- + " "
- + seq[i]
- + " "
- + str(i)
- + " "
- + str(i + 2)
- + " "
- + str(pair)
- + " "
- + str(i + 1)
- + "\n"
- )
-
- logging.debug(f"img_to_ct():\n{img=} \n{meta=} \n{seq=} \n{ct=}")
-
- return ct
-
-
-def remove_multiplets(img):
- def get_multiplets(i0, j0, img):
- mps = []
- size = len(img)
- for i in range(size):
- if img[i0, i] == 255 and (i0, i) != (i0, j0) and i0 <= i:
- mps.append((i0, i))
- if img[j0, i] == 255 and (j0, i) != (i0, j0) and j0 <= i:
- mps.append((j0, i))
- if img[i, i0] == 255 and (i, i0) != (i0, j0) and i <= i0:
- mps.append((i, i0))
- if img[i, j0] == 255 and (i, j0) != (i0, j0) and i <= j0:
- mps.append((i, j0))
- return list(set(mps))
-
- def get_stem_len(i0, j0, img):
- size = len(img)
- stem_len = 1
- i, j = i0 + 1, j0 - 1
- while (
- i < len(img)
- and j >= 0
- and img[i][j] == 255
- and len(get_multiplets(i, j, img)) == 0
- ):
- stem_len += 1
- i += 1
- j -= 1
- i, j = i0 - 1, j0 + 1
- while (
- i >= 0
- and j < len(img)
- and img[i][j] == 255
- and len(get_multiplets(i, j, img)) == 0
- ):
- stem_len += 1
- i -= 1
- j += 1
- return stem_len
-
- size = len(img)
- mps_nums = dict()
- for i in range(size):
- for j in range(i + 1, size):
- if img[i][j] == 255:
- mps = get_multiplets(i, j, img)
- if len(mps) > 0:
- mps_nums[(i, j)] = len(mps)
- mps_nums = {k: v for k, v in sorted(mps_nums.items(), key=lambda item: -item[1])}
- to_delete = []
- while len(mps_nums) > 0:
- for el in to_delete:
- del mps_nums[el]
- to_delete = []
- for (i, j) in mps_nums.keys():
- if not (i, j) in to_delete:
- mps = get_multiplets(i, j, img)
- if len(mps) > 0:
- min_stem_len = get_stem_len(i, j, img)
- i_pick, j_pick = i, j
- for (i0, j0) in mps:
- stem_len = get_stem_len(i0, j0, img)
- if stem_len < min_stem_len:
- i_pick, j_pick = i0, j0
- min_stem_len = stem_len
- img[i_pick][j_pick] = 0
- to_delete.append((i_pick, j_pick))
- else:
- to_delete.append((i, j))
- return img
-
-
-# set each gray pixel of network prediction to black/white
-# according to threshold coeff
-def img_binarize(img, coeff=0.6):
- logging.info(f"Binarize image")
-
- im = img.copy()
- size = len(img)
- for i in range(size):
- for j in range(size):
- if i != j:
- if im[i][j] > 255 * coeff:
- im[i][j] = 255
- else:
- im[i][j] = 0
-
- logging.debug(f"img_binarize():\n{img=} \n{coeff=} \n{im=}")
-
- return im
-
-
# Model definition functions
# layer that for inputs i1, i2, i3, i4
@@ -199,7 +51,7 @@ def call(self, input):
# residual unit definition, classical structure in ML
-def res_unit(inputs, filters, kernels, activ, bn=False, dr=0):
+def res_unit(inputs, filters, kernels, activ, bn=False, dr=0.0):
x = inputs
if bn:
x = BatchNormalization()(x)
@@ -217,8 +69,8 @@ def res_unit(inputs, filters, kernels, activ, bn=False, dr=0):
# residual network definition: repeating res units
-# + skip sonnections(add layers)
-def res_network(inputs, units_num, filters, kernels, activ="relu", bn=False, dr=0):
+# + skip connections(add layers)
+def res_network(inputs, units_num, filters, kernels, activ="relu", bn=False, dr=0.0):
x = res_unit(inputs, filters, kernels, activ, bn, dr)
x = add([x, inputs])
x = Activation(activ)(x)
@@ -227,14 +79,13 @@ def res_network(inputs, units_num, filters, kernels, activ="relu", bn=False, dr=
x = add([x, y])
x = Activation(activ)(x)
outputs = x
-
model = Model(inputs=inputs, outputs=outputs)
return model
# model that combines several residual networks
def parallel_res_network(
- blocks_num, units_num, filters, kernels, activ="relu", bn=False, dr=0
+ blocks_num, units_num, filters, kernels, activ="relu", bn=False, dr=0.0
):
inputs = Input(shape=(None, None, 1))
all_outputs = []
@@ -260,13 +111,13 @@ def setup_model(weights: Path):
tf_session_config = tf.compat.v1.ConfigProto(
intra_op_parallelism_threads=1, inter_op_parallelism_threads=1
)
+ tf_session_config.gpu_options.allow_growth = True
+
tf_session = tf.compat.v1.Session(
graph=tf.compat.v1.get_default_graph(), config=tf_session_config
)
K.set_session(tf_session)
- logging.info("Setup TensorFlow session")
-
# setup model
model = parallel_res_network(
blocks_num=4,
@@ -278,57 +129,33 @@ def setup_model(weights: Path):
dr=0.1,
)
model.load_weights(weights)
-
- logging.info(f"Setup model")
- logging.debug(f"setup_model():\n{weights=} \n{model=}")
-
return model
-# get model output on input image pil_img
-def img_predict(pil_img, model):
- logging.info("Predict image")
+def predict(image: np.ndarray, model: Model) -> np.ndarray:
+ """Get `model` output on input `pil_image`
- img = np.array(pil_img)
- n = len(img)
- inp = np.array([img]).reshape((1, n, n, 1))
+ Parameters
+ ----------
+ image: np.ndarray
+ Input image
+ model: Model
+ Prediction model
- pred = model.predict(inp)
+ Returns
+ -------
+ array: np.ndarray
+ Prediction result
+ """
+ n = image.shape[0]
+ inputs = np.array([image]).reshape((1, n, n, 1))
- res = np.full(shape=(n, n), fill_value=255, dtype=np.uint8)
+ prediction = model.predict(inputs)
+
+ result = np.full(shape=(n, n), fill_value=255, dtype=np.uint8)
for i in range(n):
for j in range(n):
- res[i][j] = min(pred[0][i][j][0], 255)
-
- logging.debug(
- f"img_predict():\n{pil_img=} \n{model=} \n{img=} \n{n=} \n{inp=} \n{pred=} \n{res=}"
- )
-
- return res
-
+ if prediction[0][i][j][0] < 255:
+ result[i][j] = prediction[0][i][j][0]
-def rna_predict(rna: RNA, model):
- logging.info("Predict RNA")
-
- img_rna = rna_to_img(rna)
-
- pred = img_predict(img_rna, model)
-
- pred_bin = img_binarize(pred)
-
- ct = img_to_ct(
- pred_bin,
- rna.description,
- rna.sequence.upper(),
- )
-
- logging.debug(
- f"rna_predict():\n{rna=} \n{model=} \n{img_rna=} \n{pred=} \n{pred_bin=} \n{ct=}"
- )
-
- return PredictionContext(
- rna=rna,
- img_rna=img_rna,
- img_pred=pred_bin,
- ct=ct,
- )
+ return result
diff --git a/genegram/shared.py b/genegram/shared.py
index 62cde4b..8266ef1 100644
--- a/genegram/shared.py
+++ b/genegram/shared.py
@@ -1,7 +1,52 @@
+from collections import namedtuple
from pathlib import Path
+from genegram.cfpq_pyalgo import WCNF
+
__all__ = [
"ROOT",
+ "GROUP_LEN",
+ "NUCLEOTIDE_TO_COLOR",
+ "RNA",
+ "GRAMMAR",
]
+GROUP_LEN = 100_000
+
ROOT = Path(__file__).parent.resolve()
+
+NUCLEOTIDE_TO_COLOR = {"A": 32, "C": 64, "G": 96, "U": 128}
+
+RNA = namedtuple("RNA", ["description", "sequence"])
+
+GRAMMAR = WCNF.from_text(
+ """
+S -> S1
+S0 -> Any_str | Any_str S1 S0
+S2 -> a S0 u | g S0 c | u S0 a | c S0 g
+S3 -> a S2 u | g S2 c | u S2 a | c S2 g
+S4 -> a S3 u | g S3 c | u S3 a | c S3 g
+S1 -> a S1 u | u S1 a | c S1 g | g S1 c | S4
+Any -> a | u | c | g
+Any_str -> Any
+Any_str -> Any Any
+Any_str -> Any Any Any
+Any_str -> Any Any Any Any
+Any_str -> Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
+Any_str -> Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any Any
+"""
+)
diff --git a/genegram/utils.py b/genegram/utils.py
new file mode 100644
index 0000000..772c041
--- /dev/null
+++ b/genegram/utils.py
@@ -0,0 +1,166 @@
+"""Post-processing utilities"""
+__all__ = [
+ "binarize_image",
+ "create_connectivity_table",
+ "remove_multiplets",
+]
+
+import numpy as np
+
+
+def create_connectivity_table(image: np.ndarray, meta: str, seq: str) -> str:
+ """Creates a Connectivity Table from an RNA Secondary Structure
+ represented as an image
+
+ Parameters
+ ----------
+ image: np.ndarray
+ RNA Secondary Structure
+ meta: str
+ RNA description
+ seq: str
+ RNA sequence
+
+ Returns
+ -------
+ ct: str
+ Connectivity Table
+ """
+ size = len(image)
+ # ct = " " + str(size) + " " + meta + "\n"
+ ct = f" {size} {meta}\n"
+ for i in range(size):
+ pair = 0
+ for j in range(size):
+ if image[i][j] == 255 or image[j][i] == 255:
+ pair = j + 1
+ ct += f" {i + 1} {seq[i]} {i} {i + 2} {pair} {i + 1}\n"
+ # ct += (
+ # " "
+ # + str(i + 1)
+ # + " "
+ # + seq[i]
+ # + " "
+ # + str(i)
+ # + " "
+ # + str(i + 2)
+ # + " "
+ # + str(pair)
+ # + " "
+ # + str(i + 1)
+ # + "\n"
+ # )
+ return ct
+
+
+def remove_multiplets(image: np.ndarray) -> np.ndarray:
+ """Remove multiplets from network prediction of RNA Secondary Structure
+
+ Parameters
+ ----------
+ image: np.ndarray
+ RNA Secondary Structure
+
+ Returns
+ -------
+ image: np.ndarray
+ RNA Secondary Structure with removed multiplets
+ """
+
+ def get_multiplets(i0, j0, image):
+ mps = []
+ size = len(image)
+ for i in range(size):
+ if image[i0, i] == 255 and (i0, i) != (i0, j0) and i0 <= i:
+ mps.append((i0, i))
+ if image[j0, i] == 255 and (j0, i) != (i0, j0) and j0 <= i:
+ mps.append((j0, i))
+ if image[i, i0] == 255 and (i, i0) != (i0, j0) and i <= i0:
+ mps.append((i, i0))
+ if image[i, j0] == 255 and (i, j0) != (i0, j0) and i <= j0:
+ mps.append((i, j0))
+ return list(set(mps))
+
+ def get_stem_len(i0, j0, image):
+ size = len(image)
+ stem_len = 1
+ i, j = i0 + 1, j0 - 1
+ while (
+ i < len(image)
+ and j >= 0
+ and image[i][j] == 255
+ and len(get_multiplets(i, j, image)) == 0
+ ):
+ stem_len += 1
+ i += 1
+ j -= 1
+ i, j = i0 - 1, j0 + 1
+ while (
+ i >= 0
+ and j < len(image)
+ and image[i][j] == 255
+ and len(get_multiplets(i, j, image)) == 0
+ ):
+ stem_len += 1
+ i -= 1
+ j += 1
+ return stem_len
+
+ size = len(image)
+ mps_nums = dict()
+ for i in range(size):
+ for j in range(i + 1, size):
+ if image[i][j] == 255:
+ mps = get_multiplets(i, j, image)
+ if len(mps) > 0:
+ mps_nums[(i, j)] = len(mps)
+ mps_nums = {k: v for k, v in sorted(mps_nums.items(), key=lambda item: -item[1])}
+ to_delete = []
+ while len(mps_nums) > 0:
+ for el in to_delete:
+ del mps_nums[el]
+ to_delete = []
+ for (i, j) in mps_nums.keys():
+ if not (i, j) in to_delete:
+ mps = get_multiplets(i, j, image)
+ if len(mps) > 0:
+ min_stem_len = get_stem_len(i, j, image)
+ i_pick, j_pick = i, j
+ for (i0, j0) in mps:
+ stem_len = get_stem_len(i0, j0, image)
+ if stem_len < min_stem_len:
+ i_pick, j_pick = i0, j0
+ min_stem_len = stem_len
+ image[i_pick][j_pick] = 0
+ to_delete.append((i_pick, j_pick))
+ else:
+ to_delete.append((i, j))
+ return image
+
+
+def binarize_image(image: np.ndarray, bin_coeff: float = 0.6) -> np.ndarray:
+ """Set each gray pixel of network prediction `image` to black/white
+ according to threshold coeff
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Network prediction image
+ bin_coeff: float
+ Binarization coefficient
+
+ Returns
+ -------
+ im: np.ndarray
+ Binarized image
+ """
+ im = image.copy()
+ size = len(image)
+ for i in range(size):
+ for j in range(size):
+ if i != j:
+ if im[i][j] > 255 * bin_coeff:
+ im[i][j] = 255
+ else:
+ im[i][j] = 0
+ return im
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..374b58c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+requires = [
+ "setuptools>=42",
+ "wheel"
+]
+build-backend = "setuptools.build_meta"
diff --git a/requirements/default.txt b/requirements/default.txt
new file mode 100644
index 0000000..3a854d8
--- /dev/null
+++ b/requirements/default.txt
@@ -0,0 +1,3 @@
+tensorflow==2.7.0
+pygraphblas==4.2.2
+pyformlang==0.1.26
diff --git a/requirements/developer.txt b/requirements/developer.txt
new file mode 100644
index 0000000..d3b5927
--- /dev/null
+++ b/requirements/developer.txt
@@ -0,0 +1,2 @@
+pre-commit==2.15.0
+black==22.3.0
diff --git a/requirements/test.txt b/requirements/test.txt
new file mode 100644
index 0000000..c2845bf
--- /dev/null
+++ b/requirements/test.txt
@@ -0,0 +1 @@
+pytest==7.0.1
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..ddd3612
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,93 @@
+from pathlib import Path
+
+from setuptools import setup, find_packages
+
+root = Path(__file__).parent.resolve()
+
+with open(root / "README.md", "r", encoding="utf-8") as f:
+ long_description = f.read()
+
+with open(root / "genegram/__init__.py", "r", encoding="utf-8") as f:
+ for line in f:
+ if line.startswith("__version__"):
+ version = line.strip().split()[-1][1:-1]
+ break
+
+name = "genegram"
+
+description = (
+ "Project for genomic sequences analysis "
+ "employing the combination of formal grammars and neural networks"
+)
+
+authors = {
+ "vadyushkins": ("Vadim Abzalov", "vadim.i.abzalov@gmail.com"),
+ "LuninaPolina": ("Polina Lunina", "lunina_polina@mail.ru"),
+}
+
+url = "https://github.com/JetBrains-Research/Genegram"
+
+project_urls = {
+ "Documentation": "https://github.com/JetBrains-Research/Genegram",
+ "Source Code": "https://github.com/JetBrains-Research/Genegram",
+ "Bug Tracker": "https://github.com/JetBrains-Research/Genegram/issues",
+}
+
+platforms = ["Linux", "Mac OSX", "Unix"]
+
+keywords = []
+
+classifiers = [
+ "Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Science/Research",
+ "Intended Audience :: Education",
+ "License :: OSI Approved :: Apache Software License",
+ "Operating System :: POSIX :: Linux",
+ "Operating System :: MacOS",
+ "Operating System :: Unix",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3 :: Only",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
+ "Topic :: Scientific/Engineering :: Information Analysis",
+]
+
+
+def parse_requirements_file(filename):
+ with open(filename) as fid:
+ requires = [l.strip() for l in fid.readlines() if not l.startswith("#")]
+
+ return requires
+
+
+install_requires = parse_requirements_file(root / "requirements" / "default.txt")
+extras_require = {
+ dep: parse_requirements_file(root / "requirements" / f"{dep}.txt")
+ for dep in ["developer", "test"]
+}
+
+if __name__ == "__main__":
+ setup(
+ name=name,
+ description=description,
+ long_description=long_description,
+ author=authors["vadyushkins"][0],
+ author_email=authors["vadyushkins"][1],
+ maintainer=authors["LuninaPolina"][0],
+ maintainer_email=authors["LuninaPolina"][1],
+ version=version,
+ keywords=keywords,
+ packages=find_packages(),
+ package_data={"": ["weights/*.h5"]},
+ platforms=platforms,
+ url=url,
+ project_urls=project_urls,
+ classifiers=classifiers,
+ install_requires=install_requires,
+ extras_require=extras_require,
+ python_requires=">=3.8",
+ zip_safe=False,
+ entry_points={"console_scripts": ["genegram=genegram.__main__:main"]},
+ )
diff --git a/tests/cfpq_pyalgo/test_all_pairs_reachability_matrix.py b/tests/cfpq_pyalgo/test_all_pairs_reachability_matrix.py
new file mode 100644
index 0000000..901db29
--- /dev/null
+++ b/tests/cfpq_pyalgo/test_all_pairs_reachability_matrix.py
@@ -0,0 +1,61 @@
+from pyformlang.cfg import CFG
+
+from genegram import BooleanMatrixGraph, WCNF, all_pairs_reachability_matrix
+
+
+def test_empty_graph():
+ bmg = BooleanMatrixGraph()
+ wcnf = WCNF.from_text("S -> a")
+
+ I, J, _ = all_pairs_reachability_matrix(bmg, wcnf).to_lists()
+
+ assert set(zip(I, J)) == set()
+
+
+def test_no_reachable_vertices():
+ bmg = BooleanMatrixGraph()
+ bmg.add_edge(0, 1, "b")
+ bmg.add_edge(1, 2, "c")
+ bmg.add_edge(2, 0, "d")
+
+ wcnf = WCNF.from_text("S -> S S | a")
+
+ I, J, _ = all_pairs_reachability_matrix(bmg, wcnf).to_lists()
+
+ assert set(zip(I, J)) == set()
+
+
+def test_worst_case():
+ # The graph is two cycles of coprime lengths with a single common vertex
+ # The first cycle is labeled by the open bracket
+ # The second cycle is labeled by the close bracket
+ bmg = BooleanMatrixGraph()
+ bmg.add_edge(0, 1, "a")
+ bmg.add_edge(1, 2, "a")
+ bmg.add_edge(2, 0, "a")
+ bmg.add_edge(0, 3, "b")
+ bmg.add_edge(3, 0, "b")
+
+ wcnf = WCNF.from_text("S -> a S b | a b")
+
+ I, J, _ = all_pairs_reachability_matrix(bmg, wcnf).to_lists()
+
+ assert set(zip(I, J)) == {(0, 0), (1, 0), (0, 3), (1, 3), (2, 0), (2, 3)}
+
+
+def test_full_graph_result():
+ # The case when the input graph is sparse, but the result is a full graph.
+ # Input graph is a cycle, all edges of which are labeled by the same token
+ bmg = BooleanMatrixGraph()
+ bmg.add_edge(0, 1, label="a")
+ bmg.add_edge(1, 2, label="a")
+ bmg.add_edge(2, 3, label="a")
+ bmg.add_edge(3, 0, label="a")
+
+ wcnf = WCNF.from_text("S -> S S | a")
+
+ I, J, _ = all_pairs_reachability_matrix(bmg, wcnf).to_lists()
+
+ assert set(zip(I, J)) == {
+ (v, to) for v in range(bmg.number_of_nodes) for to in range(bmg.number_of_nodes)
+ }
diff --git a/tests/cfpq_pyalgo/test_boolean_matrix_graph.py b/tests/cfpq_pyalgo/test_boolean_matrix_graph.py
new file mode 100644
index 0000000..8be31c3
--- /dev/null
+++ b/tests/cfpq_pyalgo/test_boolean_matrix_graph.py
@@ -0,0 +1,53 @@
+from pygraphblas import Matrix, BOOL
+
+from genegram import BooleanMatrixGraph
+
+
+def test_empty():
+ bmg = BooleanMatrixGraph()
+
+ assert bmg.number_of_nodes == 0
+ assert bmg._matrices == dict()
+
+
+def test_one_edge():
+ bmg = BooleanMatrixGraph()
+ bmg.add_edge(0, 1, "label")
+
+ assert bmg.number_of_nodes == 2
+ assert bmg._matrices == {
+ "label": Matrix.from_lists(
+ I=[0],
+ J=[1],
+ V=[True],
+ nrows=2,
+ ncols=2,
+ typ=BOOL,
+ )
+ }
+
+
+def test_two_edges():
+ bmg = BooleanMatrixGraph()
+ bmg.add_edge(0, 1, "A")
+ bmg.add_edge(1, 2, "B")
+
+ assert bmg._number_of_nodes == 3
+ assert bmg._matrices == {
+ "A": Matrix.from_lists(
+ I=[0],
+ J=[1],
+ V=[True],
+ nrows=3,
+ ncols=3,
+ typ=BOOL,
+ ),
+ "B": Matrix.from_lists(
+ I=[1],
+ J=[2],
+ V=[True],
+ nrows=3,
+ ncols=3,
+ typ=BOOL,
+ ),
+ }
diff --git a/tests/cfpq_pyalgo/test_wcnf.py b/tests/cfpq_pyalgo/test_wcnf.py
new file mode 100644
index 0000000..42e07f2
--- /dev/null
+++ b/tests/cfpq_pyalgo/test_wcnf.py
@@ -0,0 +1,31 @@
+from pyformlang.cfg import CFG, Production, Variable, Terminal
+
+from genegram import WCNF
+
+
+def test_empty():
+ cfg = CFG.from_text("S -> epsilon")
+
+ wcnf = WCNF(cfg)
+
+ assert wcnf.start_variable == Variable("S")
+ assert wcnf.variables == [Variable("S")]
+ assert wcnf.terminals == []
+ assert wcnf.productions == [Production(Variable("S"), [])]
+ assert wcnf.epsilon_productions == [Production(Variable("S"), [])]
+ assert wcnf.unary_productions == []
+ assert wcnf.binary_productions == []
+
+
+def test_a():
+ cfg = CFG.from_text("S -> a")
+
+ wcnf = WCNF(cfg)
+
+ assert wcnf.start_variable == Variable("S")
+ assert wcnf.variables == [Variable("S")]
+ assert wcnf.terminals == [Terminal("a")]
+ assert wcnf.productions == [Production(Variable("S"), [Terminal("a")])]
+ assert wcnf.epsilon_productions == []
+ assert wcnf.unary_productions == [Production(Variable("S"), [Terminal("a")])]
+ assert wcnf.binary_productions == []
diff --git a/tests/data/binarize/34551.png b/tests/data/binarize/34551.png
new file mode 100644
index 0000000..9f9be6f
Binary files /dev/null and b/tests/data/binarize/34551.png differ
diff --git a/tests/data/binarize/34552.png b/tests/data/binarize/34552.png
new file mode 100644
index 0000000..4354477
Binary files /dev/null and b/tests/data/binarize/34552.png differ
diff --git a/tests/data/binarize/34553.png b/tests/data/binarize/34553.png
new file mode 100644
index 0000000..679d142
Binary files /dev/null and b/tests/data/binarize/34553.png differ
diff --git a/tests/data/binarize/34735.png b/tests/data/binarize/34735.png
new file mode 100644
index 0000000..e9d9850
Binary files /dev/null and b/tests/data/binarize/34735.png differ
diff --git a/tests/data/binarize/34736.png b/tests/data/binarize/34736.png
new file mode 100644
index 0000000..ac7e3fe
Binary files /dev/null and b/tests/data/binarize/34736.png differ
diff --git a/tests/data/binarize/34737.png b/tests/data/binarize/34737.png
new file mode 100644
index 0000000..992b05f
Binary files /dev/null and b/tests/data/binarize/34737.png differ
diff --git a/tests/data/binarize/34738.png b/tests/data/binarize/34738.png
new file mode 100644
index 0000000..648001a
Binary files /dev/null and b/tests/data/binarize/34738.png differ
diff --git a/tests/data/binarize/34745.png b/tests/data/binarize/34745.png
new file mode 100644
index 0000000..7b8f094
Binary files /dev/null and b/tests/data/binarize/34745.png differ
diff --git a/tests/data/binarize/34767.png b/tests/data/binarize/34767.png
new file mode 100644
index 0000000..44c23a6
Binary files /dev/null and b/tests/data/binarize/34767.png differ
diff --git a/tests/data/binarize/34840.png b/tests/data/binarize/34840.png
new file mode 100644
index 0000000..d3ec01d
Binary files /dev/null and b/tests/data/binarize/34840.png differ
diff --git a/tests/data/parsing/34551.png b/tests/data/parsing/34551.png
new file mode 100644
index 0000000..de05415
Binary files /dev/null and b/tests/data/parsing/34551.png differ
diff --git a/tests/data/parsing/34552.png b/tests/data/parsing/34552.png
new file mode 100644
index 0000000..db0cfe3
Binary files /dev/null and b/tests/data/parsing/34552.png differ
diff --git a/tests/data/parsing/34553.png b/tests/data/parsing/34553.png
new file mode 100644
index 0000000..fd6dd08
Binary files /dev/null and b/tests/data/parsing/34553.png differ
diff --git a/tests/data/parsing/34735.png b/tests/data/parsing/34735.png
new file mode 100644
index 0000000..291d7f3
Binary files /dev/null and b/tests/data/parsing/34735.png differ
diff --git a/tests/data/parsing/34736.png b/tests/data/parsing/34736.png
new file mode 100644
index 0000000..398aef5
Binary files /dev/null and b/tests/data/parsing/34736.png differ
diff --git a/tests/data/parsing/34737.png b/tests/data/parsing/34737.png
new file mode 100644
index 0000000..548dfeb
Binary files /dev/null and b/tests/data/parsing/34737.png differ
diff --git a/tests/data/parsing/34738.png b/tests/data/parsing/34738.png
new file mode 100644
index 0000000..0e317ae
Binary files /dev/null and b/tests/data/parsing/34738.png differ
diff --git a/tests/data/parsing/34745.png b/tests/data/parsing/34745.png
new file mode 100644
index 0000000..1dfb466
Binary files /dev/null and b/tests/data/parsing/34745.png differ
diff --git a/tests/data/parsing/34767.png b/tests/data/parsing/34767.png
new file mode 100644
index 0000000..fba9cd5
Binary files /dev/null and b/tests/data/parsing/34767.png differ
diff --git a/tests/data/parsing/34840.png b/tests/data/parsing/34840.png
new file mode 100644
index 0000000..cfcd3b1
Binary files /dev/null and b/tests/data/parsing/34840.png differ
diff --git a/tests/data/predict/34551.png b/tests/data/predict/34551.png
new file mode 100644
index 0000000..9f9be6f
Binary files /dev/null and b/tests/data/predict/34551.png differ
diff --git a/tests/data/predict/34552.png b/tests/data/predict/34552.png
new file mode 100644
index 0000000..abc8d2c
Binary files /dev/null and b/tests/data/predict/34552.png differ
diff --git a/tests/data/predict/34553.png b/tests/data/predict/34553.png
new file mode 100644
index 0000000..a6b9b0e
Binary files /dev/null and b/tests/data/predict/34553.png differ
diff --git a/tests/data/predict/34735.png b/tests/data/predict/34735.png
new file mode 100644
index 0000000..0b5ac65
Binary files /dev/null and b/tests/data/predict/34735.png differ
diff --git a/tests/data/predict/34736.png b/tests/data/predict/34736.png
new file mode 100644
index 0000000..59ba7d3
Binary files /dev/null and b/tests/data/predict/34736.png differ
diff --git a/tests/data/predict/34737.png b/tests/data/predict/34737.png
new file mode 100644
index 0000000..5676881
Binary files /dev/null and b/tests/data/predict/34737.png differ
diff --git a/tests/data/predict/34738.png b/tests/data/predict/34738.png
new file mode 100644
index 0000000..8ed11ef
Binary files /dev/null and b/tests/data/predict/34738.png differ
diff --git a/tests/data/predict/34745.png b/tests/data/predict/34745.png
new file mode 100644
index 0000000..55b3c21
Binary files /dev/null and b/tests/data/predict/34745.png differ
diff --git a/tests/data/predict/34767.png b/tests/data/predict/34767.png
new file mode 100644
index 0000000..4602fab
Binary files /dev/null and b/tests/data/predict/34767.png differ
diff --git a/tests/data/predict/34840.png b/tests/data/predict/34840.png
new file mode 100644
index 0000000..adc8874
Binary files /dev/null and b/tests/data/predict/34840.png differ
diff --git a/tests/data/process/34551.ct b/tests/data/process/34551.ct
new file mode 100644
index 0000000..181febc
--- /dev/null
+++ b/tests/data/process/34551.ct
@@ -0,0 +1,28 @@
+ 27 34551
+ 1 G 0 2 27 1
+ 2 G 1 3 26 2
+ 3 C 2 4 25 3
+ 4 C 3 5 24 4
+ 5 U 4 6 22 5
+ 6 C 5 7 21 6
+ 7 C 6 8 20 7
+ 8 A 7 9 19 8
+ 9 A 8 10 18 9
+ 10 G 9 11 17 10
+ 11 C 10 12 0 11
+ 12 U 11 13 0 12
+ 13 G 12 14 0 13
+ 14 U 13 15 0 14
+ 15 G 14 16 0 15
+ 16 C 15 17 0 16
+ 17 C 16 18 10 17
+ 18 U 17 19 9 18
+ 19 U 18 20 8 19
+ 20 G 19 21 7 20
+ 21 G 20 22 6 21
+ 22 G 21 23 5 22
+ 23 U 22 24 0 23
+ 24 G 23 25 4 24
+ 25 G 24 26 3 25
+ 26 C 25 27 2 26
+ 27 C 26 28 1 27
diff --git a/tests/data/process/34552.ct b/tests/data/process/34552.ct
new file mode 100644
index 0000000..5c54f96
--- /dev/null
+++ b/tests/data/process/34552.ct
@@ -0,0 +1,18 @@
+ 17 34552
+ 1 C 0 2 17 1
+ 2 C 1 3 16 2
+ 3 U 2 4 15 3
+ 4 C 3 5 14 4
+ 5 C 4 6 13 5
+ 6 C 5 7 12 6
+ 7 U 6 8 0 7
+ 8 U 7 9 0 8
+ 9 A 8 10 0 9
+ 10 C 9 11 0 10
+ 11 A 10 12 0 11
+ 12 A 11 13 6 12
+ 13 G 12 14 5 13
+ 14 G 13 15 4 14
+ 15 A 14 16 3 15
+ 16 G 15 17 2 16
+ 17 G 16 18 1 17
diff --git a/tests/data/process/34553.ct b/tests/data/process/34553.ct
new file mode 100644
index 0000000..0c4a2c6
--- /dev/null
+++ b/tests/data/process/34553.ct
@@ -0,0 +1,23 @@
+ 22 34553
+ 1 G 0 2 22 1
+ 2 G 1 3 21 2
+ 3 A 2 4 20 3
+ 4 G 3 5 19 4
+ 5 U 4 6 18 5
+ 6 G 5 7 17 6
+ 7 G 6 8 16 7
+ 8 C 7 9 15 8
+ 9 C 8 10 14 9
+ 10 G 9 11 13 10
+ 11 A 10 12 0 11
+ 12 A 11 13 0 12
+ 13 A 12 14 10 13
+ 14 G 13 15 9 14
+ 15 G 14 16 8 15
+ 16 C 15 17 7 16
+ 17 A 16 18 6 17
+ 18 U 17 19 5 18
+ 19 C 18 20 4 19
+ 20 U 19 21 3 20
+ 21 C 20 22 2 21
+ 22 C 21 23 1 22
diff --git a/tests/data/process/34735.ct b/tests/data/process/34735.ct
new file mode 100644
index 0000000..8f820d8
--- /dev/null
+++ b/tests/data/process/34735.ct
@@ -0,0 +1,16 @@
+ 15 34735
+ 1 G 0 2 15 1
+ 2 G 1 3 14 2
+ 3 C 2 4 13 3
+ 4 U 3 5 12 4
+ 5 C 4 6 11 5
+ 6 U 5 7 0 6
+ 7 C 6 8 0 7
+ 8 A 7 9 0 8
+ 9 G 8 10 0 9
+ 10 U 9 11 0 10
+ 11 G 10 12 5 11
+ 12 A 11 13 4 12
+ 13 G 12 14 3 13
+ 14 C 13 15 2 14
+ 15 C 14 16 1 15
diff --git a/tests/data/process/34736.ct b/tests/data/process/34736.ct
new file mode 100644
index 0000000..9bcf1a5
--- /dev/null
+++ b/tests/data/process/34736.ct
@@ -0,0 +1,28 @@
+ 27 34736
+ 1 G 0 2 27 1
+ 2 G 1 3 26 2
+ 3 U 2 4 25 3
+ 4 G 3 5 24 4
+ 5 C 4 6 23 5
+ 6 U 5 7 22 6
+ 7 C 6 8 21 7
+ 8 A 7 9 0 8
+ 9 G 8 10 0 9
+ 10 U 9 11 0 10
+ 11 A 10 12 18 11
+ 12 G 11 13 0 12
+ 13 G 12 14 0 13
+ 14 A 13 15 0 14
+ 15 G 14 16 0 15
+ 16 A 15 17 0 16
+ 17 C 16 18 0 17
+ 18 G 17 19 11 18
+ 19 A 18 20 0 19
+ 20 A 19 21 0 20
+ 21 C 20 22 7 21
+ 22 C 21 23 6 22
+ 23 G 22 24 5 23
+ 24 C 23 25 4 24
+ 25 A 24 26 3 25
+ 26 C 25 27 2 26
+ 27 C 26 28 1 27
diff --git a/tests/data/process/34737.ct b/tests/data/process/34737.ct
new file mode 100644
index 0000000..f6ffe14
--- /dev/null
+++ b/tests/data/process/34737.ct
@@ -0,0 +1,11 @@
+ 10 34737
+ 1 G 0 2 10 1
+ 2 G 1 3 9 2
+ 3 G 2 4 8 3
+ 4 C 3 5 0 4
+ 5 A 4 6 0 5
+ 6 A 5 7 0 6
+ 7 G 6 8 0 7
+ 8 C 7 9 3 8
+ 9 C 8 10 2 9
+ 10 C 9 11 1 10
diff --git a/tests/data/process/34738.ct b/tests/data/process/34738.ct
new file mode 100644
index 0000000..bb594b2
--- /dev/null
+++ b/tests/data/process/34738.ct
@@ -0,0 +1,26 @@
+ 25 34738
+ 1 G 0 2 0 1
+ 2 G 1 3 0 2
+ 3 C 2 4 0 3
+ 4 A 3 5 0 4
+ 5 G 4 6 22 5
+ 6 U 5 7 21 6
+ 7 G 6 8 20 7
+ 8 U 7 9 19 8
+ 9 G 8 10 18 9
+ 10 A 9 11 17 10
+ 11 G 10 12 16 11
+ 12 U 11 13 0 12
+ 13 A 12 14 0 13
+ 14 C 13 15 0 14
+ 15 C 14 16 0 15
+ 16 U 15 17 11 16
+ 17 U 16 18 10 17
+ 18 C 17 19 9 18
+ 19 A 18 20 8 19
+ 20 C 19 21 7 20
+ 21 A 20 22 6 21
+ 22 C 21 23 5 22
+ 23 G 22 24 0 23
+ 24 U 23 25 0 24
+ 25 C 24 26 0 25
diff --git a/tests/data/process/34745.ct b/tests/data/process/34745.ct
new file mode 100644
index 0000000..606adb8
--- /dev/null
+++ b/tests/data/process/34745.ct
@@ -0,0 +1,13 @@
+ 12 34745
+ 1 G 0 2 12 1
+ 2 G 1 3 11 2
+ 3 U 2 4 10 3
+ 4 G 3 5 9 4
+ 5 U 4 6 0 5
+ 6 G 5 7 0 6
+ 7 A 6 8 0 7
+ 8 A 7 9 0 8
+ 9 C 8 10 4 9
+ 10 A 9 11 3 10
+ 11 C 10 12 2 11
+ 12 C 11 13 1 12
diff --git a/tests/data/process/34767.ct b/tests/data/process/34767.ct
new file mode 100644
index 0000000..1cc9dbe
--- /dev/null
+++ b/tests/data/process/34767.ct
@@ -0,0 +1,14 @@
+ 13 34767
+ 1 G 0 2 13 1
+ 2 G 1 3 12 2
+ 3 U 2 4 11 3
+ 4 G 3 5 10 4
+ 5 C 4 6 9 5
+ 6 A 5 7 0 6
+ 7 U 6 8 0 7
+ 8 G 7 9 0 8
+ 9 G 8 10 5 9
+ 10 C 9 11 4 10
+ 11 A 10 12 3 11
+ 12 C 11 13 2 12
+ 13 C 12 14 1 13
diff --git a/tests/data/process/34840.ct b/tests/data/process/34840.ct
new file mode 100644
index 0000000..f9ad82d
--- /dev/null
+++ b/tests/data/process/34840.ct
@@ -0,0 +1,102 @@
+ 101 34840
+ 1 G 0 2 0 1
+ 2 G 1 3 0 2
+ 3 C 2 4 0 3
+ 4 G 3 5 0 4
+ 5 G 4 6 0 5
+ 6 U 5 7 0 6
+ 7 A 6 8 24 7
+ 8 C 7 9 23 8
+ 9 U 8 10 22 9
+ 10 A 9 11 68 10
+ 11 G 10 12 20 11
+ 12 U 11 13 19 12
+ 13 U 12 14 18 13
+ 14 G 13 15 17 14
+ 15 A 14 16 0 15
+ 16 G 15 17 0 16
+ 17 A 16 18 14 17
+ 18 A 17 19 13 18
+ 19 A 18 20 12 19
+ 20 C 19 21 11 20
+ 21 U 20 22 10 21
+ 22 A 21 23 9 22
+ 23 G 22 24 8 23
+ 24 C 23 25 7 24
+ 25 U 24 26 0 25
+ 26 C 25 27 0 26
+ 27 U 26 28 0 27
+ 28 G 27 29 0 28
+ 29 U 28 30 0 29
+ 30 A 29 31 0 30
+ 31 U 30 32 0 31
+ 32 C 31 33 0 32
+ 33 U 32 34 0 33
+ 34 G 33 35 0 34
+ 35 G 34 36 77 35
+ 36 C 35 37 76 36
+ 37 G 36 38 75 37
+ 38 G 37 39 74 38
+ 39 A 38 40 0 39
+ 40 C 39 41 0 40
+ 41 C 40 42 73 41
+ 42 C 41 43 72 42
+ 43 G 42 44 71 43
+ 44 U 43 45 0 44
+ 45 G 44 46 70 45
+ 46 G 45 47 69 46
+ 47 U 46 48 68 47
+ 48 G 47 49 67 48
+ 49 G 48 50 62 49
+ 50 A 49 51 61 50
+ 51 A 50 52 60 51
+ 52 C 51 53 59 52
+ 53 U 52 54 58 53
+ 54 G 53 55 0 54
+ 55 U 54 56 0 55
+ 56 G 55 57 0 56
+ 57 A 56 58 0 57
+ 58 A 57 59 53 58
+ 59 G 58 60 52 59
+ 60 U 59 61 51 60
+ 61 U 60 62 50 61
+ 62 C 61 63 49 62
+ 63 G 62 64 0 63
+ 64 G 63 65 0 64
+ 65 A 64 66 0 65
+ 66 A 65 67 0 66
+ 67 C 66 68 48 67
+ 68 A 67 69 47 68
+ 69 C 68 70 46 69
+ 70 C 69 71 45 70
+ 71 C 70 72 43 71
+ 72 G 71 73 42 72
+ 73 G 72 74 41 73
+ 74 C 73 75 38 74
+ 75 C 74 76 37 75
+ 76 G 75 77 36 76
+ 77 C 76 78 35 77
+ 78 A 77 79 101 78
+ 79 A 78 80 100 79
+ 80 C 79 81 99 80
+ 81 C 80 82 98 81
+ 82 C 81 83 97 82
+ 83 U 82 84 96 83
+ 84 G 83 85 95 84
+ 85 G 84 86 94 85
+ 86 G 85 87 93 86
+ 87 A 86 88 92 87
+ 88 G 87 89 0 88
+ 89 A 88 90 0 89
+ 90 G 89 91 0 90
+ 91 G 90 92 0 91
+ 92 U 91 93 87 92
+ 93 C 92 94 86 93
+ 94 C 93 95 85 94
+ 95 C 94 96 84 95
+ 96 A 95 97 83 96
+ 97 G 96 98 82 97
+ 98 G 97 99 81 98
+ 99 G 98 100 80 99
+ 100 U 99 101 79 100
+ 101 U 100 102 78 101
diff --git a/tests/data/seq.fasta b/tests/data/seq.fasta
new file mode 100644
index 0000000..b1d5cad
--- /dev/null
+++ b/tests/data/seq.fasta
@@ -0,0 +1,20 @@
+>34551
+GGCCUCCAAGCUGUGCCUUGGGUGGCC
+>34552
+CCUCCCUUACAAGGAGG
+>34553
+GGAGUGGCCGAAAGGCAUCUCC
+>34735
+GGCUCUCAGUGAGCC
+>34736
+GGUGCUCAGUAGGAGACGAACCGCACC
+>34737
+GGGCAAGCCC
+>34738
+GGCAGUGUGAGUACCUUCACACGUC
+>34745
+GGUGUGAACACC
+>34767
+GGUGCAUGGCACC
+>34840
+GGCGGUACUAGUUGAGAAACUAGCUCUGUAUCUGGCGGACCCGUGGUGGAACUGUGAAGUUCGGAACACCCGGCCGCAACCCUGGGAGAGGUCCCAGGGUU
diff --git a/tests/parsing/test_parse_rna_group.py b/tests/parsing/test_parse_rna_group.py
new file mode 100644
index 0000000..0bd61b2
--- /dev/null
+++ b/tests/parsing/test_parse_rna_group.py
@@ -0,0 +1,23 @@
+from pathlib import Path
+
+import numpy as np
+from PIL import Image
+from genegram import read_fasta_group, parse_rna_group
+
+root = Path(__file__).parent.resolve()
+fasta = root.parent / "data" / "seq.fasta"
+
+
+def test_parse_rna_group():
+ for rna_group in read_fasta_group(fasta, 50):
+ for index, image_actual in parse_rna_group(rna_group):
+ image_expected = np.array(
+ Image.open(
+ root.parent
+ / "data"
+ / "parsing"
+ / f"{rna_group[index].description}.png"
+ )
+ )
+
+ assert np.array_equal(image_actual, image_expected)
diff --git a/tests/parsing/test_parse_rna_single.py b/tests/parsing/test_parse_rna_single.py
new file mode 100644
index 0000000..de76416
--- /dev/null
+++ b/tests/parsing/test_parse_rna_single.py
@@ -0,0 +1,19 @@
+from pathlib import Path
+
+import numpy as np
+from PIL import Image
+
+from genegram import read_fasta_single, parse_rna_single
+
+root = Path(__file__).parent.resolve()
+fasta = root.parent / "data" / "seq.fasta"
+
+
+def test_parse_rna_single():
+ for rna in read_fasta_single(fasta):
+ image_actual = parse_rna_single(rna)
+ image_expected = np.array(
+ Image.open(root.parent / "data" / "parsing" / f"{rna.description}.png")
+ )
+
+ assert np.array_equal(image_actual, image_expected)
diff --git a/tests/parsing/test_read_fasta_group.py b/tests/parsing/test_read_fasta_group.py
new file mode 100644
index 0000000..58517a0
--- /dev/null
+++ b/tests/parsing/test_read_fasta_group.py
@@ -0,0 +1,78 @@
+from pathlib import Path
+
+from genegram import RNA, read_fasta_group
+
+root = Path(__file__).parent.resolve()
+fasta = root.parent / "data" / "seq.fasta"
+
+
+def test_limit_0():
+ data = list(read_fasta_group(fasta, 0))
+
+ assert data == [
+ [RNA(description="34551", sequence="GGCCUCCAAGCUGUGCCUUGGGUGGCC")],
+ [RNA(description="34552", sequence="CCUCCCUUACAAGGAGG")],
+ [RNA(description="34553", sequence="GGAGUGGCCGAAAGGCAUCUCC")],
+ [RNA(description="34735", sequence="GGCUCUCAGUGAGCC")],
+ [RNA(description="34736", sequence="GGUGCUCAGUAGGAGACGAACCGCACC")],
+ [RNA(description="34737", sequence="GGGCAAGCCC")],
+ [RNA(description="34738", sequence="GGCAGUGUGAGUACCUUCACACGUC")],
+ [RNA(description="34745", sequence="GGUGUGAACACC")],
+ [RNA(description="34767", sequence="GGUGCAUGGCACC")],
+ [
+ RNA(
+ description="34840",
+ sequence="GGCGGUACUAGUUGAGAAACUAGCUCUGUAUCUGGCGGACCCGUGGUGGAACUGUGAAGUUCGGAACACCCGGCCGCAACCCUGGGAGAGGUCCCAGGGUU",
+ )
+ ],
+ ]
+
+
+def test_limit_50():
+ data = list(read_fasta_group(fasta, 50))
+
+ assert data == [
+ [
+ RNA(description="34551", sequence="GGCCUCCAAGCUGUGCCUUGGGUGGCC"),
+ RNA(description="34552", sequence="CCUCCCUUACAAGGAGG"),
+ ],
+ [
+ RNA(description="34553", sequence="GGAGUGGCCGAAAGGCAUCUCC"),
+ RNA(description="34735", sequence="GGCUCUCAGUGAGCC"),
+ RNA(description="34736", sequence="GGUGCUCAGUAGGAGACGAACCGCACC"),
+ ],
+ [
+ RNA(description="34737", sequence="GGGCAAGCCC"),
+ RNA(description="34738", sequence="GGCAGUGUGAGUACCUUCACACGUC"),
+ RNA(description="34745", sequence="GGUGUGAACACC"),
+ ],
+ [
+ RNA(description="34767", sequence="GGUGCAUGGCACC"),
+ RNA(
+ description="34840",
+ sequence="GGCGGUACUAGUUGAGAAACUAGCUCUGUAUCUGGCGGACCCGUGGUGGAACUGUGAAGUUCGGAACACCCGGCCGCAACCCUGGGAGAGGUCCCAGGGUU",
+ ),
+ ],
+ ]
+
+
+def test_limit_500():
+ data = list(read_fasta_group(fasta, 500))
+
+ assert data == [
+ [
+ RNA(description="34551", sequence="GGCCUCCAAGCUGUGCCUUGGGUGGCC"),
+ RNA(description="34552", sequence="CCUCCCUUACAAGGAGG"),
+ RNA(description="34553", sequence="GGAGUGGCCGAAAGGCAUCUCC"),
+ RNA(description="34735", sequence="GGCUCUCAGUGAGCC"),
+ RNA(description="34736", sequence="GGUGCUCAGUAGGAGACGAACCGCACC"),
+ RNA(description="34737", sequence="GGGCAAGCCC"),
+ RNA(description="34738", sequence="GGCAGUGUGAGUACCUUCACACGUC"),
+ RNA(description="34745", sequence="GGUGUGAACACC"),
+ RNA(description="34767", sequence="GGUGCAUGGCACC"),
+ RNA(
+ description="34840",
+ sequence="GGCGGUACUAGUUGAGAAACUAGCUCUGUAUCUGGCGGACCCGUGGUGGAACUGUGAAGUUCGGAACACCCGGCCGCAACCCUGGGAGAGGUCCCAGGGUU",
+ ),
+ ]
+ ]
diff --git a/tests/parsing/test_read_fasta_single.py b/tests/parsing/test_read_fasta_single.py
new file mode 100644
index 0000000..57b04c4
--- /dev/null
+++ b/tests/parsing/test_read_fasta_single.py
@@ -0,0 +1,26 @@
+from pathlib import Path
+
+from genegram import RNA, read_fasta_single
+
+root = Path(__file__).parent.resolve()
+fasta = root.parent / "data" / "seq.fasta"
+
+
+def test_read_fasta():
+ data = list(read_fasta_single(fasta))
+
+ assert data == [
+ RNA(description="34551", sequence="GGCCUCCAAGCUGUGCCUUGGGUGGCC"),
+ RNA(description="34552", sequence="CCUCCCUUACAAGGAGG"),
+ RNA(description="34553", sequence="GGAGUGGCCGAAAGGCAUCUCC"),
+ RNA(description="34735", sequence="GGCUCUCAGUGAGCC"),
+ RNA(description="34736", sequence="GGUGCUCAGUAGGAGACGAACCGCACC"),
+ RNA(description="34737", sequence="GGGCAAGCCC"),
+ RNA(description="34738", sequence="GGCAGUGUGAGUACCUUCACACGUC"),
+ RNA(description="34745", sequence="GGUGUGAACACC"),
+ RNA(description="34767", sequence="GGUGCAUGGCACC"),
+ RNA(
+ description="34840",
+ sequence="GGCGGUACUAGUUGAGAAACUAGCUCUGUAUCUGGCGGACCCGUGGUGGAACUGUGAAGUUCGGAACACCCGGCCGCAACCCUGGGAGAGGUCCCAGGGUU",
+ ),
+ ]
diff --git a/tests/predict/test_predict.py b/tests/predict/test_predict.py
new file mode 100644
index 0000000..e5e4715
--- /dev/null
+++ b/tests/predict/test_predict.py
@@ -0,0 +1,25 @@
+from glob import glob
+from pathlib import Path
+
+import numpy as np
+from PIL import Image, ImageChops
+
+from genegram import setup_model, predict, clear_session, __path__ as genegram_path
+
+root = Path(__file__).parent.resolve()
+
+
+def test_predict():
+ model = setup_model(Path(genegram_path[0]) / "weights" / "main.h5")
+ for image_path in glob(str(root.parent / "data" / "parsing" / "*")):
+ image = Image.open(image_path)
+ actual_prediction = Image.fromarray(predict(np.array(image), model))
+ expected_prediction = Image.open(
+ root.parent / "data" / "predict" / f"{Path(image_path).stem}.png"
+ )
+
+ assert (
+ ImageChops.difference(actual_prediction, expected_prediction).getbbox()
+ is None
+ )
+ clear_session()
diff --git a/tests/process/test_process.py b/tests/process/test_process.py
new file mode 100644
index 0000000..23eb780
--- /dev/null
+++ b/tests/process/test_process.py
@@ -0,0 +1,18 @@
+import os
+from filecmp import dircmp
+from pathlib import Path
+
+root = Path(__file__).parent.resolve()
+fasta = root.parent / "data" / "seq.fasta"
+
+
+def test_process(tmpdir):
+ tmp = tmpdir.mkdir("tmp")
+ os.system(f"python -m genegram -i {fasta} -o {tmp}")
+
+ cmp = dircmp(tmp, root.parent / "data" / "process")
+
+ assert cmp.left_only == []
+ assert cmp.right_only == []
+ assert cmp.diff_files == []
+ assert cmp.funny_files == []
diff --git a/tests/process/test_process_group.py b/tests/process/test_process_group.py
new file mode 100644
index 0000000..e5d4397
--- /dev/null
+++ b/tests/process/test_process_group.py
@@ -0,0 +1,19 @@
+from filecmp import dircmp
+from pathlib import Path
+
+from genegram import process_fasta_group
+
+root = Path(__file__).parent.resolve()
+fasta = root.parent / "data" / "seq.fasta"
+
+
+def test_process_fasta_single(tmpdir):
+ tmp = tmpdir.mkdir("tmp")
+ process_fasta_group(fasta, tmp)
+
+ cmp = dircmp(tmp, root.parent / "data" / "process")
+
+ assert cmp.left_only == []
+ assert cmp.right_only == []
+ assert cmp.diff_files == []
+ assert cmp.funny_files == []
diff --git a/tests/process/test_process_single.py b/tests/process/test_process_single.py
new file mode 100644
index 0000000..5e95eda
--- /dev/null
+++ b/tests/process/test_process_single.py
@@ -0,0 +1,19 @@
+from filecmp import dircmp
+from pathlib import Path
+
+from genegram import process_fasta_single
+
+root = Path(__file__).parent.resolve()
+fasta = root.parent / "data" / "seq.fasta"
+
+
+def test_process_fasta_single(tmpdir):
+ tmp = tmpdir.mkdir("tmp")
+ process_fasta_single(fasta, tmp)
+
+ cmp = dircmp(tmp, root.parent / "data" / "process")
+
+ assert cmp.left_only == []
+ assert cmp.right_only == []
+ assert cmp.diff_files == []
+ assert cmp.funny_files == []
diff --git a/tests/utils/test_binarize_image.py b/tests/utils/test_binarize_image.py
new file mode 100644
index 0000000..c3ebb65
--- /dev/null
+++ b/tests/utils/test_binarize_image.py
@@ -0,0 +1,34 @@
+from glob import glob
+from pathlib import Path
+
+import numpy as np
+from PIL import Image, ImageChops
+
+from genegram import (
+ setup_model,
+ predict,
+ binarize_image,
+ remove_multiplets,
+ clear_session,
+ __path__ as genegram_path,
+)
+
+root = Path(__file__).parent.resolve()
+
+
+def test_binarize_image():
+ model = setup_model(Path(genegram_path[0]) / "weights" / "main.h5")
+ for image_path in glob(str(root.parent / "data" / "parsing" / "*")):
+ image = Image.open(image_path)
+ prediction = predict(np.array(image), model)
+ pred_bin = binarize_image(prediction)
+
+ actual_binarized = Image.fromarray(pred_bin)
+ expected_binarized = Image.open(
+ root.parent / "data" / "binarize" / f"{Path(image_path).stem}.png"
+ )
+
+ assert (
+ ImageChops.difference(actual_binarized, expected_binarized).getbbox()
+ is None
+ )