Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SYMBOLS_MANIFEST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ System`Disk
System`DiskBox
System`DiskMatrix
System`Dispatch
System`Distribute
System`Divide
System`DivideBy
System`Divisible
Expand Down
8 changes: 5 additions & 3 deletions mathics/builtin/exp_structure/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Expression Structure
r"""
Structural Operations on Expressions

Here we have functions which work purely on \Mathics3 Expressions transforming them in some way.
"""

# This tells documentation how to sort this module
sort_order = "mathics.builtin.expression-structure"
sort_order = "mathics.builtin.structual-operations-on-expressions"
157 changes: 157 additions & 0 deletions mathics/builtin/exp_structure/miscelleneous.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
"""
Miscellaneous Structural Operations on Expressions
"""

from mathics.core.attributes import A_PROTECTED
from mathics.core.builtin import Builtin
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.systemsymbols import SymbolIdentity
from mathics.eval.exp_structure import eval_Distribute
from mathics.eval.tensors import eval_Outer


class Distribute(Builtin):
"""
<url>:WMA link:https://reference.wolfram.com/language/ref/Distribute.html</url>

<dl>
<dt>'Distribute'[$expr$]
<dd>distributes $expr$ over 'Plus' (addition).
<dt>'Distribute'[$expr$, $operator$]
<dd>distributes $expr$ over the specified $operator$.
<dt>'Distribute'[$expr$, $operator$, $f$]
<dd>applies $f$ to each component of the result.

## <dt>'Distribute'[$expr$, $operator$, $f$, $gp$, $fp$]
## <dd>distributes $expr$ over $operator$, replacing outer function with $gp$ and inner function with $fp$.
</dl>

Distribute multiplication over addition:
>> Distribute[a(b + c)]
= a b + a c

>> Distribute[(a + b)(c + d)]
= a c + a d + b c + b d

Using a custom target head:
>> Distribute[f[a + b, c], Plus]
= f[a, c] + f[b, c]

Distribute can also work with lists:
>> Distribute[{a(b + c), d(e + f)}]
= {a b + a c, d e + d f}

## Applying a function to results:
## >> Distribute[a(b + c), Plus, Square]
## = Square[a b] + Square[a c]

Special forms:
>> Distribute[f[g[a + b]]]
= f[g[a]] + f[g[b]]

Distribute $f$ over $g$:
>> Distribute[f[g[a, b], g[c, d, e]], g]
= g[f[a, c], f[a, d], f[a, e], f[b, c], f[b, d], f[b, e]]

## Using a custom operator and functions:
## >> Distribute[f[g[a, b], g[c, d, e]], g, f, gp, fp]
## = gp[fp[a, c], fp[a, d], fp[a, e], fp[b, c], fp[b, d], fp[b, e]]
"""

attributes = A_PROTECTED

eval_error = Builtin.generic_argument_error
expected_args = range(1, 6)

rules = {
"Distribute[expr_]": "Distribute[expr, Plus]",
"Distribute[expr_, operator_]": "Distribute[expr, operator, Identity]",
}

summary_text = "distribute functions over a head"

def eval(self, expr, operator, filt, evaluation: Evaluation):
"Distribute[expr_, operator_, filt_]"

# Handle Identity filter
if filt is SymbolIdentity:
filt = None

result = eval_Distribute(expr, operator, evaluation)

if result is None:
return expr

if filt:
return Expression(filt, result)

return result

# def eval_with_function_replacement(
# self, expr, operator, f, g, gp, fp, evaluation: Evaluation
# ):
# "Distribute[expr_, f_, g_, gp_, fp_]"

# result = eval_Distribute_with_replacement(expr, f, g, gp, fp, evaluation)

# if result is None:
# return expr

# return result


class Outer(Builtin):
"""
<url>:Outer product:https://en.wikipedia.org/wiki/Outer_product</url> \
(<url>:WMA link: https://reference.wolfram.com/language/ref/Outer.html</url>)

<dl>
<dt>'Outer'[$f$, $x$, $y$]
<dd>computes a generalised outer product of $x$ and $y$, using the function $f$ in place of multiplication.
</dl>

>> Outer[f, {a, b}, {1, 2, 3}]
= {{f[a, 1], f[a, 2], f[a, 3]}, {f[b, 1], f[b, 2], f[b, 3]}}

Outer product of two matrices:
>> Outer[Times, {{a, b}, {c, d}}, {{1, 2}, {3, 4}}]
= {{{{a, 2 a}, {3 a, 4 a}}, {{b, 2 b}, {3 b, 4 b}}}, {{{c, 2 c}, {3 c, 4 c}}, {{d, 2 d}, {3 d, 4 d}}}}

Outer product of two sparse arrays:
>> Outer[Times, SparseArray[{{1, 2} -> a, {2, 1} -> b}], SparseArray[{{1, 2} -> c, {2, 1} -> d}]]
= SparseArray[Automatic, {2, 2, 2, 2}, 0, {{1, 2, 1, 2} ⇾ a c, {1, 2, 2, 1} ⇾ a d, {2, 1, 1, 2} ⇾ b c, {2, 1, 2, 1} ⇾ b d}]

'Outer' of multiple lists:
>> Outer[f, {a, b}, {x, y, z}, {1, 2}]
= {{{f[a, x, 1], f[a, x, 2]}, {f[a, y, 1], f[a, y, 2]}, {f[a, z, 1], f[a, z, 2]}}, {{f[b, x, 1], f[b, x, 2]}, {f[b, y, 1], f[b, y, 2]}, {f[b, z, 1], f[b, z, 2]}}}

'Outer' converts input sparse arrays to lists if f=!=Times, or if the input is a mixture of sparse arrays and lists:
>> Outer[f, SparseArray[{{1, 2} -> a, {2, 1} -> b}], SparseArray[{{1, 2} -> c, {2, 1} -> d}]]
= {{{{f[0, 0], f[0, c]}, {f[0, d], f[0, 0]}}, {{f[a, 0], f[a, c]}, {f[a, d], f[a, 0]}}}, {{{f[b, 0], f[b, c]}, {f[b, d], f[b, 0]}}, {{f[0, 0], f[0, c]}, {f[0, d], f[0, 0]}}}}

>> Outer[Times, SparseArray[{{1, 2} -> a, {2, 1} -> b}], {c, d}]
= {{{0, 0}, {a c, a d}}, {{b c, b d}, {0, 0}}}

Arrays can be ragged:
>> Outer[Times, {{1, 2}}, {{a, b}, {c, d, e}}]
= {{{{a, b}, {c, d, e}}, {{2 a, 2 b}, {2 c, 2 d, 2 e}}}}

Word combinations:
>> Outer[StringJoin, {"", "re", "un"}, {"cover", "draw", "wind"}, {"", "ing", "s"}] // InputForm
= {{{"cover", "covering", "covers"}, {"draw", "drawing", "draws"}, {"wind", "winding", "winds"}}, {{"recover", "recovering", "recovers"}, {"redraw", "redrawing", "redraws"}, {"rewind", "rewinding", "rewinds"}}, {{"uncover", "uncovering", "uncovers"}, {"undraw", "undrawing", "undraws"}, {"unwind", "unwinding", "unwinds"}}}

Compositions of trigonometric functions:
>> trigs = Outer[Composition, {Sin, Cos, Tan}, {ArcSin, ArcCos, ArcTan}]
= {{Composition[Sin, ArcSin], Composition[Sin, ArcCos], Composition[Sin, ArcTan]}, {Composition[Cos, ArcSin], Composition[Cos, ArcCos], Composition[Cos, ArcTan]}, {Composition[Tan, ArcSin], Composition[Tan, ArcCos], Composition[Tan, ArcTan]}}
Evaluate at 0:
>> Map[#[0] &, trigs, {2}]
= {{0, 1, 0}, {1, 0, 1}, {0, ComplexInfinity, 0}}
"""

summary_text = "generalized outer product"

def eval(self, f, lists, evaluation: Evaluation):
"Outer[f_, lists__]"

return eval_Outer(f, lists, evaluation)
9 changes: 5 additions & 4 deletions mathics/builtin/numbers/algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from mathics.core.systemsymbols import (
SymbolAssumptions,
SymbolEqual,
SymbolIdentity,
SymbolIndeterminate,
SymbolLess,
SymbolRule,
Expand Down Expand Up @@ -550,7 +551,7 @@ class Collect(Builtin):

def eval_var_filter(self, expr, varlist, filt, evaluation):
"""Collect[expr_, varlist_, filt_]"""
if filt is Symbol("Identity"):
if filt is SymbolIdentity:
filt = None
if isinstance(varlist, Symbol):
var_exprs = [varlist]
Expand Down Expand Up @@ -845,9 +846,9 @@ def eval(self, expr, evaluation: Evaluation, options: dict):
return expand_polynomial(expr, False, True, **kwargs)


## Our expand_polynomial routine and SymPy's do not match
## what WMA is doing. Failing a good reason to get this working,
## I, rocky, do not thing it is worth the effort.
# Our expand_polynomial routine and SymPy's do not match
# what WMA is doing. Failing a good reason to get this working,
# I, rocky, do not thing it is worth the effort.
#
# class ExpandNumerator(_Expand):
# """
Expand Down
57 changes: 0 additions & 57 deletions mathics/builtin/tensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from mathics.eval.tensors import (
eval_Inner,
eval_LeviCivitaTensor,
eval_Outer,
eval_Transpose,
get_dimensions,
)
Expand Down Expand Up @@ -168,62 +167,6 @@ def eval(self, f, list1, list2, g, evaluation: Evaluation):
return eval_Inner(f, list1, list2, g, evaluation)


class Outer(Builtin):
"""
<url>:Outer product:https://en.wikipedia.org/wiki/Outer_product</url> \
(<url>:WMA link: https://reference.wolfram.com/language/ref/Outer.html</url>)

<dl>
<dt>'Outer'[$f$, $x$, $y$]
<dd>computes a generalised outer product of $x$ and $y$, using the function $f$ in place of multiplication.
</dl>

>> Outer[f, {a, b}, {1, 2, 3}]
= {{f[a, 1], f[a, 2], f[a, 3]}, {f[b, 1], f[b, 2], f[b, 3]}}

Outer product of two matrices:
>> Outer[Times, {{a, b}, {c, d}}, {{1, 2}, {3, 4}}]
= {{{{a, 2 a}, {3 a, 4 a}}, {{b, 2 b}, {3 b, 4 b}}}, {{{c, 2 c}, {3 c, 4 c}}, {{d, 2 d}, {3 d, 4 d}}}}

Outer product of two sparse arrays:
>> Outer[Times, SparseArray[{{1, 2} -> a, {2, 1} -> b}], SparseArray[{{1, 2} -> c, {2, 1} -> d}]]
= SparseArray[Automatic, {2, 2, 2, 2}, 0, {{1, 2, 1, 2} ⇾ a c, {1, 2, 2, 1} ⇾ a d, {2, 1, 1, 2} ⇾ b c, {2, 1, 2, 1} ⇾ b d}]

'Outer' of multiple lists:
>> Outer[f, {a, b}, {x, y, z}, {1, 2}]
= {{{f[a, x, 1], f[a, x, 2]}, {f[a, y, 1], f[a, y, 2]}, {f[a, z, 1], f[a, z, 2]}}, {{f[b, x, 1], f[b, x, 2]}, {f[b, y, 1], f[b, y, 2]}, {f[b, z, 1], f[b, z, 2]}}}

'Outer' converts input sparse arrays to lists if f=!=Times, or if the input is a mixture of sparse arrays and lists:
>> Outer[f, SparseArray[{{1, 2} -> a, {2, 1} -> b}], SparseArray[{{1, 2} -> c, {2, 1} -> d}]]
= {{{{f[0, 0], f[0, c]}, {f[0, d], f[0, 0]}}, {{f[a, 0], f[a, c]}, {f[a, d], f[a, 0]}}}, {{{f[b, 0], f[b, c]}, {f[b, d], f[b, 0]}}, {{f[0, 0], f[0, c]}, {f[0, d], f[0, 0]}}}}

>> Outer[Times, SparseArray[{{1, 2} -> a, {2, 1} -> b}], {c, d}]
= {{{0, 0}, {a c, a d}}, {{b c, b d}, {0, 0}}}

Arrays can be ragged:
>> Outer[Times, {{1, 2}}, {{a, b}, {c, d, e}}]
= {{{{a, b}, {c, d, e}}, {{2 a, 2 b}, {2 c, 2 d, 2 e}}}}

Word combinations:
>> Outer[StringJoin, {"", "re", "un"}, {"cover", "draw", "wind"}, {"", "ing", "s"}] // InputForm
= {{{"cover", "covering", "covers"}, {"draw", "drawing", "draws"}, {"wind", "winding", "winds"}}, {{"recover", "recovering", "recovers"}, {"redraw", "redrawing", "redraws"}, {"rewind", "rewinding", "rewinds"}}, {{"uncover", "uncovering", "uncovers"}, {"undraw", "undrawing", "undraws"}, {"unwind", "unwinding", "unwinds"}}}

Compositions of trigonometric functions:
>> trigs = Outer[Composition, {Sin, Cos, Tan}, {ArcSin, ArcCos, ArcTan}]
= {{Composition[Sin, ArcSin], Composition[Sin, ArcCos], Composition[Sin, ArcTan]}, {Composition[Cos, ArcSin], Composition[Cos, ArcCos], Composition[Cos, ArcTan]}, {Composition[Tan, ArcSin], Composition[Tan, ArcCos], Composition[Tan, ArcTan]}}
Evaluate at 0:
>> Map[#[0] &, trigs, {2}]
= {{0, 1, 0}, {1, 0, 1}, {0, ComplexInfinity, 0}}
"""

summary_text = "generalized outer product"

def eval(self, f, lists, evaluation: Evaluation):
"Outer[f_, lists__]"

return eval_Outer(f, lists, evaluation)


class RotationTransform(Builtin):
"""
<url>:WMA link: https://reference.wolfram.com/language/ref/RotationTransform.html</url>
Expand Down
1 change: 1 addition & 0 deletions mathics/core/systemsymbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
SymbolHoldPattern = Symbol("System`HoldPattern")
SymbolHue = Symbol("System`Hue")
SymbolI = Symbol("System`I")
SymbolIdentity = Symbol("System`Identity")
SymbolIf = Symbol("System`If")
SymbolIm = Symbol("System`Im")
SymbolImage = Symbol("System`Image")
Expand Down
13 changes: 13 additions & 0 deletions mathics/eval/exp_structure/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"Evaluation methods for builtin functions of mathics.builtin.exp_structure"

from mathics.eval.exp_structure.distribute import eval_Distribute

# from mathics.eval.exp_structure.outer import eval_Outer

# TODO: add FlattenAt
# from mathics.eval.exp_structure.flattenAt import eval_At
__all__ = [
"eval_Distribute",
# "eval_FlattenAt",
# "eval_Outer",
]
Loading
Loading