Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/functions/min_max.py
8815 views
1
r"""
2
Symbolic Minimum and Maximum
3
4
Sage provides a symbolic maximum and minimum due to the fact that the Python
5
builtin max and min are not able to deal with variables as users might expect.
6
These functions wait to evaluate if there are variables.
7
8
Here you can see some differences::
9
10
sage: max(x,x^2)
11
x
12
sage: max_symbolic(x,x^2)
13
max(x, x^2)
14
sage: f(x) = max_symbolic(x,x^2); f(1/2)
15
1/2
16
17
This works as expected for more than two entries::
18
19
sage: max(3,5,x)
20
5
21
sage: min(3,5,x)
22
3
23
sage: max_symbolic(3,5,x)
24
max(x, 5)
25
sage: min_symbolic(3,5,x)
26
min(x, 3)
27
28
"""
29
###############################################################################
30
# Sage: Open Source Mathematical Software
31
# Copyright (C) 2010 Burcin Erocal <[email protected]>
32
# Distributed under the terms of the GNU General Public License (GPL),
33
# version 2 or any later version. The full text of the GPL is available at:
34
# http://www.gnu.org/licenses/
35
###############################################################################
36
37
from sage.symbolic.function import BuiltinFunction
38
from sage.symbolic.expression import Expression
39
from sage.symbolic.ring import SR
40
41
from __builtin__ import max as builtin_max, min as builtin_min
42
43
class MinMax_base(BuiltinFunction):
44
def eval_helper(self, this_f, builtin_f, initial_val, args):
45
"""
46
EXAMPLES::
47
48
sage: max_symbolic(3,5,x) # indirect doctest
49
max(x, 5)
50
sage: min_symbolic(3,5,x)
51
min(x, 3)
52
"""
53
# __call__ ensures that if args is a singleton, the element is iterable
54
arg_is_iter = False
55
if len(args) == 1:
56
arg_is_iter = True
57
args = args[0]
58
59
symb_args = []
60
res = initial_val
61
num_non_symbolic_args = 0
62
for x in args:
63
if isinstance(x, Expression):
64
symb_args.append(x)
65
else:
66
num_non_symbolic_args += 1
67
res = builtin_f(res, x)
68
69
# if no symbolic arguments, return the result
70
if len(symb_args) == 0:
71
if res is None:
72
# this is a hack to get the function to return None to the user
73
# the convention to leave a given symbolic function unevaluated
74
# is to return None from the _eval_ function, so we need
75
# a trick to indicate that the return value of the function is
76
# really None
77
# this is caught in the __call__ method, which knows to return
78
# None in this case
79
raise ValueError("return None")
80
return res
81
82
# if all arguments were symbolic return
83
if num_non_symbolic_args <= 1 and not arg_is_iter:
84
return None
85
86
if res is not None: symb_args.append(res)
87
return this_f(*symb_args)
88
89
def __call__(self, *args, **kwds):
90
"""
91
EXAMPLES::
92
93
sage: max_symbolic(3,5,x)
94
max(x, 5)
95
sage: max_symbolic(3,5,x, hold=True)
96
max(3, 5, x)
97
sage: max_symbolic([3,5,x])
98
max(x, 5)
99
100
::
101
102
sage: min_symbolic(3,5,x)
103
min(x, 3)
104
sage: min_symbolic(3,5,x, hold=True)
105
min(3, 5, x)
106
sage: min_symbolic([3,5,x])
107
min(x, 3)
108
109
TESTS:
110
111
We get an exception if no arguments are given::
112
113
sage: max_symbolic()
114
Traceback (most recent call last):
115
...
116
ValueError: number of arguments must be > 0
117
118
Check if we return None, when the builtin function would::
119
120
sage: max_symbolic([None]) is None
121
True
122
sage: max_symbolic([None, None]) is None
123
True
124
sage: min_symbolic([None]) is None
125
True
126
sage: min_symbolic([None, None]) is None
127
True
128
129
Check if a single argument which is not iterable works::
130
131
sage: max_symbolic(None)
132
Traceback (most recent call last):
133
...
134
TypeError: 'NoneType' object is not iterable
135
sage: max_symbolic(5)
136
Traceback (most recent call last):
137
...
138
TypeError: 'sage.rings.integer.Integer' object is not iterable
139
sage: max_symbolic(x)
140
Traceback (most recent call last):
141
...
142
TypeError: 'sage.symbolic.expression.Expression' object is not iterable
143
sage: min_symbolic(5)
144
Traceback (most recent call last):
145
...
146
TypeError: 'sage.rings.integer.Integer' object is not iterable
147
sage: min_symbolic(x)
148
Traceback (most recent call last):
149
...
150
TypeError: 'sage.symbolic.expression.Expression' object is not iterable
151
"""
152
if len(args) == 0:
153
raise ValueError("number of arguments must be > 0")
154
if len(args) == 1:
155
try:
156
args=(SR._force_pyobject(iter(args[0])),)
157
except TypeError, e:
158
raise e
159
160
try:
161
return BuiltinFunction.__call__(self, *args, **kwds)
162
except ValueError, e:
163
if e.args[0] == "return None":
164
return None
165
166
class MaxSymbolic(MinMax_base):
167
def __init__(self):
168
r"""
169
Symbolic `\max` function.
170
171
The Python builtin `\max` function doesn't work as expected when symbolic
172
expressions are given as arguments. This function delays evaluation
173
until all symbolic arguments are substituted with values.
174
175
EXAMPLES::
176
177
sage: max_symbolic(3, x)
178
max(3, x)
179
sage: max_symbolic(3, x).subs(x=5)
180
5
181
sage: max_symbolic(3, 5, x)
182
max(x, 5)
183
sage: max_symbolic([3,5,x])
184
max(x, 5)
185
186
TESTS::
187
188
sage: loads(dumps(max_symbolic(x,5)))
189
max(x, 5)
190
sage: latex(max_symbolic(x,5))
191
\max\left(x, 5\right)
192
"""
193
BuiltinFunction.__init__(self, 'max', nargs=0, latex_name="\max")
194
195
def _eval_(self, *args):
196
"""
197
EXAMPLES::
198
199
sage: t = max_symbolic(x, 5); t
200
max(x, 5)
201
sage: t.subs(x=3) # indirect doctest
202
5
203
sage: max_symbolic(5,3)
204
5
205
sage: u = max_symbolic(*(range(10)+[x])); u
206
max(x, 9)
207
sage: u.subs(x=-1)
208
9
209
sage: u.subs(x=10)
210
10
211
sage: max_symbolic([0,x])
212
max(x, 0)
213
214
TESTS::
215
216
sage: max_symbolic()
217
Traceback (most recent call last):
218
...
219
ValueError: number of arguments must be > 0
220
"""
221
return self.eval_helper(max_symbolic, builtin_max, None, args)
222
223
def _evalf_(self, *args, **kwds):
224
"""
225
EXAMPLES::
226
227
sage: t = max_symbolic(sin(x), cos(x))
228
sage: t.subs(x=1).n(200)
229
0.84147098480789650665250232163029899962256306079837106567275
230
sage: var('y')
231
y
232
sage: t = max_symbolic(sin(x), cos(x), y)
233
sage: u = t.subs(x=1); u
234
max(sin(1), cos(1), y)
235
sage: u.n()
236
Traceback (most recent call last):
237
...
238
TypeError: cannot evaluate symbolic expression numerically
239
240
::
241
242
sage: f = max_symbolic(sin(x), cos(x))
243
sage: r = integral(f, x, 0, 1)
244
sage: r.n()
245
0.8739124411567263
246
"""
247
return max_symbolic(args)
248
249
max_symbolic = MaxSymbolic()
250
251
252
class MinSymbolic(MinMax_base):
253
def __init__(self):
254
r"""
255
Symbolic `\min` function.
256
257
The Python builtin `\min` function doesn't work as expected when symbolic
258
expressions are given as arguments. This function delays evaluation
259
until all symbolic arguments are substituted with values.
260
261
EXAMPLES::
262
263
sage: min_symbolic(3, x)
264
min(3, x)
265
sage: min_symbolic(3, x).subs(x=5)
266
3
267
sage: min_symbolic(3, 5, x)
268
min(x, 3)
269
sage: min_symbolic([3,5,x])
270
min(x, 3)
271
272
TESTS::
273
274
sage: loads(dumps(min_symbolic(x,5)))
275
min(x, 5)
276
sage: latex(min_symbolic(x,5))
277
\min\left(x, 5\right)
278
"""
279
BuiltinFunction.__init__(self, 'min', nargs=0, latex_name="\min")
280
281
def _eval_(self, *args):
282
"""
283
EXAMPLES::
284
285
sage: t = min_symbolic(x, 5); t
286
min(x, 5)
287
sage: t.subs(x=3) # indirect doctest
288
3
289
sage: min_symbolic(5,3)
290
3
291
sage: u = min_symbolic(*(range(10)+[x])); u
292
min(x, 0)
293
sage: u.subs(x=-1)
294
-1
295
sage: u.subs(x=10)
296
0
297
sage: min_symbolic([3,x])
298
min(x, 3)
299
300
TESTS::
301
302
sage: min_symbolic()
303
Traceback (most recent call last):
304
...
305
ValueError: number of arguments must be > 0
306
"""
307
return self.eval_helper(min_symbolic, builtin_min, float('inf'), args)
308
309
def _evalf_(self, *args, **kwds):
310
"""
311
EXAMPLES::
312
313
sage: t = min_symbolic(sin(x), cos(x))
314
sage: t.subs(x=1).n(200)
315
0.54030230586813971740093660744297660373231042061792222767010
316
sage: var('y')
317
y
318
sage: t = min_symbolic(sin(x), cos(x), y)
319
sage: u = t.subs(x=1); u
320
min(sin(1), cos(1), y)
321
sage: u.n()
322
Traceback (most recent call last):
323
...
324
TypeError: cannot evaluate symbolic expression numerically
325
"""
326
return min_symbolic(args)
327
328
min_symbolic = MinSymbolic()
329
330