pymodab 1.1.2__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.
- {pymodab-1.1.2/src/pymodab.egg-info → pymodab-1.1.3}/PKG-INFO +15 -13
- {pymodab-1.1.2 → pymodab-1.1.3}/README.md +14 -12
- {pymodab-1.1.2 → pymodab-1.1.3}/pyproject.toml +1 -1
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab/ModAB.dll +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab/__init__.py +1 -1
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab/_modab.c +6 -14
- pymodab-1.1.3/src/pymodab/libModAB.so +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab/libModAB_arm64.dylib +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab/libModAB_x64.dylib +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3/src/pymodab.egg-info}/PKG-INFO +15 -13
- pymodab-1.1.2/src/pymodab/libModAB.so +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/LICENSE +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/MANIFEST.in +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/setup.cfg +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/setup.py +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab/ModAB.lib +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab/modab.py +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab.egg-info/SOURCES.txt +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab.egg-info/dependency_links.txt +0 -0
- {pymodab-1.1.2 → pymodab-1.1.3}/src/pymodab.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymodab
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.3
|
|
4
4
|
Summary: Fast and robust root-finding library using the Modified Anderson-Bjork method
|
|
5
5
|
Author: Ganchovski, N.; Smith, O.; Rackauckas, C.; Tomov, L.; Traykov, A.
|
|
6
6
|
License-Expression: MIT
|
|
@@ -90,6 +90,8 @@ Version 1.1.1 separates the bisection and Anderson-Björck steps in the solver l
|
|
|
90
90
|
|
|
91
91
|
Version 1.1.2 streamlines the solver loop. The bracket width and the difference of the true residuals are computed once per step and reused. The exits on a zero and on a `NaN` residual share a single test on the hot path. The best true residual of the bracket, which the fallback test needs, is now computed only when a secant step fails to shrink the bracket fast enough, instead of on every secant step, and the test is written as `2·|y3| >= ymin` instead of `|y3| >= 0.5·ymin`. The 101 benchmark problems give the same roots and evaluation counts as with 1.1.1.
|
|
92
92
|
|
|
93
|
+
Version 1.1.3 replaces the capped residual exception of 1.1.1 with a stricter test and removes the `MAX_RESIDUAL_STEPS` counter. A secant step that does not shrink the bracket fast enough is now kept only if it reduces the residual more than 42 times, that is `42·|y3| < ymin`, where `ymin` is the smaller true residual of the bracket. The factor comes from 2^(1074/200) ≈ 41.4: at this rate a residual that starts near 1 underflows to zero within the default limit of 200 iterations, because the smallest positive double is 2^-1074. A search that stays on secant steps this way therefore ends by itself, without a counter. The factor is a fixed constant and does not follow `max_iter`, so raising the limit does not weaken the test. On the benchmark, problem f101 now needs 65 evaluations instead of 76, and the other 100 problems give the same roots and evaluation counts as with 1.1.2; all 101 need 1960 evaluations in total instead of 1971.
|
|
94
|
+
|
|
93
95
|
For maximum speed, pass a compiled function, e.g. from [numba](https://numba.pydata.org/). It is then called from C with no Python overhead:
|
|
94
96
|
|
|
95
97
|
```python
|
|
@@ -142,27 +144,27 @@ The modAB algorithm is benchmarked against the available algorithms in Python/Sc
|
|
|
142
144
|
|
|
143
145
|
Func| bisect| brentq| brenth| ridder| chandr| cybrentq| modAB_ct| <mark>**modAB_SG**</mark>|
|
|
144
146
|
----- | ------: | ------: | ------: | ------: | ------: | ------: | ------: | ------: |
|
|
145
|
-
SUM| 4883| 2810| 2769| 3425| 2112| 2810| 1993| <mark>**
|
|
146
|
-
AVG| 48| 28| 27| 34| 21| 28| 20| <mark>**
|
|
147
|
+
SUM| 4883| 2810| 2769| 3425| 2112| 2810| 1993| <mark>**1960**</mark>|
|
|
148
|
+
AVG| 48| 28| 27| 34| 21| 28| 20| <mark>**19**</mark>|
|
|
147
149
|
MEDIAN| 49| 13| 12| 16| 12| 13| 13| <mark>**13**</mark>|
|
|
148
150
|
MIN| 3| 4| 4| 3| 3| 4| 3| <mark>**3**</mark>|
|
|
149
|
-
MAX| 53| 102| 102| 202| 70| 102| 78| <mark>**
|
|
150
|
-
FACTOR| 2.
|
|
151
|
+
MAX| 53| 102| 102| 202| 70| 102| 78| <mark>**65**</mark>|
|
|
152
|
+
FACTOR| 2.491x| 1.434x| 1.413x| 1.747x| 1.078x| 1.434x| 1.017x| <mark>**1.000x**</mark>|
|
|
151
153
|
|
|
152
154
|
#### Execution times (ms per problem, 200 iterations)
|
|
153
155
|
|
|
154
156
|
Func| bisect| brentq| brenth| ridder| chandr| cybrentq| modAB_ct| <mark>**modAB_SG**</mark>|
|
|
155
157
|
----- | ------: | ------: | ------: | ------: | ------: | ------: | ------: | ------: |
|
|
156
|
-
SUM|
|
|
157
|
-
AVG|
|
|
158
|
-
MEDIAN| 14.
|
|
159
|
-
MIN| 1.
|
|
160
|
-
MAX|
|
|
161
|
-
FACTOR| 16.
|
|
158
|
+
SUM| 1535.42| 931.31| 878.87| 1047.95| 58524.74| 115.55| 175.60| <mark>**91.23**</mark>|
|
|
159
|
+
AVG| 15.2021| 9.2209| 8.7017| 10.3758| 579.4528| 1.1440| 1.7386| <mark>**0.9033**</mark>|
|
|
160
|
+
MEDIAN| 14.7569| 5.1910| 4.9383| 6.4764| 345.7968| 0.5879| 1.3410| <mark>**0.6511**</mark>|
|
|
161
|
+
MIN| 1.7242| 1.8918| 1.8852| 2.0780| 73.8264| 0.2071| 0.5655| <mark>**0.1677**</mark>|
|
|
162
|
+
MAX| 70.1038| 32.1594| 41.2759| 53.5572|1979.9811| 6.4304| 5.1045| <mark>**3.8393**</mark>|
|
|
163
|
+
FACTOR| 16.829x| 10.208x| 9.633x| 11.486x| 641.480x| 1.266x| 1.925x| <mark>**1.000x**</mark>|
|
|
162
164
|
|
|
163
165
|
#### Notes:
|
|
164
166
|
|
|
165
|
-
Last Run on:
|
|
167
|
+
Last Run on: 01.11.2026
|
|
166
168
|
Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz (1.50 GHz) with 16.0 GB RAM
|
|
167
169
|
Windows 11 Home
|
|
168
170
|
Python Version: 3.14.7
|
|
@@ -170,4 +172,4 @@ numpy Version: 2.4.6
|
|
|
170
172
|
scipy Version: 1.18.0
|
|
171
173
|
cybrentq Version: 0.1.5 - by Gledis Caushaj (https://github.com/gledi-ai/cybrentq)
|
|
172
174
|
modAB_ct: pymodab version 1.0.5 from PyPI - the previous implementation with ctypes
|
|
173
|
-
modAB_SG: pymodab version 1.1.
|
|
175
|
+
modAB_SG: pymodab version 1.1.3 - the latest implementation of the safeguarded modab as native C extension
|
|
@@ -60,6 +60,8 @@ Version 1.1.1 separates the bisection and Anderson-Björck steps in the solver l
|
|
|
60
60
|
|
|
61
61
|
Version 1.1.2 streamlines the solver loop. The bracket width and the difference of the true residuals are computed once per step and reused. The exits on a zero and on a `NaN` residual share a single test on the hot path. The best true residual of the bracket, which the fallback test needs, is now computed only when a secant step fails to shrink the bracket fast enough, instead of on every secant step, and the test is written as `2·|y3| >= ymin` instead of `|y3| >= 0.5·ymin`. The 101 benchmark problems give the same roots and evaluation counts as with 1.1.1.
|
|
62
62
|
|
|
63
|
+
Version 1.1.3 replaces the capped residual exception of 1.1.1 with a stricter test and removes the `MAX_RESIDUAL_STEPS` counter. A secant step that does not shrink the bracket fast enough is now kept only if it reduces the residual more than 42 times, that is `42·|y3| < ymin`, where `ymin` is the smaller true residual of the bracket. The factor comes from 2^(1074/200) ≈ 41.4: at this rate a residual that starts near 1 underflows to zero within the default limit of 200 iterations, because the smallest positive double is 2^-1074. A search that stays on secant steps this way therefore ends by itself, without a counter. The factor is a fixed constant and does not follow `max_iter`, so raising the limit does not weaken the test. On the benchmark, problem f101 now needs 65 evaluations instead of 76, and the other 100 problems give the same roots and evaluation counts as with 1.1.2; all 101 need 1960 evaluations in total instead of 1971.
|
|
64
|
+
|
|
63
65
|
For maximum speed, pass a compiled function, e.g. from [numba](https://numba.pydata.org/). It is then called from C with no Python overhead:
|
|
64
66
|
|
|
65
67
|
```python
|
|
@@ -112,27 +114,27 @@ The modAB algorithm is benchmarked against the available algorithms in Python/Sc
|
|
|
112
114
|
|
|
113
115
|
Func| bisect| brentq| brenth| ridder| chandr| cybrentq| modAB_ct| <mark>**modAB_SG**</mark>|
|
|
114
116
|
----- | ------: | ------: | ------: | ------: | ------: | ------: | ------: | ------: |
|
|
115
|
-
SUM| 4883| 2810| 2769| 3425| 2112| 2810| 1993| <mark>**
|
|
116
|
-
AVG| 48| 28| 27| 34| 21| 28| 20| <mark>**
|
|
117
|
+
SUM| 4883| 2810| 2769| 3425| 2112| 2810| 1993| <mark>**1960**</mark>|
|
|
118
|
+
AVG| 48| 28| 27| 34| 21| 28| 20| <mark>**19**</mark>|
|
|
117
119
|
MEDIAN| 49| 13| 12| 16| 12| 13| 13| <mark>**13**</mark>|
|
|
118
120
|
MIN| 3| 4| 4| 3| 3| 4| 3| <mark>**3**</mark>|
|
|
119
|
-
MAX| 53| 102| 102| 202| 70| 102| 78| <mark>**
|
|
120
|
-
FACTOR| 2.
|
|
121
|
+
MAX| 53| 102| 102| 202| 70| 102| 78| <mark>**65**</mark>|
|
|
122
|
+
FACTOR| 2.491x| 1.434x| 1.413x| 1.747x| 1.078x| 1.434x| 1.017x| <mark>**1.000x**</mark>|
|
|
121
123
|
|
|
122
124
|
#### Execution times (ms per problem, 200 iterations)
|
|
123
125
|
|
|
124
126
|
Func| bisect| brentq| brenth| ridder| chandr| cybrentq| modAB_ct| <mark>**modAB_SG**</mark>|
|
|
125
127
|
----- | ------: | ------: | ------: | ------: | ------: | ------: | ------: | ------: |
|
|
126
|
-
SUM|
|
|
127
|
-
AVG|
|
|
128
|
-
MEDIAN| 14.
|
|
129
|
-
MIN| 1.
|
|
130
|
-
MAX|
|
|
131
|
-
FACTOR| 16.
|
|
128
|
+
SUM| 1535.42| 931.31| 878.87| 1047.95| 58524.74| 115.55| 175.60| <mark>**91.23**</mark>|
|
|
129
|
+
AVG| 15.2021| 9.2209| 8.7017| 10.3758| 579.4528| 1.1440| 1.7386| <mark>**0.9033**</mark>|
|
|
130
|
+
MEDIAN| 14.7569| 5.1910| 4.9383| 6.4764| 345.7968| 0.5879| 1.3410| <mark>**0.6511**</mark>|
|
|
131
|
+
MIN| 1.7242| 1.8918| 1.8852| 2.0780| 73.8264| 0.2071| 0.5655| <mark>**0.1677**</mark>|
|
|
132
|
+
MAX| 70.1038| 32.1594| 41.2759| 53.5572|1979.9811| 6.4304| 5.1045| <mark>**3.8393**</mark>|
|
|
133
|
+
FACTOR| 16.829x| 10.208x| 9.633x| 11.486x| 641.480x| 1.266x| 1.925x| <mark>**1.000x**</mark>|
|
|
132
134
|
|
|
133
135
|
#### Notes:
|
|
134
136
|
|
|
135
|
-
Last Run on:
|
|
137
|
+
Last Run on: 01.11.2026
|
|
136
138
|
Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz (1.50 GHz) with 16.0 GB RAM
|
|
137
139
|
Windows 11 Home
|
|
138
140
|
Python Version: 3.14.7
|
|
@@ -140,4 +142,4 @@ numpy Version: 2.4.6
|
|
|
140
142
|
scipy Version: 1.18.0
|
|
141
143
|
cybrentq Version: 0.1.5 - by Gledis Caushaj (https://github.com/gledi-ai/cybrentq)
|
|
142
144
|
modAB_ct: pymodab version 1.0.5 from PyPI - the previous implementation with ctypes
|
|
143
|
-
modAB_SG: pymodab version 1.1.
|
|
145
|
+
modAB_SG: pymodab version 1.1.3 - the latest implementation of the safeguarded modab as native C extension
|
|
Binary file
|
|
@@ -148,8 +148,6 @@ static double modab_core(eval_fn f, void *ctx, double x1, double x2,
|
|
|
148
148
|
double threshold = x2 - x1;
|
|
149
149
|
double f1 = y1, f2 = y2; /* True residuals, kept unmodified by A&B corrections */
|
|
150
150
|
const double C = 2.0;
|
|
151
|
-
const int MAX_RESIDUAL_STEPS = 3; /* Max consecutive A&B steps kept by the residual test alone */
|
|
152
|
-
int residual_steps = 0;
|
|
153
151
|
for (int i = 1; i <= maxIter; ++i) {
|
|
154
152
|
double x3 = bisection ? safe_midpoint(x1, x2) : safe_secant(x1, y1, x2, y2);
|
|
155
153
|
double dx = x2 - x1; /* Bracket width */
|
|
@@ -169,7 +167,6 @@ static double modab_core(eval_fn f, void *ctx, double x1, double x2,
|
|
|
169
167
|
if (fabs(ym - y3) < k * fabs(ym) + k * fabs(y3)) {
|
|
170
168
|
bisection = 0;
|
|
171
169
|
threshold = C * dx;
|
|
172
|
-
residual_steps = 0;
|
|
173
170
|
y1 = f1; y2 = f2; /* A&B starts from the true residuals */
|
|
174
171
|
}
|
|
175
172
|
}
|
|
@@ -213,17 +210,12 @@ static double modab_core(eval_fn f, void *ctx, double x1, double x2,
|
|
|
213
210
|
side = -1;
|
|
214
211
|
x2 = x3; f2 = y2 = y3;
|
|
215
212
|
}
|
|
216
|
-
/* Fallback if AB fails to reduce the bracket width, unless it still
|
|
217
|
-
|
|
218
|
-
if (x2 - x1 > threshold) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
side = 0;
|
|
223
|
-
} else
|
|
224
|
-
++residual_steps;
|
|
225
|
-
} else
|
|
226
|
-
residual_steps = 0;
|
|
213
|
+
/* Fallback if AB fails to reduce the bracket width, unless it still shrinks the residual more than 42 times
|
|
214
|
+
(2^(1074/200) = 41.4: at this rate the residual underflows within 200 steps from |y| = 1) */
|
|
215
|
+
if (x2 - x1 > threshold && 42.0 * fabs(y3) >= fmin(fabs(yl), fabs(yr))) {
|
|
216
|
+
bisection = 1;
|
|
217
|
+
side = 0;
|
|
218
|
+
}
|
|
227
219
|
}
|
|
228
220
|
}
|
|
229
221
|
return NAN;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymodab
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.3
|
|
4
4
|
Summary: Fast and robust root-finding library using the Modified Anderson-Bjork method
|
|
5
5
|
Author: Ganchovski, N.; Smith, O.; Rackauckas, C.; Tomov, L.; Traykov, A.
|
|
6
6
|
License-Expression: MIT
|
|
@@ -90,6 +90,8 @@ Version 1.1.1 separates the bisection and Anderson-Björck steps in the solver l
|
|
|
90
90
|
|
|
91
91
|
Version 1.1.2 streamlines the solver loop. The bracket width and the difference of the true residuals are computed once per step and reused. The exits on a zero and on a `NaN` residual share a single test on the hot path. The best true residual of the bracket, which the fallback test needs, is now computed only when a secant step fails to shrink the bracket fast enough, instead of on every secant step, and the test is written as `2·|y3| >= ymin` instead of `|y3| >= 0.5·ymin`. The 101 benchmark problems give the same roots and evaluation counts as with 1.1.1.
|
|
92
92
|
|
|
93
|
+
Version 1.1.3 replaces the capped residual exception of 1.1.1 with a stricter test and removes the `MAX_RESIDUAL_STEPS` counter. A secant step that does not shrink the bracket fast enough is now kept only if it reduces the residual more than 42 times, that is `42·|y3| < ymin`, where `ymin` is the smaller true residual of the bracket. The factor comes from 2^(1074/200) ≈ 41.4: at this rate a residual that starts near 1 underflows to zero within the default limit of 200 iterations, because the smallest positive double is 2^-1074. A search that stays on secant steps this way therefore ends by itself, without a counter. The factor is a fixed constant and does not follow `max_iter`, so raising the limit does not weaken the test. On the benchmark, problem f101 now needs 65 evaluations instead of 76, and the other 100 problems give the same roots and evaluation counts as with 1.1.2; all 101 need 1960 evaluations in total instead of 1971.
|
|
94
|
+
|
|
93
95
|
For maximum speed, pass a compiled function, e.g. from [numba](https://numba.pydata.org/). It is then called from C with no Python overhead:
|
|
94
96
|
|
|
95
97
|
```python
|
|
@@ -142,27 +144,27 @@ The modAB algorithm is benchmarked against the available algorithms in Python/Sc
|
|
|
142
144
|
|
|
143
145
|
Func| bisect| brentq| brenth| ridder| chandr| cybrentq| modAB_ct| <mark>**modAB_SG**</mark>|
|
|
144
146
|
----- | ------: | ------: | ------: | ------: | ------: | ------: | ------: | ------: |
|
|
145
|
-
SUM| 4883| 2810| 2769| 3425| 2112| 2810| 1993| <mark>**
|
|
146
|
-
AVG| 48| 28| 27| 34| 21| 28| 20| <mark>**
|
|
147
|
+
SUM| 4883| 2810| 2769| 3425| 2112| 2810| 1993| <mark>**1960**</mark>|
|
|
148
|
+
AVG| 48| 28| 27| 34| 21| 28| 20| <mark>**19**</mark>|
|
|
147
149
|
MEDIAN| 49| 13| 12| 16| 12| 13| 13| <mark>**13**</mark>|
|
|
148
150
|
MIN| 3| 4| 4| 3| 3| 4| 3| <mark>**3**</mark>|
|
|
149
|
-
MAX| 53| 102| 102| 202| 70| 102| 78| <mark>**
|
|
150
|
-
FACTOR| 2.
|
|
151
|
+
MAX| 53| 102| 102| 202| 70| 102| 78| <mark>**65**</mark>|
|
|
152
|
+
FACTOR| 2.491x| 1.434x| 1.413x| 1.747x| 1.078x| 1.434x| 1.017x| <mark>**1.000x**</mark>|
|
|
151
153
|
|
|
152
154
|
#### Execution times (ms per problem, 200 iterations)
|
|
153
155
|
|
|
154
156
|
Func| bisect| brentq| brenth| ridder| chandr| cybrentq| modAB_ct| <mark>**modAB_SG**</mark>|
|
|
155
157
|
----- | ------: | ------: | ------: | ------: | ------: | ------: | ------: | ------: |
|
|
156
|
-
SUM|
|
|
157
|
-
AVG|
|
|
158
|
-
MEDIAN| 14.
|
|
159
|
-
MIN| 1.
|
|
160
|
-
MAX|
|
|
161
|
-
FACTOR| 16.
|
|
158
|
+
SUM| 1535.42| 931.31| 878.87| 1047.95| 58524.74| 115.55| 175.60| <mark>**91.23**</mark>|
|
|
159
|
+
AVG| 15.2021| 9.2209| 8.7017| 10.3758| 579.4528| 1.1440| 1.7386| <mark>**0.9033**</mark>|
|
|
160
|
+
MEDIAN| 14.7569| 5.1910| 4.9383| 6.4764| 345.7968| 0.5879| 1.3410| <mark>**0.6511**</mark>|
|
|
161
|
+
MIN| 1.7242| 1.8918| 1.8852| 2.0780| 73.8264| 0.2071| 0.5655| <mark>**0.1677**</mark>|
|
|
162
|
+
MAX| 70.1038| 32.1594| 41.2759| 53.5572|1979.9811| 6.4304| 5.1045| <mark>**3.8393**</mark>|
|
|
163
|
+
FACTOR| 16.829x| 10.208x| 9.633x| 11.486x| 641.480x| 1.266x| 1.925x| <mark>**1.000x**</mark>|
|
|
162
164
|
|
|
163
165
|
#### Notes:
|
|
164
166
|
|
|
165
|
-
Last Run on:
|
|
167
|
+
Last Run on: 01.11.2026
|
|
166
168
|
Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz (1.50 GHz) with 16.0 GB RAM
|
|
167
169
|
Windows 11 Home
|
|
168
170
|
Python Version: 3.14.7
|
|
@@ -170,4 +172,4 @@ numpy Version: 2.4.6
|
|
|
170
172
|
scipy Version: 1.18.0
|
|
171
173
|
cybrentq Version: 0.1.5 - by Gledis Caushaj (https://github.com/gledi-ai/cybrentq)
|
|
172
174
|
modAB_ct: pymodab version 1.0.5 from PyPI - the previous implementation with ctypes
|
|
173
|
-
modAB_SG: pymodab version 1.1.
|
|
175
|
+
modAB_SG: pymodab version 1.1.3 - the latest implementation of the safeguarded modab as native C extension
|
|
Binary file
|
|
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
|