brisc 0.2.2__tar.gz → 0.2.3__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 (61) hide show
  1. {brisc-0.2.2 → brisc-0.2.3}/PKG-INFO +1 -1
  2. {brisc-0.2.2 → brisc-0.2.3}/brisc/single_cell.py +103 -95
  3. {brisc-0.2.2 → brisc-0.2.3}/brisc/threadpoolctl.py +4 -1
  4. {brisc-0.2.2 → brisc-0.2.3}/brisc.egg-info/PKG-INFO +1 -1
  5. brisc-0.2.3/brisc.egg-info/scm_version.json +8 -0
  6. brisc-0.2.2/brisc.egg-info/scm_version.json +0 -8
  7. {brisc-0.2.2 → brisc-0.2.3}/.git_archival.txt +0 -0
  8. {brisc-0.2.2 → brisc-0.2.3}/.gitattributes +0 -0
  9. {brisc-0.2.2 → brisc-0.2.3}/.gitignore +0 -0
  10. {brisc-0.2.2 → brisc-0.2.3}/LICENSE +0 -0
  11. {brisc-0.2.2 → brisc-0.2.3}/MANIFEST.in +0 -0
  12. {brisc-0.2.2 → brisc-0.2.3}/README.md +0 -0
  13. {brisc-0.2.2 → brisc-0.2.3}/brisc/__init__.py +0 -0
  14. {brisc-0.2.2 → brisc-0.2.3}/brisc/colorspacious.py +0 -0
  15. {brisc-0.2.2 → brisc-0.2.3}/brisc/concatenate.py +0 -0
  16. {brisc-0.2.2 → brisc-0.2.3}/brisc/cysparse.pyx +0 -0
  17. {brisc-0.2.2 → brisc-0.2.3}/brisc/cyutils.pxd +0 -0
  18. {brisc-0.2.2 → brisc-0.2.3}/brisc/cyutils.pyx +0 -0
  19. {brisc-0.2.2 → brisc-0.2.3}/brisc/de.py +0 -0
  20. {brisc-0.2.2 → brisc-0.2.3}/brisc/doublets.pyx +0 -0
  21. {brisc-0.2.2 → brisc-0.2.3}/brisc/embed.pyx +0 -0
  22. {brisc-0.2.2 → brisc-0.2.3}/brisc/harmonize.pyx +0 -0
  23. {brisc-0.2.2 → brisc-0.2.3}/brisc/hdf5.pyx +0 -0
  24. {brisc-0.2.2 → brisc-0.2.3}/brisc/hvg.pyx +0 -0
  25. {brisc-0.2.2 → brisc-0.2.3}/brisc/kmeans.pyx +0 -0
  26. {brisc-0.2.2 → brisc-0.2.3}/brisc/knn.pyx +0 -0
  27. {brisc-0.2.2 → brisc-0.2.3}/brisc/labels.pyx +0 -0
  28. {brisc-0.2.2 → brisc-0.2.3}/brisc/leiden.pyx +0 -0
  29. {brisc-0.2.2 → brisc-0.2.3}/brisc/loess.pyx +0 -0
  30. {brisc-0.2.2 → brisc-0.2.3}/brisc/norm_factors.pyx +0 -0
  31. {brisc-0.2.2 → brisc-0.2.3}/brisc/normalize.pyx +0 -0
  32. {brisc-0.2.2 → brisc-0.2.3}/brisc/pca.pyx +0 -0
  33. {brisc-0.2.2 → brisc-0.2.3}/brisc/pseudobulk.py +0 -0
  34. {brisc-0.2.2 → brisc-0.2.3}/brisc/pseudobulk_and_markers.pyx +0 -0
  35. {brisc-0.2.2 → brisc-0.2.3}/brisc/qc.pyx +0 -0
  36. {brisc-0.2.2 → brisc-0.2.3}/brisc/snn.pyx +0 -0
  37. {brisc-0.2.2 → brisc-0.2.3}/brisc/sparse.py +0 -0
  38. {brisc-0.2.2 → brisc-0.2.3}/brisc/type_aliases.py +0 -0
  39. {brisc-0.2.2 → brisc-0.2.3}/brisc/utils.py +0 -0
  40. {brisc-0.2.2 → brisc-0.2.3}/brisc/validated_dict.py +0 -0
  41. {brisc-0.2.2 → brisc-0.2.3}/brisc.egg-info/SOURCES.txt +0 -0
  42. {brisc-0.2.2 → brisc-0.2.3}/brisc.egg-info/dependency_links.txt +0 -0
  43. {brisc-0.2.2 → brisc-0.2.3}/brisc.egg-info/requires.txt +0 -0
  44. {brisc-0.2.2 → brisc-0.2.3}/brisc.egg-info/scm_file_list.json +0 -0
  45. {brisc-0.2.2 → brisc-0.2.3}/brisc.egg-info/top_level.txt +0 -0
  46. {brisc-0.2.2 → brisc-0.2.3}/pyproject.toml +0 -0
  47. {brisc-0.2.2 → brisc-0.2.3}/setup.cfg +0 -0
  48. {brisc-0.2.2 → brisc-0.2.3}/setup.py +0 -0
  49. {brisc-0.2.2 → brisc-0.2.3}/tests/conftest.py +0 -0
  50. {brisc-0.2.2 → brisc-0.2.3}/tests/make_test_data.py +0 -0
  51. {brisc-0.2.2 → brisc-0.2.3}/tests/test_cluster.py +0 -0
  52. {brisc-0.2.2 → brisc-0.2.3}/tests/test_de.py +0 -0
  53. {brisc-0.2.2 → brisc-0.2.3}/tests/test_embedding.py +0 -0
  54. {brisc-0.2.2 → brisc-0.2.3}/tests/test_hvg.py +0 -0
  55. {brisc-0.2.2 → brisc-0.2.3}/tests/test_integration.py +0 -0
  56. {brisc-0.2.2 → brisc-0.2.3}/tests/test_markers.py +0 -0
  57. {brisc-0.2.2 → brisc-0.2.3}/tests/test_neighbors.py +0 -0
  58. {brisc-0.2.2 → brisc-0.2.3}/tests/test_normalize.py +0 -0
  59. {brisc-0.2.2 → brisc-0.2.3}/tests/test_pca.py +0 -0
  60. {brisc-0.2.2 → brisc-0.2.3}/tests/test_pseudobulk.py +0 -0
  61. {brisc-0.2.2 → brisc-0.2.3}/tests/test_qc.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brisc
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Fast single-cell toolkit
5
5
  Author-email: Michael Wainberg <m.wainberg@utoronto.ca>
6
6
  License-Expression: MIT
@@ -11391,103 +11391,111 @@ class SingleCell:
11391
11391
  thread_sums = np.empty((num_threads, max(
11392
11392
  dataset._X.shape[1] for dataset in datasets), 3),
11393
11393
  dtype=np.uint64)
11394
- for X, cell_mask, gene_indices in batches:
11395
- num_dataset_genes = X.shape[1]
11396
- mean = np.empty(num_dataset_genes, dtype=np.float32)
11397
- var = np.empty(num_dataset_genes, dtype=np.float32)
11398
- nonzero_count = np.empty(num_dataset_genes, dtype=np.uint32)
11399
- is_csr = isinstance(X, csr_array)
11400
- if is_csr:
11401
- # For CSR, `cell_mask` is either `None` (all cells) or a
11402
- # pre-computed int64 array of cell indices
11403
- if cell_mask is None:
11404
- cell_indices = np.array([], dtype=np.int64)
11405
- num_cells = X.shape[0]
11406
- else:
11407
- cell_indices = cell_mask
11408
- num_cells = len(cell_indices)
11409
- counts_sum = np.empty(num_dataset_genes, dtype=np.uint64)
11410
- squared_counts_sum = np.empty(num_dataset_genes,
11411
- dtype=np.uint64)
11412
- gene_mean_and_variance_csr(
11413
- data=X.data, indices=X.indices, indptr=X.indptr,
11414
- cell_indices=cell_indices, num_cells=num_cells,
11415
- num_dataset_genes=num_dataset_genes,
11416
- thread_sums=thread_sums, counts_sum=counts_sum,
11417
- squared_counts_sum=squared_counts_sum, mean=mean, var=var,
11418
- nonzero_count=nonzero_count, num_threads=num_threads)
11419
- else:
11420
- if cell_mask is None:
11421
- cell_mask = np.array([], dtype=bool)
11422
- num_cells = X.shape[0]
11394
+ with threadpool_limits(
11395
+ 1, user_api=None if num_threads == 1 else 'blas'):
11396
+ for X, cell_mask, gene_indices in batches:
11397
+ num_dataset_genes = X.shape[1]
11398
+ mean = np.empty(num_dataset_genes, dtype=np.float32)
11399
+ var = np.empty(num_dataset_genes, dtype=np.float32)
11400
+ nonzero_count = np.empty(num_dataset_genes, dtype=np.uint32)
11401
+ is_csr = isinstance(X, csr_array)
11402
+ if is_csr:
11403
+ # For CSR, `cell_mask` is either `None` (all cells) or a
11404
+ # pre-computed int64 array of cell indices
11405
+ if cell_mask is None:
11406
+ cell_indices = np.array([], dtype=np.int64)
11407
+ num_cells = X.shape[0]
11408
+ else:
11409
+ cell_indices = cell_mask
11410
+ num_cells = len(cell_indices)
11411
+ counts_sum = np.empty(num_dataset_genes, dtype=np.uint64)
11412
+ squared_counts_sum = np.empty(num_dataset_genes,
11413
+ dtype=np.uint64)
11414
+ gene_mean_and_variance_csr(
11415
+ data=X.data, indices=X.indices, indptr=X.indptr,
11416
+ cell_indices=cell_indices, num_cells=num_cells,
11417
+ num_dataset_genes=num_dataset_genes,
11418
+ thread_sums=thread_sums, counts_sum=counts_sum,
11419
+ squared_counts_sum=squared_counts_sum, mean=mean,
11420
+ var=var, nonzero_count=nonzero_count,
11421
+ num_threads=num_threads)
11423
11422
  else:
11424
- # The cast to int is necessary for floating-point identical
11425
- # results: in NumPy ≥ 2.0, a Python int is a "weak" scalar
11426
- # (int * float32 array -> float32) but a NumPy integer is
11427
- # "strong" (np.int64 * float32 array -> float64 since
11428
- # `np.promote_types(int64, float32) == float64`).
11429
- num_cells = int(cell_mask.sum())
11430
- gene_mean_and_variance_csc(
11431
- data=X.data, indices=X.indices, indptr=X.indptr,
11432
- cell_mask=cell_mask, num_cells=num_cells,
11433
- num_dataset_genes=num_dataset_genes, mean=mean,
11434
- var=var, nonzero_count=nonzero_count,
11435
- num_threads=num_threads)
11423
+ if cell_mask is None:
11424
+ cell_mask = np.array([], dtype=bool)
11425
+ num_cells = X.shape[0]
11426
+ else:
11427
+ # The cast to int is necessary for floating-point
11428
+ # identical results: in NumPy ≥ 2.0, a Python int is a
11429
+ # "weak" scalar (int * float32 array -> float32) but a
11430
+ # NumPy integer is "strong" (np.int64 * float32 array
11431
+ # -> float64 since
11432
+ # `np.promote_types(int64, float32) == float64`).
11433
+ num_cells = int(cell_mask.sum())
11434
+ gene_mean_and_variance_csc(
11435
+ data=X.data, indices=X.indices, indptr=X.indptr,
11436
+ cell_mask=cell_mask, num_cells=num_cells,
11437
+ num_dataset_genes=num_dataset_genes, mean=mean,
11438
+ var=var, nonzero_count=nonzero_count,
11439
+ num_threads=num_threads)
11436
11440
 
11437
- not_constant = var > 0
11438
- y = np.log10(var[not_constant])
11439
- x = np.log10(mean[not_constant])
11440
- model = loess(x, y, span=span)
11441
- try:
11442
- model.fit()
11443
- except ValueError as e:
11444
- error_message = (
11445
- f'LOESS model fitting failed; this typically happens when '
11446
- f'there are very few cells (under ~1000), or when '
11447
- f'batch_column is specified and certain batches have very '
11448
- f'few cells')
11449
- if batch_column is not None:
11450
- error_message += ': consider not specifying batch_column'
11451
- raise ValueError(error_message) from e
11452
-
11453
- estimated_variance = np.zeros(num_dataset_genes, dtype=np.float32)
11454
- estimated_variance[not_constant] = model.outputs.fitted_values
11455
- estimated_stddev = np.sqrt(10 ** estimated_variance)
11456
- clip_val = mean + estimated_stddev * np.sqrt(num_cells,
11457
- dtype=np.float32)
11458
- batch_counts_sum = np.empty(num_dataset_genes, dtype=np.float32)
11459
- squared_batch_counts_sum = np.empty(num_dataset_genes,
11460
- dtype=np.float32)
11461
- if is_csr:
11462
- clipped_sum_csr(
11463
- data=X.data, indices=X.indices, indptr=X.indptr,
11464
- num_cells=num_cells, num_dataset_genes=num_dataset_genes,
11465
- cell_indices=cell_indices, clip_val=clip_val,
11466
- thread_sums=thread_sums, counts_sum=counts_sum,
11467
- squared_counts_sum=squared_counts_sum,
11468
- batch_counts_sum=batch_counts_sum,
11469
- squared_batch_counts_sum=squared_batch_counts_sum,
11470
- num_threads=num_threads)
11471
- else:
11472
- clipped_sum_csc(
11473
- data=X.data, indices=X.indices, indptr=X.indptr,
11474
- cell_mask=cell_mask, clip_val=clip_val,
11475
- batch_counts_sum=batch_counts_sum,
11476
- squared_batch_counts_sum=squared_batch_counts_sum,
11477
- num_threads=num_threads)
11478
- norm_gene_var = pl.Series(
11479
- (1 / ((num_cells - 1) * np.square(estimated_stddev))) *
11480
- ((num_cells * np.square(mean)) + squared_batch_counts_sum -
11481
- 2 * batch_counts_sum * mean))
11482
-
11483
- # `norm_gene_var` and `nonzero_count` are with respect to the genes
11484
- # in `dataset.var_names`; if needed, map them to the genes in
11485
- # `genes_in_all_datasets`
11486
- if gene_indices is not None:
11487
- norm_gene_var = norm_gene_var[gene_indices]
11488
- nonzero_count = nonzero_count[gene_indices.to_numpy()]
11489
- norm_gene_vars.append(norm_gene_var)
11490
- total_nonzero_count += nonzero_count
11441
+ not_constant = var > 0
11442
+ y = np.log10(var[not_constant])
11443
+ x = np.log10(mean[not_constant])
11444
+ model = loess(x, y, span=span)
11445
+ try:
11446
+ model.fit()
11447
+ except ValueError as e:
11448
+ error_message = (
11449
+ f'LOESS model fitting failed; this typically happens '
11450
+ f'when there are very few cells (under ~1000), or '
11451
+ f'when batch_column is specified and certain batches '
11452
+ f'have very few cells')
11453
+ if batch_column is not None:
11454
+ error_message += \
11455
+ ': consider not specifying batch_column'
11456
+ raise ValueError(error_message) from e
11457
+
11458
+ estimated_variance = np.zeros(num_dataset_genes,
11459
+ dtype=np.float32)
11460
+ estimated_variance[not_constant] = model.outputs.fitted_values
11461
+ estimated_stddev = np.sqrt(10 ** estimated_variance)
11462
+ clip_val = mean + estimated_stddev * np.sqrt(num_cells,
11463
+ dtype=np.float32)
11464
+ batch_counts_sum = np.empty(num_dataset_genes,
11465
+ dtype=np.float32)
11466
+ squared_batch_counts_sum = np.empty(num_dataset_genes,
11467
+ dtype=np.float32)
11468
+ if is_csr:
11469
+ clipped_sum_csr(
11470
+ data=X.data, indices=X.indices, indptr=X.indptr,
11471
+ num_cells=num_cells,
11472
+ num_dataset_genes=num_dataset_genes,
11473
+ cell_indices=cell_indices, clip_val=clip_val,
11474
+ thread_sums=thread_sums, counts_sum=counts_sum,
11475
+ squared_counts_sum=squared_counts_sum,
11476
+ batch_counts_sum=batch_counts_sum,
11477
+ squared_batch_counts_sum=squared_batch_counts_sum,
11478
+ num_threads=num_threads)
11479
+ else:
11480
+ clipped_sum_csc(
11481
+ data=X.data, indices=X.indices, indptr=X.indptr,
11482
+ cell_mask=cell_mask, clip_val=clip_val,
11483
+ batch_counts_sum=batch_counts_sum,
11484
+ squared_batch_counts_sum=squared_batch_counts_sum,
11485
+ num_threads=num_threads)
11486
+ norm_gene_var = pl.Series(
11487
+ (1 / ((num_cells - 1) * np.square(estimated_stddev))) *
11488
+ ((num_cells * np.square(mean)) + squared_batch_counts_sum -
11489
+ 2 * batch_counts_sum * mean))
11490
+
11491
+ # `norm_gene_var` and `nonzero_count` are with respect to the
11492
+ # genes in `dataset.var_names`; if needed, map them to the
11493
+ # genes in `genes_in_all_datasets`
11494
+ if gene_indices is not None:
11495
+ norm_gene_var = norm_gene_var[gene_indices]
11496
+ nonzero_count = nonzero_count[gene_indices.to_numpy()]
11497
+ norm_gene_vars.append(norm_gene_var)
11498
+ total_nonzero_count += nonzero_count
11491
11499
 
11492
11500
  rank = pl.exclude('gene').rank('min', descending=True)
11493
11501
  final_rank = pl.struct(
@@ -160,7 +160,10 @@ class _FlexiBLAS(_Library):
160
160
 
161
161
  class _MKL(_Library):
162
162
  name = 'mkl'
163
- filename_prefixes = 'libmkl_rt', 'mkl_rt', 'libblas'
163
+ # Also match MKL's interface layers (e.g. `libmkl_intel_lp64()`), which
164
+ # export the threading functions when MKL is linked without libmkl_rt
165
+ filename_prefixes = \
166
+ 'libmkl_rt', 'mkl_rt', 'libmkl_intel_', 'libmkl_gf_', 'libblas'
164
167
  check_symbols = 'MKL_Set_Num_Threads',
165
168
 
166
169
  def get(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brisc
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Fast single-cell toolkit
5
5
  Author-email: Michael Wainberg <m.wainberg@utoronto.ca>
6
6
  License-Expression: MIT
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.2.3",
3
+ "distance": 0,
4
+ "node": "g7458aedfcaa8dbcfe4436b468bd19a068abbe8ae",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-25"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.2.2",
3
- "distance": 0,
4
- "node": "g0a16f206c3772da54539139bb13d522c030a32ff",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-23"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes