polysolve 0.4.2__tar.gz → 0.5.0__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.2/src/polysolve.egg-info → polysolve-0.5.0}/PKG-INFO +1 -1
- {polysolve-0.4.2 → polysolve-0.5.0}/pyproject.toml +1 -1
- {polysolve-0.4.2 → polysolve-0.5.0}/src/polysolve/__init__.py +43 -18
- {polysolve-0.4.2 → polysolve-0.5.0/src/polysolve.egg-info}/PKG-INFO +1 -1
- {polysolve-0.4.2 → polysolve-0.5.0}/tests/test_polysolve.py +2 -2
- {polysolve-0.4.2 → polysolve-0.5.0}/LICENSE +0 -0
- {polysolve-0.4.2 → polysolve-0.5.0}/README.md +0 -0
- {polysolve-0.4.2 → polysolve-0.5.0}/setup.cfg +0 -0
- {polysolve-0.4.2 → polysolve-0.5.0}/src/polysolve.egg-info/SOURCES.txt +0 -0
- {polysolve-0.4.2 → polysolve-0.5.0}/src/polysolve.egg-info/dependency_links.txt +0 -0
- {polysolve-0.4.2 → polysolve-0.5.0}/src/polysolve.egg-info/requires.txt +0 -0
- {polysolve-0.4.2 → polysolve-0.5.0}/src/polysolve.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polysolve
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
|
|
@@ -49,8 +49,6 @@ class GA_Options:
|
|
|
49
49
|
Default: 100.0
|
|
50
50
|
num_of_generations (int): The number of iterations the algorithm will run.
|
|
51
51
|
Default: 10
|
|
52
|
-
sample_size (int): The number of top solutions to *return* at the end.
|
|
53
|
-
Default: 1000
|
|
54
52
|
data_size (int): The total number of solutions (population size)
|
|
55
53
|
generated in each generation. Default: 100000
|
|
56
54
|
mutation_strength (float): The percentage (e.g., 0.01 for 1%) by which
|
|
@@ -64,16 +62,21 @@ class GA_Options:
|
|
|
64
62
|
mutation_ratio (float): The percentage (e.g., 0.40 for 40%) of the next
|
|
65
63
|
generation to be created by mutating solutions
|
|
66
64
|
from the parent pool. Default: 0.40
|
|
65
|
+
root_precision (int): The number of decimal places to round roots to
|
|
66
|
+
when clustering. A smaller number (e.g., 3)
|
|
67
|
+
groups roots more aggressively. A larger number
|
|
68
|
+
(e.g., 7) is more precise but may return
|
|
69
|
+
multiple near-identical roots. Default: 5
|
|
67
70
|
"""
|
|
68
71
|
min_range: float = -100.0
|
|
69
72
|
max_range: float = 100.0
|
|
70
73
|
num_of_generations: int = 10
|
|
71
|
-
sample_size: int = 1000
|
|
72
74
|
data_size: int = 100000
|
|
73
75
|
mutation_strength: float = 0.01
|
|
74
76
|
elite_ratio: float = 0.05
|
|
75
77
|
crossover_ratio: float = 0.45
|
|
76
78
|
mutation_ratio: float = 0.40
|
|
79
|
+
root_precision: int = 5
|
|
77
80
|
|
|
78
81
|
def __post_init__(self):
|
|
79
82
|
"""Validates the GA options after initialization."""
|
|
@@ -84,11 +87,6 @@ class GA_Options:
|
|
|
84
87
|
)
|
|
85
88
|
if any(r < 0 for r in [self.elite_ratio, self.crossover_ratio, self.mutation_ratio]):
|
|
86
89
|
raise ValueError("GA ratios cannot be negative.")
|
|
87
|
-
if self.data_size < self.sample_size:
|
|
88
|
-
warnings.warn(
|
|
89
|
-
f"data_size ({self.data_size}) is less than sample_size ({self.sample_size}). "
|
|
90
|
-
"The number of returned solutions will be limited to data_size."
|
|
91
|
-
)
|
|
92
90
|
|
|
93
91
|
def _get_cauchy_bound(coeffs: np.ndarray) -> float:
|
|
94
92
|
"""
|
|
@@ -380,12 +378,26 @@ class Function:
|
|
|
380
378
|
error = y_calculated - y_val
|
|
381
379
|
with np.errstate(divide='ignore'):
|
|
382
380
|
ranks = np.where(error == 0, np.finfo(float).max, np.abs(1.0 / error))
|
|
383
|
-
sorted_indices = np.argsort(-ranks)
|
|
384
381
|
|
|
385
|
-
#
|
|
386
|
-
|
|
382
|
+
# 1. Define quality based on the user's desired precision
|
|
383
|
+
# (e.g., precision=5 -> rank > 1e6, precision=8 -> rank > 1e9)
|
|
384
|
+
# We add +1 for a buffer, ensuring we only get high-quality roots.
|
|
385
|
+
quality_threshold = 10**(options.root_precision + 1)
|
|
386
|
+
|
|
387
|
+
# 2. Get all solutions that meet this quality threshold
|
|
388
|
+
high_quality_solutions = solutions[ranks > quality_threshold]
|
|
389
|
+
|
|
390
|
+
if high_quality_solutions.size == 0:
|
|
391
|
+
# No roots found that meet the quality, return empty
|
|
392
|
+
return np.array([])
|
|
393
|
+
|
|
394
|
+
# 3. Cluster these high-quality solutions by rounding
|
|
395
|
+
rounded_solutions = np.round(high_quality_solutions, options.root_precision)
|
|
396
|
+
|
|
397
|
+
# 4. Return only the unique roots
|
|
398
|
+
unique_roots = np.unique(rounded_solutions)
|
|
387
399
|
|
|
388
|
-
return np.sort(
|
|
400
|
+
return np.sort(unique_roots)
|
|
389
401
|
|
|
390
402
|
def _solve_x_cuda(self, y_val: float, options: GA_Options) -> np.ndarray:
|
|
391
403
|
"""Genetic algorithm implementation using CuPy (GPU/CUDA)."""
|
|
@@ -490,13 +502,26 @@ class Function:
|
|
|
490
502
|
(blocks_per_grid,), (threads_per_block,),
|
|
491
503
|
(d_coefficients, d_coefficients.size, d_solutions, d_ranks, d_solutions.size, y_val)
|
|
492
504
|
)
|
|
493
|
-
sorted_indices = cupy.argsort(-d_ranks)
|
|
494
505
|
|
|
495
|
-
#
|
|
496
|
-
|
|
506
|
+
# 1. Define quality based on the user's desired precision
|
|
507
|
+
# (e.g., precision=5 -> rank > 1e6, precision=8 -> rank > 1e9)
|
|
508
|
+
# We add +1 for a buffer, ensuring we only get high-quality roots.
|
|
509
|
+
quality_threshold = 10**(options.root_precision + 1)
|
|
510
|
+
|
|
511
|
+
# 2. Get all solutions that meet this quality threshold
|
|
512
|
+
d_high_quality_solutions = d_solutions[d_ranks > quality_threshold]
|
|
513
|
+
|
|
514
|
+
if d_high_quality_solutions.size == 0:
|
|
515
|
+
return np.array([])
|
|
516
|
+
|
|
517
|
+
# 3. Cluster these high-quality solutions on the GPU by rounding
|
|
518
|
+
d_rounded_solutions = cupy.round(d_high_quality_solutions, options.root_precision)
|
|
519
|
+
|
|
520
|
+
# 4. Get only the unique roots
|
|
521
|
+
d_unique_roots = cupy.unique(d_rounded_solutions)
|
|
497
522
|
|
|
498
|
-
#
|
|
499
|
-
final_solutions_gpu = cupy.sort(
|
|
523
|
+
# Sort the unique roots and copy back to CPU
|
|
524
|
+
final_solutions_gpu = cupy.sort(d_unique_roots)
|
|
500
525
|
return final_solutions_gpu.get()
|
|
501
526
|
|
|
502
527
|
|
|
@@ -692,7 +717,7 @@ if __name__ == '__main__':
|
|
|
692
717
|
print(f"Analytic roots of f1: {roots_analytic}") # Expected: -1, 2.5
|
|
693
718
|
|
|
694
719
|
# 2. Genetic algorithm solution
|
|
695
|
-
ga_opts = GA_Options(num_of_generations=20, data_size=50000
|
|
720
|
+
ga_opts = GA_Options(num_of_generations=20, data_size=50000)
|
|
696
721
|
print("\nFinding roots with Genetic Algorithm (CPU)...")
|
|
697
722
|
roots_ga_cpu = f1.get_real_roots(ga_opts)
|
|
698
723
|
print(f"Approximate roots from GA (CPU): {roots_ga_cpu}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polysolve
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
|
|
@@ -101,7 +101,7 @@ def test_get_real_roots_numpy(quadratic_func):
|
|
|
101
101
|
Tests that the NumPy-based genetic algorithm approximates the roots correctly.
|
|
102
102
|
"""
|
|
103
103
|
# Using more generations for higher accuracy in testing
|
|
104
|
-
ga_opts = GA_Options(num_of_generations=
|
|
104
|
+
ga_opts = GA_Options(num_of_generations=50, data_size=200000, root_precision=3)
|
|
105
105
|
|
|
106
106
|
roots = quadratic_func.get_real_roots(ga_opts, use_cuda=False)
|
|
107
107
|
|
|
@@ -124,7 +124,7 @@ def test_get_real_roots_cuda(quadratic_func):
|
|
|
124
124
|
It will be skipped automatically if CuPy is not available.
|
|
125
125
|
"""
|
|
126
126
|
|
|
127
|
-
ga_opts = GA_Options(num_of_generations=
|
|
127
|
+
ga_opts = GA_Options(num_of_generations=50, data_size=200000, root_precision=3)
|
|
128
128
|
|
|
129
129
|
roots = quadratic_func.get_real_roots(ga_opts, use_cuda=True)
|
|
130
130
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|