Ticket #6949: trac_6949-symbolic_min_max.take3.patch

File trac_6949-symbolic_min_max.take3.patch, 10.8 KB (added by burcin, 12 years ago)

apply only this patch

  • sage/functions/all.py

    # HG changeset patch
    # User Burcin Erocal <burcin@erocal.org>
    # Date 1270567369 -7200
    # Node ID 27eacad95e3db9088495ba8c8ce3ce8eb275236a
    # Parent  3c2477b86e7e89405c92c8133f0fe5e7d6a88cb5
    trac 6949: Implement symbolic min and max functions.
    
    diff --git a/sage/functions/all.py b/sage/functions/all.py
    a b  
    6262
    6363from generalized import (dirac_delta, heaviside, unit_step, sgn,
    6464                         kronecker_delta)
     65
     66from min_max import max_symbolic, min_symbolic
  • new file sage/functions/min_max.py

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

    diff --git a/sage/symbolic/ring.pyx b/sage/symbolic/ring.pyx
    a b  
    271271
    272272        return new_Expression_from_GEx(self, exp)
    273273
     274    def _force_pyobject(self, x):
     275        """
     276        Wrap the given Python object in a symbolic expression even if it
     277        cannot be coerced to the Symbolic Ring.
     278
     279        EXAMPLES::
     280
     281            sage: t = SR._force_pyobject([3,4,5]); t
     282            [3, 4, 5]
     283            sage: type(t)
     284            <type 'sage.symbolic.expression.Expression'>
     285        """
     286        cdef GEx exp
     287        GEx_construct_pyobject(exp, x)
     288        return new_Expression_from_GEx(self, exp)
     289
    274290    def wild(self, unsigned int n=0):
    275291        """
    276292        Return the n-th wild-card for pattern matching and substitution.