Skip to content

Commit 067ffda

Browse files
authored
Merge pull request #1053 from mathics/SympyForm
Sympy form
2 parents e69573a + 907e241 commit 067ffda

8 files changed

Lines changed: 221 additions & 83 deletions

File tree

mathics/builtin/arithmetic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,7 @@ class Sum(_IterationFunction, SympyFunction):
18741874
= 0
18751875
18761876
>> (-1 + a^n) Sum[a^(k n), {k, 0, m-1}] // Simplify
1877-
= Piecewise[{{m (-1 + a ^ n), a ^ n == 1}, {-1 + (a ^ n) ^ m, True}}]
1877+
= -1 + (a ^ n) ^ m
18781878
18791879
Infinite sums:
18801880
>> Sum[1 / 2 ^ i, {i, 1, Infinity}]

mathics/builtin/inout.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,6 +1974,35 @@ def apply(self, expr, evaluation) -> Expression:
19741974
return self.apply_python(expr, evaluation)
19751975

19761976

1977+
class SympyForm(Builtin):
1978+
"""
1979+
<dl>
1980+
<dt>'SympyForm[$expr$]'
1981+
<dd>returns an Sympy $expr$ in Python. Sympy is used internally
1982+
to implement a number of Mathics functions, like Simplify.
1983+
</dl>
1984+
1985+
>> SympyForm[Pi^2]
1986+
= pi**2
1987+
>> E^2 + 3E // SympyForm
1988+
= exp(2) + 3*E
1989+
"""
1990+
1991+
def apply_sympy(self, expr, evaluation) -> Expression:
1992+
'MakeBoxes[expr_, SympyForm]'
1993+
1994+
try:
1995+
# from trepan.api import debug; debug()
1996+
sympy_equivalent = expr.to_sympy()
1997+
except:
1998+
return
1999+
return StringFromPython(sympy_equivalent)
2000+
2001+
def apply(self, expr, evaluation) -> Expression:
2002+
"SympyForm[expr_]"
2003+
return self.apply_sympy(expr, evaluation)
2004+
2005+
19772006
class TeXForm(Builtin):
19782007
r"""
19792008
<dl>

mathics/builtin/linalg.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,24 @@ class Tr(Builtin):
5858
<dt>'Tr[$m$]'
5959
<dd>computes the trace of the matrix $m$.
6060
</dl>
61-
61+
6262
>> Tr[{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}]
6363
= 15
64-
64+
6565
Symbolic trace:
6666
>> Tr[{{a, b, c}, {d, e, f}, {g, h, i}}]
6767
= a + e + i
6868
"""
69-
69+
7070
messages = {
7171
'matsq': "The matrix `1` is not square."
7272
}
73-
73+
7474
#TODO: generalize to vectors and higher-rank tensors, and allow function arguments for application
75-
75+
7676
def apply(self, m, evaluation):
7777
'Tr[m_]'
78-
78+
7979
matrix = to_sympy_matrix(m)
8080
if matrix is None or matrix.cols != matrix.rows or matrix.cols == 0:
8181
return evaluation.message('Tr', 'matsq', m)
@@ -701,7 +701,7 @@ class Eigenvalues(Builtin):
701701
= {-1, 1, 2}
702702
703703
>> Eigenvalues[{{Cos[theta],Sin[theta],0},{-Sin[theta],Cos[theta],0},{0,0,1}}] // Sort
704-
= {1, Cos[theta] + Sqrt[-1 + Cos[theta] ^ 2], Cos[theta] - Sqrt[-1 + Cos[theta] ^ 2]}
704+
= {1, Cos[theta] + Sqrt[(-1 + Cos[theta]) (1 + Cos[theta])], Cos[theta] - Sqrt[(-1 + Cos[theta]) (1 + Cos[theta])]}
705705
706706
>> Eigenvalues[{{7, 1}, {-4, 3}}]
707707
= {5, 5}
@@ -731,7 +731,7 @@ def apply(self, m, evaluation):
731731
eigenvalues.sort(key=lambda v: (abs(v[0]), - re(v[0]), - im(v[0])),
732732
reverse=True)
733733

734-
eigenvalues = [from_sympy(v) for (v, c) in eigenvalues
734+
eigenvalues = [from_sympy(v) for (v, c) in eigenvalues
735735
for _ in range(c)]
736736
# Sort the eigenvalues in an arbitrary yet deterministic order
737737
else:

mathics/builtin/lists.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
PartError, PartDepthError, PartRangeError, Predefined, SympyFunction)
1414
from mathics.builtin.scoping import dynamic_scoping
1515
from mathics.builtin.base import MessageException, NegativeIntegerException, CountableInteger
16-
from mathics.core.expression import Expression, String, Symbol, Integer, Number, Real, strip_context, from_python
16+
from mathics.core.expression import Expression, String, Symbol, SymbolNull, Integer, Number, Real, strip_context, from_python
1717
from mathics.core.expression import min_prec, machine_precision
1818
from mathics.core.expression import structure
1919
from mathics.core.evaluation import BreakInterrupt, ContinueInterrupt, ReturnInterrupt
@@ -37,8 +37,8 @@
3737
def deletecases_with_levelspec(expr, pattern, evaluation, levelspec=1, n=-1 ):
3838
"""
3939
This function walks the expression `expr` and deleting occurrencies of `pattern`
40-
41-
If levelspec specifies a number, only those positions with `levelspec` "coordinates" are return. By default, it just return occurences in the first level.
40+
41+
If levelspec specifies a number, only those positions with `levelspec` "coordinates" are return. By default, it just return occurences in the first level.
4242
If a tuple (nmin, nmax) is provided, it just return those occurences with a number of "coordinates" between nmin and nmax.
4343
n indicates the number of occurrences to return. By default, it returns all the occurences.
4444
"""
@@ -74,7 +74,7 @@ def deletecases_with_levelspec(expr, pattern, evaluation, levelspec=1, n=-1 ):
7474
break
7575
idx = curr_index[-1]
7676
changed = changed or changed_marks[-1][idx]
77-
changed_marks[-1][idx] = changed
77+
changed_marks[-1][idx] = changed
7878
if changed:
7979
head = tree[-1][curr_index[-1]].get_head()
8080
tree[-1][idx] = Expression(head, *leaves)
@@ -83,12 +83,12 @@ def deletecases_with_levelspec(expr, pattern, evaluation, levelspec=1, n=-1 ):
8383
curr_index[-1] = curr_index[-1] + 1
8484
continue
8585
curr_leave = tree[-1][curr_index[-1]]
86-
if (match(curr_leave, evaluation) and
87-
(len(curr_index) > lsmin) ):
86+
if (match(curr_leave, evaluation) and
87+
(len(curr_index) > lsmin) ):
8888
tree[-1][curr_index[-1]] = nothing
8989
changed_marks[-1][curr_index[-1]] = True
9090
curr_index[-1] = curr_index[-1] + 1
91-
n = n - 1
91+
n = n - 1
9292
continue
9393
if curr_leave.is_atom() or lsmax == len(curr_index):
9494
curr_index[-1] = curr_index[-1] + 1
@@ -104,7 +104,7 @@ def find_matching_indices_with_levelspec(expr, pattern, evaluation,levelspec=1,n
104104
"""
105105
This function walks the expression `expr` looking for a pattern `pattern`
106106
and returns the positions of each occurence.
107-
If levelspec specifies a number, only those positions with `levelspec` "coordinates" are return. By default, it just return occurences in the first level.
107+
If levelspec specifies a number, only those positions with `levelspec` "coordinates" are return. By default, it just return occurences in the first level.
108108
If a tuple (nmin, nmax) is provided, it just return those occurences with a number of "coordinates" between nmin and nmax.
109109
n indicates the number of occurrences to return. By default, it returns all the occurences.
110110
"""
@@ -130,11 +130,11 @@ def find_matching_indices_with_levelspec(expr, pattern, evaluation,levelspec=1,n
130130
curr_index[-1] = curr_index[-1] + 1
131131
continue
132132
curr_leave = tree[-1][curr_index[-1]]
133-
if (match(curr_leave, evaluation) and
133+
if (match(curr_leave, evaluation) and
134134
(len(curr_index) >= lsmin) ):
135135
found.append([from_python(i) for i in curr_index])
136136
curr_index[-1] = curr_index[-1] + 1
137-
n = n - 1
137+
n = n - 1
138138
continue
139139
if curr_leave.is_atom() or lsmax == len(curr_index):
140140
curr_index[-1] = curr_index[-1] + 1
@@ -1840,11 +1840,11 @@ class DeleteCases(Builtin):
18401840
<dd>returns the elements of $list$ that do not match $pattern$.
18411841
18421842
<dt>'DeleteCases[$list$, $pattern$, $levelspec$]'
1843-
<dd> removes all parts of $list on levels specified by $levelspec$
1843+
<dd> removes all parts of $list on levels specified by $levelspec$
18441844
that match pattern (not fully implemented).
18451845
18461846
<dt>'DeleteCases[$list$, $pattern$, $levelspec$, $n$]'
1847-
<dd> removes the first $n$ parts of $list$ that match $pattern$.
1847+
<dd> removes the first $n$ parts of $list$ that match $pattern$.
18481848
</dl>
18491849
18501850
>> DeleteCases[{a, 1, 2.5, "string"}, _Integer|_Real]
@@ -1861,16 +1861,16 @@ class DeleteCases(Builtin):
18611861
messages = {'level': 'Level specification `1` is not of the form n, {n}, or {m, n}.',
18621862
'innf': 'Non-negative integer or Infinity expected at position 4 in `1`',
18631863
}
1864-
1864+
18651865
# def apply(self, items, pattern, evaluation):
18661866
# 'DeleteCases[items_, pattern_]'
1867-
# return self.apply_ls_n(items, pattern, Integer(1), Symbol("System`Null"), evaluation)
1867+
# return self.apply_ls_n(items, pattern, Integer(1), SymbolNull, evaluation)
18681868

18691869

18701870
# def apply_ls(self, items, pattern, levelspec, evaluation):
18711871
# 'DeleteCases[items_, pattern_, levelspec_]'
1872-
# return self.apply_ls_n(items, pattern, levelspec, Symbol("System`Null"), evaluation)
1873-
1872+
# return self.apply_ls_n(items, pattern, levelspec, SymbolNull, evaluation)
1873+
18741874
def apply_ls_n(self, items, pattern, levelspec, n, evaluation):
18751875
'DeleteCases[items_, pattern_, levelspec_:1, n_:System`Infinity]'
18761876

@@ -1893,8 +1893,8 @@ def apply_ls_n(self, items, pattern, levelspec, n, evaluation):
18931893
evaluation.message('DeleteCases','innf',Expression("DeleteCases", items, pattern, levelspec, n))
18941894
else:
18951895
evaluation.message('DeleteCases','innf',Expression("DeleteCases", items, pattern, levelspec, n))
1896-
return Symbol('System`Null')
1897-
1896+
return SymbolNull
1897+
18981898
if levelspec[0] !=1 or levelspec[1] !=1:
18991899
return deletecases_with_levelspec(items, pattern, evaluation, levelspec, n)
19001900
else:

0 commit comments

Comments
 (0)