polysolve 0.1.1__tar.gz → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polysolve
3
- Version: 0.1.1
3
+ Version: 0.2.1
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
@@ -106,17 +106,22 @@ print(f"Value of f1 at x=5 is: {y_val}")
106
106
  # > Value of f1 at x=5 is: 30.0
107
107
 
108
108
  # 3. Get the derivative: 4x - 3
109
- df1 = f1.differential()
109
+ df1 = f1.derivative()
110
110
  print(f"Derivative of f1: {df1}")
111
111
  # > Derivative of f1: 4x - 3
112
112
 
113
- # 4. Find roots analytically using the quadratic formula
113
+ # 4. Get the 2nd derivative: 4
114
+ ddf1 = f1.nth_derivative(2)
115
+ print(f"2nd Derivative of f1: {ddf1}")
116
+ # > Derivative of f1: 4
117
+
118
+ # 5. Find roots analytically using the quadratic formula
114
119
  # This is exact and fast for degree-2 polynomials.
115
120
  roots_analytic = quadratic_solve(f1)
116
121
  print(f"Analytic roots: {sorted(roots_analytic)}")
117
122
  # > Analytic roots: [-1.0, 2.5]
118
123
 
119
- # 5. Find roots with the genetic algorithm (CPU)
124
+ # 6. Find roots with the genetic algorithm (CPU)
120
125
  # This can solve polynomials of any degree.
121
126
  ga_opts = GA_Options(num_of_generations=20)
122
127
  roots_ga = f1.get_real_roots(ga_opts, use_cuda=False)
@@ -139,10 +144,41 @@ While the code may work on other configurations, all contributions must pass the
139
144
 
140
145
  ## Contributing
141
146
 
147
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
148
+ [![GitHub issues](https://img.shields.io/github/issues/jono-rams/PolySolve.svg?style=flat-square)](https://github.com/jono-rams/PolySolve/issues)
149
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/jono-rams/PolySolve.svg?style=flat-square)](https://github.com/jono-rams/PolySolve/pulls)
150
+
142
151
  Contributions are welcome! Whether it's a bug report, a feature request, or a pull request, please feel free to get involved.
143
152
 
144
153
  Please read our `CONTRIBUTING.md` file for details on our code of conduct and the process for submitting pull requests.
145
154
 
155
+ ## Contributors
156
+
157
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
158
+ <!-- prettier-ignore-start -->
159
+ <!-- markdownlint-disable -->
160
+ <table>
161
+ <tbody>
162
+ <tr>
163
+ <td align="center" valign="top" width="14.28%"><a href="https://jono-rams.work"><img src="https://avatars.githubusercontent.com/u/29872001?v=4?s=100" width="100px;" alt="Jonathan Rampersad"/><br /><sub><b>Jonathan Rampersad</b></sub></a><br /><a href="https://github.com/jono-rams/PolySolve/commits?author=jono-rams" title="Code">💻</a> <a href="https://github.com/jono-rams/PolySolve/commits?author=jono-rams" title="Documentation">📖</a> <a href="#infra-jono-rams" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
164
+ </tr>
165
+ </tbody>
166
+ <tfoot>
167
+ <tr>
168
+ <td align="center" size="13px" colspan="7">
169
+ <img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg">
170
+ <a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a>
171
+ </img>
172
+ </td>
173
+ </tr>
174
+ </tfoot>
175
+ </table>
176
+
177
+ <!-- markdownlint-restore -->
178
+ <!-- prettier-ignore-end -->
179
+
180
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
181
+
146
182
  ## License
147
183
 
148
184
  This project is licensed under the MIT License - see the `LICENSE` file for details.
@@ -56,17 +56,22 @@ print(f"Value of f1 at x=5 is: {y_val}")
56
56
  # > Value of f1 at x=5 is: 30.0
57
57
 
58
58
  # 3. Get the derivative: 4x - 3
59
- df1 = f1.differential()
59
+ df1 = f1.derivative()
60
60
  print(f"Derivative of f1: {df1}")
61
61
  # > Derivative of f1: 4x - 3
62
62
 
63
- # 4. Find roots analytically using the quadratic formula
63
+ # 4. Get the 2nd derivative: 4
64
+ ddf1 = f1.nth_derivative(2)
65
+ print(f"2nd Derivative of f1: {ddf1}")
66
+ # > Derivative of f1: 4
67
+
68
+ # 5. Find roots analytically using the quadratic formula
64
69
  # This is exact and fast for degree-2 polynomials.
65
70
  roots_analytic = quadratic_solve(f1)
66
71
  print(f"Analytic roots: {sorted(roots_analytic)}")
67
72
  # > Analytic roots: [-1.0, 2.5]
68
73
 
69
- # 5. Find roots with the genetic algorithm (CPU)
74
+ # 6. Find roots with the genetic algorithm (CPU)
70
75
  # This can solve polynomials of any degree.
71
76
  ga_opts = GA_Options(num_of_generations=20)
72
77
  roots_ga = f1.get_real_roots(ga_opts, use_cuda=False)
@@ -89,10 +94,41 @@ While the code may work on other configurations, all contributions must pass the
89
94
 
90
95
  ## Contributing
91
96
 
97
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
98
+ [![GitHub issues](https://img.shields.io/github/issues/jono-rams/PolySolve.svg?style=flat-square)](https://github.com/jono-rams/PolySolve/issues)
99
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/jono-rams/PolySolve.svg?style=flat-square)](https://github.com/jono-rams/PolySolve/pulls)
100
+
92
101
  Contributions are welcome! Whether it's a bug report, a feature request, or a pull request, please feel free to get involved.
93
102
 
94
103
  Please read our `CONTRIBUTING.md` file for details on our code of conduct and the process for submitting pull requests.
95
104
 
105
+ ## Contributors
106
+
107
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
108
+ <!-- prettier-ignore-start -->
109
+ <!-- markdownlint-disable -->
110
+ <table>
111
+ <tbody>
112
+ <tr>
113
+ <td align="center" valign="top" width="14.28%"><a href="https://jono-rams.work"><img src="https://avatars.githubusercontent.com/u/29872001?v=4?s=100" width="100px;" alt="Jonathan Rampersad"/><br /><sub><b>Jonathan Rampersad</b></sub></a><br /><a href="https://github.com/jono-rams/PolySolve/commits?author=jono-rams" title="Code">💻</a> <a href="https://github.com/jono-rams/PolySolve/commits?author=jono-rams" title="Documentation">📖</a> <a href="#infra-jono-rams" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
114
+ </tr>
115
+ </tbody>
116
+ <tfoot>
117
+ <tr>
118
+ <td align="center" size="13px" colspan="7">
119
+ <img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg">
120
+ <a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a>
121
+ </img>
122
+ </td>
123
+ </tr>
124
+ </tfoot>
125
+ </table>
126
+
127
+ <!-- markdownlint-restore -->
128
+ <!-- prettier-ignore-end -->
129
+
130
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
131
+
96
132
  ## License
97
133
 
98
134
  This project is licensed under the MIT License - see the `LICENSE` file for details.
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  # --- Core Metadata ---
7
7
  name = "polysolve"
8
- version = "0.1.1"
8
+ version = "0.2.1"
9
9
  authors = [
10
10
  { name="Jonathan Rampersad", email="jonathan@jono-rams.work" },
11
11
  ]
@@ -1,7 +1,7 @@
1
1
  import math
2
2
  import numpy as np
3
3
  from dataclasses import dataclass
4
- from typing import List, Optional
4
+ from typing import List, Optional, Union
5
5
  import warnings
6
6
 
7
7
  # Attempt to import CuPy for CUDA acceleration.
@@ -108,6 +108,11 @@ class Function:
108
108
  def largest_exponent(self) -> int:
109
109
  """Returns the largest exponent of the function."""
110
110
  return self._largest_exponent
111
+
112
+ @property
113
+ def degree(self) -> int:
114
+ """Returns the largest exponent of the function."""
115
+ return self._largest_exponent
111
116
 
112
117
  def solve_y(self, x_val: float) -> float:
113
118
  """
@@ -129,15 +134,66 @@ class Function:
129
134
  Returns:
130
135
  Function: A new Function object representing the derivative.
131
136
  """
137
+ warnings.warn(
138
+ "The 'differential' function has been renamed. Please use 'derivative' instead.",
139
+ DeprecationWarning,
140
+ stacklevel=2
141
+ )
142
+
132
143
  self._check_initialized()
133
144
  if self._largest_exponent == 0:
134
145
  raise ValueError("Cannot differentiate a constant (Function of degree 0).")
135
146
 
147
+ return self.derivitive()
148
+
149
+
150
+ def derivative(self) -> 'Function':
151
+ """
152
+ Calculates the derivative of the function.
153
+
154
+ Returns:
155
+ Function: A new Function object representing the derivative.
156
+ """
157
+ self._check_initialized()
158
+ if self._largest_exponent == 0:
159
+ raise ValueError("Cannot differentiate a constant (Function of degree 0).")
160
+
136
161
  derivative_coefficients = np.polyder(self.coefficients)
137
162
 
138
163
  diff_func = Function(self._largest_exponent - 1)
139
164
  diff_func.set_coeffs(derivative_coefficients.tolist())
140
165
  return diff_func
166
+
167
+
168
+ def nth_derivative(self, n: int) -> 'Function':
169
+ """
170
+ Calculates the nth derivative of the function.
171
+
172
+ Args:
173
+ n (int): The order of the derivative to calculate.
174
+
175
+ Returns:
176
+ Function: A new Function object representing the nth derivative.
177
+ """
178
+ self._check_initialized()
179
+
180
+ if not isinstance(n, int) or n < 1:
181
+ raise ValueError("Derivative order 'n' must be a positive integer.")
182
+
183
+ if n > self.largest_exponent:
184
+ function = Function(0)
185
+ function.set_coeffs([0])
186
+ return function
187
+
188
+ if n == 1:
189
+ return self.derivative()
190
+
191
+ function = self
192
+ for _ in range(n):
193
+ function = function.derivative()
194
+
195
+ return function
196
+
141
197
 
142
198
  def get_real_roots(self, options: GA_Options = GA_Options(), use_cuda: bool = False) -> np.ndarray:
143
199
  """
@@ -336,34 +392,55 @@ class Function:
336
392
  result_func = Function(len(new_coefficients) - 1)
337
393
  result_func.set_coeffs(new_coefficients.tolist())
338
394
  return result_func
339
-
340
- def __mul__(self, scalar: int) -> 'Function':
341
- """Multiplies the function by a scalar constant."""
342
- self._check_initialized()
343
- if not isinstance(scalar, (int, float)):
344
- return NotImplemented
345
- if scalar == 0:
346
- raise ValueError("Cannot multiply a function by 0.")
395
+
396
+ def _multiply_by_scalar(self, scalar: Union[int, float]) -> 'Function':
397
+ """Helper method to multiply the function by a scalar constant."""
398
+ self._check_initialized() # It's good practice to check here too
347
399
 
400
+ if scalar == 0:
401
+ result_func = Function(0)
402
+ result_func.set_coeffs([0])
403
+ return result_func
404
+
348
405
  new_coefficients = self.coefficients * scalar
349
-
406
+
350
407
  result_func = Function(self._largest_exponent)
351
408
  result_func.set_coeffs(new_coefficients.tolist())
352
409
  return result_func
353
410
 
354
- def __rmul__(self, scalar: int) -> 'Function':
411
+ def _multiply_by_function(self, other: 'Function') -> 'Function':
412
+ """Helper method for polynomial multiplication (Function * Function)."""
413
+ self._check_initialized()
414
+ other._check_initialized()
415
+
416
+ # np.polymul performs convolution of coefficients to multiply polynomials
417
+ new_coefficients = np.polymul(self.coefficients, other.coefficients)
418
+
419
+ # The degree of the resulting polynomial is derived from the new coefficients
420
+ new_degree = len(new_coefficients) - 1
421
+
422
+ result_func = Function(new_degree)
423
+ result_func.set_coeffs(new_coefficients.tolist())
424
+ return result_func
425
+
426
+ def __mul__(self, other: Union['Function', int, float]) -> 'Function':
427
+ """Multiplies the function by a scalar constant."""
428
+ if isinstance(other, (int, float)):
429
+ return self._multiply_by_scalar(other)
430
+ elif isinstance(other, self.__class__):
431
+ return self._multiply_by_function(other)
432
+ else:
433
+ return NotImplemented
434
+
435
+ def __rmul__(self, scalar: Union[int, float]) -> 'Function':
355
436
  """Handles scalar multiplication from the right (e.g., 3 * func)."""
437
+
356
438
  return self.__mul__(scalar)
357
439
 
358
- def __imul__(self, scalar: int) -> 'Function':
440
+ def __imul__(self, other: Union['Function', int, float]) -> 'Function':
359
441
  """Performs in-place multiplication by a scalar (func *= 3)."""
360
- self._check_initialized()
361
- if not isinstance(scalar, (int, float)):
362
- return NotImplemented
363
- if scalar == 0:
364
- raise ValueError("Cannot multiply a function by 0.")
365
-
366
- self.coefficients *= scalar
442
+
443
+ self.coefficients *= other
367
444
  return self
368
445
 
369
446
 
@@ -408,9 +485,13 @@ if __name__ == '__main__':
408
485
  print(f"Value of f1 at x=5 is: {y}") # Expected: 2*(25) - 3*(5) - 5 = 50 - 15 - 5 = 30
409
486
 
410
487
  # Find the derivative: 4x - 3
411
- df1 = f1.differential()
488
+ df1 = f1.derivative()
412
489
  print(f"Derivative of f1: {df1}")
413
490
 
491
+ # Find the second derivative: 4
492
+ ddf1 = f1.nth_derivative(2)
493
+ print(f"Second derivative of f1: {ddf1}")
494
+
414
495
  # --- Root Finding ---
415
496
  # 1. Analytical solution for quadratic
416
497
  roots_analytic = quadratic_solve(f1)
@@ -448,4 +529,18 @@ if __name__ == '__main__':
448
529
 
449
530
  # Multiplication: (x + 10) * 3 = 3x + 30
450
531
  f_mul = f2 * 3
451
- print(f"f2 * 3 = {f_mul}")
532
+ print(f"f2 * 3 = {f_mul}")
533
+
534
+ # f3 represents 2x^2 + 3x + 1
535
+ f3 = Function(2)
536
+ f3.set_coeffs([2, 3, 1])
537
+ print(f"Function f3: {f3}")
538
+
539
+ # f4 represents 5x - 4
540
+ f4 = Function(1)
541
+ f4.set_coeffs([5, -4])
542
+ print(f"Function f4: {f4}")
543
+
544
+ # Multiply the two functions
545
+ product_func = f3 * f4
546
+ print(f"f3 * f4 = {product_func}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polysolve
3
- Version: 0.1.1
3
+ Version: 0.2.1
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
@@ -106,17 +106,22 @@ print(f"Value of f1 at x=5 is: {y_val}")
106
106
  # > Value of f1 at x=5 is: 30.0
107
107
 
108
108
  # 3. Get the derivative: 4x - 3
109
- df1 = f1.differential()
109
+ df1 = f1.derivative()
110
110
  print(f"Derivative of f1: {df1}")
111
111
  # > Derivative of f1: 4x - 3
112
112
 
113
- # 4. Find roots analytically using the quadratic formula
113
+ # 4. Get the 2nd derivative: 4
114
+ ddf1 = f1.nth_derivative(2)
115
+ print(f"2nd Derivative of f1: {ddf1}")
116
+ # > Derivative of f1: 4
117
+
118
+ # 5. Find roots analytically using the quadratic formula
114
119
  # This is exact and fast for degree-2 polynomials.
115
120
  roots_analytic = quadratic_solve(f1)
116
121
  print(f"Analytic roots: {sorted(roots_analytic)}")
117
122
  # > Analytic roots: [-1.0, 2.5]
118
123
 
119
- # 5. Find roots with the genetic algorithm (CPU)
124
+ # 6. Find roots with the genetic algorithm (CPU)
120
125
  # This can solve polynomials of any degree.
121
126
  ga_opts = GA_Options(num_of_generations=20)
122
127
  roots_ga = f1.get_real_roots(ga_opts, use_cuda=False)
@@ -139,10 +144,41 @@ While the code may work on other configurations, all contributions must pass the
139
144
 
140
145
  ## Contributing
141
146
 
147
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
148
+ [![GitHub issues](https://img.shields.io/github/issues/jono-rams/PolySolve.svg?style=flat-square)](https://github.com/jono-rams/PolySolve/issues)
149
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/jono-rams/PolySolve.svg?style=flat-square)](https://github.com/jono-rams/PolySolve/pulls)
150
+
142
151
  Contributions are welcome! Whether it's a bug report, a feature request, or a pull request, please feel free to get involved.
143
152
 
144
153
  Please read our `CONTRIBUTING.md` file for details on our code of conduct and the process for submitting pull requests.
145
154
 
155
+ ## Contributors
156
+
157
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
158
+ <!-- prettier-ignore-start -->
159
+ <!-- markdownlint-disable -->
160
+ <table>
161
+ <tbody>
162
+ <tr>
163
+ <td align="center" valign="top" width="14.28%"><a href="https://jono-rams.work"><img src="https://avatars.githubusercontent.com/u/29872001?v=4?s=100" width="100px;" alt="Jonathan Rampersad"/><br /><sub><b>Jonathan Rampersad</b></sub></a><br /><a href="https://github.com/jono-rams/PolySolve/commits?author=jono-rams" title="Code">💻</a> <a href="https://github.com/jono-rams/PolySolve/commits?author=jono-rams" title="Documentation">📖</a> <a href="#infra-jono-rams" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
164
+ </tr>
165
+ </tbody>
166
+ <tfoot>
167
+ <tr>
168
+ <td align="center" size="13px" colspan="7">
169
+ <img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg">
170
+ <a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a>
171
+ </img>
172
+ </td>
173
+ </tr>
174
+ </tfoot>
175
+ </table>
176
+
177
+ <!-- markdownlint-restore -->
178
+ <!-- prettier-ignore-end -->
179
+
180
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
181
+
146
182
  ## License
147
183
 
148
184
  This project is licensed under the MIT License - see the `LICENSE` file for details.
@@ -24,6 +24,18 @@ def linear_func() -> Function:
24
24
  f.set_coeffs([1, 10])
25
25
  return f
26
26
 
27
+ @pytest.fixture
28
+ def m_func_1() -> Function:
29
+ f = Function(2)
30
+ f.set_coeffs([2, 3, 1])
31
+ return f
32
+
33
+ @pytest.fixture
34
+ def m_func_2() -> Function:
35
+ f = Function(1)
36
+ f.set_coeffs([5, -4])
37
+ return f
38
+
27
39
  # --- Core Functionality Tests ---
28
40
 
29
41
  def test_solve_y(quadratic_func):
@@ -32,13 +44,20 @@ def test_solve_y(quadratic_func):
32
44
  assert quadratic_func.solve_y(0) == -5.0
33
45
  assert quadratic_func.solve_y(-1) == 0.0
34
46
 
35
- def test_differential(quadratic_func):
47
+ def test_derivative(quadratic_func):
36
48
  """Tests the calculation of the function's derivative."""
37
- derivative = quadratic_func.differential()
49
+ derivative = quadratic_func.derivative()
38
50
  assert derivative.largest_exponent == 1
39
51
  # The derivative of 2x^2 - 3x - 5 is 4x - 3
40
52
  assert np.array_equal(derivative.coefficients, [4, -3])
41
53
 
54
+ def test_nth_derivative(quadratic_func):
55
+ """Tests the calculation of the function's 2nd derivative."""
56
+ derivative = quadratic_func.nth_derivative(2)
57
+ assert derivative.largest_exponent == 0
58
+ # The derivative of 2x^2 - 3x - 5 is 4x - 3
59
+ assert np.array_equal(derivative.coefficients, [4])
60
+
42
61
  def test_quadratic_solve(quadratic_func):
43
62
  """Tests the analytical quadratic solver for exact roots."""
44
63
  roots = quadratic_solve(quadratic_func)
@@ -61,13 +80,20 @@ def test_subtraction(quadratic_func, linear_func):
61
80
  assert result.largest_exponent == 2
62
81
  assert np.array_equal(result.coefficients, [2, -4, -15])
63
82
 
64
- def test_multiplication(linear_func):
83
+ def test_scalar_multiplication(linear_func):
65
84
  """Tests the multiplication of a Function object by a scalar."""
66
85
  # (x + 10) * 3 = 3x + 30
67
86
  result = linear_func * 3
68
87
  assert result.largest_exponent == 1
69
88
  assert np.array_equal(result.coefficients, [3, 30])
70
89
 
90
+ def test_function_multiplication(m_func_1, m_func_2):
91
+ """Tests the multiplication of two Function objects."""
92
+ # (2x^2 + 3x + 1) * (5x -4) = 10x^3 + 7x^2 - 7x -4
93
+ result = m_func_1 * m_func_2
94
+ assert result.largest_exponent == 3
95
+ assert np.array_equal(result.coefficients, [10, 7, -7, -4])
96
+
71
97
  # --- Genetic Algorithm Root-Finding Tests ---
72
98
 
73
99
  def test_get_real_roots_numpy(quadratic_func):
File without changes
File without changes