Skip to content

Commit

Permalink
Merge pull request #94 from 1e9abhi1e10/subresultant
Browse files Browse the repository at this point in the history
Add benchmarks for subresultants PRS method
  • Loading branch information
oscarbenjamin authored Jul 20, 2023
2 parents ece1ec2 + ef0a824 commit 8b75a9a
Showing 1 changed file with 150 additions and 14 deletions.
164 changes: 150 additions & 14 deletions benchmarks/polys.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sympy import symbols, prod, prem, rem, degree, LC
from sympy import symbols, prod, prem, rem, degree, LC, subresultants
from sympy.polys import QQ, Poly


Expand Down Expand Up @@ -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))
Expand All @@ -61,8 +81,29 @@ 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."""
"""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))
Expand All @@ -73,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))
Expand All @@ -84,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))
Expand All @@ -93,6 +174,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.
Expand All @@ -111,12 +193,22 @@ 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):
# some methods output a list of polynomials
expected = [examples.to_poly(p) for p in expected]
else:
# others output only a single polynomial.
expected = examples.to_poly(expected)

elif impl == 'sparse':
func = self.get_func_sparse(*examples.as_ring())
expected = examples.to_ring(expected)
if isinstance(expected, list):
expected = [examples.to_ring(p) for p in expected]
else:
expected = examples.to_ring(expected)

self.func = func
self.expected_result = expected
Expand Down Expand Up @@ -147,20 +239,64 @@ 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
# This case is slow for n>5.
params = [(1, 3, 5), ('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
# This case is slow for n>5.
params = [(1, 3, 5), ('expr', 'dense', 'sparse')]


class _TimeSUBRESULTANTS(_TimeOP):
"""Benchmarks for subresultants PRS method"""

def expected(self, f, g, d, syms):
x = syms[0]
subresultant = subresultants(f, g, x)

return 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.
# This case is slow for n>3.
params = [(1, 2, 3), ('expr', 'dense', 'sparse')]


class TimePREM_SparseGCDHighDegree(_TimePREM):
class TimeSUBRESULTANTS_SparseGCDHighDegree(_TimeSUBRESULTANTS):
GCDExampleCLS = _SparseGCDHighDegree
params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')]
params = [(1, 3, 5), ('expr', 'dense', 'sparse')]


class TimePREM_QuadraticNonMonicGCD(_TimePREM):
class TimeSUBRESULTANTS_QuadraticNonMonicGCD(_TimeSUBRESULTANTS):
GCDExampleCLS = _QuadraticNonMonicGCD
params = [(1, 3, 5), ('expr', 'dense', 'sparse')] # This case is slow for n=8.
# This case is slow for n>3.
params = [(1, 2, 3), ('expr', 'dense', 'sparse')]


class TimePREM_SparseNonMonicQuadratic(_TimePREM):
class TimeSUBRESULTANTS_SparseNonMonicQuadratic(_TimeSUBRESULTANTS):
GCDExampleCLS = _SparseNonMonicQuadratic
params = [(1, 3, 5, 8), ('expr', 'dense', 'sparse')]
params = [(1, 3, 5), ('expr', 'dense', 'sparse')]

0 comments on commit 8b75a9a

Please sign in to comment.