Skip to content

Commit f5a5b71

Browse files
mmaterarocky
authored andcommitted
Merge pull request #1209 from mathics/fixcomparisons
* Equal[] comparision use more specialized equal2 and sameQ instance methods to isolate logic. * Extensive comparison tests were added in test/test_compare.py which use make use of the Commutative property of Equal. * Equal, Unequal, SameQ and UnsameQ docs gone over and make explicit the commutative aspect of these operators * Integer1 symbolic constant introduced.
2 parents 40f8b58 + a908043 commit f5a5b71

File tree

11 files changed

+869
-187
lines changed

11 files changed

+869
-187
lines changed

mathics/builtin/algebra.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
Atom,
1111
Expression,
1212
Integer,
13+
Integer1,
1314
Number,
1415
Symbol,
1516
SymbolFalse,
@@ -151,10 +152,7 @@ def unconvert_subexprs(expr):
151152

152153
if deep:
153154
# thread over everything
154-
for (
155-
i,
156-
sub_expr,
157-
) in enumerate(sub_exprs):
155+
for (i, sub_expr,) in enumerate(sub_exprs):
158156
if not sub_expr.is_atom():
159157
head = _expand(sub_expr.head) # also expand head
160158
leaves = sub_expr.get_leaves()
@@ -497,17 +495,17 @@ class FactorTermsList(Builtin):
497495
def apply_list(self, expr, vars, evaluation):
498496
"FactorTermsList[expr_, vars_List]"
499497
if expr == Integer(0):
500-
return Expression("List", Integer(1), Integer(0))
498+
return Expression("List", Integer1, Integer(0))
501499
elif isinstance(expr, Number):
502-
return Expression("List", expr, Integer(1))
500+
return Expression("List", expr, Integer1)
503501

504502
for x in vars.leaves:
505503
if not (isinstance(x, Atom)):
506504
return evaluation.message("CoefficientList", "ivar", x)
507505

508506
sympy_expr = expr.to_sympy()
509507
if sympy_expr is None:
510-
return Expression("List", Integer(1), expr)
508+
return Expression("List", Integer1, expr)
511509
sympy_expr = sympy.together(sympy_expr)
512510

513511
sympy_vars = [
@@ -1160,7 +1158,7 @@ def apply_noform(self, expr, evaluation):
11601158

11611159
def apply(self, expr, form, evaluation):
11621160
"Coefficient[expr_, form_]"
1163-
return _coefficient(self.__class__.__name__, expr, form, Integer(1), evaluation)
1161+
return _coefficient(self.__class__.__name__, expr, form, Integer1, evaluation)
11641162

11651163
def apply_n(self, expr, form, n, evaluation):
11661164
"Coefficient[expr_, form_, n_]"
@@ -1401,7 +1399,7 @@ class Exponent(Builtin):
14011399

14021400
def apply_novar(self, expr, evaluation):
14031401
"Exponent[expr_]"
1404-
return evaluation.message("Exponent", "argtu", Integer(1))
1402+
return evaluation.message("Exponent", "argtu", Integer1)
14051403

14061404
def apply(self, expr, form, h, evaluation):
14071405
"Exponent[expr_, form_, h_]"

mathics/builtin/arithmetic.py

Lines changed: 126 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,21 @@
2626
Complex,
2727
Expression,
2828
Integer,
29+
Integer1,
2930
Number,
3031
Rational,
3132
Real,
3233
String,
3334
Symbol,
3435
SymbolComplexInfinity,
3536
SymbolDirectedInfinity,
36-
SymbolFalse,
3737
SymbolInfinity,
3838
SymbolN,
3939
SymbolNull,
4040
SymbolSequence,
4141
SymbolTrue,
42+
SymbolFalse,
43+
SymbolUndefined,
4244
from_mpmath,
4345
from_python,
4446
)
@@ -112,7 +114,7 @@ def apply(self, z, evaluation):
112114
if mpmath.isinf(result) and isinstance(result, mpmath.mpc):
113115
result = Symbol("ComplexInfinity")
114116
elif mpmath.isinf(result) and result > 0:
115-
result = Expression("DirectedInfinity", Integer(1))
117+
result = Expression("DirectedInfinity", Integer1)
116118
elif mpmath.isinf(result) and result < 0:
117119
result = Expression("DirectedInfinity", Integer(-1))
118120
elif mpmath.isnan(result):
@@ -260,7 +262,7 @@ def negate(item):
260262
if item.has_form("Times", 1, None):
261263
if isinstance(item.leaves[0], Number):
262264
neg = -item.leaves[0]
263-
if neg.sameQ(Integer(1)):
265+
if neg.sameQ(Integer1):
264266
if len(item.leaves) == 1:
265267
return neg
266268
else:
@@ -583,7 +585,7 @@ def inverse(item):
583585
item.leaves[1], (Integer, Rational, Real)
584586
):
585587
neg = -item.leaves[1]
586-
if neg.sameQ(Integer(1)):
588+
if neg.sameQ(Integer1):
587589
return item.leaves[0]
588590
else:
589591
return Expression("Power", item.leaves[0], neg)
@@ -603,7 +605,7 @@ def inverse(item):
603605
negative.append(inverse(item))
604606
elif isinstance(item, Rational):
605607
numerator = item.numerator()
606-
if not numerator.sameQ(Integer(1)):
608+
if not numerator.sameQ(Integer1):
607609
positive.append(numerator)
608610
negative.append(item.denominator())
609611
else:
@@ -618,7 +620,7 @@ def inverse(item):
618620
if positive:
619621
positive = create_infix(positive, op, 400, "None")
620622
else:
621-
positive = Integer(1)
623+
positive = Integer1
622624
if negative:
623625
negative = create_infix(negative, op, 400, "None")
624626
result = Expression(
@@ -675,18 +677,20 @@ def apply(self, items, evaluation):
675677
Expression("Plus", item.leaves[1], leaves[-1].leaves[1]),
676678
)
677679
elif (
678-
leaves and item.has_form("Power", 2) and item.leaves[0].sameQ(leaves[-1])
680+
leaves
681+
and item.has_form("Power", 2)
682+
and item.leaves[0].sameQ(leaves[-1])
679683
):
680684
leaves[-1] = Expression(
681-
"Power", leaves[-1], Expression("Plus", item.leaves[1], Integer(1))
685+
"Power", leaves[-1], Expression("Plus", item.leaves[1], Integer1)
682686
)
683687
elif (
684688
leaves
685689
and leaves[-1].has_form("Power", 2)
686690
and leaves[-1].leaves[0].sameQ(item)
687691
):
688692
leaves[-1] = Expression(
689-
"Power", item, Expression("Plus", Integer(1), leaves[-1].leaves[1])
693+
"Power", item, Expression("Plus", Integer1, leaves[-1].leaves[1])
690694
)
691695
elif item.get_head().sameQ(SymbolDirectedInfinity):
692696
infinity_factor = True
@@ -716,9 +720,9 @@ def apply(self, items, evaluation):
716720
number = sympy.Mul(*[item.to_sympy() for item in numbers])
717721
number = from_sympy(number)
718722
else:
719-
number = Integer(1)
723+
number = Integer1
720724

721-
if number.sameQ(Integer(1)):
725+
if number.sameQ(Integer1):
722726
number = None
723727
elif number.is_zero:
724728
if infinity_factor:
@@ -740,7 +744,7 @@ def apply(self, items, evaluation):
740744
if not leaves:
741745
if infinity_factor:
742746
return SymbolComplexInfinity
743-
return Integer(1)
747+
return Integer1
744748

745749
if len(leaves) == 1:
746750
ret = leaves[0]
@@ -1135,12 +1139,16 @@ class DirectedInfinity(SympyFunction):
11351139
}
11361140

11371141
def to_sympy(self, expr, **kwargs):
1138-
if len(expr.leaves) == 1:
1142+
if len(expr._leaves) == 1:
11391143
dir = expr.leaves[0].get_int_value()
11401144
if dir == 1:
11411145
return sympy.oo
11421146
elif dir == -1:
11431147
return -sympy.oo
1148+
else:
1149+
return sympy.Mul((expr._leaves[0].to_sympy()), sympy.zoo)
1150+
else:
1151+
return sympy.zoo
11441152

11451153

11461154
class Re(SympyFunction):
@@ -1347,7 +1355,7 @@ class I(Predefined):
13471355
python_equivalent = 1j
13481356

13491357
def evaluate(self, evaluation):
1350-
return Complex(Integer(0), Integer(1))
1358+
return Complex(Integer(0), Integer1)
13511359

13521360

13531361
class NumberQ(Test):
@@ -2201,7 +2209,110 @@ def apply(self, expr, evaluation):
22012209
"%(name)s[expr_]"
22022210
if isinstance(expr, Symbol):
22032211
if expr == SymbolTrue:
2204-
return Integer(1)
2212+
return Integer1
22052213
elif expr == SymbolFalse:
22062214
return Integer(0)
22072215
return None
2216+
2217+
2218+
class Assumptions(Predefined):
2219+
"""
2220+
<dl>
2221+
<dt>'$Assumptions'
2222+
<dd>is the default setting for the Assumptions option used in such
2223+
functions as Simplify, Refine, and Integrate.
2224+
</dl>
2225+
"""
2226+
2227+
name = "$Assumptions"
2228+
attributes = ("Unprotected",)
2229+
rules = {
2230+
"$Assumptions": "True",
2231+
}
2232+
2233+
2234+
class Assuming(Builtin):
2235+
"""
2236+
<dl>
2237+
<dt>'Assuming[$cond$, $expr$]'
2238+
<dd>Evaluates $expr$ assuming the conditions $cond$
2239+
</dl>
2240+
>> $Assumptions = { x > 0 }
2241+
= {x > 0}
2242+
>> Assuming[y>0, $Assumptions]
2243+
= {x > 0, y > 0}
2244+
"""
2245+
2246+
attributes = ("HoldRest",)
2247+
2248+
def apply_assuming(self, cond, expr, evaluation):
2249+
"Assuming[cond_, expr_]"
2250+
cond = cond.evaluate(evaluation)
2251+
if cond.is_true():
2252+
cond = []
2253+
elif cond.is_symbol() or not cond.has_form("List", None):
2254+
cond = [cond]
2255+
else:
2256+
cond = cond.leaves
2257+
assumptions = evaluation.definitions.get_definition(
2258+
"System`$Assumptions", only_if_exists=True
2259+
)
2260+
2261+
if assumptions:
2262+
assumptions = assumptions.ownvalues
2263+
if len(assumptions) > 0:
2264+
assumptions = assumptions[0].replace
2265+
else:
2266+
assumptions = None
2267+
if assumptions:
2268+
if assumptions.is_symbol() or not assumptions.has_form("List", None):
2269+
assumptions = [assumptions]
2270+
else:
2271+
assumptions = assumptions.leaves
2272+
cond = assumptions + tuple(cond)
2273+
Expression(
2274+
"Set", Symbol("System`$Assumptions"), Expression("List", *cond)
2275+
).evaluate(evaluation)
2276+
ret = expr.evaluate(evaluation)
2277+
if assumptions:
2278+
Expression(
2279+
"Set", Symbol("System`$Assumptions"), Expression("List", *assumptions)
2280+
).evaluate(evaluation)
2281+
else:
2282+
Expression(
2283+
"Set", Symbol("System`$Assumptions"), Expression("List", SymbolTrue)
2284+
).evaluate(evaluation)
2285+
return ret
2286+
2287+
2288+
class ConditionalExpression(Builtin):
2289+
"""
2290+
<dl>
2291+
<dt>'ConditionalExpression[$expr$, $cond$]'
2292+
<dd>returns $expr$ if $cond$ evaluates to $True$, $Undefined$ if
2293+
$cond$ evaluates to $False$.
2294+
</dl>
2295+
2296+
>> f = ConditionalExpression[x^2, x>0]
2297+
= ConditionalExpression[x ^ 2, x > 0]
2298+
>> f /. x -> 2
2299+
= 4
2300+
>> f /. x -> -2
2301+
= Undefined
2302+
"""
2303+
2304+
rules = {
2305+
"ConditionalExpression[expr_, True]": "expr",
2306+
"ConditionalExpression[expr_, False]": "Undefined",
2307+
}
2308+
2309+
def apply_generic(self, expr, cond, evaluation):
2310+
"ConditionalExpression[expr_, cond_]"
2311+
cond = cond.evaluate(evaluation)
2312+
if cond is None:
2313+
return
2314+
if cond.is_true():
2315+
return expr
2316+
if cond == SymbolFalse:
2317+
return SymbolUndefined
2318+
return

mathics/builtin/calculus.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from mathics.core.expression import (
1010
Expression,
1111
Integer,
12+
Integer1,
1213
Number,
1314
SymbolTrue,
1415
SymbolFalse,
@@ -148,11 +149,9 @@ def apply(self, f, x, evaluation):
148149
"D[f_, x_?NotListQ]"
149150

150151
if f == x:
151-
return Integer(1)
152+
return Integer1
152153
elif not f.is_atom() and len(f.leaves) == 1 and f.leaves[0] == x:
153-
return Expression(
154-
Expression(Expression("Derivative", Integer(1)), f.head), x
155-
)
154+
return Expression(Expression(Expression("Derivative", Integer1), f.head), x)
156155
elif not f.is_atom() and len(f.leaves) == 1:
157156
g = f.leaves[0]
158157
return Expression(
@@ -170,7 +169,7 @@ def summand(leaf, index):
170169
"Derivative",
171170
*(
172171
[Integer(0)] * (index)
173-
+ [Integer(1)]
172+
+ [Integer1]
174173
+ [Integer(0)] * (len(f.leaves) - index - 1)
175174
)
176175
),
@@ -667,7 +666,7 @@ class Solve(Builtin):
667666
>> sol = Solve[eqs, {x, y}] // Simplify
668667
= {{x -> 0, y -> 0}, {x -> 1, y -> 1}, {x -> -1 / 2 + I / 2 Sqrt[3], y -> -1 / 2 - I / 2 Sqrt[3]}, {x -> (1 - I Sqrt[3]) ^ 2 / 4, y -> -1 / 2 + I / 2 Sqrt[3]}}
669668
>> eqs /. sol // Simplify
670-
= {{True, True}, {True, True}, {False, False}, {True, True}}
669+
= {{True, True}, {True, True}, {True, True}, {True, True}}
671670
672671
An underdetermined system:
673672
>> Solve[x^2 == 1 && z^2 == -1, {x, y, z}]

0 commit comments

Comments
 (0)