@@ -256,6 +256,13 @@ def eval_Sign(expr: BaseElement) -> Optional[BaseElement]:
256
256
"""
257
257
if expr is a number, return its sign.
258
258
"""
259
+ sympy_expr = expr .to_sympy ()
260
+ if sympy_expr is not None :
261
+ print (" sympy_expr" , sympy_expr )
262
+ result = from_sympy (sympy .sign (sympy_expr ))
263
+ if result is not None :
264
+ return result
265
+ return None
259
266
260
267
def eval_complex_sign (n : BaseElement ) -> Optional [BaseElement ]:
261
268
if isinstance (n , Complex ):
@@ -694,36 +701,6 @@ def eval_Times(*items: BaseElement) -> BaseElement:
694
701
)
695
702
696
703
697
- # Here I used the convention of calling eval_* to functions that can produce a new expression, or None
698
- # if the result can not be evaluated, or is trivial. For example, if we call eval_Power_number(Integer2, RationalOneHalf)
699
- # it returns ``None`` instead of ``Expression(SymbolPower, Integer2, RationalOneHalf)``.
700
- # The reason is that these functions are written to be part of replacement rules, to be applied during the evaluation process.
701
- # In that process, a rule is considered applied if produces an expression that is different from the original one, or
702
- # if the replacement function returns (Python's) ``None``.
703
- #
704
- # For example, when the expression ``Power[4, 1/2]`` is evaluated, a (Builtin) rule ``Power[base_, exp_]->eval_repl_rule(base, expr)``
705
- # is applied. If the rule matches, `repl_rule` is called with arguments ``(4, 1/2)`` and produces `2`. As `Integer2.sameQ(Power[4, 1/2])`
706
- # is False, then no new rules for `Power` are checked, and a new round of evaluation is atempted.
707
- #
708
- # On the other hand, if ``Power[3, 1/2]``, ``repl_rule`` can do two possible things: one is return ``Power[3, 1/2]``. If it does,
709
- # the rule is considered applied. Then, the evaluation method checks if `Power[3, 1/2].sameQ(Power[3, 1/2])`. In this case it is true,
710
- # and then the expression is kept as it is.
711
- # The other possibility is to return (Python's) `None`. In that case, the evaluator considers that the rule failed to be applied,
712
- # and look for another rule associated to ``Power``. To return ``None`` produces then a faster evaluation, since no ``sameQ`` call is needed,
713
- # and do not prevent that other rules are attempted.
714
- #
715
- # The bad part of using ``None`` as a return is that I would expect that ``eval`` produces always a valid Expression, so if at some point of
716
- # the code I call ``eval_Power_number(Integer3, RationalOneHalf)`` I get ``Expression(SymbolPower, Integer3, RationalOneHalf)``.
717
- #
718
- # From my point of view, it would make more sense to use the following convention:
719
- # * if the method has signature ``eval_method(...)->BaseElement:`` then use the prefix ``eval_``
720
- # * if the method has the siguature ``apply_method(...)->Optional[BaseElement]`` use the prefix ``apply_`` or maybe ``repl_``.
721
- #
722
- # In any case, let's keep the current convention.
723
- #
724
- #
725
-
726
-
727
704
def associate_powers (expr : BaseElement , power : BaseElement = Integer1 ) -> BaseElement :
728
705
"""
729
706
base^a^b^c^...^power -> base^(a*b*c*...power)
0 commit comments