bs-python-utils 1.0.1__tar.gz → 1.1__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 (91) hide show
  1. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/PKG-INFO +3 -2
  2. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/opt/bs_opt.py +4 -4
  3. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/stats/bivariate_quantiles.py +94 -28
  4. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils.egg-info/PKG-INFO +3 -2
  5. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils.egg-info/requires.txt +1 -0
  6. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/pyproject.toml +7 -2
  7. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_bivariate_quantiles.py +20 -0
  8. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/LICENSE +0 -0
  9. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/README.md +0 -0
  10. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid1prec13.txt +0 -0
  11. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid1prec17.txt +0 -0
  12. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid1prec9.txt +0 -0
  13. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid2prec13.txt +0 -0
  14. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid2prec17.txt +0 -0
  15. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid2prec9.txt +0 -0
  16. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid3prec13.txt +0 -0
  17. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid3prec17.txt +0 -0
  18. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid3prec9.txt +0 -0
  19. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid4prec13.txt +0 -0
  20. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid4prec17.txt +0 -0
  21. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid4prec9.txt +0 -0
  22. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid5prec13.txt +0 -0
  23. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid5prec17.txt +0 -0
  24. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid5prec9.txt +0 -0
  25. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/Timer.py +0 -0
  26. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/__init__.py +0 -0
  27. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bivariate_quantiles.py +0 -0
  28. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_altair.py +0 -0
  29. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_logging.py +0 -0
  30. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_mathstr.py +0 -0
  31. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_mem.py +0 -0
  32. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_opt.py +0 -0
  33. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_plots.py +0 -0
  34. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_seaborn.py +0 -0
  35. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bs_sparse_gaussian.py +0 -0
  36. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bsmplutils.py +0 -0
  37. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bsnputils.py +0 -0
  38. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bssputils.py +0 -0
  39. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bsstats.py +0 -0
  40. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/bsutils.py +0 -0
  41. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/chebyshev.py +0 -0
  42. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/core/Timer.py +0 -0
  43. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/core/__init__.py +0 -0
  44. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/core/bs_logging.py +0 -0
  45. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/core/bs_mathstr.py +0 -0
  46. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/core/bs_mem.py +0 -0
  47. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/core/bsutils.py +0 -0
  48. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/data_anal/__init__.py +0 -0
  49. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/data_anal/pandas_utils.py +0 -0
  50. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/data_anal/sklearn_utils.py +0 -0
  51. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/distance_covariances.py +0 -0
  52. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_altair.py +0 -0
  53. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_distance_covariances.py +0 -0
  54. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_mem.py +0 -0
  55. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_mpl.py +0 -0
  56. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_opt.py +0 -0
  57. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_seaborn.py +0 -0
  58. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_sklearn.py +0 -0
  59. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/examples/examples_sparse_gaussian.py +0 -0
  60. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/numerical/__init__.py +0 -0
  61. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/numerical/bs_sparse_gaussian.py +0 -0
  62. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/numerical/bsnputils.py +0 -0
  63. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/numerical/bssputils.py +0 -0
  64. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/numerical/chebyshev.py +0 -0
  65. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/opt/__init__.py +0 -0
  66. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/pandas_utils.py +0 -0
  67. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/sklearn_utils.py +0 -0
  68. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/stats/__init__.py +0 -0
  69. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/stats/bsstats.py +0 -0
  70. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/stats/distance_covariances.py +0 -0
  71. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/streamlit_utils.py +0 -0
  72. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/viz/__init__.py +0 -0
  73. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/viz/bs_altair.py +0 -0
  74. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/viz/bs_plots.py +0 -0
  75. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/viz/bs_seaborn.py +0 -0
  76. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/viz/bsmplutils.py +0 -0
  77. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils/viz/streamlit_utils.py +0 -0
  78. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils.egg-info/SOURCES.txt +0 -0
  79. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils.egg-info/dependency_links.txt +0 -0
  80. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/bs_python_utils.egg-info/top_level.txt +0 -0
  81. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/setup.cfg +0 -0
  82. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_bs_opt.py +0 -0
  83. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_bs_sparse_gaussian.py +0 -0
  84. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_bsnputils.py +0 -0
  85. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_bssputils.py +0 -0
  86. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_bsstats.py +0 -0
  87. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_bsutils.py +0 -0
  88. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_chebyshev.py +0 -0
  89. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_nptri.py +0 -0
  90. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_random_draws.py +0 -0
  91. {bs_python_utils-1.0.1 → bs_python_utils-1.1}/tests/test_sklearn_utils.py +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bs-python-utils
3
- Version: 1.0.1
3
+ Version: 1.1
4
4
  Summary: Utilities programs for my Python code
5
- Requires-Python: >=3.12
5
+ Requires-Python: >=3.13
6
6
  Description-Content-Type: text/markdown
7
7
  License-File: LICENSE
8
8
  Requires-Dist: altair>=5.5.0
@@ -26,6 +26,7 @@ Requires-Dist: streamlit>=1.49.1
26
26
  Requires-Dist: vega-datasets>=0.9.0
27
27
  Requires-Dist: colorama>=0.4.6
28
28
  Requires-Dist: pyarrow>=23.0.0
29
+ Requires-Dist: scipy-stubs~=1.16.2
29
30
  Dynamic: license-file
30
31
 
31
32
  ## bs-python-utils
@@ -25,6 +25,7 @@ import numpy as np
25
25
  import scipy.linalg as spla
26
26
  import scipy.optimize as spopt
27
27
 
28
+
28
29
  from bs_python_utils.numerical.bsnputils import TwoArrays, check_vector, npmaxabs
29
30
  from bs_python_utils.core.bsutils import bs_error_abort, print_stars
30
31
  from bs_python_utils.core.Timer import timeit
@@ -221,11 +222,11 @@ def check_gradient_scalar_function(
221
222
  fg: should return the scalar value, and the gradient if its `gr` argument is `True`
222
223
  p: where we are checking the gradient
223
224
  args: other arguments passed to `fg`
224
- mode: "central" or "forward" derivatives
225
- EPS: the step for forward or central derivatives
225
+ mode: ``"central"`` or ``"forward"``
226
+ EPS: the step for forward or central finite differences
226
227
 
227
228
  Returns:
228
- the analytic and numeric gradients.
229
+ the analytic and numeric (or AD) gradients.
229
230
  """
230
231
  f0, f_grad = fg(p, args, gr=True) # type: ignore
231
232
  f0 = cast(float, f0)
@@ -285,7 +286,6 @@ def acc_grad_descent(
285
286
  Returns:
286
287
  A pair ``(x_star, status)`` where ``status`` is ``0`` on convergence and ``1`` otherwise.
287
288
  """
288
-
289
289
  # no proximal projection if no h
290
290
  local_prox_h: ProximalFunction = prox_h if prox_h else lambda x, t, p: x
291
291
 
@@ -15,6 +15,8 @@ References:
15
15
  Quantiles, Ranks and Signs." *Annals of Statistics* 45(1), 2017.
16
16
  """
17
17
 
18
+ from __future__ import annotations
19
+
18
20
  from typing import cast
19
21
 
20
22
  import numpy as np
@@ -23,6 +25,74 @@ from bs_python_utils.core.bsutils import bs_error_abort
23
25
  from bs_python_utils.numerical.bsnputils import TwoArrays, npmaxabs
24
26
  from bs_python_utils.numerical.chebyshev import Interval, cheb_get_nodes_1d
25
27
  from bs_python_utils.opt.bs_opt import minimize_free, print_optimization_results
28
+ from bs_python_utils.numerical.bsnputils import check_matrix
29
+ from scipy.special import logsumexp
30
+
31
+
32
+ def bivariate_ranks_simul(
33
+ x: np.ndarray,
34
+ rng: np.random.Generator,
35
+ n_draws: int = 10_000,
36
+ h_mult: float = 100.0,
37
+ ) -> np.ndarray:
38
+ """This computes bivariate ranks for a matrix ``x` using simulations
39
+
40
+ Args:
41
+ x: Input matrix of shape ``(n, 2)``.
42
+ rng: Random number generator for reproducibility.
43
+ n_draws: Number of random draws for the simulation.
44
+ h_mult: we set the bandwidth h as std(v_init)/h_mult, default is 100.0
45
+ """
46
+ n, d = check_matrix(x)
47
+ if d != 2:
48
+ bs_error_abort("Input matrix x must have 2 columns for bivariate ranks.")
49
+
50
+ v_init = np.mean(x, axis=1)[:-1]
51
+ h = np.std(v_init) / 100.0
52
+
53
+ tau_draws = rng.uniform(low=0.0, high=1.0, size=2 * n_draws).reshape((n_draws, 2))
54
+
55
+ def objv_and_grad(
56
+ v: np.ndarray,
57
+ ret: int = 0,
58
+ ) -> float | np.ndarray | None:
59
+ vn = np.zeros(n)
60
+ vn[:-1] = v.copy()
61
+ vn[-1] = -np.sum(v)
62
+ psi_vals = tau_draws @ x.T - vn
63
+ lse_vals = logsumexp(psi_vals / h, axis=1)
64
+ psi_maxs = h * lse_vals
65
+ obj_val = np.mean(psi_maxs)
66
+ probs = np.exp(psi_vals / h - lse_vals.reshape((-1, 1)))
67
+ mean_probs = np.mean(probs, axis=0)
68
+ if ret == 0:
69
+ return obj_val
70
+ elif ret == 1:
71
+ grad = -mean_probs[:-1] + mean_probs[-1]
72
+ return grad
73
+ elif ret == 2:
74
+ ranks = (probs.T @ tau_draws / n_draws) / mean_probs.reshape((-1, 1))
75
+ return ranks
76
+ else:
77
+ bs_error_abort("Invalid value for ret. Must be 0, 1, or 2.")
78
+ return None
79
+
80
+ def objv(v: np.ndarray, args: list) -> float:
81
+ return objv_and_grad(v, ret=0)
82
+
83
+ def grad_objv(v: np.ndarray, args: list) -> np.ndarray:
84
+ return objv_and_grad(v, ret=1)
85
+
86
+ def ranks(v: np.ndarray, args: list) -> np.ndarray:
87
+ return objv_and_grad(v, ret=2)
88
+
89
+ resv = minimize_free(objv, grad_objv, v_init, args=[])
90
+ if not resv.success:
91
+ bs_error_abort(f"Optimization failed, message: {resv.message}")
92
+
93
+ v_sol = resv.x
94
+ r_x = ranks(v_sol, args=[])
95
+ return r_x
26
96
 
27
97
 
28
98
  def _compute_ad(y: np.ndarray) -> TwoArrays:
@@ -54,16 +124,11 @@ def _compute_m_M(
54
124
  Args:
55
125
  v: Dual weights of length ``n``.
56
126
  a_mat: Pairwise slope matrix returned by :func:`_compute_ad`.
57
- dy2: Pairwise differences in the second coordinate.
127
+ dy2: Pairwise differences in the second coordinate (1 on diagonal).
58
128
  tau1_nodes: Quadrature nodes for the first coordinate.
59
129
 
60
130
  Returns:
61
131
  A tuple ``(m, M)`` with arrays of shape ``(n, len(tau1_nodes))``.
62
-
63
- Warning:
64
- The (rare) ``dy2 == 0`` case currently raises warnings in computing ``b_mat``.
65
- That logic works for the present implementation but should be refactored into a cleaner, more explicit
66
- branch.
67
132
  """
68
133
  dv = np.subtract.outer(v, v)
69
134
  b_mat = dv / dy2
@@ -71,17 +136,12 @@ def _compute_m_M(
71
136
  EPS = 1e-12
72
137
  maskp = dy2 < EPS
73
138
  maskm = dy2 > -EPS
74
- n, n_nodes = v.size, tau1_nodes.size
75
- m_low = np.empty((n, n_nodes))
76
- m_high = np.empty((n, n_nodes))
77
- for i, tau1 in enumerate(tau1_nodes):
78
- f_mat = tau1 * a_mat - b_mat
79
- f_matp = f_mat.copy()
80
- f_matm = f_mat.copy()
81
- f_matp[maskp] = 1
82
- f_matm[maskm] = 0
83
- m_low[:, i] = np.max(f_matm, axis=1)
84
- m_high[:, i] = np.min(f_matp, axis=1)
139
+ # Vectorised over all quadrature nodes at once: (n_nodes, n, n)
140
+ f_mats = tau1_nodes[:, None, None] * a_mat[None, :, :] - b_mat[None, :, :]
141
+ f_mats_p = np.where(maskp, 1.0, f_mats)
142
+ f_mats_m = np.where(maskm, 0.0, f_mats)
143
+ m_low = np.max(f_mats_m, axis=2).T # (n, n_nodes)
144
+ m_high = np.min(f_mats_p, axis=2).T
85
145
  return np.clip(m_low, 0.0, 1.0), np.clip(m_high, 0.0, 1.0)
86
146
 
87
147
 
@@ -132,11 +192,6 @@ def _objgrad(
132
192
  tau1_weights = args[4]
133
193
  vs1 = np.append(v, -np.sum(v))
134
194
  m, M = _compute_m_M(vs1, a_mat, dy2, tau1_nodes)
135
- # print(f"m is {m}")
136
- # print(f"M is {M}")
137
- # import sys
138
-
139
- # sys.exit(1)
140
195
 
141
196
  EPS = 1e-12
142
197
  bivrank = np.zeros((n, 2))
@@ -190,7 +245,11 @@ def _grad(v: np.ndarray, args: list):
190
245
  return grad_val
191
246
 
192
247
 
193
- def _solve_for_v(y: np.ndarray, n_nodes: int = 32, verbose: bool = False) -> TwoArrays:
248
+ def _solve_for_v(
249
+ y: np.ndarray,
250
+ n_nodes: int = 32,
251
+ verbose: bool = False,
252
+ ) -> TwoArrays:
194
253
  """Solve the dual optimization problem for the sample.
195
254
 
196
255
  Args:
@@ -221,16 +280,21 @@ def _solve_for_v(y: np.ndarray, n_nodes: int = 32, verbose: bool = False) -> Two
221
280
  argsog = [y, a_mat, dy2, tau1_nodes, tau1_weights, verbose]
222
281
 
223
282
  res = minimize_free(_obj, _grad, v0, args=argsog)
283
+
224
284
  if verbose:
225
285
  print_optimization_results(res, "Minimizing over v")
226
286
 
227
287
  if not res.success:
228
288
  bs_error_abort("Problem! the optimization failed.")
229
- vstar = res.x
289
+
290
+ vstar_free = res.x
291
+
230
292
  if verbose:
231
293
  print(f"The final gradient over v is close to 0: error {npmaxabs(res.jac)}")
232
- _, _, bivranks = cast(tuple, _objgrad(vstar, argsog, gr=True))
233
- vstar = np.append(vstar, -np.sum(vstar))
294
+
295
+ _, _, bivranks = cast(tuple, _objgrad(vstar_free, argsog, gr=True))
296
+
297
+ vstar = np.append(vstar_free, -np.sum(vstar_free))
234
298
  return cast(np.ndarray, vstar), cast(np.ndarray, bivranks)
235
299
 
236
300
 
@@ -255,11 +319,13 @@ def bivariate_ranks(
255
319
  bs_error_abort(f"only works for 2-dimensional y, not for {d}")
256
320
 
257
321
  _, bivranks = _solve_for_v(y, n_nodes, verbose)
258
- return cast(np.ndarray, bivranks)
259
322
 
260
323
 
261
324
  def bivariate_quantiles(
262
- y: np.ndarray, tau: np.ndarray, n_nodes: int = 32, verbose: bool = False
325
+ y: np.ndarray,
326
+ tau: np.ndarray,
327
+ n_nodes: int = 32,
328
+ verbose: bool = False,
263
329
  ) -> np.ndarray:
264
330
  """Solve for the dual weights and evaluate bivariate quantiles.
265
331
 
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bs-python-utils
3
- Version: 1.0.1
3
+ Version: 1.1
4
4
  Summary: Utilities programs for my Python code
5
- Requires-Python: >=3.12
5
+ Requires-Python: >=3.13
6
6
  Description-Content-Type: text/markdown
7
7
  License-File: LICENSE
8
8
  Requires-Dist: altair>=5.5.0
@@ -26,6 +26,7 @@ Requires-Dist: streamlit>=1.49.1
26
26
  Requires-Dist: vega-datasets>=0.9.0
27
27
  Requires-Dist: colorama>=0.4.6
28
28
  Requires-Dist: pyarrow>=23.0.0
29
+ Requires-Dist: scipy-stubs~=1.16.2
29
30
  Dynamic: license-file
30
31
 
31
32
  ## bs-python-utils
@@ -19,3 +19,4 @@ streamlit>=1.49.1
19
19
  vega-datasets>=0.9.0
20
20
  colorama>=0.4.6
21
21
  pyarrow>=23.0.0
22
+ scipy-stubs~=1.16.2
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "bs-python-utils"
3
- version = "1.0.1"
3
+ version = "1.1"
4
4
  description = "Utilities programs for my Python code"
5
5
  readme = "README.md"
6
- requires-python = ">=3.12"
6
+ requires-python = ">=3.13"
7
7
  dependencies = [
8
8
  "altair>=5.5.0",
9
9
  "altair-saver>=0.5.0",
@@ -26,8 +26,13 @@ dependencies = [
26
26
  "vega-datasets>=0.9.0",
27
27
  "colorama>=0.4.6",
28
28
  "pyarrow>=23.0.0",
29
+ "scipy-stubs~=1.16.2",
29
30
  ]
30
31
 
32
+ [build-system]
33
+ requires = ["setuptools>=61"]
34
+ build-backend = "setuptools.build_meta"
35
+
31
36
  [tool.setuptools.packages.find]
32
37
  where = ["."]
33
38
  include = ["bs_python_utils*"]
@@ -4,6 +4,7 @@ from bs_python_utils.numerical.bsnputils import npmaxabs
4
4
  from bs_python_utils.stats.bivariate_quantiles import (
5
5
  _compute_ad,
6
6
  _solve_for_v,
7
+ bivariate_ranks_simul,
7
8
  )
8
9
 
9
10
 
@@ -27,6 +28,25 @@ def test_bivariate_ranks():
27
28
  assert npmaxabs(bivranks - bivranks_th) < 0.1
28
29
 
29
30
 
31
+ def test_bivariate_ranks_simul():
32
+ rng = np.random.default_rng(123)
33
+ n = 500
34
+ y = rng.normal(size=(n, 2))
35
+
36
+ bivranks = bivariate_ranks_simul(y, rng)
37
+
38
+ bivranks_th = np.empty_like(bivranks)
39
+ for k in range(n):
40
+ bivranks_th[k, 0] = np.mean(y[:, 0] < y[k, 0]) + 0.5 * np.mean(
41
+ y[:, 0] == y[k, 0]
42
+ )
43
+ bivranks_th[k, 1] = np.mean(y[:, 1] < y[k, 1]) + 0.5 * np.mean(
44
+ y[:, 1] == y[k, 1]
45
+ )
46
+
47
+ assert npmaxabs(bivranks - bivranks_th) < 0.1
48
+
49
+
30
50
  def test_compute_ad():
31
51
  y = np.array([[0.0, 1.0], [1.0, 1.3], [-1.0, 3.0]])
32
52
  a_mat, dy2 = _compute_ad(y)
File without changes
File without changes
File without changes