Skip to content

Commit d46fdb1

Browse files
committed
fix Times with infinite factors. I^q->(-1)^(q/2)
adding an option to mathics/test.py for storing errors in a log file. Fixing some tests. Fixing -Infinity. adding an option to mathics/test.py for storing errors in a log file. Fixing some tests. Fixing -Infinity.
1 parent 4f7c670 commit d46fdb1

10 files changed

Lines changed: 91 additions & 721 deletions

File tree

CHANGES.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Enhancements
2626
``Compile[] and CompiledFunction[]`` every expression can have a compiled form,
2727
as a Python function.
2828
* ``Equal[]`` now compares complex against other numbers properly.
29-
29+
* Improvements in handling products with infinite factors: ``0 Infinity``-> ``Indeterminate``, and ``expr Infinity``-> ``DirectedInfinite[expr]``
3030

3131
Bug fixes
3232
+++++++++

mathics/builtin/arithmetic.py

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from mathics.builtin.lists import _IterationFunction
4747
from mathics.core.convert import from_sympy, SympyExpression
4848

49+
4950
@lru_cache(maxsize=1024)
5051
def call_mpmath(mpmath_function, mpmath_args):
5152
try:
@@ -687,15 +688,14 @@ def apply(self, items, evaluation):
687688
)
688689
elif item.get_head().same(SymbolDirectedInfinity):
689690
infinity_factor = True
690-
direction = item.leaves[0]
691-
if isinstance(direction, Number):
692-
numbers.append(direction)
693-
else:
694-
leaves.append(direction)
695-
item.leaves[0]
696-
elif (item.same(SymbolInfinity) or item.same(SymbolComplexInfinity)):
691+
if len(item.leaves)>1:
692+
direction = item.leaves[0]
693+
if isinstance(direction, Number):
694+
numbers.append(direction)
695+
else:
696+
leaves.append(direction)
697+
elif item.same(SymbolInfinity) or item.same(SymbolComplexInfinity):
697698
infinity_factor = True
698-
item.leaves[0]
699699
else:
700700
leaves.append(item)
701701

@@ -720,7 +720,7 @@ def apply(self, items, evaluation):
720720
number = None
721721
elif number.is_zero:
722722
if infinity_factor:
723-
return Symbol('Indeterminate')
723+
return Symbol("Indeterminate")
724724
return number
725725
elif number.same(Integer(-1)) and leaves and leaves[0].has_form("Plus", None):
726726
leaves[0] = Expression(
@@ -733,16 +733,14 @@ def apply(self, items, evaluation):
733733
leaf.clear_cache()
734734

735735
if number is not None:
736-
if infinity_factor:
737-
number = Expression(SymbolDirectedInfinity,number/Expression("Abs",number))
738736
leaves.insert(0, number)
739737

740738
if not leaves:
741739
if infinity_factor:
742740
return SymbolInfinity
743741
return Integer(1)
744-
745-
elif len(leaves) == 1:
742+
743+
if len(leaves) == 1:
746744
ret = leaves[0]
747745
else:
748746
ret = Expression("Times", *leaves)
@@ -855,7 +853,7 @@ class Power(BinaryOperator, _MPMathFunction):
855853
856854
#> 1/0
857855
: Infinite expression 1 / 0 encountered.
858-
= ComplexInfinity
856+
= Infinity
859857
#> 0 ^ -2
860858
: Infinite expression 1 / 0 ^ 2 encountered.
861859
= ComplexInfinity
@@ -883,7 +881,7 @@ class Power(BinaryOperator, _MPMathFunction):
883881
#> (3/2+1/2I)^2
884882
= 2 + 3 I / 2
885883
#> I ^ I
886-
= I ^ I
884+
= -1 ^ (I / 2)
887885
888886
#> 2 ^ 2.0
889887
= 4.
@@ -916,7 +914,6 @@ class Power(BinaryOperator, _MPMathFunction):
916914
}
917915

918916
formats = {
919-
920917
Expression(
921918
"Power",
922919
Expression("Pattern", Symbol("x"), Expression("Blank")),
@@ -934,7 +931,7 @@ class Power(BinaryOperator, _MPMathFunction):
934931
),
935932
("", "x_?Negative ^ y_"): (
936933
'Infix[{HoldForm[(x)], HoldForm[y]},"^", 590, Right]'
937-
),
934+
),
938935
}
939936

940937
rules = {
@@ -963,8 +960,8 @@ def apply_check(self, x, y, evaluation):
963960
return Symbol("ComplexInfinity")
964961
if isinstance(x, Complex) and x.real.is_zero:
965962
yhalf = Expression("Times", y, Rational(1, 2))
966-
factor = self.apply(Expression("Sequence", x.imag, y), evaluation)
967-
return Expression("Times", factor , Expression("Power", Integer(-1), yhalf))
963+
factor = self.apply(Expression("Sequence", x.imag, y), evaluation)
964+
return Expression("Times", factor, Expression("Power", Integer(-1), yhalf))
968965

969966
result = self.apply(Expression("Sequence", x, y), evaluation)
970967
if result is None or result != SymbolNull:
@@ -1083,6 +1080,10 @@ class DirectedInfinity(SympyFunction):
10831080
: Indeterminate expression -Infinity + Infinity encountered.
10841081
= Indeterminate
10851082
1083+
>> DirectedInfinity[0]
1084+
: Indeterminate expression 0 Infinity encountered.
1085+
= Indeterminate
1086+
10861087
#> DirectedInfinity[1+I]+DirectedInfinity[2+I]
10871088
= (2 / 5 + I / 5) Sqrt[5] Infinity + (1 / 2 + I / 2) Sqrt[2] Infinity
10881089
@@ -1091,15 +1092,16 @@ class DirectedInfinity(SympyFunction):
10911092
"""
10921093

10931094
rules = {
1095+
"DirectedInfinity[Indeterminate]":"Indeterminate",
10941096
"DirectedInfinity[args___] ^ -1": "0",
10951097
"0 * DirectedInfinity[args___]": "Message[Infinity::indet, Unevaluated[0 DirectedInfinity[args]]]; Indeterminate",
10961098
"DirectedInfinity[a_?NumericQ] /; N[Abs[a]] != 1": "DirectedInfinity[a / Abs[a]]",
10971099
"DirectedInfinity[a_] * DirectedInfinity[b_]": "DirectedInfinity[a*b]",
10981100
"DirectedInfinity[] * DirectedInfinity[args___]": "DirectedInfinity[]",
10991101
"DirectedInfinity[0]": "DirectedInfinity[]",
1100-
# Rules already implemented in Times.apply
1101-
# "z_?NumberQ * DirectedInfinity[]": "DirectedInfinity[]",
1102-
# "z_?NumberQ * DirectedInfinity[a_]": "DirectedInfinity[z * a]",
1102+
# Rules already implemented in Times.apply
1103+
# "z_?NumberQ * DirectedInfinity[]": "DirectedInfinity[]",
1104+
# "z_?NumberQ * DirectedInfinity[a_]": "DirectedInfinity[z * a]",
11031105
"DirectedInfinity[a_] + DirectedInfinity[b_] /; b == -a": (
11041106
"Message[Infinity::indet,"
11051107
" Unevaluated[DirectedInfinity[a] + DirectedInfinity[b]]];"
@@ -1111,12 +1113,23 @@ class DirectedInfinity(SympyFunction):
11111113
"Indeterminate"
11121114
),
11131115
"DirectedInfinity[args___] + _?NumberQ": "DirectedInfinity[args]",
1116+
"DirectedInfinity[0]": (
1117+
"Message[Infinity::indet,"
1118+
" Unevaluated[DirectedInfinity[0]]];"
1119+
"Indeterminate"
1120+
),
1121+
"DirectedInfinity[0.]": (
1122+
"Message[Infinity::indet,"
1123+
" Unevaluated[DirectedInfinity[0.]]];"
1124+
"Indeterminate"
1125+
),
11141126
}
11151127

11161128
formats = {
11171129
"DirectedInfinity[1]": "HoldForm[Infinity]",
11181130
"DirectedInfinity[-1]": "HoldForm[-Infinity]",
11191131
"DirectedInfinity[]": "HoldForm[ComplexInfinity]",
1132+
"DirectedInfinity[DirectedInfinity[z_]]": "DirectedInfinity[z]",
11201133
"DirectedInfinity[z_?NumericQ]": "HoldForm[z Infinity]",
11211134
}
11221135

@@ -1304,19 +1317,12 @@ class Sign(SympyFunction):
13041317
def apply(self, x, evaluation):
13051318
"%(name)s[x_]"
13061319
# Sympy and mpmath do not give the desired form of complex number
1307-
print(x)
13081320
if isinstance(x, Complex):
13091321
return Expression("Times", x, Expression("Power", Expression("Abs", x), -1))
13101322

13111323
sympy_x = x.to_sympy()
13121324
if sympy_x is None:
1313-
print(x, " does not have a sympy form")
1314-
if x.is_zero():
1315-
return Real(0)
1316-
return Expression("Times", x,
1317-
Expression("Power",
1318-
Expression("Abs", x), -1)).evaluate(evaluation)
1319-
print(sympy_x)
1325+
return None
13201326
return super().apply(x)
13211327

13221328
def apply_error(self, x, seqs, evaluation):
@@ -1407,7 +1413,7 @@ def apply(self, expr, evaluation):
14071413
sympy_expr = expr.to_sympy()
14081414
result = _iszero(sympy_expr)
14091415
if result is None:
1410-
# try expanding the expression
1416+
# try expanding the expression
14111417
exprexp = Expression("ExpandAll", expr).evaluate(evaluation)
14121418
exprexp = exprexp.to_sympy()
14131419
result = _iszero(exprexp)

mathics/builtin/base.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ def get_sympy_names(self) -> typing.List[str]:
447447
return [self.sympy_name]
448448
return []
449449

450+
450451
class UnaryOperator(Operator):
451452
def __init__(self, format_function, *args, **kwargs):
452453
super().__init__(*args, **kwargs)
@@ -534,7 +535,6 @@ def apply(self, expr, evaluation) -> Symbol:
534535

535536

536537
class SympyFunction(SympyObject):
537-
538538
def apply(self, *args):
539539
"""
540540
Generic apply method that uses the class sympy_name.
@@ -585,8 +585,6 @@ def prepare_mathics(self, sympy_expr):
585585
return sympy_expr
586586

587587

588-
589-
590588
class InvalidLevelspecError(Exception):
591589
pass
592590

mathics/builtin/comparison.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from mathics.version import __version__ # noqa used in loading to check consistency.
55

6+
import itertools
67
from typing import Optional, Union
78

89
import sympy
@@ -217,7 +218,6 @@ class _EqualityOperator(_InequalityOperator):
217218
"Compares all pairs e.g. a == b == c compares a == b, b == c, and a == c."
218219

219220
def do_compare(self, l1, l2) -> Union[bool, None]:
220-
print("do_compare:", (l1,l2))
221221
if l1.same(l2):
222222
return True
223223
elif l1 == SymbolTrue and l2 == SymbolFalse:
@@ -275,13 +275,11 @@ def apply(self, items, evaluation):
275275
if n <= 1:
276276
return SymbolTrue
277277
is_exact_vals = [Expression("ExactNumberQ", arg).evaluate(evaluation) for arg in items_sequence]
278-
if all(test is SymbolTrue for test in is_exact_vals):
278+
if all(val == SymbolTrue for val in is_exact_vals):
279279
return self.apply_other(items, evaluation)
280280
args = self.numerify_args(items, evaluation)
281281
wanted = operators[self.get_name()]
282-
pairs = zip(args[:-1],args[1:])
283-
print("Compare.apply:", args)
284-
for x, y in pairs:
282+
for x, y in itertools.combinations(args, 2):
285283
if isinstance(x, String) or isinstance(y, String):
286284
if not (isinstance(x, String) and isinstance(y, String)):
287285
c = 1
@@ -299,9 +297,7 @@ def apply(self, items, evaluation):
299297
def apply_other(self, args, evaluation):
300298
"%(name)s[args___?(!ExactNumberQ[#]&)]"
301299
args = args.get_sequence()
302-
pairs = zip(args[:-1],args[1:])
303-
print("apply_other:", args)
304-
for x, y in pairs:
300+
for x, y in itertools.combinations(args, 2):
305301
c = self.do_compare(x, y)
306302
if c is None:
307303
return

mathics/builtin/inout.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,7 @@ class Check(Builtin):
14091409
14101410
#> Check[1/0, err, Compile::cpbool]
14111411
: Infinite expression 1 / 0 encountered.
1412-
= ComplexInfinity
1412+
= Infinity
14131413
14141414
#> Check[{0^0, 1/0}, err]
14151415
: Indeterminate expression 0 ^ 0 encountered.
@@ -1432,7 +1432,7 @@ class Check(Builtin):
14321432
14331433
#> Off[Power::infy]
14341434
#> Check[1 / 0, err]
1435-
= ComplexInfinity
1435+
= Infinity
14361436
14371437
#> On[Power::infy]
14381438
#> Check[1 / 0, err]
@@ -1627,7 +1627,7 @@ class Off(Builtin):
16271627
16281628
>> Off[Power::infy]
16291629
>> 1 / 0
1630-
= ComplexInfinity
1630+
= Infinity
16311631
16321632
>> Off[Power::indet, Syntax::com]
16331633
>> {0 ^ 0,}
@@ -1673,11 +1673,11 @@ class On(Builtin):
16731673
16741674
>> Off[Power::infy]
16751675
>> 1 / 0
1676-
= ComplexInfinity
1676+
= Infinity
16771677
>> On[Power::infy]
16781678
>> 1 / 0
16791679
: Infinite expression 1 / 0 encountered.
1680-
= ComplexInfinity
1680+
= Infinity
16811681
"""
16821682

16831683
# TODO

mathics/core/expression.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,6 +2018,7 @@ def __getnewargs__(self):
20182018
SymbolDirectedInfinity = Symbol("DirectedInfinity")
20192019
SymbolList = Symbol("List")
20202020

2021+
20212022
@lru_cache(maxsize=1024)
20222023
def from_mpmath(value, prec=None):
20232024
"Converts mpf or mpc to Number."

mathics/doc/documentation/1-Manual.mdoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ The precision of numerical evaluation can be set:
140140
Division by zero is forbidden:
141141
>> 1 / 0
142142
: Infinite expression 1 / 0 encountered.
143-
= ComplexInfinity
143+
= Infinity
144144
Other expressions involving 'Infinity' are evaluated:
145145
>> Infinity + 2 Infinity
146146
= Infinity

0 commit comments

Comments
 (0)