ldpart 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ldpart-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gennady Khvorykh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
ldpart-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: ldpart
3
+ Version: 0.1.0
4
+ Summary: Certified multicollinearity partitioning of LD matrices into blocks of correlated SNPs
5
+ Author-email: Gennady Khvorykh <info@inzilico.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/gkhvorykh/ldpart
8
+ Project-URL: Documentation, https://github.com/gkhvorykh/ldpart#readme
9
+ Keywords: linkage disequilibrium,LD blocks,multicollinearity,variance inflation factor,population genetics,genetics
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy>=1.20
23
+ Requires-Dist: h5py>=3.0
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest>=7; extra == "test"
26
+ Dynamic: license-file
27
+
28
+ # Linkage Disequilibrium Partition (ldpart)
29
+
30
+ Certified multicollinearity partitioning of linkage disequilibrium (LD) matrices: group SNPs
31
+ into contiguous blocks of correlated SNPs with greedy criteria built
32
+ on classical multicollinearity diagnostics.
33
+
34
+ Every saved block is **certified** — its submatrix of the LD matrix
35
+ provably satisfies the criterion — and the monotone criteria
36
+ (determinant, condition number, maximal VIF) additionally certify that
37
+ every block is **maximal**: no neighbouring SNP could join it without
38
+ violating the criterion. NaN values never extend a block.
39
+
40
+ ## Criteria
41
+
42
+ | function | method | criterion | certified | maximal | cost per candidate |
43
+ |---|---|---|---|---|---|
44
+ | `partition_by_determinant` | `fast` | det(block) > θ (Schur updates) | yes | yes (det is monotone under growth) | O(k²) |
45
+ | `partition_by_determinant_slogdet` | `slogdet` | det(block) > θ (LAPACK reference) | yes | yes | O(k³) |
46
+ | `partition_by_condition` | `condition` | κ(block) = λmax/\|λmin\| ≤ θ | yes | yes (Cauchy interlacing) | O(k³) |
47
+ | `partition_by_vif` | `vif` | max VIF = max diag(R⁻¹) ≤ θ | yes | yes (nested regressions) | O(k³) |
48
+ | `partition_by_reciprocal_eigenvalues` | `reciprocal` | Σ 1/λq ≤ θ·k | yes | no (the ratio can recover) | O(k³) |
49
+ | `partition_by_pairwise` | `pairwise` | max r2(candidate, member) ≥ θ | yes (pairwise sense) | — marginal screen | O(k) |
50
+
51
+ Classical operating points: det θ = 0.001, κ = 1000 (squared Belsley
52
+ CN ≈ 31.6), VIF 5/10, Σ1/λ ≈ 5·k (Chatterjee & Price), pairwise
53
+ r² = 0.8.
54
+
55
+ The determinant, condition, VIF and reciprocal criteria certify that
56
+ a block is **not too jointly redundant** (joint criteria); the
57
+ pairwise criterion groups SNPs that **are** in LD (marginal screen).
58
+ Their cuts land in different places — the joint criteria cut inside
59
+ strong LD where redundancy accumulates, the pairwise criterion cuts
60
+ where LD has decayed.
61
+
62
+ ## Install
63
+
64
+ ```bash
65
+ pip install ldpart
66
+ ```
67
+
68
+ ## Python API
69
+
70
+ The input is a square symmetric LD matrix (r or r2, 1 on the
71
+ diagonal, SNPs ordered as the rows and columns) — a numpy array or an
72
+ open h5py dataset (the matrix is streamed row by row, never copied).
73
+
74
+ ```python
75
+ import h5py
76
+ from ldpart import partition_by_determinant, labels_to_blocks
77
+
78
+ with h5py.File("ld.h5", "r") as f:
79
+ matrix = f["r2"]
80
+ labels, nblocks = partition_by_determinant(matrix, min_det=0.001)
81
+
82
+ blocks = labels_to_blocks(labels) # [(block, [snp indexes]), ...]
83
+ ```
84
+
85
+ Every function returns `(labels, nblocks)`, where labels is a per-SNP
86
+ list of `[index, block]` with blocks numbered from 1.
87
+
88
+ ## Command line
89
+
90
+ ```bash
91
+ ldpart -i ld.h5 -o labels.txt # det 0.001
92
+ ldpart -i ld.h5 -o labels.txt -m condition -c 1000
93
+ ldpart -i ld.h5 -o labels.txt -m vif -v 10
94
+ ldpart -i ld.h5 -o labels.txt -m reciprocal -r 5
95
+ ldpart -i ld.h5 -o labels.txt -m pairwise -p 0.8
96
+ ```
97
+
98
+ The output has two columns, the zero-based SNP index and the block
99
+ label.
100
+
101
+ ## Semantics
102
+
103
+ - **Greedy growth:** the block starting at SNP i1 is extended by the
104
+ candidate SNP j only while the criterion holds over the window
105
+ matrix[i1:j+1, i1:j+1] *including the candidate*; the first failing
106
+ candidate seeds the next block, so blocks are contiguous and every
107
+ block satisfies its criterion at its final size and at every prefix.
108
+ - **Certified maximality:** the determinant can only decrease when a
109
+ SNP is added (Schur complement: each step multiplies it by
110
+ 1 − R² ≤ 1), the condition number cannot recover (Cauchy
111
+ interlacing), the maximal VIF cannot recover (nested regressions) —
112
+ so the greedy cut yields the largest admissible block. The sum of
113
+ reciprocal eigenvalues per window size can recover, so its blocks
114
+ are certified but not maximal.
115
+ - **NaN semantics:** a NaN anywhere in the candidate window (or the
116
+ candidate's row segment for the pairwise screen) fails the
117
+ extension — NaN never silently extends a block. A SNP with a NaN
118
+ diagonal stays a singleton seed.
119
+
120
+ ## Testing
121
+
122
+ ```bash
123
+ pip install -e ".[test]"
124
+ pytest tests
125
+ ```
126
+
127
+ The suite holds property tests on random correlation matrices:
128
+ certification of every block by independent LAPACK recomputation,
129
+ maximality of the monotone criteria against brute force, the NaN
130
+ semantics, fast/slogdet agreement, numpy/h5py equivalence, and the
131
+ command line interface end to end.
132
+
133
+ ## References
134
+
135
+ - Rogers & Huff (2008), *Heredity* — the r² estimator used in the
136
+ companion study.
137
+ - Belsley, Kuh & Welsch (1980) — regression diagnostics, condition
138
+ indices.
139
+ - Chatterjee & Price (1977); Dillon & Goldstein (1984) — the
140
+ sum-of-reciprocal-eigenvalues rule.
141
+ - Khvorykh, G., Khrunin, A., 2025. Determinant-based grouping of SNPs and its application for detecting disease-associated genomic loci. NAR Genomics and Bioinformatics 7. https://doi.org/10.1093/nargab/lqaf024
142
+ - The method is developed and validated in the LD matrix partition study (in preparation)
143
+
144
+
145
+ ## License
146
+
147
+ MIT © Gennady Khvorykh
148
+
149
+ ## Author
150
+
151
+ Gennady Khvorykh, info [at] inzilico.com
ldpart-0.1.0/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Linkage Disequilibrium Partition (ldpart)
2
+
3
+ Certified multicollinearity partitioning of linkage disequilibrium (LD) matrices: group SNPs
4
+ into contiguous blocks of correlated SNPs with greedy criteria built
5
+ on classical multicollinearity diagnostics.
6
+
7
+ Every saved block is **certified** — its submatrix of the LD matrix
8
+ provably satisfies the criterion — and the monotone criteria
9
+ (determinant, condition number, maximal VIF) additionally certify that
10
+ every block is **maximal**: no neighbouring SNP could join it without
11
+ violating the criterion. NaN values never extend a block.
12
+
13
+ ## Criteria
14
+
15
+ | function | method | criterion | certified | maximal | cost per candidate |
16
+ |---|---|---|---|---|---|
17
+ | `partition_by_determinant` | `fast` | det(block) > θ (Schur updates) | yes | yes (det is monotone under growth) | O(k²) |
18
+ | `partition_by_determinant_slogdet` | `slogdet` | det(block) > θ (LAPACK reference) | yes | yes | O(k³) |
19
+ | `partition_by_condition` | `condition` | κ(block) = λmax/\|λmin\| ≤ θ | yes | yes (Cauchy interlacing) | O(k³) |
20
+ | `partition_by_vif` | `vif` | max VIF = max diag(R⁻¹) ≤ θ | yes | yes (nested regressions) | O(k³) |
21
+ | `partition_by_reciprocal_eigenvalues` | `reciprocal` | Σ 1/λq ≤ θ·k | yes | no (the ratio can recover) | O(k³) |
22
+ | `partition_by_pairwise` | `pairwise` | max r2(candidate, member) ≥ θ | yes (pairwise sense) | — marginal screen | O(k) |
23
+
24
+ Classical operating points: det θ = 0.001, κ = 1000 (squared Belsley
25
+ CN ≈ 31.6), VIF 5/10, Σ1/λ ≈ 5·k (Chatterjee & Price), pairwise
26
+ r² = 0.8.
27
+
28
+ The determinant, condition, VIF and reciprocal criteria certify that
29
+ a block is **not too jointly redundant** (joint criteria); the
30
+ pairwise criterion groups SNPs that **are** in LD (marginal screen).
31
+ Their cuts land in different places — the joint criteria cut inside
32
+ strong LD where redundancy accumulates, the pairwise criterion cuts
33
+ where LD has decayed.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install ldpart
39
+ ```
40
+
41
+ ## Python API
42
+
43
+ The input is a square symmetric LD matrix (r or r2, 1 on the
44
+ diagonal, SNPs ordered as the rows and columns) — a numpy array or an
45
+ open h5py dataset (the matrix is streamed row by row, never copied).
46
+
47
+ ```python
48
+ import h5py
49
+ from ldpart import partition_by_determinant, labels_to_blocks
50
+
51
+ with h5py.File("ld.h5", "r") as f:
52
+ matrix = f["r2"]
53
+ labels, nblocks = partition_by_determinant(matrix, min_det=0.001)
54
+
55
+ blocks = labels_to_blocks(labels) # [(block, [snp indexes]), ...]
56
+ ```
57
+
58
+ Every function returns `(labels, nblocks)`, where labels is a per-SNP
59
+ list of `[index, block]` with blocks numbered from 1.
60
+
61
+ ## Command line
62
+
63
+ ```bash
64
+ ldpart -i ld.h5 -o labels.txt # det 0.001
65
+ ldpart -i ld.h5 -o labels.txt -m condition -c 1000
66
+ ldpart -i ld.h5 -o labels.txt -m vif -v 10
67
+ ldpart -i ld.h5 -o labels.txt -m reciprocal -r 5
68
+ ldpart -i ld.h5 -o labels.txt -m pairwise -p 0.8
69
+ ```
70
+
71
+ The output has two columns, the zero-based SNP index and the block
72
+ label.
73
+
74
+ ## Semantics
75
+
76
+ - **Greedy growth:** the block starting at SNP i1 is extended by the
77
+ candidate SNP j only while the criterion holds over the window
78
+ matrix[i1:j+1, i1:j+1] *including the candidate*; the first failing
79
+ candidate seeds the next block, so blocks are contiguous and every
80
+ block satisfies its criterion at its final size and at every prefix.
81
+ - **Certified maximality:** the determinant can only decrease when a
82
+ SNP is added (Schur complement: each step multiplies it by
83
+ 1 − R² ≤ 1), the condition number cannot recover (Cauchy
84
+ interlacing), the maximal VIF cannot recover (nested regressions) —
85
+ so the greedy cut yields the largest admissible block. The sum of
86
+ reciprocal eigenvalues per window size can recover, so its blocks
87
+ are certified but not maximal.
88
+ - **NaN semantics:** a NaN anywhere in the candidate window (or the
89
+ candidate's row segment for the pairwise screen) fails the
90
+ extension — NaN never silently extends a block. A SNP with a NaN
91
+ diagonal stays a singleton seed.
92
+
93
+ ## Testing
94
+
95
+ ```bash
96
+ pip install -e ".[test]"
97
+ pytest tests
98
+ ```
99
+
100
+ The suite holds property tests on random correlation matrices:
101
+ certification of every block by independent LAPACK recomputation,
102
+ maximality of the monotone criteria against brute force, the NaN
103
+ semantics, fast/slogdet agreement, numpy/h5py equivalence, and the
104
+ command line interface end to end.
105
+
106
+ ## References
107
+
108
+ - Rogers & Huff (2008), *Heredity* — the r² estimator used in the
109
+ companion study.
110
+ - Belsley, Kuh & Welsch (1980) — regression diagnostics, condition
111
+ indices.
112
+ - Chatterjee & Price (1977); Dillon & Goldstein (1984) — the
113
+ sum-of-reciprocal-eigenvalues rule.
114
+ - Khvorykh, G., Khrunin, A., 2025. Determinant-based grouping of SNPs and its application for detecting disease-associated genomic loci. NAR Genomics and Bioinformatics 7. https://doi.org/10.1093/nargab/lqaf024
115
+ - The method is developed and validated in the LD matrix partition study (in preparation)
116
+
117
+
118
+ ## License
119
+
120
+ MIT © Gennady Khvorykh
121
+
122
+ ## Author
123
+
124
+ Gennady Khvorykh, info [at] inzilico.com
@@ -0,0 +1,48 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ldpart"
7
+ version = "0.1.0"
8
+ description = "Certified multicollinearity partitioning of LD matrices into blocks of correlated SNPs"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Gennady Khvorykh", email = "info@inzilico.com" }]
13
+ keywords = [
14
+ "linkage disequilibrium",
15
+ "LD blocks",
16
+ "multicollinearity",
17
+ "variance inflation factor",
18
+ "population genetics",
19
+ "genetics",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 4 - Beta",
23
+ "Intended Audience :: Science/Research",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.9",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
31
+ ]
32
+ dependencies = [
33
+ "numpy>=1.20",
34
+ "h5py>=3.0",
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/gkhvorykh/ldpart"
39
+ Documentation = "https://github.com/gkhvorykh/ldpart#readme"
40
+
41
+ [project.scripts]
42
+ ldpart = "ldpart.cli:main"
43
+
44
+ [project.optional-dependencies]
45
+ test = ["pytest>=7"]
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["src"]
ldpart-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,36 @@
1
+ """
2
+ ldpart: certified multicollinearity partitioning of LD matrices.
3
+
4
+ Group SNPs into contiguous blocks of correlated SNPs from a square LD
5
+ matrix (r or r2 with 1 on the diagonal, SNPs ordered as the rows and
6
+ columns), with six greedy criteria built on classical
7
+ multicollinearity diagnostics: the determinant (fast Schur updates
8
+ and the LAPACK slogdet reference), the condition number, the maximal
9
+ variance inflation factor, the sum of reciprocal eigenvalues, and the
10
+ marginal pairwise r2 screen. Every saved block is certified: it
11
+ satisfies its criterion, and the monotone criteria additionally
12
+ certify maximality. See partitioner for the semantics.
13
+ """
14
+
15
+ from .partitioner import (
16
+ partition_by_determinant,
17
+ partition_by_determinant_slogdet,
18
+ partition_by_condition,
19
+ partition_by_vif,
20
+ partition_by_reciprocal_eigenvalues,
21
+ partition_by_pairwise,
22
+ labels_to_blocks,
23
+ )
24
+
25
+ __version__ = "0.1.0"
26
+
27
+ __all__ = [
28
+ "partition_by_determinant",
29
+ "partition_by_determinant_slogdet",
30
+ "partition_by_condition",
31
+ "partition_by_vif",
32
+ "partition_by_reciprocal_eigenvalues",
33
+ "partition_by_pairwise",
34
+ "labels_to_blocks",
35
+ "__version__",
36
+ ]
@@ -0,0 +1,115 @@
1
+ """
2
+ Command line interface of ldpart: partition a square LD matrix into
3
+ blocks of correlated SNPs by a multicollinearity criterion. The input
4
+ file holds the matrix (1 on the diagonal, SNPs ordered as the rows and
5
+ columns) in HDF5; the output holds two columns, the zero-based SNP
6
+ index and the block label of every SNP, the format consumed by the
7
+ reproducibility layer of the ld-matrix-partition-01 project.
8
+
9
+ Installed as the console script `ldpart`:
10
+
11
+ ldpart -i LD.h5 -o labels.txt -m fast -d 0.001
12
+ ldpart -i LD.h5 -o labels.txt -m condition -c 1000
13
+ ldpart -i LD.h5 -o labels.txt -m vif -v 10
14
+ ldpart -i LD.h5 -o labels.txt -m reciprocal -r 5
15
+ ldpart -i LD.h5 -o labels.txt -m pairwise -p 0.8
16
+ """
17
+
18
+ import argparse
19
+ import time
20
+
21
+ import numpy as np
22
+ import h5py
23
+
24
+ from . import __version__
25
+ from .helpers import (attach_matrix, check_input_files,
26
+ check_output_dir, show_time_elapsed)
27
+ from .partitioner import (
28
+ partition_by_determinant,
29
+ partition_by_determinant_slogdet,
30
+ partition_by_condition,
31
+ partition_by_vif,
32
+ partition_by_reciprocal_eigenvalues,
33
+ partition_by_pairwise,
34
+ )
35
+
36
+ # Method -> (partition function, criterion argument, printed label)
37
+ METHODS = {
38
+ "fast": (partition_by_determinant, "min_det", "Minimal determinant"),
39
+ "slogdet": (partition_by_determinant_slogdet, "min_det",
40
+ "Minimal determinant"),
41
+ "condition": (partition_by_condition, "max_cond",
42
+ "Maximal condition number"),
43
+ "vif": (partition_by_vif, "max_vif", "Maximal VIF"),
44
+ "reciprocal": (partition_by_reciprocal_eigenvalues, "max_ratio",
45
+ "Maximal sum of reciprocal eigenvalues per block "
46
+ "size"),
47
+ "pairwise": (partition_by_pairwise, "min_r2",
48
+ "Minimal pairwise r2"),
49
+ }
50
+
51
+
52
+ def parser_args(argv=None) -> argparse.Namespace:
53
+ parser = argparse.ArgumentParser(
54
+ prog="ldpart",
55
+ description="Partition a square LD matrix into blocks of "
56
+ "correlated SNPs by a multicollinearity criterion")
57
+ parser.add_argument("-i", "--input", required=True,
58
+ help="/path/to/input.h5 with the matrix in "
59
+ "HDF5 format")
60
+ parser.add_argument("-o", "--output", required=True,
61
+ help="/path/to/output.txt for the block labels")
62
+ parser.add_argument("-d", "--min_det", type=float, default=0.001,
63
+ help="minimal determinant of a block submatrix, "
64
+ "methods fast and slogdet (default 0.001)")
65
+ parser.add_argument("-c", "--max_cond", type=float, default=1000.0,
66
+ help="maximal condition number of a block "
67
+ "submatrix, method condition "
68
+ "(default 1000)")
69
+ parser.add_argument("-v", "--max_vif", type=float, default=10.0,
70
+ help="maximal variance inflation factor of a "
71
+ "block submatrix, method vif (default 10)")
72
+ parser.add_argument("-r", "--max_ratio", type=float, default=5.0,
73
+ help="maximal sum of reciprocal eigenvalues "
74
+ "per block size, method reciprocal "
75
+ "(default 5)")
76
+ parser.add_argument("-p", "--min_r2", type=float, default=0.8,
77
+ help="minimal pairwise r2 between the "
78
+ "candidate and a block member, method "
79
+ "pairwise (default 0.8)")
80
+ parser.add_argument("-m", "--method", choices=tuple(METHODS),
81
+ default="fast",
82
+ help="partition function: fast, slogdet, "
83
+ "condition, vif, reciprocal or pairwise "
84
+ "(default fast)")
85
+ parser.add_argument("--version", action="version",
86
+ version=f"ldpart {__version__}")
87
+ return parser.parse_args(argv)
88
+
89
+
90
+ def main(argv=None) -> None:
91
+ args = parser_args(argv)
92
+ ts = time.time()
93
+
94
+ check_input_files([args.input])
95
+ check_output_dir(args.output)
96
+
97
+ print("Input:", args.input)
98
+ print("Output:", args.output)
99
+ print("Method:", args.method)
100
+
101
+ fun, arg_name, label = METHODS[args.method]
102
+ params = {arg_name: getattr(args, arg_name)}
103
+ print(label + ":", params[arg_name])
104
+
105
+ with h5py.File(args.input, "r") as f:
106
+ matrix = attach_matrix(f)
107
+ labels, nblocks = fun(matrix, **params)
108
+
109
+ np.savetxt(args.output, labels, delimiter=" ", fmt="%d")
110
+ print("Number of blocks:", nblocks)
111
+ show_time_elapsed(ts)
112
+
113
+
114
+ if __name__ == "__main__":
115
+ main()
@@ -0,0 +1,57 @@
1
+ """
2
+ Assisting functions of the ldpart command line interface: the LD
3
+ matrix is read straight from its HDF5 dataset (no copy into memory),
4
+ and the small file and folder checks live here. Trimmed from the
5
+ helpers of the ld-matrix-partition-01 project, pandas free.
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import time
11
+ from typing import Union
12
+
13
+ import h5py
14
+
15
+
16
+ def attach_matrix(file_obj: h5py.File) -> Union[h5py.Dataset,
17
+ h5py.Group]:
18
+ """
19
+ The square matrix of the first object of an open HDF5 file: a
20
+ plain dataset, or a group of chunked pandas arrays
21
+ (block0_values).
22
+ """
23
+ key = list(file_obj.keys())[0]
24
+ obj = file_obj[key]
25
+ if isinstance(obj, h5py.Dataset):
26
+ ds_obj = obj
27
+ elif isinstance(obj, h5py.Group):
28
+ ds_obj = obj["block0_values"]
29
+ else:
30
+ print("Unknown type of dataset")
31
+ sys.exit(1)
32
+
33
+ n, m = ds_obj.shape[0], ds_obj.shape[1]
34
+ if n != m:
35
+ print("Dataset is not a square matrix")
36
+ sys.exit(1)
37
+ print(f"Dataset shape: {n} x {m}")
38
+ return ds_obj
39
+
40
+
41
+ def check_output_dir(output: str) -> None:
42
+ # Create the folder holding an output path when missing
43
+ dir_name = os.path.dirname(output)
44
+ if dir_name:
45
+ os.makedirs(dir_name, exist_ok=True)
46
+
47
+
48
+ def check_input_files(files: list) -> None:
49
+ for file in files:
50
+ if file and not os.path.isfile(file):
51
+ print(f"{file} doesn't exist")
52
+ sys.exit(1)
53
+
54
+
55
+ def show_time_elapsed(ts: float) -> None:
56
+ dur = time.strftime("%H:%M:%S", time.gmtime(time.time() - ts))
57
+ print("Time spent:", dur)