polysolve 0.4.0__tar.gz → 0.4.2__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.
- {polysolve-0.4.0/src/polysolve.egg-info → polysolve-0.4.2}/PKG-INFO +1 -1
- {polysolve-0.4.0 → polysolve-0.4.2}/pyproject.toml +1 -1
- {polysolve-0.4.0 → polysolve-0.4.2}/src/polysolve/__init__.py +55 -6
- {polysolve-0.4.0 → polysolve-0.4.2/src/polysolve.egg-info}/PKG-INFO +1 -1
- {polysolve-0.4.0 → polysolve-0.4.2}/LICENSE +0 -0
- {polysolve-0.4.0 → polysolve-0.4.2}/README.md +0 -0
- {polysolve-0.4.0 → polysolve-0.4.2}/setup.cfg +0 -0
- {polysolve-0.4.0 → polysolve-0.4.2}/src/polysolve.egg-info/SOURCES.txt +0 -0
- {polysolve-0.4.0 → polysolve-0.4.2}/src/polysolve.egg-info/dependency_links.txt +0 -0
- {polysolve-0.4.0 → polysolve-0.4.2}/src/polysolve.egg-info/requires.txt +0 -0
- {polysolve-0.4.0 → polysolve-0.4.2}/src/polysolve.egg-info/top_level.txt +0 -0
- {polysolve-0.4.0 → polysolve-0.4.2}/tests/test_polysolve.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polysolve
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python library for representing, manipulating, and solving exponential functions using analytical methods and genetic algorithms, with optional CUDA acceleration.
|
|
5
5
|
Author-email: Jonathan Rampersad <jonathan@jono-rams.work>
|
|
6
6
|
License: MIT License
|
|
@@ -90,6 +90,23 @@ class GA_Options:
|
|
|
90
90
|
"The number of returned solutions will be limited to data_size."
|
|
91
91
|
)
|
|
92
92
|
|
|
93
|
+
def _get_cauchy_bound(coeffs: np.ndarray) -> float:
|
|
94
|
+
"""
|
|
95
|
+
Calculates Cauchy's bound for the roots of a polynomial.
|
|
96
|
+
This provides a radius R such that all roots (real and complex)
|
|
97
|
+
have an absolute value less than or equal to R.
|
|
98
|
+
|
|
99
|
+
R = 1 + max(|c_n-1/c_n|, |c_n-2/c_n|, ..., |c_0/c_n|)
|
|
100
|
+
Where c_n is the leading coefficient (coeffs[0]).
|
|
101
|
+
"""
|
|
102
|
+
# Normalize all coefficients by the leading coefficient
|
|
103
|
+
normalized_coeffs = np.abs(coeffs[1:] / coeffs[0])
|
|
104
|
+
|
|
105
|
+
# The bound is 1 + the maximum of these normalized values
|
|
106
|
+
R = 1 + np.max(normalized_coeffs)
|
|
107
|
+
|
|
108
|
+
return R
|
|
109
|
+
|
|
93
110
|
class Function:
|
|
94
111
|
"""
|
|
95
112
|
Represents an exponential function (polynomial) of the form:
|
|
@@ -287,15 +304,31 @@ class Function:
|
|
|
287
304
|
mutation_size = int(data_size * mutation_ratio)
|
|
288
305
|
random_size = data_size - elite_size - crossover_size - mutation_size
|
|
289
306
|
|
|
307
|
+
# Check if the user is using the default, non-expert range
|
|
308
|
+
user_range_is_default = (options.min_range == -100.0 and options.max_range == 100.0)
|
|
309
|
+
|
|
310
|
+
if user_range_is_default:
|
|
311
|
+
# User hasn't specified a custom range.
|
|
312
|
+
# We are the expert; use the smart, guaranteed bound.
|
|
313
|
+
bound = _get_cauchy_bound(self.coefficients)
|
|
314
|
+
min_r = -bound
|
|
315
|
+
max_r = bound
|
|
316
|
+
else:
|
|
317
|
+
# User has provided a custom range.
|
|
318
|
+
# Trust the expert; use their range.
|
|
319
|
+
min_r = options.min_range
|
|
320
|
+
max_r = options.max_range
|
|
321
|
+
|
|
290
322
|
# Create initial random solutions
|
|
291
|
-
solutions = np.random.uniform(
|
|
323
|
+
solutions = np.random.uniform(min_r, max_r, data_size)
|
|
292
324
|
|
|
293
325
|
for _ in range(options.num_of_generations):
|
|
294
326
|
# Calculate fitness for all solutions (vectorized)
|
|
295
327
|
y_calculated = np.polyval(self.coefficients, solutions)
|
|
296
328
|
error = y_calculated - y_val
|
|
297
329
|
|
|
298
|
-
|
|
330
|
+
with np.errstate(divide='ignore'):
|
|
331
|
+
ranks = np.where(error == 0, np.finfo(float).max, np.abs(1.0 / error))
|
|
299
332
|
|
|
300
333
|
# Sort solutions by fitness (descending)
|
|
301
334
|
sorted_indices = np.argsort(-ranks)
|
|
@@ -331,7 +364,7 @@ class Function:
|
|
|
331
364
|
mutated_solutions = mutation_candidates * mutation_factors
|
|
332
365
|
|
|
333
366
|
# 4. New Randoms: Add new blood to prevent getting stuck
|
|
334
|
-
random_solutions = np.random.uniform(
|
|
367
|
+
random_solutions = np.random.uniform(min_r, max_r, random_size)
|
|
335
368
|
|
|
336
369
|
# Assemble the new generation
|
|
337
370
|
solutions = np.concatenate([
|
|
@@ -345,7 +378,8 @@ class Function:
|
|
|
345
378
|
# After all generations, do one last ranking to find the best solutions
|
|
346
379
|
y_calculated = np.polyval(self.coefficients, solutions)
|
|
347
380
|
error = y_calculated - y_val
|
|
348
|
-
|
|
381
|
+
with np.errstate(divide='ignore'):
|
|
382
|
+
ranks = np.where(error == 0, np.finfo(float).max, np.abs(1.0 / error))
|
|
349
383
|
sorted_indices = np.argsort(-ranks)
|
|
350
384
|
|
|
351
385
|
# Get the top 'sample_size' solutions the user asked for
|
|
@@ -371,9 +405,24 @@ class Function:
|
|
|
371
405
|
fitness_gpu = cupy.RawKernel(_FITNESS_KERNEL_FLOAT, 'fitness_kernel')
|
|
372
406
|
d_coefficients = cupy.array(self.coefficients, dtype=cupy.float64)
|
|
373
407
|
|
|
408
|
+
# Check if the user is using the default, non-expert range
|
|
409
|
+
user_range_is_default = (options.min_range == -100.0 and options.max_range == 100.0)
|
|
410
|
+
|
|
411
|
+
if user_range_is_default:
|
|
412
|
+
# User hasn't specified a custom range.
|
|
413
|
+
# We are the expert; use the smart, guaranteed bound.
|
|
414
|
+
bound = _get_cauchy_bound(self.coefficients)
|
|
415
|
+
min_r = -bound
|
|
416
|
+
max_r = bound
|
|
417
|
+
else:
|
|
418
|
+
# User has provided a custom range.
|
|
419
|
+
# Trust the expert; use their range.
|
|
420
|
+
min_r = options.min_range
|
|
421
|
+
max_r = options.max_range
|
|
422
|
+
|
|
374
423
|
# Create initial random solutions on the GPU
|
|
375
424
|
d_solutions = cupy.random.uniform(
|
|
376
|
-
|
|
425
|
+
min_r, max_r, options.data_size, dtype=cupy.float64
|
|
377
426
|
)
|
|
378
427
|
d_ranks = cupy.empty(options.data_size, dtype=cupy.float64)
|
|
379
428
|
|
|
@@ -424,7 +473,7 @@ class Function:
|
|
|
424
473
|
|
|
425
474
|
# 4. New Randoms
|
|
426
475
|
d_random_solutions = cupy.random.uniform(
|
|
427
|
-
|
|
476
|
+
min_r, max_r, random_size, dtype=cupy.float64
|
|
428
477
|
)
|
|
429
478
|
|
|
430
479
|
# Assemble the new generation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polysolve
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python library for representing, manipulating, and solving exponential functions using analytical methods and genetic algorithms, with optional CUDA acceleration.
|
|
5
5
|
Author-email: Jonathan Rampersad <jonathan@jono-rams.work>
|
|
6
6
|
License: MIT License
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|