Skip to content

Commit

Permalink
Improve PolynomialQ[] one arg...
Browse files Browse the repository at this point in the history
We now handle a variable functions, e.g. x[1], x[6], etc.

Simplfy some argument processing.
  • Loading branch information
rocky committed Dec 23, 2024
1 parent 6b19e87 commit 23bcb52
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 17 deletions.
17 changes: 13 additions & 4 deletions mathics/builtin/numbers/algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import sympy

import mathics.eval.tracing as tracing
from mathics.builtin.options import options_to_rules
from mathics.builtin.scoping import dynamic_scoping
from mathics.core.atoms import (
Expand All @@ -30,7 +31,7 @@
from mathics.core.attributes import A_LISTABLE, A_PROTECTED
from mathics.core.builtin import Builtin
from mathics.core.convert.python import from_bool
from mathics.core.convert.sympy import from_sympy, sympy_symbol_prefix
from mathics.core.convert.sympy import SympyExpression, from_sympy, sympy_symbol_prefix
from mathics.core.element import BaseElement
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
Expand Down Expand Up @@ -1808,8 +1809,14 @@ def eval(self, expr, v, evaluation):
evaluation.message("PolynomialQ", "argt", Integer(len(v) + 1))
return
elif len(v) == 0:
sympy_expr = expr.to_sympy()
sympy_result = sympy_expr.is_polynomial()
sympy_expr = expr.to_sympy(convert_functions_for_polynomialq=True)
sympy_result = tracing.run_sympy(
sympy_expr.is_polynomial,
*[
SympyExpression(free_symbol)
for free_symbol in sympy_expr.free_symbols
],
)
return from_bool(sympy_result)

var = v[0]
Expand All @@ -1824,7 +1831,9 @@ def eval(self, expr, v, evaluation):
sympy_var = [var.to_sympy()]

sympy_expr = expr.to_sympy()
sympy_result = sympy_expr.is_polynomial(*[x for x in sympy_var])
sympy_result = tracing.run_sympy(
sympy_expr.is_polynomial, *[x for x in sympy_var]
)
return from_bool(sympy_result)


Expand Down
24 changes: 14 additions & 10 deletions mathics/core/convert/sympy.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class SympyExpression(BasicSympy):
nargs = None
expr: Expression

def __new__(cls, *exprs):
def __new__(cls, *exprs, **kwargs):
# sympy simplify may also recreate the object if simplification occurred
# in the elements

Expand All @@ -148,7 +148,10 @@ def __new__(cls, *exprs):
# called with Mathics argument
expr = exprs[0]
sympy_head = expr.head.to_sympy()
sympy_elements = [element.to_sympy() for element in expr.elements]
if kwargs.get("convert_functions_for_polynomialq", False):
sympy_elements = []
else:
sympy_elements = [element.to_sympy() for element in expr.elements]
if sympy_head is None or None in sympy_elements:
return None
obj = super().__new__(cls, sympy_head, *sympy_elements)
Expand Down Expand Up @@ -226,14 +229,15 @@ def expression_to_sympy(expr: Expression, **kwargs):
Convert `expr` to its sympy form.
"""

if "convert_all_global_functions" in kwargs:
if len(expr.elements) > 0 and kwargs["convert_all_global_functions"]:
if expr.get_head_name().startswith("Global`"):
return expr._as_sympy_function(**kwargs)
if len(expr.elements) > 0:
head_name = expr.get_head_name()
if head_name.startswith("Global`"):
if kwargs.get("convert_all_global_functions", False):
if expr.get_head_name().startswith("Global`"):
return expr._as_sympy_function(**kwargs)

if "converted_functions" in kwargs:
functions = kwargs["converted_functions"]
if len(expr._elements) > 0 and expr.get_head_name() in functions:
functions = kwargs.get("converted_functions", [])
if head_name in functions:
sym_args = [element.to_sympy() for element in expr._elements]
if None in sym_args:
return None
Expand All @@ -248,7 +252,7 @@ def expression_to_sympy(expr: Expression, **kwargs):
sympy_expr = builtin.to_sympy(expr, **kwargs)
if sympy_expr is not None:
return sympy_expr
return SympyExpression(expr)
return SympyExpression(expr, **kwargs)


def symbol_to_sympy(symbol: Symbol, **kwargs) -> Sympy_Symbol:
Expand Down
11 changes: 9 additions & 2 deletions mathics/core/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,15 +322,22 @@ def __str__(self) -> str:
", ".join([str(element) for element in self.elements]),
)

def _as_sympy_function(self, **kwargs) -> Optional[sympy.Function]:
def _as_sympy_function(self, **kwargs):
from mathics.core.convert.sympy import sympy_symbol_prefix

function_name = str(sympy_symbol_prefix + self.get_head_name())
f = sympy.Function(function_name)

if kwargs.get("convert_functions_for_polynomial", False):
# For polynomials, we ignore the arguments in a PolynomialQ
return f()

f = sympy.Function(function_name)
sym_args = [element.to_sympy(**kwargs) for element in self._elements]

if None in sym_args:
return None

f = sympy.Function(str(sympy_symbol_prefix + self.get_head_name()))
return f(*sym_args)

# Note: this function is called a *lot* so it needs to be fast.
Expand Down
2 changes: 1 addition & 1 deletion mathics/packages/Combinatorica-repo
9 changes: 9 additions & 0 deletions test/builtin/numbers/test_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,15 @@ def test_factor_terms_list():
check_evaluation(str_expr, str_expected)


def test_polynomialq():
for str_expr, str_expected in [
("PolynomialQ[1/x[1]^2]", "False"),
("PolynomialQ[x[1]^2]", "True"),
("PolynomialQ[y[1] ^ 3 / 6 + y[3] / 3 + y[1] y[2] / 2]", "True"),
]:
check_evaluation(str_expr, str_expected)


def test_simplify():
for str_expr, str_expected in (
(
Expand Down

0 comments on commit 23bcb52

Please sign in to comment.