Skip to content

Commit 1774535

Browse files
committed
merge constant-method-option
2 parents a1f3fe5 + 09afe33 commit 1774535

7 files changed

Lines changed: 166 additions & 82 deletions

File tree

mathics/builtin/assignment.py

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -861,20 +861,27 @@ class Information(PrefixOperator):
861861
'Information' does not print information for 'ReadProtected' symbols.
862862
'Information' uses 'InputForm' to format values.
863863
864+
#> a = 2;
865+
#> Information[a]
866+
| a = 2
867+
.
868+
= Null
864869
865-
>> a = 2;
866-
>> Information[a]
867-
= a = 2
868-
870+
#> f[x_] := x ^ 2;
871+
#> g[f] ^:= 2;
872+
#> f::usage = "f[x] returns the square of x";
873+
#> Information[f]
874+
| f[x] returns the square of x
875+
.
876+
. f[x_] = x ^ 2
877+
.
878+
. g[f] ^= 2
879+
.
880+
= Null
869881
870-
>> f[x_] := x ^ 2
871-
>> g[f] ^:= 2
872-
>> f::usage = "f[x] returns the square of x";
873-
X> Information[f]
874-
= f[x] returns the square of x
875882
876-
>> ? Table
877-
=
883+
#> ? Table
884+
|
878885
. 'Table[expr, {i, n}]'
879886
. evaluates expr with i ranging from 1 to n, returning
880887
. a list of the results.
@@ -885,9 +892,10 @@ class Information(PrefixOperator):
885892
. evaluates expr with i taking on the values e1, e2,
886893
. ..., ei.
887894
.
895+
= Null
888896
889-
>> Information[Table]
890-
=
897+
#> Information[Table]
898+
|
891899
. 'Table[expr, {i, n}]'
892900
. evaluates expr with i ranging from 1 to n, returning
893901
. a list of the results.
@@ -900,6 +908,7 @@ class Information(PrefixOperator):
900908
.
901909
. Attributes[Table] = {HoldAll, Protected}
902910
.
911+
= Null
903912
"""
904913

905914
operator = "??"
@@ -910,15 +919,14 @@ class Information(PrefixOperator):
910919

911920
def format_definition(self, symbol, evaluation, options, grid=True):
912921
'StandardForm,TraditionalForm,OutputForm: Information[symbol_, OptionsPattern[Information]]'
913-
from mathics.core.expression import from_python
922+
ret = Symbol('Null')
914923
lines = []
915924
if isinstance(symbol, String):
916925
evaluation.print_out(symbol)
917-
evaluation.evaluate(Expression('Information', Symbol('System`String')))
918-
return
926+
return ret
919927
if not isinstance(symbol, Symbol):
920928
evaluation.message('Information', 'notfound', symbol)
921-
return Symbol('Null')
929+
return ret
922930
# Print the "usage" message if available.
923931
usagetext = _get_usage_string(symbol, evaluation)
924932
if usagetext is not None:
@@ -929,17 +937,16 @@ def format_definition(self, symbol, evaluation, options, grid=True):
929937

930938
if grid:
931939
if lines:
932-
return Expression(
940+
infoshow = Expression(
933941
'Grid', Expression(
934942
'List', *(Expression('List', line) for line in lines)),
935943
Expression(
936944
'Rule', Symbol('ColumnAlignments'), Symbol('Left')))
937-
else:
938-
return Symbol('Null')
945+
evaluation.print_out(infoshow)
939946
else:
940947
for line in lines:
941948
evaluation.print_out(Expression('InputForm', line))
942-
return Symbol('Null')
949+
return ret
943950

944951
# It would be deserable to call here the routine inside Definition, but for some reason it fails...
945952
# Instead, I just copy the code from Definition
@@ -1006,7 +1013,9 @@ def rhs(expr):
10061013

10071014
def format_definition_input(self, symbol, evaluation, options):
10081015
'InputForm: Information[symbol_, OptionsPattern[Information]]'
1009-
return self.format_definition(symbol, evaluation, options, grid=False)
1016+
self.format_definition(symbol, evaluation, options, grid=False)
1017+
ret = Symbol("Null")
1018+
return ret
10101019

10111020

10121021
class Clear(Builtin):

mathics/builtin/constants.py

Lines changed: 107 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
Symbol,
2020
strip_context,
2121
)
22-
from mathics.core.numbers import get_precision, PrecisionValueError
22+
from mathics.core.numbers import get_precision, PrecisionValueError, machine_precision
2323

2424

2525
def mp_constant(fn: str, d=None) -> mpmath.ctx_mp_python.mpf:
@@ -29,7 +29,11 @@ def mp_constant(fn: str, d=None) -> mpmath.ctx_mp_python.mpf:
2929
if d is None:
3030
return getattr(mpmath, fn)()
3131
else:
32-
mpmath.mp.dps = int_d = int(d)
32+
# TODO: In some functions like Pi, you can
33+
# ask for a certain number of digits, but the
34+
# accuracy will be less than that. Figure out
35+
# what's up and compensate somehow.
36+
mpmath.mp.dps = int_d = int(d * 3.321928)
3337
return getattr(mpmath, fn)(prec=int_d)
3438

3539

@@ -43,7 +47,16 @@ def mp_convert_constant(obj, **kwargs):
4347

4448

4549
def numpy_constant(name: str, d=None) -> float:
46-
return getattr(numpy, name)
50+
if d:
51+
# by mmatera: Here I have a question:
52+
# 0.0123`2 should be rounded to
53+
# 0.01 or to 0.0123?
54+
# (absolute versus relative accuracy)
55+
val = getattr(numpy, name)
56+
val = numpy.round(val, d)
57+
return val
58+
else:
59+
return getattr(numpy, name)
4760

4861

4962
def sympy_constant(fn, d=None):
@@ -54,46 +67,75 @@ class _Constant_Common(Predefined):
5467

5568
attributes = ("Constant", "Protected", "ReadProtected")
5669
nargs = 0
70+
options = {"Method": "Automatic"}
5771

58-
def apply_N(self, precision, evaluation):
59-
"N[%(name)s, precision_]"
60-
return self.get_constant(precision, evaluation)
72+
def apply_N(self, precision, evaluation, options={}):
73+
"N[%(name)s, precision_?NumericQ, OptionsPattern[%(name)s]]"
74+
75+
preference = self.get_option(options, "Method", evaluation).get_string_value()
76+
if preference == "Automatic":
77+
return self.get_constant(precision, evaluation)
78+
else:
79+
return self.get_constant(precision, evaluation, preference)
80+
81+
def apply_N2(self, evaluation, options={}):
82+
"N[%(name)s, OptionsPattern[%(name)s]]"
83+
return self.apply_N(None, evaluation, options)
6184

6285
def is_constant(self) -> bool:
6386
return True
6487

6588
def get_constant(self, precision, evaluation, preference=None):
66-
## print("XXX", self, preference)
67-
if preference is None:
68-
preference = (
69-
evaluation.parse("Settings`$PreferredBackendMethod")
70-
.evaluate(evaluation)
71-
.get_string_value()
72-
)
73-
# TODO: validate PreferredBackendMethod is in "mpmath", "numpy", "sympy"
74-
try:
75-
d = get_precision(precision, evaluation)
76-
except PrecisionValueError:
77-
d = None
89+
# first, determine the precision
90+
machine_d = int( 0.30103 * machine_precision)
91+
d = None
92+
if precision:
93+
try:
94+
d = get_precision(precision, evaluation)
95+
except PrecisionValueError:
96+
pass
7897

79-
conversion_fn = MachineReal if d is None else PrecisionReal
80-
81-
# print("XXX1", self, preference, conversion_fn)
98+
if d is None:
99+
d = machine_d
82100

83-
if preference == "sympy" and hasattr(self, "sympy_name"):
84-
value = sympy_constant(self.sympy_name, d)
85-
elif preference == "mpmath" and hasattr(self, "mpmath_name"):
86-
value = mp_constant(self.mpmath_name, d)
87-
elif preference == "numpy" and hasattr(self, "numpy_name"):
88-
value = numpy_constant(self.numpy_name)
89-
elif hasattr(self, "mpmath_name"):
90-
value = mp_constant(self.mpmath_name, d)
91-
elif hasattr(self, "sympy_name"):
92-
value = sympy_constant(self.sympy_name, d)
93-
elif hasattr(self, "numpy_name"):
101+
# If preference not especified, determine it
102+
# from the precision.
103+
if preference is None:
104+
if d <= machine_d:
105+
preference = "numpy"
106+
else:
107+
preference = "mpmath"
108+
# If preference is not valid, send a message and return.
109+
if not (preference in ("sympy", "numpy", "mpmath")):
110+
evaluation.message(f'{preference} not in ("sympy", "numpy", "mpmath")')
111+
return
112+
# Try to determine the numeric value
113+
value = None
114+
if preference == "mpmath" and not hasattr(self, "mpmath_name"):
115+
preference = "numpy"
116+
elif preference == "sympy" and not hasattr(self, "sympy_name"):
117+
preference = "numpy"
118+
119+
if preference == "numpy" and not hasattr(self, "numpy_name"):
120+
if hasattr(self, "sympy_name"):
121+
preference = "sympy"
122+
elif hasattr(self, "mpmath_name"):
123+
preference = "mpmath"
124+
else:
125+
preference = ""
126+
if preference == "numpy":
94127
value = numpy_constant(self.numpy_name)
95-
return conversion_fn(value)
96-
128+
if d == machine_d:
129+
return MachineReal(value)
130+
if preference == "sympy":
131+
value = sympy_constant(self.sympy_name, d+2)
132+
if preference == "mpmath":
133+
value = mp_constant(self.mpmath_name, d*2)
134+
if value:
135+
return PrecisionReal(sympy.Float(str(value), d))
136+
# If the value is not available, return none
137+
# and keep it unevaluated.
138+
return
97139

98140
class MPMathConstant(_Constant_Common):
99141
"""Representation of a constant in mpmath, e.g. Pi, E, I, etc."""
@@ -152,22 +194,22 @@ def to_sympy(self, expr=None, **kwargs):
152194
return None
153195

154196

155-
class Catalan(MPMathConstant, NumpyConstant, SympyConstant):
197+
class Catalan(MPMathConstant, SympyConstant):
156198
"""
157199
<dl>
158200
<dt>'Catalan'
159201
<dd>is Catalan's constant with numerical value \u2243 0.915966.
160202
</dl>
161203
162204
>> Catalan // N
163-
= 0.915966
205+
= 0.915965594177219
164206
165207
>> N[Catalan, 20]
166208
= 0.91596559417721901505
167209
"""
168210

169211
mpmath_name = "catalan"
170-
numpy_name = "catalan"
212+
# numpy_name = "catalan" ## This is not defined in numpy
171213
sympy_name = "Catalan"
172214

173215

@@ -239,10 +281,13 @@ def to_numpy(self, expr=None, **kwargs):
239281
# return mpmath.degree
240282
return numpy.pi / 180
241283

242-
def apply_N(self, precision, evaluation):
243-
"N[Degree, precision_]"
284+
def apply_N(self, precision, evaluation, options={}):
285+
"N[Degree, precision_, OptionsPattern[%(name)s]]"
244286
try:
245-
d = get_precision(precision, evaluation)
287+
if precision:
288+
d = get_precision(precision, evaluation)
289+
else:
290+
d = get_precision(Symbol("System`MachinePrecision"), evaluation)
246291
except PrecisionValueError:
247292
return
248293

@@ -278,8 +323,8 @@ class E(MPMathConstant, NumpyConstant, SympyConstant):
278323
numpy_name = "e"
279324
sympy_name = "E"
280325

281-
def apply_N(self, precision, evaluation):
282-
"N[E, precision_]"
326+
def apply_N(self, precision, evaluation, options={}):
327+
"N[E, precision_, OptionsPattern[%(name)s]]"
283328
return self.get_constant(precision, evaluation)
284329

285330

@@ -310,9 +355,10 @@ class Glaisher(MPMathConstant):
310355
</dl>
311356
312357
>> N[Glaisher]
313-
= 1.28243
358+
= 1.28242712910062
314359
>> N[Glaisher, 50]
315-
= 1.2824271291006219541941391071304678916931152343750
360+
= 1.2824271291006226368753425688697917277676889273250
361+
# 1.2824271291006219541941391071304678916931152343750
316362
"""
317363

318364
mpmath_name = "glaisher"
@@ -326,7 +372,7 @@ class GoldenRatio(MPMathConstant, SympyConstant):
326372
</dl>
327373
328374
>> GoldenRatio // N
329-
= 1.61803
375+
= 1.61803398874989
330376
>> N[GoldenRatio, 40]
331377
= 1.618033988749894848204586834365638117720
332378
"""
@@ -399,9 +445,10 @@ class Khinchin(MPMathConstant):
399445
</dl>
400446
401447
>> N[Khinchin]
402-
= 2.68545
448+
= 2.68545200106531
403449
>> N[Khinchin, 50]
404-
= 2.6854520010653075701156922150403261184692382812500
450+
= 2.6854520010653064453097148354817956938203822939945
451+
# = 2.6854520010653075701156922150403261184692382812500
405452
"""
406453

407454
mpmath_name = "khinchin"
@@ -416,7 +463,19 @@ class Pi(MPMathConstant, SympyConstant):
416463
417464
>> N[Pi]
418465
= 3.14159
419-
>> N[Pi, 50]
466+
467+
Force using the value given from numpy to compute Pi.
468+
>> N[Pi, Method->"numpy"]
469+
= 3.14159
470+
471+
Force using the value given from sympy to compute Pi to 3 places,
472+
two places after the decimal point.
473+
474+
Note that sympy is the default method.
475+
>> N[Pi, 3, Method->"sympy"]
476+
= 3.14
477+
478+
>> N[Pi, 50]
420479
= 3.1415926535897932384626433832795028841971693993751
421480
>> Attributes[Pi]
422481
= {Constant, Protected, ReadProtected}

mathics/builtin/inout.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,9 @@ class Print(Builtin):
19011901
| μ
19021902
#> Print["μ"]
19031903
| μ
1904+
#> Print["-Hola\\n-Qué tal?"]
1905+
| -Hola
1906+
. -Qué tal?
19041907
"""
19051908

19061909
def apply(self, expr, evaluation):

mathics/builtin/linalg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ def mp_eig(mp_matrix) -> Expression:
739739
return Expression("List", *eigenvalues)
740740

741741
options = {
742-
"Method": "Sympy",
742+
"Method": "sympy",
743743
}
744744

745745
def apply(self, m, evaluation, options={}) -> Expression:

mathics/builtin/system.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ def evaluate(self, evaluation) -> String:
414414
try:
415415
return String(os.getlogin())
416416
except:
417-
evaluation.message('$UserName', 'nologin')
417+
evaluation.message('$UserName', 'nologin')
418418
return
419419

420420

0 commit comments

Comments
 (0)