diff --git a/CHANGES.rst b/CHANGES.rst index 8e602d47c..c9b22ebaf 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,9 +8,10 @@ New Builtins ++++++++++++ -* `Elements` -* `RealAbs` and `RealSign` -* `RealValuedNumberQ` +* ``Elements`` +* ``LeviCivitaTensor`` +* ``RealAbs`` and ``RealSign`` +* ``RealValuedNumberQ`` Compatibility diff --git a/mathics/builtin/tensors.py b/mathics/builtin/tensors.py index d58c86bff..f084cdd26 100644 --- a/mathics/builtin/tensors.py +++ b/mathics/builtin/tensors.py @@ -19,13 +19,18 @@ """ +from sympy.combinatorics import Permutation +from sympy.utilities.iterables import permutations + from mathics.core.atoms import Integer, String from mathics.core.attributes import A_FLAT, A_ONE_IDENTITY, A_PROTECTED from mathics.core.builtin import BinaryOperator, Builtin +from mathics.core.convert.python import from_python from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression from mathics.core.symbols import Atom, Symbol, SymbolFalse, SymbolTrue +from mathics.core.systemsymbols import SymbolRule, SymbolSparseArray from mathics.eval.parts import get_part @@ -490,3 +495,46 @@ def eval(self, m, evaluation: Evaluation): else: result[col_index].append(item) return ListExpression(*[ListExpression(*row) for row in result]) + + +class LeviCivitaTensor(Builtin): + """ + :Levi-Civita tensor:https://en.wikipedia.org/wiki/Levi-Civita_symbol \ + (:WMA link:https://reference.wolfram.com/language/ref/LeviCivitaTensor.html) + +
+
'LeviCivitaTensor[$d$]' +
gives the $d$-dimensional Levi-Civita totally antisymmetric tensor. +
+ + >> LeviCivitaTensor[3] + = SparseArray[Automatic, {3, 3, 3}, 0, {{1, 2, 3} -> 1, {1, 3, 2} -> -1, {2, 1, 3} -> -1, {2, 3, 1} -> 1, {3, 1, 2} -> 1, {3, 2, 1} -> -1}] + + >> LeviCivitaTensor[3, List] + = {{{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{0, 0, -1}, {0, 0, 0}, {1, 0, 0}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0}}} + """ + + rules = { + "LeviCivitaTensor[d_Integer]/; Greater[d, 0]": "LeviCivitaTensor[d, SparseArray]", + "LeviCivitaTensor[d_Integer, List] /; Greater[d, 0]": "LeviCivitaTensor[d, SparseArray] // Normal", + } + + summary_text = "give the Levi-Civita tensor with a given dimension" + + def eval(self, d, type, evaluation: Evaluation): + "LeviCivitaTensor[d_Integer, type_]" + + if isinstance(d, Integer) and type == SymbolSparseArray: + d = d.get_int_value() + perms = list(permutations([i for i in range(1, d + 1)])) + rules = [ + Expression( + SymbolRule, + from_python(p), + from_python(Permutation.from_sequence(p).signature()), + ) + for p in perms + ] + return Expression( + SymbolSparseArray, from_python(rules), from_python([d] * d) + )