bs-python-utils 1.1__tar.gz → 1.1.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 (96) hide show
  1. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/PKG-INFO +8 -1
  2. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/README.md +7 -0
  3. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/__init__.py +2 -1
  4. bs_python_utils-1.1.3/bs_python_utils/bs_derivs.py +1 -0
  5. bs_python_utils-1.1.3/bs_python_utils/core/Timer.py +176 -0
  6. bs_python_utils-1.1.3/bs_python_utils/numerical/bs_derivs.py +49 -0
  7. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/numerical/bsnputils.py +1 -3
  8. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/opt/bs_opt.py +8 -8
  9. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/stats/bivariate_quantiles.py +7 -6
  10. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/stats/bsstats.py +1 -0
  11. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils.egg-info/PKG-INFO +8 -1
  12. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils.egg-info/SOURCES.txt +5 -1
  13. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/pyproject.toml +1 -1
  14. bs_python_utils-1.1.3/tests/test_bs_derivs.py +365 -0
  15. bs_python_utils-1.1.3/tests/test_timer.py +225 -0
  16. bs_python_utils-1.1/bs_python_utils/core/Timer.py +0 -81
  17. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/LICENSE +0 -0
  18. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid1prec13.txt +0 -0
  19. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid1prec17.txt +0 -0
  20. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid1prec9.txt +0 -0
  21. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid2prec13.txt +0 -0
  22. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid2prec17.txt +0 -0
  23. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid2prec9.txt +0 -0
  24. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid3prec13.txt +0 -0
  25. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid3prec17.txt +0 -0
  26. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid3prec9.txt +0 -0
  27. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid4prec13.txt +0 -0
  28. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid4prec17.txt +0 -0
  29. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid4prec9.txt +0 -0
  30. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid5prec13.txt +0 -0
  31. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid5prec17.txt +0 -0
  32. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/GaussHermiteSparseGrids/GHsparseGrid5prec9.txt +0 -0
  33. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/Timer.py +0 -0
  34. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bivariate_quantiles.py +0 -0
  35. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_altair.py +0 -0
  36. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_logging.py +0 -0
  37. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_mathstr.py +0 -0
  38. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_mem.py +0 -0
  39. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_opt.py +0 -0
  40. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_plots.py +0 -0
  41. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_seaborn.py +0 -0
  42. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bs_sparse_gaussian.py +0 -0
  43. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bsmplutils.py +0 -0
  44. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bsnputils.py +0 -0
  45. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bssputils.py +0 -0
  46. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bsstats.py +0 -0
  47. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/bsutils.py +0 -0
  48. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/chebyshev.py +0 -0
  49. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/core/__init__.py +0 -0
  50. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/core/bs_logging.py +0 -0
  51. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/core/bs_mathstr.py +0 -0
  52. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/core/bs_mem.py +0 -0
  53. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/core/bsutils.py +0 -0
  54. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/data_anal/__init__.py +0 -0
  55. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/data_anal/pandas_utils.py +0 -0
  56. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/data_anal/sklearn_utils.py +0 -0
  57. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/distance_covariances.py +0 -0
  58. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_altair.py +0 -0
  59. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_distance_covariances.py +0 -0
  60. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_mem.py +0 -0
  61. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_mpl.py +0 -0
  62. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_opt.py +0 -0
  63. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_seaborn.py +0 -0
  64. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_sklearn.py +0 -0
  65. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/examples/examples_sparse_gaussian.py +0 -0
  66. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/numerical/__init__.py +0 -0
  67. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/numerical/bs_sparse_gaussian.py +0 -0
  68. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/numerical/bssputils.py +0 -0
  69. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/numerical/chebyshev.py +0 -0
  70. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/opt/__init__.py +0 -0
  71. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/pandas_utils.py +0 -0
  72. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/sklearn_utils.py +0 -0
  73. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/stats/__init__.py +0 -0
  74. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/stats/distance_covariances.py +0 -0
  75. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/streamlit_utils.py +0 -0
  76. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/viz/__init__.py +0 -0
  77. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/viz/bs_altair.py +0 -0
  78. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/viz/bs_plots.py +0 -0
  79. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/viz/bs_seaborn.py +0 -0
  80. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/viz/bsmplutils.py +0 -0
  81. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils/viz/streamlit_utils.py +0 -0
  82. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils.egg-info/dependency_links.txt +0 -0
  83. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils.egg-info/requires.txt +0 -0
  84. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/bs_python_utils.egg-info/top_level.txt +0 -0
  85. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/setup.cfg +0 -0
  86. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_bivariate_quantiles.py +0 -0
  87. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_bs_opt.py +0 -0
  88. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_bs_sparse_gaussian.py +0 -0
  89. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_bsnputils.py +0 -0
  90. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_bssputils.py +0 -0
  91. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_bsstats.py +0 -0
  92. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_bsutils.py +0 -0
  93. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_chebyshev.py +0 -0
  94. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_nptri.py +0 -0
  95. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_random_draws.py +0 -0
  96. {bs_python_utils-1.1 → bs_python_utils-1.1.3}/tests/test_sklearn_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bs-python-utils
3
- Version: 1.1
3
+ Version: 1.1.3
4
4
  Summary: Utilities programs for my Python code
5
5
  Requires-Python: >=3.13
6
6
  Description-Content-Type: text/markdown
@@ -50,6 +50,13 @@ Dynamic: license-file
50
50
 
51
51
  ### Release notes
52
52
 
53
+ #### 1.1.2 and 1.1.3(September 11, 2026)
54
+ - Improved the `Timer` class.
55
+ - added `bs_derivs` with Richardson derivatives.
56
+
57
+ #### 1.1.1 (September 04, 2026)
58
+ Added simulation-based bivariate ranks.
59
+
53
60
  #### 1.0.1 (May 9, 2026)
54
61
  Fixed badges.
55
62
 
@@ -19,6 +19,13 @@
19
19
 
20
20
  ### Release notes
21
21
 
22
+ #### 1.1.2 and 1.1.3(September 11, 2026)
23
+ - Improved the `Timer` class.
24
+ - added `bs_derivs` with Richardson derivatives.
25
+
26
+ #### 1.1.1 (September 04, 2026)
27
+ Added simulation-based bivariate ranks.
28
+
22
29
  #### 1.0.1 (May 9, 2026)
23
30
  Fixed badges.
24
31
 
@@ -6,7 +6,8 @@ programming.
6
6
  * `bs_logging` has customized logging
7
7
  * `bs_mathstr` has Unicode for math strings
8
8
  * `bs_mem` reports memory usage
9
- * `Timer` has a `Timer` class to time code execution.
9
+ * `Timer` has a `Timer` context manager to time code execution.
10
+ * `bs_derivs` has Richardson derivatives
10
11
  * `bsnputils` has Numpy functions
11
12
  * `bssputils` has Scipy functions
12
13
  * `sklearn_utils` has Sklearn functions
@@ -0,0 +1 @@
1
+ from bs_python_utils.numerical.bs_derivs import * # noqa: F401, F403
@@ -0,0 +1,176 @@
1
+ """
2
+ Utilities to time code:
3
+
4
+ * a `Timer` class that can be used as a context manager
5
+ * a `timeit` decorator for functions.
6
+ """
7
+
8
+ import time
9
+ from collections.abc import Callable, Iterable
10
+ from dataclasses import dataclass, field
11
+ from functools import wraps
12
+ from typing import Any, ClassVar, Self
13
+
14
+
15
+ def timeit(func: Callable) -> Callable:
16
+ """Decorator to measure and print execution time of a function.
17
+
18
+ Wraps a function to measure its execution time using perf_counter()
19
+ for high precision, and prints the elapsed time to stdout.
20
+
21
+ Args:
22
+ func: The function to be timed.
23
+
24
+ Returns:
25
+ A wrapped function that prints the execution time when called.
26
+
27
+ Example:
28
+ >>> @timeit
29
+ ... def slow_function():
30
+ ... time.sleep(0.1) # doctest: +SKIP
31
+ >>> slow_function() # doctest: +SKIP
32
+ slow_function executed in 0.100 seconds
33
+ """
34
+
35
+ @wraps(func)
36
+ def wrapper(*args: Iterable, **kwargs: dict) -> Any:
37
+ start = time.perf_counter()
38
+ result = func(*args, **kwargs)
39
+ end = time.perf_counter()
40
+ print(f"{func.__name__} executed in {end - start:.3f} seconds")
41
+ return result
42
+
43
+ return wrapper
44
+
45
+
46
+ class TimerError(Exception):
47
+ """A custom exception used to report errors in use of Timer class"""
48
+
49
+
50
+ @dataclass
51
+ class Timer:
52
+ """A flexible timer class for measuring execution time.
53
+
54
+ This class can be used in three ways:
55
+
56
+ 1. **As a context manager**: automatically starts and stops timing
57
+ 2. **With manual calls**: call start() and stop() explicitly
58
+ 3. **As a named timer**: accumulate timing across multiple calls using the `name` attribute
59
+
60
+ Attributes:
61
+ name: Optional name for the timer. If provided, cumulative elapsed time is stored
62
+ in the class-level `timers` dict. Use None for one-off timings.
63
+ text: Format string for displaying elapsed time. Defaults to "Elapsed time: {:0.4f} seconds".
64
+ The string is formatted with a single float representing elapsed seconds.
65
+ logger: Callable to handle output. Defaults to print(). Set to None to suppress output.
66
+ timers: Class-level dictionary storing cumulative times for all named timers.
67
+
68
+ Raises:
69
+ TimerError: If stop() is called without start(), or start() is called on a running timer.
70
+
71
+ Example:
72
+ >>> # As a context manager (recommended for simple use cases)
73
+ >>> with Timer():
74
+ ... time.sleep(0.1) # doctest: +SKIP
75
+ Elapsed time: 0.1000 seconds
76
+
77
+ >>> # With a custom message
78
+ >>> with Timer(text="My code took {:0.2f}s"):
79
+ ... time.sleep(0.05) # doctest: +SKIP
80
+ My code took 0.05s
81
+
82
+ >>> # Suppress output
83
+ >>> with Timer(logger=None):
84
+ ... time.sleep(0.1) # doctest: +SKIP
85
+
86
+ >>> # Suppress output and capture elapsed time
87
+ >>> with Timer(logger=None) as t:
88
+ ... time.sleep(0.1) # doctest: +SKIP
89
+ >>> elapsed = t.stop()
90
+
91
+ >>> # Manual start/stop
92
+ >>> timer = Timer()
93
+ >>> timer.start() # doctest: +SKIP
94
+ >>> time.sleep(0.1) # doctest: +SKIP
95
+ >>> elapsed = timer.stop() # doctest: +SKIP
96
+ Elapsed time: 0.1000 seconds
97
+
98
+ >>> # Named timer for cumulative timing
99
+ >>> Timer(name="db_queries").start() # doctest: +SKIP
100
+ >>> time.sleep(0.05) # doctest: +SKIP
101
+ >>> Timer(name="db_queries").stop() # doctest: +SKIP
102
+ Elapsed time: 0.0500 seconds
103
+ >>> Timer.timers # doctest: +SKIP
104
+ {'db_queries': 0.05}
105
+ """
106
+
107
+ timers: ClassVar = {}
108
+ name: Any = None
109
+ text: Any = "Elapsed time: {:0.4f} seconds"
110
+ logger: Any = print
111
+ _start_time: Any = field(default=None, init=False, repr=False)
112
+
113
+ def __post_init__(self):
114
+ """Initialize the timer and register it if named.
115
+
116
+ For named timers, creates an entry in the class-level `timers` dict
117
+ to accumulate elapsed time across multiple start/stop cycles.
118
+ """
119
+ if self.name is not None:
120
+ self.timers.setdefault(self.name, 0)
121
+
122
+ def start(self):
123
+ """Start the timer.
124
+
125
+ Records the current time using perf_counter() for high precision.
126
+
127
+ Raises:
128
+ TimerError: If the timer is already running.
129
+ """
130
+ if self._start_time is not None:
131
+ raise TimerError("Timer is running. Use .stop() to stop it")
132
+
133
+ self._start_time = time.perf_counter()
134
+
135
+ def stop(self) -> float:
136
+ """Stop the timer and report elapsed time.
137
+
138
+ Calculates elapsed time since start() was called, sends output to the logger
139
+ if configured, and accumulates the time if this is a named timer.
140
+
141
+ Returns:
142
+ Elapsed time in seconds as a float.
143
+
144
+ Raises:
145
+ TimerError: If the timer is not running.
146
+ """
147
+ if self._start_time is None:
148
+ raise TimerError("Timer is not running. Use .start() to start it")
149
+
150
+ # Calculate elapsed time
151
+ elapsed_time: float = time.perf_counter() - self._start_time
152
+ self._start_time = None
153
+
154
+ # Report elapsed time
155
+ if self.logger:
156
+ self.logger(self.text.format(elapsed_time))
157
+ if self.name:
158
+ self.timers[self.name] += elapsed_time
159
+
160
+ return elapsed_time
161
+
162
+ def __enter__(self) -> Self:
163
+ """Enter context manager: start the timer.
164
+
165
+ Returns:
166
+ self: The Timer instance.
167
+ """
168
+ self.start()
169
+ return self
170
+
171
+ def __exit__(self, *exc_info):
172
+ """Exit context manager: stop the timer.
173
+
174
+ Stops the timer regardless of whether an exception occurred in the with block.
175
+ """
176
+ self.stop()
@@ -0,0 +1,49 @@
1
+ from collections.abc import Callable
2
+
3
+
4
+ def richardson_derivative(
5
+ f: Callable[[float, list], float], x: float, args: list, h: float
6
+ ) -> float:
7
+ """Compute the first derivative of $f(x, args)$ at $x$ via Richardson extrapolation.
8
+
9
+ Uses a 5-point central-difference stencil (step `h` and `2h`) that is
10
+ fourth-order accurate.
11
+
12
+ Args:
13
+ f: The function to differentiate, called as `f(x, args)`.
14
+ x: The point at which to differentiate.
15
+ args: Other arguments passed through to `f`.
16
+ h: The step size.
17
+
18
+ Returns:
19
+ An approximation of the first derivative of `f` at `x`.
20
+ """
21
+ f1 = f(x + h, args)
22
+ f2 = f(x - h, args)
23
+ f3 = f(x + 2.0 * h, args)
24
+ f4 = f(x - 2.0 * h, args)
25
+ return (8.0 * (f1 - f2) - (f3 - f4)) / (12.0 * h)
26
+
27
+
28
+ def richardson_second_derivative(
29
+ f: Callable[[float, list], float], x: float, args: list, h: float
30
+ ) -> float:
31
+ """Compute the second derivative of $f(x, args)$ at $x$ via Richardson extrapolation.
32
+
33
+ Applies `richardson_derivative` to the (Richardson-extrapolated) first
34
+ derivative of `f`.
35
+
36
+ Args:
37
+ f: The function to differentiate, called as `f(x, args)`.
38
+ x: The point at which to differentiate.
39
+ args: Other arguments passed through to `f`.
40
+ h: The step size.
41
+
42
+ Returns:
43
+ An approximation of the second derivative of `f` at `x`.
44
+ """
45
+
46
+ def fprime(y, a):
47
+ return richardson_derivative(f, y, a, h)
48
+
49
+ return richardson_derivative(fprime, x, args, h)
@@ -300,9 +300,7 @@ def npmaxabs(arr: np.ndarray) -> float:
300
300
  return cast(float, np.max(np.abs(arr)))
301
301
 
302
302
 
303
- def rice_stderr(
304
- y: np.ndarray, x: np.ndarray, is_sorted: bool = False
305
- ) -> np.ndarray | float:
303
+ def rice_stderr(y: np.ndarray, x: np.ndarray, is_sorted: bool = False) -> np.ndarray:
306
304
  """
307
305
  computes the Rice local estimators of the standard error of y | x
308
306
 
@@ -420,8 +420,8 @@ def minimize_some_fixed(
420
420
  obj,
421
421
  x_init,
422
422
  method="L-BFGS-B",
423
- args=args,
424
- options=options,
423
+ args=(args,),
424
+ options=cast(Any, options),
425
425
  jac=grad_obj,
426
426
  bounds=bounds,
427
427
  )
@@ -453,8 +453,8 @@ def minimize_some_fixed(
453
453
  fixed_obj,
454
454
  t_init,
455
455
  method="L-BFGS-B",
456
- args=args,
457
- options=options,
456
+ args=(args,),
457
+ options=cast(Any, options),
458
458
  jac=fixed_grad_obj,
459
459
  bounds=t_bounds,
460
460
  )
@@ -508,8 +508,8 @@ def minimize_free(
508
508
  obj,
509
509
  x_init,
510
510
  method="BFGS",
511
- args=args,
512
- options=options,
511
+ args=(args,),
512
+ options=cast(Any, options),
513
513
  jac=grad_obj,
514
514
  )
515
515
  else:
@@ -517,8 +517,8 @@ def minimize_free(
517
517
  obj,
518
518
  x_init,
519
519
  method="L-BFGS-B",
520
- args=args,
521
- options=options,
520
+ args=(args,),
521
+ options=cast(Any, options),
522
522
  jac=grad_obj,
523
523
  bounds=bounds,
524
524
  )
@@ -66,25 +66,25 @@ def bivariate_ranks_simul(
66
66
  probs = np.exp(psi_vals / h - lse_vals.reshape((-1, 1)))
67
67
  mean_probs = np.mean(probs, axis=0)
68
68
  if ret == 0:
69
- return obj_val
69
+ return cast(float, obj_val)
70
70
  elif ret == 1:
71
71
  grad = -mean_probs[:-1] + mean_probs[-1]
72
- return grad
72
+ return cast(np.ndarray, grad)
73
73
  elif ret == 2:
74
74
  ranks = (probs.T @ tau_draws / n_draws) / mean_probs.reshape((-1, 1))
75
- return ranks
75
+ return cast(np.ndarray, ranks)
76
76
  else:
77
77
  bs_error_abort("Invalid value for ret. Must be 0, 1, or 2.")
78
78
  return None
79
79
 
80
80
  def objv(v: np.ndarray, args: list) -> float:
81
- return objv_and_grad(v, ret=0)
81
+ return cast(float, objv_and_grad(v, ret=0))
82
82
 
83
83
  def grad_objv(v: np.ndarray, args: list) -> np.ndarray:
84
- return objv_and_grad(v, ret=1)
84
+ return cast(np.ndarray, objv_and_grad(v, ret=1))
85
85
 
86
86
  def ranks(v: np.ndarray, args: list) -> np.ndarray:
87
- return objv_and_grad(v, ret=2)
87
+ return cast(np.ndarray, objv_and_grad(v, ret=2))
88
88
 
89
89
  resv = minimize_free(objv, grad_objv, v_init, args=[])
90
90
  if not resv.success:
@@ -319,6 +319,7 @@ def bivariate_ranks(
319
319
  bs_error_abort(f"only works for 2-dimensional y, not for {d}")
320
320
 
321
321
  _, bivranks = _solve_for_v(y, n_nodes, verbose)
322
+ return bivranks
322
323
 
323
324
 
324
325
  def bivariate_quantiles(
@@ -342,6 +342,7 @@ def bs_multivariate_normal_pdf(
342
342
  bs_error_abort(
343
343
  f"cov_mat should be a matrix ({nvars}, {nvars}) not ({nrows}, {ncols})"
344
344
  )
345
+ cov_mat = cast(np.ndarray, cov_mat)
345
346
  resid = values_x - means_x
346
347
  argresid = spla.solve(cov_mat, resid.T)
347
348
  argexp = np.zeros(n)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bs-python-utils
3
- Version: 1.1
3
+ Version: 1.1.3
4
4
  Summary: Utilities programs for my Python code
5
5
  Requires-Python: >=3.13
6
6
  Description-Content-Type: text/markdown
@@ -50,6 +50,13 @@ Dynamic: license-file
50
50
 
51
51
  ### Release notes
52
52
 
53
+ #### 1.1.2 and 1.1.3(September 11, 2026)
54
+ - Improved the `Timer` class.
55
+ - added `bs_derivs` with Richardson derivatives.
56
+
57
+ #### 1.1.1 (September 04, 2026)
58
+ Added simulation-based bivariate ranks.
59
+
53
60
  #### 1.0.1 (May 9, 2026)
54
61
  Fixed badges.
55
62
 
@@ -5,6 +5,7 @@ bs_python_utils/Timer.py
5
5
  bs_python_utils/__init__.py
6
6
  bs_python_utils/bivariate_quantiles.py
7
7
  bs_python_utils/bs_altair.py
8
+ bs_python_utils/bs_derivs.py
8
9
  bs_python_utils/bs_logging.py
9
10
  bs_python_utils/bs_mathstr.py
10
11
  bs_python_utils/bs_mem.py
@@ -60,6 +61,7 @@ bs_python_utils/examples/examples_seaborn.py
60
61
  bs_python_utils/examples/examples_sklearn.py
61
62
  bs_python_utils/examples/examples_sparse_gaussian.py
62
63
  bs_python_utils/numerical/__init__.py
64
+ bs_python_utils/numerical/bs_derivs.py
63
65
  bs_python_utils/numerical/bs_sparse_gaussian.py
64
66
  bs_python_utils/numerical/bsnputils.py
65
67
  bs_python_utils/numerical/bssputils.py
@@ -77,6 +79,7 @@ bs_python_utils/viz/bs_seaborn.py
77
79
  bs_python_utils/viz/bsmplutils.py
78
80
  bs_python_utils/viz/streamlit_utils.py
79
81
  tests/test_bivariate_quantiles.py
82
+ tests/test_bs_derivs.py
80
83
  tests/test_bs_opt.py
81
84
  tests/test_bs_sparse_gaussian.py
82
85
  tests/test_bsnputils.py
@@ -86,4 +89,5 @@ tests/test_bsutils.py
86
89
  tests/test_chebyshev.py
87
90
  tests/test_nptri.py
88
91
  tests/test_random_draws.py
89
- tests/test_sklearn_utils.py
92
+ tests/test_sklearn_utils.py
93
+ tests/test_timer.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bs-python-utils"
3
- version = "1.1"
3
+ version = "1.1.3"
4
4
  description = "Utilities programs for my Python code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"