fastmixture2 2.0.3__tar.gz → 2.0.4__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.
Files changed (68) hide show
  1. {fastmixture2-2.0.3/fastmixture2.egg-info → fastmixture2-2.0.4}/PKG-INFO +50 -26
  2. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/README.md +47 -23
  3. fastmixture2-2.0.4/fastmixture2/__init__.py +1 -0
  4. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/defaults.py +3 -3
  5. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/em.pyx +10 -19
  6. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/fastmixture2.py +13 -10
  7. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/gpu.py +341 -240
  8. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/main.py +1 -1
  9. fastmixture2-2.0.4/fastmixture2/packed.pxd +261 -0
  10. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/shared.pyx +12 -21
  11. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/sqp.pyx +43 -5
  12. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/svd.pyx +17 -1
  13. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/utils.py +143 -40
  14. {fastmixture2-2.0.3 → fastmixture2-2.0.4/fastmixture2.egg-info}/PKG-INFO +50 -26
  15. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2.egg-info/SOURCES.txt +4 -4
  16. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/pyproject.toml +3 -2
  17. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/check_portable.py +1 -0
  18. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/helpers.py +28 -2
  19. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_cli.py +23 -16
  20. fastmixture2-2.0.4/tests/test_cpu_subset.py +331 -0
  21. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_cross_validation.py +8 -15
  22. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_frequency_cache.py +15 -19
  23. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_genotypes.py +44 -1
  24. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_called.py +7 -3
  25. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_gl_precision.py +28 -5
  26. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_large.py +2 -1
  27. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_modes.py +8 -6
  28. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_precision.py +321 -8
  29. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_safety.py +126 -8
  30. fastmixture2-2.0.4/tests/test_gpu_streamed.py +401 -0
  31. fastmixture2-2.0.4/tests/test_gpu_subset.py +501 -0
  32. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_svd_cache.py +7 -9
  33. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_initialization.py +50 -13
  34. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_numerical_equivalence.py +22 -1
  35. fastmixture2-2.0.4/tests/test_sqp_solver.py +435 -0
  36. fastmixture2-2.0.4/tests/test_subset_modes.py +360 -0
  37. fastmixture2-2.0.3/fastmixture2/__init__.py +0 -1
  38. fastmixture2-2.0.3/fastmixture2/packed.pxd +0 -144
  39. fastmixture2-2.0.3/tests/test_gpu_als.py +0 -214
  40. fastmixture2-2.0.3/tests/test_gpu_boot_precision.py +0 -159
  41. fastmixture2-2.0.3/tests/test_gpu_em_reduction.py +0 -114
  42. fastmixture2-2.0.3/tests/test_gpu_native_precision.py +0 -76
  43. fastmixture2-2.0.3/tests/test_sqp_solver.py +0 -177
  44. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/LICENSE +0 -0
  45. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/MANIFEST.in +0 -0
  46. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/functions.py +0 -0
  47. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/kernels.py +0 -0
  48. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2/threads.pxd +0 -0
  49. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2.egg-info/dependency_links.txt +0 -0
  50. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2.egg-info/entry_points.txt +0 -0
  51. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2.egg-info/requires.txt +0 -0
  52. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/fastmixture2.egg-info/top_level.txt +0 -0
  53. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/setup.cfg +0 -0
  54. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/setup.py +0 -0
  55. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/run_tests.py +0 -0
  56. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_adversarial_io.py +0 -0
  57. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_bootstrap.py +0 -0
  58. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_convergence.py +0 -0
  59. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_cpu_scaling.py +0 -0
  60. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_distribution.py +0 -0
  61. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_stat_reuse.py +0 -0
  62. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_gpu_supervision.py +0 -0
  63. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_likelihoods.py +0 -0
  64. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_optimizers.py +0 -0
  65. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_q_constraints.py +0 -0
  66. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_sqp_scoring.py +0 -0
  67. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/test_threads.py +0 -0
  68. {fastmixture2-2.0.3 → fastmixture2-2.0.4}/tests/validate_distribution.py +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastmixture2
3
- Version: 2.0.3
4
- Summary: Fast and scalable memory-aware maximum-likelihood ancestry estimation
5
- Author-email: Jonas Meisner <meisnerucph@gmail.com>
3
+ Version: 2.0.4
4
+ Summary: Biobank-scale ancestry estimation in unrelated individuals
5
+ Author-email: "J. Meisner" <meisnerucph@gmail.com>, "L. Thunegard" <lisathunegard@icloud.com>
6
6
  License-Expression: GPL-3.0-only
7
7
  Project-URL: Homepage, https://github.com/MeisnerLab/fastmixture2
8
8
  Project-URL: Documentation, https://github.com/MeisnerLab/fastmixture2#readme
@@ -32,13 +32,14 @@ Dynamic: license-file
32
32
  # fastmixture2
33
33
 
34
34
  [![Tests](https://github.com/MeisnerLab/fastmixture2/actions/workflows/ci.yml/badge.svg)](https://github.com/MeisnerLab/fastmixture2/actions/workflows/ci.yml)
35
- [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)
35
+ [![PyPI](https://img.shields.io/pypi/v/fastmixture2.svg)](https://pypi.org/project/fastmixture2/)
36
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/MeisnerLab/fastmixture2/blob/main/LICENSE)
36
37
 
37
38
  `fastmixture2` estimates ancestry proportions (`Q`) and ancestral allele
38
39
  frequencies (`P`) by maximum likelihood. It reads SNP-major PLINK genotypes
39
40
  or ANGSD Beagle genotype likelihoods. Unsupervised initialization uses SVD/ALS
40
- for K > 1. All modes use safeguarded SQP/ZAL updates on CPU or, with `--gpu`,
41
- on NVIDIA CUDA.
41
+ for K > 1, with subset likelihood refinement for large panels.
42
+ All modes use safeguarded SQP/ZAL updates on CPU or, with `--gpu`, on NVIDIA CUDA.
42
43
 
43
44
  ## Installation
44
45
 
@@ -58,7 +59,8 @@ Source builds need a C compiler with OpenMP. On macOS, install OpenMP with
58
59
  `brew install libomp`. On HPC, build on the compute-node type used for your
59
60
  analyses.
60
61
 
61
- With Conda, the [CPU](environment-cpu.yml) and [GPU](environment-gpu.yml)
62
+ With Conda, the [CPU](https://github.com/MeisnerLab/fastmixture2/blob/main/environment-cpu.yml)
63
+ and [GPU](https://github.com/MeisnerLab/fastmixture2/blob/main/environment-gpu.yml)
62
64
  environments retain native CPU tuning. Run from the cloned repository:
63
65
 
64
66
  ```bash
@@ -69,7 +71,7 @@ conda activate fastmixture2-cpu
69
71
  For GPU use, select `environment-gpu.yml` and activate `fastmixture2-gpu`.
70
72
 
71
73
  PyPI wheels cover Linux (glibc) and macOS 14 or newer, on x86-64 and ARM64.
72
- They are portable and select SIMD kernels when available:
74
+ They use AVX2 on supported x86-64 CPUs and NEON on ARM64, including Apple Silicon:
73
75
 
74
76
  ```bash
75
77
  python -m pip install fastmixture2
@@ -132,20 +134,39 @@ fastmixture2 --bfile cohort --K 5 --threads 8 --gpu --out cohort.gpu
132
134
  CPU and CUDA support `1 <= K <= 128` for both input formats in all modes.
133
135
  CUDA keeps input data on the GPU when they fit and streams in blocks otherwise.
134
136
  Small CPU/GPU differences can arise from floating-point arithmetic.
135
- At K > 1, CUDA SVD starts at 256 samples. Large ALS factors at K <= 8 use
136
- CUDA ALS with float64 contractions. Smaller or high-K factors retain CPU ALS.
137
- Resident PLINK CUDA fits use float32 SQP statistics while gains remain material,
138
- then switch to float64 refinement. There is no fixed float32 iteration cap.
137
+
138
+ At K > 1, unsupervised initialization uses 10 SVD power iterations on all SNPs
139
+ up to 50,000, or a genome-wide 50,000-SNP subset otherwise. Larger panels refine
140
+ subset Q/P with SQP/ZAL, then fit full-marker P by least squares at fixed Q and
141
+ retain the refined subset rows. This applies to both input formats, including
142
+ missing genotypes.
143
+ Panels up to 50,000 SNPs proceed directly from SVD/ALS to full-data refinement,
144
+ without a duplicate subset fit or projection. For PLINK, subset refinement is
145
+ skipped if any sample has no observed subset genotypes. Exact CV folds and
146
+ `--iter 0` retain SVD/ALS without subset likelihood refinement.
147
+
148
+ Subsets exceeding 512 MiB on CPU or 256 MiB on CUDA are built in bounded blocks
149
+ into a temporary memory-mapped file. CUDA streams the subset when it does not
150
+ fit in VRAM. Temporary files use `TMPDIR`, which can point to disk-backed scratch
151
+ storage.
152
+
153
+ CUDA SVD starts at 256 samples. Both devices use CPU ALS with float64
154
+ contractions. Fixed-Q P projection uses float64 products on CPU and float32
155
+ products on CUDA.
156
+
157
+ Resident and streamed PLINK CUDA fits use float32 SQP statistics while gains
158
+ remain material, then switch to float64 refinement. There is no fixed float32
159
+ iteration cap. Tile products use float32, with float64 sums across tiles.
139
160
  Parameters, constrained solves and likelihood checks stay in float64.
140
- PLINK cuBLAS uses float32 tile products with float64 accumulation.
141
161
 
142
162
  Genotype-likelihood fits use Q-first SQP/ZAL on both CPU and CUDA, with exact
143
- EM/QN rescue and an independent EM check before convergence. Resident CUDA
144
- fits start with float32 probabilities, derivatives and statistics,
163
+ EM/QN rescue and an independent EM check before convergence. CUDA fits start
164
+ with float32 probabilities, derivatives and statistics in either storage mode,
145
165
  then switch to float64 refinement. Near frequency bounds, GL probabilities
146
166
  and derivatives use float64. cuBLAS tile sums, parameters, solves and scores stay
147
167
  in float64.
148
- CPU and CUDA start directly with SQP. `--iter` limits refinement.
168
+ CPU and CUDA start directly with SQP and use ZAL history depth 3.
169
+ `--iter` and `--tole` apply to each SQP/ZAL stage.
149
170
  EM skips missing genotypes and exactly uniform likelihood triplets, with
150
171
  normalization over informative entries. Nonuniform likelihoods are retained.
151
172
  Full likelihood scores retain the constant contribution from uniform triplets.
@@ -157,13 +178,16 @@ use 4096-sample shards with a separate 4 GiB cap. Optional update caches
157
178
  remain capped at 64 MiB. Input storage, factors and optimizer history are
158
179
  additional allocations.
159
180
 
160
- Resident CUDA uses native kernels at K = 1..3 and tiled cuBLAS for Q and P
161
- at K = 4..16 during float32 refinement, regardless of input format or dataset size.
162
- Tiles share at most 64 MiB of scratch and keep float32 copies of P and Q.
163
- Solves and likelihood checks remain in float64. At K <= 16, final refinement
164
- and streamed fits use native float64 kernels, except resident GL P updates at
165
- K = 8..16 with up to 1024 samples. Those share the tiled cuBLAS P routine and
166
- keep combined scratch within 64 MiB.
181
+ At K <= 16, CUDA fits use native kernels at K = 1..3
182
+ and tiled cuBLAS at K = 4..16 during float32 refinement. Resident tiles share
183
+ 64 MiB of scratch and keep float32 copies of P and Q. At K = 8..16,
184
+ resident mixed fits reuse frequency scratch for cooperative float64 solves.
185
+ Tiles that cannot hold the solve tables use the native solve. Streamed fits keep
186
+ float32 copies within tiles and reuse their float64 Q-statistics buffers, with
187
+ up to 128 MiB of compute scratch.
188
+ Final refinement uses native float64 kernels, except
189
+ resident GL P updates at K = 8..16 with up to 1024 samples. Those share the tiled
190
+ cuBLAS P routine and keep combined scratch within 64 MiB.
167
191
  Unsupervised resident PLINK fits at K = 10..16 keep the first eight iterations
168
192
  fresh, then alternate Q-Hessian reuse during float32 refinement. The cache is
169
193
  capped at 64 MiB. Weak cached proposals retry with fresh curvature, and
@@ -172,8 +196,8 @@ float64 refinement always uses fresh curvature.
172
196
  At K > 16, CUDA uses tiled cuBLAS statistics and a cooperative active-set
173
197
  solver for both input formats. Resident and bootstrap maps share 64 MiB of
174
198
  scratch. Streamed maps allow up to 128 MiB of compute scratch and 512 MiB of
175
- Q statistics, with free-VRAM guards. Curvature stays fresh. Larger K still
176
- increases compute cost, especially for the quadratic solves.
199
+ Q statistics, with free-VRAM guards. Streamed tiles adapt to the panel width,
200
+ with at most 8192 rows within the same memory caps. Curvature stays fresh.
177
201
 
178
202
  The defaults are `--threads 1`, `--seed 42`, `--iter 1000` and `--tole 1e-10`.
179
203
  `--threads` caps CPU computation, including BLAS and GPU host copies.
@@ -333,4 +357,4 @@ fastmixture2 does not create filesystem locks or require private lock directorie
333
357
  ## Authors and license
334
358
 
335
359
  Lisa Thunegard and Jonas Meisner. Developed at **MeisnerLab** and distributed
336
- under the [GNU General Public License v3.0](LICENSE).
360
+ under the [GNU General Public License v3.0](https://github.com/MeisnerLab/fastmixture2/blob/main/LICENSE).
@@ -1,13 +1,14 @@
1
1
  # fastmixture2
2
2
 
3
3
  [![Tests](https://github.com/MeisnerLab/fastmixture2/actions/workflows/ci.yml/badge.svg)](https://github.com/MeisnerLab/fastmixture2/actions/workflows/ci.yml)
4
- [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)
4
+ [![PyPI](https://img.shields.io/pypi/v/fastmixture2.svg)](https://pypi.org/project/fastmixture2/)
5
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/MeisnerLab/fastmixture2/blob/main/LICENSE)
5
6
 
6
7
  `fastmixture2` estimates ancestry proportions (`Q`) and ancestral allele
7
8
  frequencies (`P`) by maximum likelihood. It reads SNP-major PLINK genotypes
8
9
  or ANGSD Beagle genotype likelihoods. Unsupervised initialization uses SVD/ALS
9
- for K > 1. All modes use safeguarded SQP/ZAL updates on CPU or, with `--gpu`,
10
- on NVIDIA CUDA.
10
+ for K > 1, with subset likelihood refinement for large panels.
11
+ All modes use safeguarded SQP/ZAL updates on CPU or, with `--gpu`, on NVIDIA CUDA.
11
12
 
12
13
  ## Installation
13
14
 
@@ -27,7 +28,8 @@ Source builds need a C compiler with OpenMP. On macOS, install OpenMP with
27
28
  `brew install libomp`. On HPC, build on the compute-node type used for your
28
29
  analyses.
29
30
 
30
- With Conda, the [CPU](environment-cpu.yml) and [GPU](environment-gpu.yml)
31
+ With Conda, the [CPU](https://github.com/MeisnerLab/fastmixture2/blob/main/environment-cpu.yml)
32
+ and [GPU](https://github.com/MeisnerLab/fastmixture2/blob/main/environment-gpu.yml)
31
33
  environments retain native CPU tuning. Run from the cloned repository:
32
34
 
33
35
  ```bash
@@ -38,7 +40,7 @@ conda activate fastmixture2-cpu
38
40
  For GPU use, select `environment-gpu.yml` and activate `fastmixture2-gpu`.
39
41
 
40
42
  PyPI wheels cover Linux (glibc) and macOS 14 or newer, on x86-64 and ARM64.
41
- They are portable and select SIMD kernels when available:
43
+ They use AVX2 on supported x86-64 CPUs and NEON on ARM64, including Apple Silicon:
42
44
 
43
45
  ```bash
44
46
  python -m pip install fastmixture2
@@ -101,20 +103,39 @@ fastmixture2 --bfile cohort --K 5 --threads 8 --gpu --out cohort.gpu
101
103
  CPU and CUDA support `1 <= K <= 128` for both input formats in all modes.
102
104
  CUDA keeps input data on the GPU when they fit and streams in blocks otherwise.
103
105
  Small CPU/GPU differences can arise from floating-point arithmetic.
104
- At K > 1, CUDA SVD starts at 256 samples. Large ALS factors at K <= 8 use
105
- CUDA ALS with float64 contractions. Smaller or high-K factors retain CPU ALS.
106
- Resident PLINK CUDA fits use float32 SQP statistics while gains remain material,
107
- then switch to float64 refinement. There is no fixed float32 iteration cap.
106
+
107
+ At K > 1, unsupervised initialization uses 10 SVD power iterations on all SNPs
108
+ up to 50,000, or a genome-wide 50,000-SNP subset otherwise. Larger panels refine
109
+ subset Q/P with SQP/ZAL, then fit full-marker P by least squares at fixed Q and
110
+ retain the refined subset rows. This applies to both input formats, including
111
+ missing genotypes.
112
+ Panels up to 50,000 SNPs proceed directly from SVD/ALS to full-data refinement,
113
+ without a duplicate subset fit or projection. For PLINK, subset refinement is
114
+ skipped if any sample has no observed subset genotypes. Exact CV folds and
115
+ `--iter 0` retain SVD/ALS without subset likelihood refinement.
116
+
117
+ Subsets exceeding 512 MiB on CPU or 256 MiB on CUDA are built in bounded blocks
118
+ into a temporary memory-mapped file. CUDA streams the subset when it does not
119
+ fit in VRAM. Temporary files use `TMPDIR`, which can point to disk-backed scratch
120
+ storage.
121
+
122
+ CUDA SVD starts at 256 samples. Both devices use CPU ALS with float64
123
+ contractions. Fixed-Q P projection uses float64 products on CPU and float32
124
+ products on CUDA.
125
+
126
+ Resident and streamed PLINK CUDA fits use float32 SQP statistics while gains
127
+ remain material, then switch to float64 refinement. There is no fixed float32
128
+ iteration cap. Tile products use float32, with float64 sums across tiles.
108
129
  Parameters, constrained solves and likelihood checks stay in float64.
109
- PLINK cuBLAS uses float32 tile products with float64 accumulation.
110
130
 
111
131
  Genotype-likelihood fits use Q-first SQP/ZAL on both CPU and CUDA, with exact
112
- EM/QN rescue and an independent EM check before convergence. Resident CUDA
113
- fits start with float32 probabilities, derivatives and statistics,
132
+ EM/QN rescue and an independent EM check before convergence. CUDA fits start
133
+ with float32 probabilities, derivatives and statistics in either storage mode,
114
134
  then switch to float64 refinement. Near frequency bounds, GL probabilities
115
135
  and derivatives use float64. cuBLAS tile sums, parameters, solves and scores stay
116
136
  in float64.
117
- CPU and CUDA start directly with SQP. `--iter` limits refinement.
137
+ CPU and CUDA start directly with SQP and use ZAL history depth 3.
138
+ `--iter` and `--tole` apply to each SQP/ZAL stage.
118
139
  EM skips missing genotypes and exactly uniform likelihood triplets, with
119
140
  normalization over informative entries. Nonuniform likelihoods are retained.
120
141
  Full likelihood scores retain the constant contribution from uniform triplets.
@@ -126,13 +147,16 @@ use 4096-sample shards with a separate 4 GiB cap. Optional update caches
126
147
  remain capped at 64 MiB. Input storage, factors and optimizer history are
127
148
  additional allocations.
128
149
 
129
- Resident CUDA uses native kernels at K = 1..3 and tiled cuBLAS for Q and P
130
- at K = 4..16 during float32 refinement, regardless of input format or dataset size.
131
- Tiles share at most 64 MiB of scratch and keep float32 copies of P and Q.
132
- Solves and likelihood checks remain in float64. At K <= 16, final refinement
133
- and streamed fits use native float64 kernels, except resident GL P updates at
134
- K = 8..16 with up to 1024 samples. Those share the tiled cuBLAS P routine and
135
- keep combined scratch within 64 MiB.
150
+ At K <= 16, CUDA fits use native kernels at K = 1..3
151
+ and tiled cuBLAS at K = 4..16 during float32 refinement. Resident tiles share
152
+ 64 MiB of scratch and keep float32 copies of P and Q. At K = 8..16,
153
+ resident mixed fits reuse frequency scratch for cooperative float64 solves.
154
+ Tiles that cannot hold the solve tables use the native solve. Streamed fits keep
155
+ float32 copies within tiles and reuse their float64 Q-statistics buffers, with
156
+ up to 128 MiB of compute scratch.
157
+ Final refinement uses native float64 kernels, except
158
+ resident GL P updates at K = 8..16 with up to 1024 samples. Those share the tiled
159
+ cuBLAS P routine and keep combined scratch within 64 MiB.
136
160
  Unsupervised resident PLINK fits at K = 10..16 keep the first eight iterations
137
161
  fresh, then alternate Q-Hessian reuse during float32 refinement. The cache is
138
162
  capped at 64 MiB. Weak cached proposals retry with fresh curvature, and
@@ -141,8 +165,8 @@ float64 refinement always uses fresh curvature.
141
165
  At K > 16, CUDA uses tiled cuBLAS statistics and a cooperative active-set
142
166
  solver for both input formats. Resident and bootstrap maps share 64 MiB of
143
167
  scratch. Streamed maps allow up to 128 MiB of compute scratch and 512 MiB of
144
- Q statistics, with free-VRAM guards. Curvature stays fresh. Larger K still
145
- increases compute cost, especially for the quadratic solves.
168
+ Q statistics, with free-VRAM guards. Streamed tiles adapt to the panel width,
169
+ with at most 8192 rows within the same memory caps. Curvature stays fresh.
146
170
 
147
171
  The defaults are `--threads 1`, `--seed 42`, `--iter 1000` and `--tole 1e-10`.
148
172
  `--threads` caps CPU computation, including BLAS and GPU host copies.
@@ -302,4 +326,4 @@ fastmixture2 does not create filesystem locks or require private lock directorie
302
326
  ## Authors and license
303
327
 
304
328
  Lisa Thunegard and Jonas Meisner. Developed at **MeisnerLab** and distributed
305
- under the [GNU General Public License v3.0](LICENSE).
329
+ under the [GNU General Public License v3.0](https://github.com/MeisnerLab/fastmixture2/blob/main/LICENSE).
@@ -0,0 +1 @@
1
+ __version__ = "2.0.4"
@@ -14,9 +14,9 @@ LIKELIHOOD_CACHE_HEADER_BYTES = 256
14
14
  LIKELIHOOD_CACHE_VERSION = 5
15
15
  LIKELIHOOD_FREQUENCY_VERSION = 2
16
16
 
17
- # SVD/ALS initialization
18
- INITIALIZATION_MARKERS = 100_000
19
- SVD_POWER_ITERATIONS = 5
17
+ # Initialization
18
+ INITIALIZATION_MARKERS = 50_000
19
+ SVD_POWER_ITERATIONS = 10
20
20
  SVD_CHUNK_MARKERS = 4_096
21
21
  SVD_WORKSPACE_BYTES = 512 << 20
22
22
  GPU_SVD_WORKSPACE_BYTES = 256 << 20
@@ -1244,15 +1244,17 @@ cpdef int accelPacked(
1244
1244
  return 0
1245
1245
 
1246
1246
 
1247
- ### Form one weighted packed marker-bootstrap EM map
1248
- cdef int _batchPacked(
1247
+ ### Form one multiplicity-weighted packed marker-bootstrap EM map
1248
+ cpdef int batchPackedW(
1249
1249
  const u8[:, ::1] B, const f64[:, ::1] P,
1250
1250
  f64[:, ::1] P1, const f64[:, ::1] Q,
1251
- f64[:, ::1] T, const u32[::1] s, const u32* w,
1252
- const Py_ssize_t N, const bint masked, const Py_ssize_t fold,
1253
- const Py_ssize_t folds, const uint64_t seed
1251
+ f64[:, ::1] T, const u32[::1] s, const u32[::1] w,
1252
+ const Py_ssize_t N, Py_ssize_t fold=-1,
1253
+ Py_ssize_t folds=1, uint64_t seed=0
1254
1254
  ) except -1 nogil:
1255
1255
  cdef:
1256
+ bint masked = fold >= 0
1257
+ const u32* wt = &w[0]
1256
1258
  u8* g_thr
1257
1259
  u8* g_all
1258
1260
  const f64* p
@@ -1290,7 +1292,7 @@ cdef int _batchPacked(
1290
1292
  for j in prange(M, schedule="static"):
1291
1293
  marker = s[j]
1292
1294
  p = &P[marker, 0]
1293
- if w[j] == 0:
1295
+ if wt[j] == 0:
1294
1296
  for k in range(K):
1295
1297
  P1[marker, k] = p[k]
1296
1298
  continue
@@ -1302,7 +1304,7 @@ cdef int _batchPacked(
1302
1304
  else:
1303
1305
  _unpackPackedRow(&B[marker, 0], g_thr, N)
1304
1306
  if not _specializedEmRowW(
1305
- g_thr, p, &Q[0, 0], &P1[marker, 0], q_thr, w[j], N, K
1307
+ g_thr, p, &Q[0, 0], &P1[marker, 0], q_thr, wt[j], N, K
1306
1308
  ):
1307
1309
  for i in range(N):
1308
1310
  if g_thr[i] == 9:
@@ -1311,7 +1313,7 @@ cdef int _batchPacked(
1311
1313
  h = _computeH(p, q, K)
1312
1314
  _innerJW(
1313
1315
  p, q, &p_thr[0], &p_thr[K], &q_thr[i * K],
1314
- g_thr[i], w[j], K, h
1316
+ g_thr[i], wt[j], K, h
1315
1317
  )
1316
1318
  _outerAccelP(p, &P1[marker, 0], &p_thr[0], &p_thr[K], K)
1317
1319
  for x in prange(L, schedule="static"):
@@ -1323,17 +1325,6 @@ cdef int _batchPacked(
1323
1325
  return 0
1324
1326
 
1325
1327
 
1326
- ### Form one multiplicity-weighted packed marker-bootstrap EM map
1327
- cpdef int batchPackedW(
1328
- const u8[:, ::1] B, const f64[:, ::1] P, f64[:, ::1] P1,
1329
- const f64[:, ::1] Q, f64[:, ::1] T,
1330
- const u32[::1] s, const u32[::1] w,
1331
- const Py_ssize_t N, Py_ssize_t fold=-1,
1332
- Py_ssize_t folds=1, uint64_t seed=0
1333
- ) except -1 nogil:
1334
- return _batchPacked(B, P, P1, Q, T, s, &w[0], N, fold >= 0, fold, folds, seed)
1335
-
1336
-
1337
1328
  ### Form one packed fixed-P Q map
1338
1329
  cpdef int stepQPacked(
1339
1330
  const u8[:, ::1] B, const f64[:, ::1] P,
@@ -805,6 +805,13 @@ def _run(args, stack):
805
805
  else:
806
806
  boot_h, b_chr = utils.bootBlock(args.bfile, M, args.bootstrap_block)
807
807
 
808
+ run = {
809
+ "iter": args.iter,
810
+ "tole": args.tole,
811
+ "check": check,
812
+ "gpu": use_gpu,
813
+ "log": runtime.append,
814
+ }
808
815
  print("\nInitialization:")
809
816
  resumed = pops = y = None
810
817
  if args.resume is not None:
@@ -861,6 +868,7 @@ def _run(args, stack):
861
868
  P1, Q = resumed[:2]
862
869
  if P1 is not None and not np.allclose(P1, P0, atol=1e-12, rtol=0.0):
863
870
  raise ValueError("Checkpoint frequencies do not match --projection")
871
+ del P1
864
872
  P = P0
865
873
  del P0
866
874
  sec = time() - ts
@@ -893,10 +901,12 @@ def _run(args, stack):
893
901
  elif use_gpu:
894
902
  from fastmixture2 import gpu
895
903
 
896
- P, Q = gpu.initializeUnsupervised(G, args.K, rng)
904
+ P, Q = gpu.initializeUnsupervised(G, args.K, rng, run=run)
897
905
  else:
898
- P, Q = utils.initializeUnsupervised(G, args.K, rng)
906
+ P, Q = utils.initializeUnsupervised(G, args.K, rng, run=run)
899
907
  sec = time() - ts
908
+ if "init" in run:
909
+ label = "SVD/ALS and subset refinement"
900
910
  functions.printTiming(f"{label}.", sec, replace=True)
901
911
  runtime.append(f"{label}: {sec:.1f} s")
902
912
  else:
@@ -909,14 +919,6 @@ def _run(args, stack):
909
919
  if inputKey(args) != src_key:
910
920
  raise ValueError("Analysis inputs changed while reading")
911
921
 
912
- # Build the optimizer settings
913
- run = {
914
- "iter": args.iter,
915
- "tole": args.tole,
916
- "check": check,
917
- "gpu": use_gpu,
918
- "log": runtime.append,
919
- }
920
922
  if resumed is not None:
921
923
  if not use_gpu:
922
924
  like = functions._loglike(G, q_nrm)
@@ -929,6 +931,7 @@ def _run(args, stack):
929
931
 
930
932
  # CUDA scores resumed estimates after their single host-to-device transfer
931
933
  run["off"] = resumed[3]
934
+ del resumed
932
935
  ckpt = args.checkpoint or args.resume
933
936
  if ckpt is not None:
934
937
  ### Persist the latest accepted optimizer state