Skip to content

Commit 13ec1ea

Browse files
authored
Merge branch 'master' into go-over-intfns-recurrence
2 parents d1b4293 + a5f085e commit 13ec1ea

File tree

4 files changed

+141
-32
lines changed

4 files changed

+141
-32
lines changed

mathics/builtin/drawing/plot_plot3d.py

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import numpy as np
1414

15+
from mathics.builtin.drawing import plot
1516
from mathics.builtin.drawing.graphics3d import Graphics3D
1617
from mathics.builtin.graphics import Graphics
1718
from mathics.builtin.options import filter_from_iterable, options_to_rules
@@ -21,8 +22,6 @@
2122
from mathics.core.evaluation import Evaluation
2223
from mathics.core.systemsymbols import Symbol, SymbolPlotRange, SymbolSequence
2324

24-
from . import plot
25-
2625
# This tells documentation how to sort this module
2726
sort_order = "mathics.builtin.custom-plots"
2827

@@ -143,9 +142,10 @@ def eval(
143142

144143
class ComplexPlot3D(_Plot3D):
145144
"""
146-
<url>:WMA link: https://reference.wolfram.com/language/ref/ComplexPlot3D.html</url>
145+
<url>:Domain coloring:https://en.wikipedia.org/wiki/Domain_coloring</url> (<url>
146+
:WMA link: https://reference.wolfram.com/language/ref/ComplexPlot3D.html</url>)
147147
<dl>
148-
<dt>'Plot3D'[$f$, {$z$, $z_{min}$, $z_{max}$}]
148+
<dt>'ComplexPlot3D'[$f$, {$z$, $z_{min}$, $z_{max}$}]
149149
<dd>creates a three-dimensional plot of the magnitude of $f$ with $z$ ranging from $z_{min}$ to \
150150
$z_{max}$ with surface colored according to phase
151151
@@ -154,21 +154,29 @@ class ComplexPlot3D(_Plot3D):
154154
</url> for a list of Plot options.
155155
</dl>
156156
157+
'ComplexPlot' allows to visualize the changes both in the phase and \
158+
the module of a complex function:
159+
160+
In the neighborhood of the poles, the module of a rational function \
161+
grows without limit, and the phase varies between $-\\Pi$ to $\\Pi$, \
162+
an integer number of times:
163+
>> ComplexPlot3D[(z^2 + 1)/(z^2 - 1), {z, -2 - 2 I, 2 + 2 I}]
164+
= ...
157165
"""
158166

159-
summary_text = "plots one or more complex functions as a 3D surface"
167+
graphics_class = Graphics3D
160168
expected_args = 2
161-
options = _Plot3D.options3d | {"Mesh": "None"}
162-
163169
many_functions = True
164-
graphics_class = Graphics3D
170+
options = _Plot3D.options3d | {"Mesh": "None"}
171+
summary_text = "plot one or more complex functions as a 3D surface"
165172

166173

167174
class ComplexPlot(_Plot3D):
168175
"""
176+
<url>:Domain coloring:https://en.wikipedia.org/wiki/Domain_coloring</url>
169177
<url>:WMA link: https://reference.wolfram.com/language/ref/ComplexPlot.html</url>
170178
<dl>
171-
<dt>'Plot3D'[$f$, {$z$, $z_{min}$, $z_{max}$}]
179+
<dt>'ComplexPlot'[$f$, {$z$, $z_{min}$, $z_{max}$}]
172180
<dd>creates two-dimensional plot of $f$ with $z$ ranging from $z_{min}$ to \
173181
$z_{max}$ colored according to phase
174182
@@ -177,39 +185,58 @@ class ComplexPlot(_Plot3D):
177185
</url> for a list of Plot options.
178186
</dl>
179187
188+
'ComplexPlot' allows to visualize the changes in the phase of a \
189+
complex function.
190+
In the neighborhood of the poles, the module of a rational function \
191+
the phase varies between $-\\Pi$ to $\\Pi$ an integer number of times.
192+
>> ComplexPlot[(z^2 + 1)/(z^2 - 1), {z, -2 - 2 I, 2 + 2 I}]
193+
= ...
180194
"""
181195

182-
summary_text = "plots a complex function showing phase using colors"
183196
expected_args = 2
184-
options = _Plot3D.options2d
185-
186-
many_functions = False
187197
graphics_class = Graphics
198+
many_functions = False
199+
options = _Plot3D.options2d
200+
summary_text = "plots a complex function showing phase using colors"
188201

189202

190203
class ContourPlot(_Plot3D):
191204
"""
192-
<url>:WMA link: https://reference.wolfram.com/language/ref/ContourPlot.html</url>
205+
<url>:heat map:https://en.wikipedia.org/wiki/Heat_map</url>, <url>
206+
:contour map:https://en.wikipedia.org/wiki/Contour_line</url> (<url>
207+
:WMA link: https://reference.wolfram.com/language/ref/ContourPlot.html</url>)
193208
<dl>
194209
<dt>'Contour'[$f$, {$x$, $x_{min}$, $x_{max}$}, {$y$, $y_{min}$, $y_{max}$}]
195-
<dd>creates a two-dimensional contour plot ofh $f$ over the region
210+
<dd>creates a two-dimensional contour plot ofh $f$ over the region \
196211
$x$ ranging from $x_{min}$ to $x_{max}$ and $y$ ranging from $y_{min}$ to $y_{max}$.
197212
198213
See <url>:Drawing Option and Option Values:
199214
/doc/reference-of-built-in-symbols/plotting-graphing-and-drawing/drawing-options-and-option-values
200215
</url> for a list of Plot options.
201216
</dl>
202217
218+
Colorize the regions where a function takes values close to different \
219+
numeric values
220+
>> ContourPlot[x - y^3, {x, -2, 2}, {y, -1, 1}, AspectRatio->Automatic]
221+
= ...
222+
223+
The same, but with a finer division:
224+
>> ContourPlot[x^2 - y^2, {x, -2, 2}, {y, -1, 1}, Contours->10]
225+
= ...
226+
227+
Plot curves where the real and the imaginary part of a function take
228+
specific values:
229+
>> ContourPlot[{Re[Sin[x + I y]] == 5, Im[Sin[x + I y]] == 0}, {x, -10, 10}, {y, -10, 10}]
230+
= ...
203231
"""
204232

205-
requires = ["skimage"]
206-
summary_text = "creates a contour plot"
207233
expected_args = 3
234+
graphics_class = Graphics
235+
many_functions = True
208236
options = _Plot3D.options2d | {"Contours": "Automatic"}
209237
# TODO: other options?
210-
211-
many_functions = True
212-
graphics_class = Graphics
238+
requires = ["skimage"]
239+
summary_text = "creates a contour plot"
213240

214241

215242
class DensityPlot(_Plot3D):
@@ -236,12 +263,11 @@ class DensityPlot(_Plot3D):
236263
= -Graphics-
237264
"""
238265

239-
summary_text = "density plot for a function"
240266
expected_args = 3
241-
options = _Plot3D.options2d
242-
243-
many_functions = False
244267
graphics_class = Graphics
268+
many_functions = False
269+
options = _Plot3D.options2d
270+
summary_text = "density plot for a function"
245271

246272

247273
class Plot3D(_Plot3D):
@@ -273,9 +299,8 @@ class Plot3D(_Plot3D):
273299
= -Graphics3D-
274300
"""
275301

276-
summary_text = "plots 3D surfaces of one or more functions"
277302
expected_args = 3
278-
options = _Plot3D.options3d
279-
280-
many_functions = True
281303
graphics_class = Graphics3D
304+
many_functions = True
305+
options = _Plot3D.options3d
306+
summary_text = "plots 3D surfaces of one or more functions"

mathics/builtin/functional/apply_fns_to_lists.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,21 @@ def callback(level):
179179
Map $f$ onto each element (denoted by 'level' here) at this level.
180180
With exception for expr as Association, which is mapped on values only.
181181
"""
182-
if is_association and level.has_form("Rule", 2):
182+
# TODO: This special behavior applies when the whole expression
183+
# is of the form Association[__(Rule|RuleDelayed)], i.e., when
184+
# the expression is a well-formatted Association expression.
185+
# For example,
186+
# `Map[F, Association[a->1,b->2, NotARule]`
187+
# produces in WMA
188+
# `Association[F[a->1], F[b->2], F[NotARule]`
189+
# instead of
190+
# `Association[a->F[1], b->F[2], F[NotARule]`]
191+
#
192+
# Fixing this would require a different implementation of this eval_ method.
193+
#
194+
if is_association and level.has_form(("Rule", "RuleDelayed"), 2):
183195
return Expression(
184-
SymbolRule,
196+
level.get_head(),
185197
level.elements[0],
186198
Expression(f, level.elements[1]),
187199
)

mathics/eval/functional/apply_fns_to_lists.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ def map_at_replace_one(elements: Iterable, index: ListExpression, i: int) -> lis
3838
raise PartRangeError
3939
new_elements = list(elements)
4040
replace_element = elements[j]
41-
if hasattr(replace_element, "head") and replace_element.head is SymbolRule:
41+
if replace_element.has_form(("Rule", "RuleDelayed"), 2):
4242
new_elements[j] = Expression(
43-
SymbolRule,
43+
replace_element.get_head(),
4444
replace_element.elements[0],
4545
Expression(f, replace_element.elements[1]),
4646
)

test/builtin/list/test_association.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,75 @@ def test_associations_private_doctests(
193193
failure_message=assert_message,
194194
expected_messages=expected_messages,
195195
)
196+
197+
198+
@pytest.mark.parametrize(
199+
("str_expr", "expected_messages", "str_expected", "assert_message"),
200+
[
201+
(
202+
"Map[F, Q[a->1, b:>Association[p->3,q->4]]]",
203+
None,
204+
"Q[F[a->1], F[b:>Association[p->3, q->4]]]",
205+
"Acting on a nested association, the inner association is treated as normal.",
206+
),
207+
(
208+
"Map[F, Q[a->1, b:>Association[p->3,q->4]],{2}]",
209+
None,
210+
"Q[F[a]->F[1], F[b]:>F[Association[p->3, q->4]]]",
211+
"Acting on a nested association, the inner association is treated as normal.",
212+
),
213+
(
214+
"Map[F, Association[a->1, b:>Association[p->3,q->4]], {0}]",
215+
None,
216+
"F[Association[a->1, b:>Association[p->3, q->4]]]",
217+
"Special behavior occurs at the first level.",
218+
),
219+
(
220+
"Map[F, Association[a->1, b:>2]]",
221+
None,
222+
"Association[a->F[1], b:>F[2]]",
223+
"Over associations, Map acts on the values",
224+
),
225+
(
226+
"Map[F, Association[a->1, b:>Association[p->3,q->4]]]",
227+
None,
228+
"Association[a->F[1], b:>F[Association[p->3, q->4]]]",
229+
"Acting on a nested association, the inner association is treated as normal.",
230+
),
231+
(
232+
"Map[F, Association[a->1, b:>Association[p->3,q->4]], {1}]",
233+
None,
234+
"Association[a->F[1], b:>F[Association[p->3, q->4]]]",
235+
"Special behavior occurs at the first level.",
236+
),
237+
# FIXME
238+
(
239+
"Map[F, Association[a->1,b:>2,q]]",
240+
None,
241+
"Association[F[a->1], F[b:>2], F[q]]",
242+
"Acting on an invalid association expression, works as in a normal expression.",
243+
),
244+
(
245+
"Map[F, Association[a->1, b:>Association[p->3,q->4]], {2}]",
246+
None,
247+
"Association[a->1, b:>Association[F[p->3],F[q->4]]]",
248+
"Special behavior occurs at the first level.",
249+
),
250+
(
251+
"Map[F, Association[a->1, b:>Q[p->3, q->4]], {2}]",
252+
None,
253+
"Association[a->1, b:>Q[F[p->3],F[q->4]]]",
254+
"Special behavior occurs at the first level.",
255+
),
256+
],
257+
)
258+
@pytest.mark.xfail
259+
def test_map_over_associations(
260+
str_expr, expected_messages, str_expected, assert_message
261+
):
262+
check_evaluation(
263+
str_expr,
264+
str_expected,
265+
failure_message=assert_message,
266+
expected_messages=expected_messages,
267+
)

0 commit comments

Comments
 (0)