From 361b8888802b0c9dbbaa3d2f2e38106fa01a5b71 Mon Sep 17 00:00:00 2001 From: Abhishek Patidar <1e9abhi1e10@gmail.com> Date: Sun, 16 Jul 2023 22:31:10 +0530 Subject: [PATCH 1/7] Add benchmarks for subresultants PRS method --- benchmarks/polys.py | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/benchmarks/polys.py b/benchmarks/polys.py index 60318c2..d8ce2bf 100644 --- a/benchmarks/polys.py +++ b/benchmarks/polys.py @@ -1,4 +1,4 @@ -from sympy import symbols, prod, prem, rem, degree, LC +from sympy import symbols, prod, prem, rem, degree, LC, subresultants, resultant from sympy.polys import QQ, Poly @@ -61,6 +61,7 @@ def make_poly(self, n): g = d * (2 + x + sum(y[:n])) ** 2 return f, g, d, syms + class _SparseGCDHighDegree(_GCDExample): """A pair of polynomials in n symbols with a high degree sparse GCD.""" @@ -93,6 +94,7 @@ def make_poly(self, n): g = d * (-3 + x * prod(y[:n])) return f, g, d, syms + class _TimeOP: """ Benchmarks comparing Poly implementations of a given operation. @@ -162,5 +164,44 @@ class TimePREM_QuadraticNonMonicGCD(_TimePREM): class TimePREM_SparseNonMonicQuadratic(_TimePREM): + GCDExampleCLS = _SparseNonMonicQuadratic + params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')] + + +class _TimeSUBRESULTANTS(_TimeOP): + """Benchmarks for pseudo-quotient method""" + + def expected(self, f, g, d, syms): + x = syms[0] + subresultant = resultant(f * LC(g, x) ** (degree(f, x) - degree(g, x) + 1), g, x) + return [f, g, subresultant] + + def get_func_expr(self, f, g, d, syms): + x = syms[0] + return lambda: subresultants(f, g, x) + + def get_func_poly(self, f, g, d): + return lambda: f.subresultants(g) + + def get_func_sparse(self, f, g, d, ring): + return lambda: f.subresultants(g) + + +class TimeSUBRESULTANTS_LinearDenseQuadraticGCD(_TimeSUBRESULTANTS): + GCDExampleCLS = _LinearDenseQuadraticGCD + params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. + + +class TimeSUBRESULTANTS_SparseGCDHighDegree(_TimeSUBRESULTANTS): + GCDExampleCLS = _SparseGCDHighDegree + params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')] + + +class TimeSUBRESULTANTS_QuadraticNonMonicGCD(_TimeSUBRESULTANTS): + GCDExampleCLS = _QuadraticNonMonicGCD + params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. + + +class TimeSUBRESULTANTS_SparseNonMonicQuadratic(_TimeSUBRESULTANTS): GCDExampleCLS = _SparseNonMonicQuadratic params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')] \ No newline at end of file From b9b3ba192f790178496126052cbe0329f7b2b122 Mon Sep 17 00:00:00 2001 From: Abhishek Patidar <1e9abhi1e10@gmail.com> Date: Mon, 17 Jul 2023 02:29:47 +0530 Subject: [PATCH 2/7] fixes assertion error in teardown function --- benchmarks/polys.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/benchmarks/polys.py b/benchmarks/polys.py index d8ce2bf..0164cca 100644 --- a/benchmarks/polys.py +++ b/benchmarks/polys.py @@ -1,4 +1,4 @@ -from sympy import symbols, prod, prem, rem, degree, LC, subresultants, resultant +from sympy import symbols, prod, prem, rem, degree, LC, subresultants from sympy.polys import QQ, Poly @@ -113,12 +113,20 @@ def setup(self, n, impl): if impl == 'expr': func = self.get_func_expr(*examples.as_expr()) expected = examples.to_expr(expected) + elif impl == 'dense': func = self.get_func_poly(*examples.as_poly()) - expected = examples.to_poly(expected) + if isinstance(expected, list): + expected = [examples.to_poly(polynomial) for polynomial in expected] # for the subresultants type methods the output is in form of list. + else: + expected = examples.to_poly(expected) # for those methods whose output is only a polynomial not a tuple or list. + elif impl == 'sparse': func = self.get_func_sparse(*examples.as_ring()) - expected = examples.to_ring(expected) + if isinstance(expected, list): + expected = [examples.to_ring(polynomial) for polynomial in expected] + else: + expected = examples.to_ring(expected) self.func = func self.expected_result = expected @@ -173,8 +181,9 @@ class _TimeSUBRESULTANTS(_TimeOP): def expected(self, f, g, d, syms): x = syms[0] - subresultant = resultant(f * LC(g, x) ** (degree(f, x) - degree(g, x) + 1), g, x) - return [f, g, subresultant] + subresultant = subresultants(f, g, x) + + return subresultant def get_func_expr(self, f, g, d, syms): x = syms[0] @@ -189,19 +198,19 @@ def get_func_sparse(self, f, g, d, ring): class TimeSUBRESULTANTS_LinearDenseQuadraticGCD(_TimeSUBRESULTANTS): GCDExampleCLS = _LinearDenseQuadraticGCD - params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. + params = [(1, 2, 3), ('expr', 'dense', 'sparse')] # This case is slow for n>3. class TimeSUBRESULTANTS_SparseGCDHighDegree(_TimeSUBRESULTANTS): GCDExampleCLS = _SparseGCDHighDegree - params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')] + params = [(1, 2, 3, 5), ('expr', 'dense', 'sparse')] class TimeSUBRESULTANTS_QuadraticNonMonicGCD(_TimeSUBRESULTANTS): GCDExampleCLS = _QuadraticNonMonicGCD - params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. + params = [(1, 2, 3), ('expr', 'dense', 'sparse')] # This case is slow for n>3. class TimeSUBRESULTANTS_SparseNonMonicQuadratic(_TimeSUBRESULTANTS): GCDExampleCLS = _SparseNonMonicQuadratic - params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')] \ No newline at end of file + params = [(1, 2, 3, 5), ('expr', 'dense', 'sparse')] From e4ad8f9b096f820f22344e57551ab2265235464f Mon Sep 17 00:00:00 2001 From: Abhishek Patidar <1e9abhi1e10@gmail.com> Date: Mon, 17 Jul 2023 03:27:01 +0530 Subject: [PATCH 3/7] change name --- benchmarks/polys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/polys.py b/benchmarks/polys.py index 0164cca..ff715dd 100644 --- a/benchmarks/polys.py +++ b/benchmarks/polys.py @@ -177,7 +177,7 @@ class TimePREM_SparseNonMonicQuadratic(_TimePREM): class _TimeSUBRESULTANTS(_TimeOP): - """Benchmarks for pseudo-quotient method""" + """Benchmarks for subresultants PRS method""" def expected(self, f, g, d, syms): x = syms[0] From 7f262973111c78ca4621b095ea3b69e05c51285a Mon Sep 17 00:00:00 2001 From: Abhishek Patidar <1e9abhi1e10@gmail.com> Date: Tue, 18 Jul 2023 18:22:40 +0530 Subject: [PATCH 4/7] add docstring for clear understandings --- benchmarks/polys.py | 112 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 96 insertions(+), 16 deletions(-) diff --git a/benchmarks/polys.py b/benchmarks/polys.py index ff715dd..5cb25a9 100644 --- a/benchmarks/polys.py +++ b/benchmarks/polys.py @@ -52,7 +52,27 @@ def as_ring(self): class _LinearDenseQuadraticGCD(_GCDExample): - """A pair of linearly dense quartic inputs with quadratic GCDs""" + """A pair of linearly dense quartic inputs with quadratic GCDs. + + This class generates benchmark examples with two polynomials, ``f`` and + ``g``, that are linearly dense quartic polynomials with quadratic GCDs. The + polynomials are constructed based on the input parameter ``n`. + + Examples + ======== + + >>> example = _LinearDenseQuadraticGCD(3) + >>> f, g, d, syms = example.as_expr() + >>> f + (x - y1 - y2 - y3 - 2)**2*(x + y1 + y2 + y3 + 1)**2 + >>> g + (x + y1 + y2 + y3 + 1)**2*(x + y1 + y2 + y3 + 2)**2 + >>> d + (x + y1 + y2 + y3 + 1)**2 + >>> syms + (x, y1, y2, y3) + + """ def make_poly(self, n): x, *y = syms = symbols("x, y1:{}".format(n+1)) @@ -63,7 +83,27 @@ def make_poly(self, n): class _SparseGCDHighDegree(_GCDExample): - """A pair of polynomials in n symbols with a high degree sparse GCD.""" + """A pair of polynomials in n symbols with a high degree sparse GCD. + + This class generates benchmark examples with two polynomials, ``f`` and + ``g``, that have a high degree sparse GCD. The polynomials are constructed + based on the input parameter ``n``. + + Examples + ======== + + >>> example = _SparseGCDHighDegree(3) + >>> f, g, d, syms = example.as_expr() + >>> f + (x**4 + y1**4 + y2**4 + y3**4 - 2)*(x**4 + y1**4 + y2**4 + y3**4 + 1) + >>> g + (x**4 + y1**4 + y2**4 + y3**4 + 1)*(x**4 + y1**4 + y2**4 + y3**4 + 2) + >>> d + x**4 + y1**4 + y2**4 + y3**4 + 1 + >>> syms + (x, y1, y2, y3) + + """ def make_poly(self, n): x, *y = syms = symbols("x, y1:{}".format(n+1)) @@ -74,7 +114,27 @@ def make_poly(self, n): class _QuadraticNonMonicGCD(_GCDExample): - """A pair of quadratic polynomials with a non-monic GCD.""" + """A pair of quadratic polynomials with a non-monic GCD. + + This class generates benchmark examples with two quadratic polynomials, + ``f`` and ``g``, that have a non-monic GCD. The polynomials are constructed + based on the input parameter ``n``. + + Examples + ======== + + >>> example = _QuadraticNonMonicGCD(3) + >>> f, g, d, syms = example.as_expr() + >>> f + (x**2*y1**2 + y2**2 + y3**2 + 1)*(x**2 - y1**2 + y2**2 + y3**2 - 1) + >>> g + (x*y1 + y2 + y3 + 2)**2*(x**2*y1**2 + y2**2 + y3**2 + 1) + >>> d + x**2*y1**2 + y2**2 + y3**2 + 1 + >>> syms + (x, y1, y2, y3) + + """ def make_poly(self, n): x, *y = syms = symbols("x, y1:{}".format(n+1)) @@ -85,7 +145,27 @@ def make_poly(self, n): class _SparseNonMonicQuadratic(_GCDExample): - """A pair of sparse non-monic quadratic polynomials with linear GCDs.""" + """A pair of sparse non-monic quadratic polynomials with linear GCDs. + + This class generates benchmark examples with two sparse non-monic quadratic + polynomials, ``f`` and ``g``, that have a linear GCD. The polynomials are + constructed based on the input parameter ``n``. + + Examples + ======== + + >>> example = _SparseNonMonicQuadratic(3) + >>> f, g, d, syms = example.as_expr() + >>> f + (x*y1*y2*y3 - 1)*(x*y1*y2*y3 + 3) + >>> g + (x*y1*y2*y3 - 3)*(x*y1*y2*y3 - 1) + >>> d + x*y1*y2*y3 - 1 + >>> syms + (x, y1, y2, y3) + + """ def make_poly(self, n): x, *y = syms = symbols("x, y1:{}".format(n+1)) @@ -157,25 +237,25 @@ def get_func_sparse(self, f, g, d, ring): class TimePREM_LinearDenseQuadraticGCD(_TimePREM): + """This case involves linearly dense quartic inputs with quadratic GCDs. + The quadratic GCD suggests that the pseudo remainder method could be + applicable and potentially efficient for computing the GCD of these + polynomials.""" + GCDExampleCLS = _LinearDenseQuadraticGCD params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. -class TimePREM_SparseGCDHighDegree(_TimePREM): - GCDExampleCLS = _SparseGCDHighDegree - params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')] - - class TimePREM_QuadraticNonMonicGCD(_TimePREM): + """This case deals with quadratic polynomials having a non-monic GCD. The + non-monic aspect may introduce additional complexities, but the quadratic + nature suggests that the pseudo remainder method could be useful. + """ + GCDExampleCLS = _QuadraticNonMonicGCD params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. -class TimePREM_SparseNonMonicQuadratic(_TimePREM): - GCDExampleCLS = _SparseNonMonicQuadratic - params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')] - - class _TimeSUBRESULTANTS(_TimeOP): """Benchmarks for subresultants PRS method""" @@ -203,7 +283,7 @@ class TimeSUBRESULTANTS_LinearDenseQuadraticGCD(_TimeSUBRESULTANTS): class TimeSUBRESULTANTS_SparseGCDHighDegree(_TimeSUBRESULTANTS): GCDExampleCLS = _SparseGCDHighDegree - params = [(1, 2, 3, 5), ('expr', 'dense', 'sparse')] + params = [(1, 3, 5), ('expr', 'dense', 'sparse')] class TimeSUBRESULTANTS_QuadraticNonMonicGCD(_TimeSUBRESULTANTS): @@ -213,4 +293,4 @@ class TimeSUBRESULTANTS_QuadraticNonMonicGCD(_TimeSUBRESULTANTS): class TimeSUBRESULTANTS_SparseNonMonicQuadratic(_TimeSUBRESULTANTS): GCDExampleCLS = _SparseNonMonicQuadratic - params = [(1, 2, 3, 5), ('expr', 'dense', 'sparse')] + params = [(1, 3, 5), ('expr', 'dense', 'sparse')] From 487e98188a35b2da95c44d636652f451b0884c54 Mon Sep 17 00:00:00 2001 From: Abhishek Patidar <1e9abhi1e10@gmail.com> Date: Wed, 19 Jul 2023 23:28:48 +0530 Subject: [PATCH 5/7] improve code quality --- benchmarks/polys.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/benchmarks/polys.py b/benchmarks/polys.py index 5cb25a9..438a4ee 100644 --- a/benchmarks/polys.py +++ b/benchmarks/polys.py @@ -197,9 +197,12 @@ def setup(self, n, impl): elif impl == 'dense': func = self.get_func_poly(*examples.as_poly()) if isinstance(expected, list): - expected = [examples.to_poly(polynomial) for polynomial in expected] # for the subresultants type methods the output is in form of list. + # for the subresultants type methods the output is in form of list. + expected = [examples.to_poly(polynomial) for polynomial in + expected] else: - expected = examples.to_poly(expected) # for those methods whose output is only a polynomial not a tuple or list. + # for those methods whose output is only a polynomial. + expected = examples.to_poly(expected) elif impl == 'sparse': func = self.get_func_sparse(*examples.as_ring()) From aded1b1bcaddcefebfb711a1fff0b70824e64705 Mon Sep 17 00:00:00 2001 From: Abhishek Patidar <1e9abhi1e10@gmail.com> Date: Wed, 19 Jul 2023 23:33:30 +0530 Subject: [PATCH 6/7] improve line wrapping --- benchmarks/polys.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/benchmarks/polys.py b/benchmarks/polys.py index 438a4ee..0869e95 100644 --- a/benchmarks/polys.py +++ b/benchmarks/polys.py @@ -48,7 +48,8 @@ def as_poly(self): return (self.to_poly(self.f), self.to_poly(self.g), self.to_poly(self.d)) def as_ring(self): - return (self.to_ring(self.f), self.to_ring(self.g), self.to_ring(self.d), self.ring) + return (self.to_ring(self.f), self.to_ring(self.g), self.to_ring(self. + d), self.ring) class _LinearDenseQuadraticGCD(_GCDExample): @@ -207,7 +208,8 @@ def setup(self, n, impl): elif impl == 'sparse': func = self.get_func_sparse(*examples.as_ring()) if isinstance(expected, list): - expected = [examples.to_ring(polynomial) for polynomial in expected] + expected = [examples.to_ring(polynomial) for polynomial in + expected] else: expected = examples.to_ring(expected) @@ -246,7 +248,8 @@ class TimePREM_LinearDenseQuadraticGCD(_TimePREM): polynomials.""" GCDExampleCLS = _LinearDenseQuadraticGCD - params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. + # This case is slow for n>5. + params = [(1, 3, 5), ('expr', 'dense', 'sparse')] class TimePREM_QuadraticNonMonicGCD(_TimePREM): @@ -256,7 +259,8 @@ class TimePREM_QuadraticNonMonicGCD(_TimePREM): """ GCDExampleCLS = _QuadraticNonMonicGCD - params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8. + # This case is slow for n>5. + params = [(1, 3, 5), ('expr', 'dense', 'sparse')] class _TimeSUBRESULTANTS(_TimeOP): @@ -281,7 +285,8 @@ def get_func_sparse(self, f, g, d, ring): class TimeSUBRESULTANTS_LinearDenseQuadraticGCD(_TimeSUBRESULTANTS): GCDExampleCLS = _LinearDenseQuadraticGCD - params = [(1, 2, 3), ('expr', 'dense', 'sparse')] # This case is slow for n>3. + # This case is slow for n>3. + params = [(1, 2, 3), ('expr', 'dense', 'sparse')] class TimeSUBRESULTANTS_SparseGCDHighDegree(_TimeSUBRESULTANTS): @@ -291,7 +296,8 @@ class TimeSUBRESULTANTS_SparseGCDHighDegree(_TimeSUBRESULTANTS): class TimeSUBRESULTANTS_QuadraticNonMonicGCD(_TimeSUBRESULTANTS): GCDExampleCLS = _QuadraticNonMonicGCD - params = [(1, 2, 3), ('expr', 'dense', 'sparse')] # This case is slow for n>3. + # This case is slow for n>3. + params = [(1, 2, 3), ('expr', 'dense', 'sparse')] class TimeSUBRESULTANTS_SparseNonMonicQuadratic(_TimeSUBRESULTANTS): From ef0a82436c3b8c7e45c24560ad0ff5c3cc2e9ef7 Mon Sep 17 00:00:00 2001 From: Abhishek Patidar <1e9abhi1e10@gmail.com> Date: Thu, 20 Jul 2023 14:11:52 +0530 Subject: [PATCH 7/7] improve formatting of code --- benchmarks/polys.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/benchmarks/polys.py b/benchmarks/polys.py index 0869e95..274d924 100644 --- a/benchmarks/polys.py +++ b/benchmarks/polys.py @@ -48,8 +48,7 @@ def as_poly(self): return (self.to_poly(self.f), self.to_poly(self.g), self.to_poly(self.d)) def as_ring(self): - return (self.to_ring(self.f), self.to_ring(self.g), self.to_ring(self. - d), self.ring) + return (self.to_ring(self.f), self.to_ring(self.g), self.to_ring(self.d), self.ring) class _LinearDenseQuadraticGCD(_GCDExample): @@ -198,18 +197,16 @@ def setup(self, n, impl): elif impl == 'dense': func = self.get_func_poly(*examples.as_poly()) if isinstance(expected, list): - # for the subresultants type methods the output is in form of list. - expected = [examples.to_poly(polynomial) for polynomial in - expected] + # some methods output a list of polynomials + expected = [examples.to_poly(p) for p in expected] else: - # for those methods whose output is only a polynomial. + # others output only a single polynomial. expected = examples.to_poly(expected) elif impl == 'sparse': func = self.get_func_sparse(*examples.as_ring()) if isinstance(expected, list): - expected = [examples.to_ring(polynomial) for polynomial in - expected] + expected = [examples.to_ring(p) for p in expected] else: expected = examples.to_ring(expected)