bblean 0.8.1__cp313-cp313-win_amd64.whl → 0.8.2__cp313-cp313-win_amd64.whl

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.
Binary file
bblean/_merges.py CHANGED
@@ -69,6 +69,48 @@ class DiameterMerge(MergeAcceptFunction):
69
69
  return jt_isim_from_sum(new_ls, new_n) >= threshold
70
70
 
71
71
 
72
+ class FlexibleToleranceDiameterMerge(MergeAcceptFunction):
73
+ name = "flexible-tolerance-diameter"
74
+ # NOTE: Equivalent to tolerance-diameter but uses min(old_dc, threshold) as the
75
+ # criteria
76
+
77
+ def __init__(
78
+ self,
79
+ tolerance: float = 0.05,
80
+ n_max: int = 1000,
81
+ decay: float = 1e-3,
82
+ adaptive: bool = True,
83
+ ) -> None:
84
+ self.tolerance = tolerance
85
+ self.decay = decay
86
+ self.offset = np.exp(-decay * n_max)
87
+ if not adaptive:
88
+ self.decay = 0.0
89
+ self.offset = 0.0
90
+
91
+ def __call__(
92
+ self,
93
+ threshold: float,
94
+ new_ls: NDArray[np.integer],
95
+ new_n: int,
96
+ old_ls: NDArray[np.integer],
97
+ nom_ls: NDArray[np.integer],
98
+ old_n: int,
99
+ nom_n: int,
100
+ ) -> bool:
101
+ new_dc = jt_isim_from_sum(new_ls, new_n)
102
+ if new_dc < threshold:
103
+ return False
104
+ if old_n == 1:
105
+ return True
106
+ old_dc = jt_isim_from_sum(old_ls, old_n)
107
+ tol = max(self.tolerance * (np.exp(-self.decay * old_n) - self.offset), 0.0)
108
+ return new_dc >= min(old_dc, threshold) - tol
109
+
110
+ def __repr__(self) -> str:
111
+ return f"{self.__class__.__name__}({self.tolerance})"
112
+
113
+
72
114
  class ToleranceDiameterMerge(MergeAcceptFunction):
73
115
  name = "tolerance-diameter"
74
116
  # NOTE: The reliability of the estimate of the cluster should be a function of the
@@ -202,6 +244,8 @@ def get_merge_accept_fn(
202
244
  return ToleranceMerge(tolerance)
203
245
  elif merge_criterion == "tolerance-diameter":
204
246
  return ToleranceDiameterMerge(tolerance)
247
+ elif merge_criterion == "flexible-tolerance-diameter":
248
+ return FlexibleToleranceDiameterMerge(tolerance)
205
249
  elif merge_criterion == "tolerance-radius":
206
250
  return ToleranceRadiusMerge(tolerance)
207
251
  elif merge_criterion == "never-merge":
bblean/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.8.1'
32
- __version_tuple__ = version_tuple = (0, 8, 1)
31
+ __version__ = version = '0.8.2'
32
+ __version_tuple__ = version_tuple = (0, 8, 2)
33
33
 
34
- __commit_id__ = commit_id = 'g5aa6bced2'
34
+ __commit_id__ = commit_id = 'g83842e3cd'
bblean/bitbirch.py CHANGED
@@ -75,6 +75,8 @@ from bblean.similarity import (
75
75
  jt_most_dissimilar_packed,
76
76
  jt_isim_medoid,
77
77
  centroid_from_sum,
78
+ estimate_jt_std,
79
+ jt_isim,
78
80
  )
79
81
 
80
82
  if os.getenv("BITBIRCH_NO_EXTENSIONS"):
@@ -90,6 +92,64 @@ else:
90
92
  __all__ = ["BitBirch"]
91
93
 
92
94
 
95
+ @tp.overload
96
+ def guess_threshold(
97
+ fps: NDArray[np.uint8],
98
+ input_is_packed: bool = True,
99
+ n_features: int | None = None,
100
+ max_samples: int = 1_000_000,
101
+ factor: float = 3.0,
102
+ return_mean_std: tp.Literal[False] = False,
103
+ ) -> float:
104
+ pass
105
+
106
+
107
+ @tp.overload
108
+ def guess_threshold(
109
+ fps: NDArray[np.uint8],
110
+ input_is_packed: bool = True,
111
+ n_features: int | None = None,
112
+ max_samples: int = 1_000_000,
113
+ factor: float = 3.0,
114
+ return_mean_std: tp.Literal[True] = True,
115
+ ) -> tuple[float, float, float]:
116
+ pass
117
+
118
+
119
+ def guess_threshold(
120
+ fps: NDArray[np.uint8],
121
+ input_is_packed: bool = True,
122
+ n_features: int | None = None,
123
+ max_samples: int = 1_000_000,
124
+ factor: float = 3.0,
125
+ return_mean_std: bool = False,
126
+ ) -> float | tuple[float, float, float]:
127
+ r""":meta private:
128
+
129
+ Guess the optimal bitbirch threshold
130
+
131
+ Uses the heuristic mean_tanimoto + 3.0 * std_tanimoto
132
+ """
133
+ num_fps = len(fps)
134
+ if num_fps > max_samples:
135
+ rng = np.random.default_rng(42)
136
+ random_choices = rng.choice(num_fps, size=max_samples, replace=False)
137
+ fps = fps[random_choices]
138
+ num_fps = len(fps)
139
+ mean = jt_isim(fps, input_is_packed, n_features)
140
+ if num_fps <= 50:
141
+ n_samples = num_fps
142
+ else:
143
+ n_samples = max(5 * np.sqrt(num_fps), 50)
144
+ std = estimate_jt_std(
145
+ fps, input_is_packed=input_is_packed, n_features=n_features, n_samples=n_samples
146
+ )
147
+ thresh = mean + factor * std
148
+ if return_mean_std:
149
+ return thresh, mean, std
150
+ return thresh
151
+
152
+
93
153
  # For backwards compatibility with the global "set_merge", keep weak references to all
94
154
  # the BitBirch instances and update them when set_merge is called
95
155
  _BITBIRCH_INSTANCES: WeakSet["BitBirch"] = WeakSet()
bblean/cli.py CHANGED
@@ -1,5 +1,6 @@
1
1
  r"""Command line interface entrypoints"""
2
2
 
3
+ import numpy as np
3
4
  import warnings
4
5
  import random
5
6
  import typing as tp
@@ -930,6 +931,54 @@ def _plot_summary(
930
931
  )
931
932
 
932
933
 
934
+ @app.command("thresh")
935
+ def _guess_threshold(
936
+ ctx: Context,
937
+ input_: Annotated[
938
+ Path,
939
+ Argument(help="`*.npy` file with fingerprints"),
940
+ ],
941
+ factor: Annotated[
942
+ float,
943
+ Option("-f", "--factor"),
944
+ ] = 3.0,
945
+ n_features: Annotated[
946
+ int | None,
947
+ Option(
948
+ "--n-features",
949
+ help="Number of features in the fingerprints."
950
+ " It must be provided for packed inputs *if it is not a multiple of 8*."
951
+ " For typical fingerprint sizes (e.g. 2048, 1024), it is not required",
952
+ rich_help_panel="Advanced",
953
+ ),
954
+ ] = None,
955
+ input_is_packed: Annotated[
956
+ bool,
957
+ Option(
958
+ "--packed-input/--unpacked-input",
959
+ help="Toggle whether the input consists on packed or unpacked fingerprints",
960
+ rich_help_panel="Advanced",
961
+ ),
962
+ ] = True,
963
+ max_samples: Annotated[
964
+ int,
965
+ Option("-m", "--max-samples"),
966
+ ] = 1_000_000,
967
+ ) -> None:
968
+ r"""Estimate the optimal BitBirch threshold for a fingerprints file"""
969
+ from bblean.bitbirch import guess_threshold
970
+ from bblean._console import get_console
971
+
972
+ console = get_console()
973
+ fps = np.load(input_)
974
+ thresh, mean, std = guess_threshold(
975
+ fps, input_is_packed, n_features, max_samples, factor, return_mean_std=True
976
+ )
977
+ console.print(f"Estimated average similarity: {mean:.4f}")
978
+ console.print(f"Estimated similarity deviation: {std:.4f}")
979
+ console.print(f"Estimated optimal threshold: {thresh:.4f}")
980
+
981
+
933
982
  @app.command("run")
934
983
  def _run(
935
984
  ctx: Context,
bblean/similarity.py CHANGED
@@ -293,7 +293,7 @@ def estimate_jt_std(
293
293
  n_samples: int | None = None,
294
294
  input_is_packed: bool = True,
295
295
  n_features: int | None = None,
296
- min_samples: int = 1_000_000,
296
+ max_samples: int = 1_000_000,
297
297
  ) -> float:
298
298
  r"""Estimate the std of all pairwise Tanimoto.
299
299
 
@@ -303,15 +303,19 @@ def estimate_jt_std(
303
303
  The standard deviation of all pairwise Tanimoto among the sampled fingerprints.
304
304
  """
305
305
  num_fps = len(fps)
306
- if num_fps > min_samples:
307
- np.random.seed(42)
308
- random_choices = np.random.choice(num_fps, size=min_samples, replace=False)
306
+ if num_fps > max_samples:
307
+ rng = np.random.default_rng(42)
308
+ random_choices = rng.choice(num_fps, size=max_samples, replace=False)
309
309
  fps = fps[random_choices]
310
310
  num_fps = len(fps)
311
311
  if n_samples is None:
312
312
  # Heuristic: use at least 50 samples, or 1 per 10,000 fingerprints,
313
313
  # to balance statistical representativeness and computational efficiency
314
- n_samples = max(num_fps // 10_000, 50)
314
+ # TODO: This heuristic is broken, too few samples until 500k
315
+ if num_fps <= 500_000:
316
+ n_samples = 50
317
+ else:
318
+ n_samples = num_fps // 10_000
315
319
  sample_idxs = jt_stratified_sampling(fps, n_samples, input_is_packed, n_features)
316
320
 
317
321
  # Work with only the sampled fingerprints
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bblean
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: BitBirch-Lean Python package
5
5
  Author: The Miranda-Quintana Lab and other BitBirch developers
6
6
  Author-email: Ramon Alain Miranda Quintana <quintana@chem.ufl.edu>, Krisztina Zsigmond <kzsigmond@ufl.edu>, Ignacio Pickering <ipickering@ufl.edu>, Kenneth Lopez Perez <klopezperez@chem.ufl.edu>, Miroslav Lzicar <miroslav.lzicar@deepmedchem.com>
@@ -1,20 +1,20 @@
1
1
  bblean/__init__.py,sha256=9cudBHEt0H5p0jKEvgrhLZIHPSzwNAx0uJRp-_iM32I,686
2
2
  bblean/_config.py,sha256=WaONZilOWCLFdZulqWLKRqNM-ZLhY0YCXfwk-84FYmQ,1813
3
3
  bblean/_console.py,sha256=Mk1hi1NdPw2HDmjWj1LLbCuV3vCxL5l6u2gXaEeOFBM,8021
4
- bblean/_cpp_similarity.cp313-win_amd64.pyd,sha256=5lMeakYQaYsOtx9iqFaVmFY2ihrwAIUyvU5tlzdAYb0,182272
4
+ bblean/_cpp_similarity.cp313-win_amd64.pyd,sha256=aSYT0QK8vUOafpYdGmkznvg0Xg2nslMU5rfSgxgvgnQ,182272
5
5
  bblean/_memory.py,sha256=eycXzXV_O_VEyIKpAv3QpbxtpB5WkBLChzm_e2Dqaw0,6892
6
- bblean/_merges.py,sha256=xwFMJUPJ9VMujf2nSROx0NhsPoQ_R84KIxBF81x2hks,6432
6
+ bblean/_merges.py,sha256=jcukDaE0G-0UtVF_427-17gS8vyjN0F_gx6mwWv0wmo,7831
7
7
  bblean/_py_similarity.py,sha256=VYWu7gVCEDjNaRLgxiCxCGjCfmTity86UPC0dfT83Ok,9633
8
8
  bblean/_timer.py,sha256=D1-_tTQFJqIQgzl4HSE__-P3Scw72EIVlNDaChJT8Qs,1402
9
- bblean/_version.py,sha256=htK7xKc7g_IbAV_cXMJZjpQJZZby8nFR-IRwkjsF5YA,746
9
+ bblean/_version.py,sha256=wqA_6I8sCkXGJHVuQ9EfxYbaHviAFhfz9h7Mm_kZQLM,746
10
10
  bblean/analysis.py,sha256=apD5OgSoNGbIuBLSJFFzlUkVjZHBtb3fVEeEUJGbyqc,8118
11
- bblean/bitbirch.py,sha256=0zaClnIn9Pp5h2cpI17zAg1NbEr0aVMnywHI1ZfWcF8,60517
12
- bblean/cli.py,sha256=S_y0sY5M5fFj--DfvC4I04Bzs7OAxyEoidt6jjgeavQ,74199
11
+ bblean/bitbirch.py,sha256=dgxoMUb_g6eTMLHhTq5n9vxAF8BgCgHRx-ggqTxHuTM,62164
12
+ bblean/cli.py,sha256=AamdYqxzqsiJ7WPK-z5dCSr8CmGSRfNbXq0_LeloU_E,75819
13
13
  bblean/fingerprints.py,sha256=Dz_exFq9CzkFbQvaswIqWloA83Ac_ZBahiVbVrlOFtc,20049
14
14
  bblean/metrics.py,sha256=4KB-PIQJtFMsNg7lG2uM1HEId_eR5vhqcdLpCVLuI5Y,7280
15
15
  bblean/multiround.py,sha256=5VAACXTQfLxgl6UefVpF2tQo0ifFG3ehq1_ELjoMt5k,19862
16
16
  bblean/plotting.py,sha256=B2Kpw_HuKx1KxuKXI83IIWPQVsd-uJyDSu47a6mhzwE,15956
17
- bblean/similarity.py,sha256=O2OTW5Dw64go177jwzF5skvDSJEzDS7UImyIQ2nShig,12192
17
+ bblean/similarity.py,sha256=Ih-DkzERdd5pUKJKsgJ2pBmIPhVo57zSvRfnzqYTzsY,12339
18
18
  bblean/sklearn.py,sha256=KK7rbF3gENjlv5-9uOvH-Q0LEW1RUY__xClcnLznuE0,7450
19
19
  bblean/smiles.py,sha256=ppCqAbYUElnv5NeLRgU0aaJBBGczH9j9BYEWlzNjb-g,3213
20
20
  bblean/utils.py,sha256=K0ttSPf54nxrKD1TwbLFuwDIRlAD0jdr6KnuTqXs-HQ,3836
@@ -23,9 +23,9 @@ bblean/_legacy/bb_int64.py,sha256=Otqxu8NBLrfOMpJoMrLgWtDP_9Hn4joQXZVkU1hjges,45
23
23
  bblean/_legacy/bb_uint8.py,sha256=8kbeVAq7MxiR8hS_6lKhSDhVWc6acjLmLzNFCR466iA,41573
24
24
  bblean/csrc/README.md,sha256=qOPPK6sTqkYgnlPWtcNu9P3PwuLH8cCNJ1FwJeewsrk,59
25
25
  bblean/csrc/similarity.cpp,sha256=q6oMg9Vd0REPmqze8xToTmeXZiEuHTmOfL6QsTRFkDE,23122
26
- bblean-0.8.1.dist-info/licenses/LICENSE,sha256=Dq9t2XHr5wSrykVuVo8etKsAS35ENnDobU1h7t3H_-k,2598
27
- bblean-0.8.1.dist-info/METADATA,sha256=VIXmMyP48rQgUQsLPPEqDhpou4S7xspQK9oW9MAehu0,13051
28
- bblean-0.8.1.dist-info/WHEEL,sha256=qV0EIPljj1XC_vuSatRWjn02nZIz3N1t8jsZz7HBr2U,101
29
- bblean-0.8.1.dist-info/entry_points.txt,sha256=a0jb2L5JFKioMD6CqbvJiI2unaArGzi-AMZsyY-uyGg,38
30
- bblean-0.8.1.dist-info/top_level.txt,sha256=ybxTonvTC9zR25yR5B27aEDLl6CiwID093ZyS_--Cq4,7
31
- bblean-0.8.1.dist-info/RECORD,,
26
+ bblean-0.8.2.dist-info/licenses/LICENSE,sha256=Dq9t2XHr5wSrykVuVo8etKsAS35ENnDobU1h7t3H_-k,2598
27
+ bblean-0.8.2.dist-info/METADATA,sha256=nKe-e0-WKKM2Sg67leuUCTm26Ie_8XP42C9uAf3MnCo,13051
28
+ bblean-0.8.2.dist-info/WHEEL,sha256=-WvvtQtdhM1F5HMi-4hSXLQ_1Tg6qJRWO1HnLNr4mCU,102
29
+ bblean-0.8.2.dist-info/entry_points.txt,sha256=a0jb2L5JFKioMD6CqbvJiI2unaArGzi-AMZsyY-uyGg,38
30
+ bblean-0.8.2.dist-info/top_level.txt,sha256=ybxTonvTC9zR25yR5B27aEDLl6CiwID093ZyS_--Cq4,7
31
+ bblean-0.8.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp313-cp313-win_amd64
5
5