Ticket #13355: trac_13355_plot_with_complex_intermediates.patch

File trac_13355_plot_with_complex_intermediates.patch, 7.8 KB (added by tkluck, 6 years ago)
  • sage/ext/fast_callable.pyx

    # HG changeset patch
    # User Timo Kluck <tkluck@infty.nl>
    # Date 1344514850 -7200
    # Node ID d683f2edd6b10f1e8b770dec7ebd761492c4a176
    # Parent  5528318fe402ade6c066fdea57dee958819c8494
    Fix plotting with complex intermediates
    
    diff --git a/sage/ext/fast_callable.pyx b/sage/ext/fast_callable.pyx
    a b  
    383383        sage: fc = fast_callable(expr, domain=float)
    384384        sage: fc(5, 7)
    385385        0.5514266812416906
     386
     387    Check that fast_callable also works for symbolic functions with evaluation
     388    functions:
     389
     390        sage: def evalf_func(self, x, y, parent): return parent(x*y)
     391        sage: x,y = var('x,y')
     392        sage: f = function('f', evalf_func=evalf_func)
     393        sage: fc = fast_callable(f(x,y), vars=[x,y])
     394        sage: fc(3,4)
     395        12.0
    386396    """
    387397    cdef Expression et
    388398    if isinstance(x, Expression):
  • sage/symbolic/expression.pyx

    diff --git a/sage/symbolic/expression.pyx b/sage/symbolic/expression.pyx
    a b  
    86928692        from sage.symbolic.expression_conversions import fast_float
    86938693        return fast_float(self, *vars)
    86948694
     8695
    86958696    def _fast_callable_(self, etb):
    86968697        """
    86978698        Given an ExpressionTreeBuilder *etb*, return an Expression representing
     
    88368837            sage: abs((I*10+1)^4)
    88378838            10201
    88388839            sage: plot(s)
     8840
     8841        Check that this also works when we plot a function that implicitely
     8842        takes complex values:
     8843
     8844            sage: f = function('f', evalf_func=lambda self,x,parent: I*x)
     8845            sage: plot(abs(f(x)), 0,5)
    88398846        """
    88408847        try:
    88418848            # First we try fast float.  However, this doesn't work on some
  • sage/symbolic/expression_conversions.py

    diff --git a/sage/symbolic/expression_conversions.py b/sage/symbolic/expression_conversions.py
    a b  
    12381238            1.41421356237309...
    12391239        """
    12401240        f = operator
     1241        if f.range_for_domain(float) != float:
     1242            raise TypeError("Cannot use fast_float to calculate a function with complex intermediates")
    12411243        g = map(self, ex.operands())
    12421244        try:
    12431245            return f(*g)
     
    14051407            sin(sqrt(add(v_0, v_1)))
    14061408            sage: arctan2(x,y)._fast_callable_(etb)
    14071409            {arctan2}(v_0, v_1)
     1410            sage: def evalf_func(self, x, y, parent): return parent(x*y)
     1411            sage: f = function('f', evalf_func=evalf_func)
     1412            sage: f(x,y)._fast_callable_(etb)
     1413            {evalf_func}(v_0, v_1, <type 'float'>)
    14081414        """
    1409         return self.etb.call(function, *ex.operands())
     1415        try:
     1416            domain = self.etb._domain
     1417            if domain == None:
     1418                domain = float
     1419            return self.etb.call(function._evalf_, *(ex.operands() + [domain]))
     1420        except AttributeError:
     1421            return self.etb.call(function, *ex.operands())
    14101422
    14111423
    14121424def fast_callable(ex, etb):
  • sage/symbolic/function.pyx

    diff --git a/sage/symbolic/function.pyx b/sage/symbolic/function.pyx
    a b  
    634634        """
    635635        raise NotImplementedError("The Function %s does not support numpy arrays as arguments" % self.name())
    636636
     637    def range_for_domain(self, domain):
     638        """
     639        Return the parent of self(x) when x is an element of domain
     640
     641        It is very common for functions to return real values when given a real value
     642        and complex values when given a complex value. Such functions can specify that
     643        by overriding this function, which will enable certain optimizations.
     644
     645        The default implementation returns the complex field corresponding to domain,
     646        and `complex` if it cannot find one.
     647
     648        Default behaviour:
     649
     650            sage: f = function('f')
     651            sage: f.range_for_domain(float)
     652            <type 'complex'>
     653            sage: f.range_for_domain(RR)
     654            Complex Field with 53 bits of precision
     655
     656        Common behaviour:
     657
     658            sage: sin.range_for_domain(float)
     659            <type 'float'>
     660            sage: sin.range_for_domain(RR)
     661            Real Field with 53 bits of precision
     662            sage: sin.range_for_domain(CC)
     663            Complex Field with 53 bits of precision
     664        """
     665
     666        try:
     667            return domain.complex_field()
     668        except AttributeError:
     669            return complex
     670
    637671cdef class GinacFunction(BuiltinFunction):
    638672    """
    639673    This class provides a wrapper around symbolic functions already defined in
     
    863897            # we should never end up here
    864898            raise ValueError, "cannot read pickle"
    865899
     900    def range_for_domain(self, domain):
     901        """
     902        Return the parent of self(x) when x is an element of domain
     903
     904        All builtin functions return real values when given a real value
     905        and complex values when given a complex value. We specify that
     906        in this override.
     907
     908        Behaviour for builtin functions:
     909
     910            sage: sin.range_for_domain(float)
     911            <type 'float'>
     912            sage: sin.range_for_domain(RR)
     913            Real Field with 53 bits of precision
     914            sage: sin.range_for_domain(CC)
     915            Complex Field with 53 bits of precision
     916        """
     917        return domain
     918
    866919
    867920cdef class SymbolicFunction(Function):
    868921    """
  • sage/ext/fast_callable.pyx

    # HG changeset patch
    # User Timo Kluck <tkluck@infty.nl>
    # Date 1344521180 -7200
    # Node ID aae73ef825642da8f76d731cd4d7f37d79d8d13b
    # Parent  d683f2edd6b10f1e8b770dec7ebd761492c4a176
    handle domain properly in evalf functions
    
    diff --git a/sage/ext/fast_callable.pyx b/sage/ext/fast_callable.pyx
    a b  
    387387    Check that fast_callable also works for symbolic functions with evaluation
    388388    functions:
    389389
    390         sage: def evalf_func(self, x, y, parent): return parent(x*y)
     390        sage: def evalf_func(self, x, y, parent): return parent(x*y) if parent!=None else x*y
    391391        sage: x,y = var('x,y')
    392392        sage: f = function('f', evalf_func=evalf_func)
    393393        sage: fc = fast_callable(f(x,y), vars=[x,y])
    394394        sage: fc(3,4)
    395         12.0
     395        12
     396   
     397    And also when there's complex values involved:
     398
     399        sage: def evalf_func(self, x, y, parent): return parent(I*x*y) if parent!=None else I*x*y
     400        sage: g = function('g', evalf_func=evalf_func)
     401        sage: fc = fast_callable(g(x,y), vars=[x,y])
     402        sage: fc(3,4)
     403        12*I
     404        sage: fc2 = fast_callable(g(x,y), domain=complex, vars=[x,y])
     405        sage: fc2(3,4)
     406        12j
     407        sage: fc3 = fast_callable(g(x,y), domain=float, vars=[x,y])
     408        sage: fc3(3,4)
     409        Traceback (most recent call last):
     410            ...
     411        TypeError: unable to simplify to float approximation
    396412    """
    397413    cdef Expression et
    398414    if isinstance(x, Expression):
  • sage/symbolic/expression_conversions.py

    diff --git a/sage/symbolic/expression_conversions.py b/sage/symbolic/expression_conversions.py
    a b  
    14101410            sage: def evalf_func(self, x, y, parent): return parent(x*y)
    14111411            sage: f = function('f', evalf_func=evalf_func)
    14121412            sage: f(x,y)._fast_callable_(etb)
    1413             {evalf_func}(v_0, v_1, <type 'float'>)
     1413            {placeholder_function}(v_0, v_1)
    14141414        """
    1415         try:
    1416             domain = self.etb._domain
    1417             if domain == None:
    1418                 domain = float
    1419             return self.etb.call(function._evalf_, *(ex.operands() + [domain]))
    1420         except AttributeError:
     1415        if hasattr(function, "_evalf_"):
     1416            def placeholder_function(*args):
     1417                return function._evalf_(*args, parent=self.etb._domain)
     1418            return self.etb.call(placeholder_function, *ex.operands())
     1419        else:
    14211420            return self.etb.call(function, *ex.operands())
    14221421
    14231422