Ticket #11888: trac_11888_v7.2.patch

File trac_11888_v7.2.patch, 10.3 KB (added by benjaminfjones, 12 months ago)

removed trailing whitespace

  • sage/functions/all.py

    # HG changeset patch
    # User Benjamin Jones <benjaminfjones@gmail.com>
    # Date 1328501390 21600
    # Node ID 553ea6c6f70e5890c030b00acb049b7ac0e8e371
    # Parent  9ab4ab6e12d0ce97566db069205815303514de4d
    Trac 11888: add the lambert_w symbolic function
    
    diff --git a/sage/functions/all.py b/sage/functions/all.py
    a b  
    2121                    arg, real_part, real, 
    2222                    imag_part, imag, imaginary, conjugate) 
    2323 
    24 from log import (exp, log, ln, polylog, dilog) 
     24from log import (exp, log, ln, polylog, dilog, lambert_w) 
    2525 
    2626 
    2727from transcendental import (exponential_integral_1, 
  • sage/functions/log.py

    diff --git a/sage/functions/log.py b/sage/functions/log.py
    a b  
    11""" 
    22Logarithmic functions 
    33""" 
    4 from sage.symbolic.function import GinacFunction 
     4from sage.symbolic.function import GinacFunction, BuiltinFunction, is_inexact 
     5from sage.symbolic.pynac import symbol_table 
     6from sage.symbolic.constants import e as const_e 
     7 
     8from sage.libs.mpmath import utils as mpmath_utils 
     9from sage.structure.coerce import parent as sage_structure_coerce_parent 
     10from sage.symbolic.expression import Expression 
     11from sage.rings.real_double import RDF 
     12from sage.rings.complex_double import CDF 
     13from sage.rings.all import Integer 
    514 
    615class Function_exp(GinacFunction): 
    716    def __init__(self): 
     
    429438            dilog(-1/2*I) 
    430439            sage: conjugate(dilog(2)) 
    431440            conjugate(dilog(2)) 
    432         """         
     441        """ 
    433442        GinacFunction.__init__(self, 'dilog', 
    434443                conversions=dict(maxima='li[2]')) 
    435444 
    436445dilog = Function_dilog() 
    437446 
     447 
     448class Function_lambert_w(BuiltinFunction): 
     449    r""" 
     450    The integral branches of the Lambert W function `W_n(z)`. 
     451 
     452    This function satisfies the equation 
     453 
     454    .. math:: 
     455 
     456        z = W_n(z) e^{W_n(z)} 
     457 
     458    INPUT: 
     459 
     460    - ``n`` - an integer. `n=0` corresponds to the principal branch. 
     461 
     462    - ``z`` - a complex number 
     463 
     464    If called with a single argument, that argument is ``z`` and the branch ``n`` is 
     465    assumed to be 0 (the principal branch). 
     466 
     467    ALGORITHM: 
     468 
     469    Numerical evaluation is handled using the mpmath and SciPy libraries. 
     470 
     471    REFERENCES: 
     472 
     473    - http://en.wikipedia.org/wiki/Lambert_W_function 
     474 
     475    EXAMPLES: 
     476 
     477    Evaluation of the principal branch:: 
     478 
     479        sage: lambert_w(1.0) 
     480        0.567143290409784 
     481        sage: lambert_w(-1).n() 
     482        -0.318131505204764 + 1.33723570143069*I 
     483        sage: lambert_w(-1.5 + 5*I) 
     484        1.17418016254171 + 1.10651494102011*I 
     485 
     486    Evaluation of other branches:: 
     487 
     488        sage: lambert_w(2, 1.0) 
     489        -2.40158510486800 + 10.7762995161151*I 
     490 
     491    Solutions to certain exponential equations are returned in terms of lambert_w:: 
     492 
     493        sage: S = solve(e^(5*x)+x==0, x, to_poly_solve=True) 
     494        sage: z = S[0].rhs(); z 
     495        -1/5*lambert_w(5) 
     496        sage: N(z) 
     497        -0.265344933048440 
     498 
     499    Check the defining equation numerically at `z=5`:: 
     500 
     501        sage: N(lambert_w(5)*exp(lambert_w(5)) - 5) 
     502        0.000000000000000 
     503 
     504    There are several special values of the principal branch which 
     505    are automatically simplified:: 
     506 
     507        sage: lambert_w(0) 
     508        0 
     509        sage: lambert_w(e) 
     510        1 
     511        sage: lambert_w(-1/e) 
     512        -1 
     513 
     514    Integration (of the principle branch) is evaluated using Maxima:: 
     515 
     516        sage: integrate(lambert_w(x), x) 
     517        (lambert_w(x)^2 - lambert_w(x) + 1)*x/lambert_w(x) 
     518        sage: integrate(lambert_w(x), x, 0, 1) 
     519        (lambert_w(1)^2 - lambert_w(1) + 1)/lambert_w(1) - 1 
     520        sage: integrate(lambert_w(x), x, 0, 1.0) 
     521        0.330366124762 
     522 
     523    Warning: The integral of the non-principle branch is not implemented, 
     524    neither is numerical integration using GSL. The :meth:`numerical_integral` 
     525    function does work if you pass a lambda function:: 
     526 
     527        sage: numerical_integral(lambda x: lambert_w(x), 0, 1) 
     528        (0.33036612476168054, 3.667800782666048e-15) 
     529    """ 
     530 
     531    def __init__(self): 
     532        r""" 
     533        See the docstring for :meth:`Function_lambert_w`. 
     534 
     535        EXAMPLES:: 
     536 
     537            sage: lambert_w(0, 1.0) 
     538            0.567143290409784 
     539        """ 
     540        BuiltinFunction.__init__(self, "lambert_w", nargs=2, 
     541                                 conversions={'mathematica':'ProductLog', 
     542                                              'maple':'LambertW'}) 
     543 
     544    def __call__(self, *args, **kwds): 
     545        r""" 
     546        Custom call method allows the user to pass one argument or two. If 
     547        one argument is passed, we assume it is ``z`` and that ``n=0``. 
     548 
     549        EXAMPLES:: 
     550 
     551            sage: lambert_w(1) 
     552            lambert_w(1) 
     553            sage: lambert_w(1, 2) 
     554            lambert_w(1, 2) 
     555        """ 
     556        if len(args) == 2: 
     557            return BuiltinFunction.__call__(self, *args, **kwds) 
     558        elif len(args) == 1: 
     559            return BuiltinFunction.__call__(self, 0, args[0], **kwds) 
     560        else: 
     561            raise TypeError("lambert_w takes either one or two arguments.") 
     562 
     563    def _eval_(self, n, z): 
     564        """ 
     565        EXAMPLES:: 
     566 
     567            sage: lambert_w(6.0) 
     568            1.43240477589830 
     569            sage: lambert_w(1) 
     570            lambert_w(1) 
     571            sage: lambert_w(x+1) 
     572            lambert_w(x + 1) 
     573 
     574        There are three special values which are automatically simplified:: 
     575 
     576            sage: lambert_w(0) 
     577            0 
     578            sage: lambert_w(e) 
     579            1 
     580            sage: lambert_w(-1/e) 
     581            -1 
     582            sage: lambert_w(SR(-1/e)) 
     583            -1 
     584            sage: lambert_w(SR(0)) 
     585            0 
     586 
     587        The special values only hold on the principal branch:: 
     588 
     589            sage: lambert_w(1,e) 
     590            lambert_w(1, e) 
     591            sage: lambert_w(1, e.n()) 
     592            -0.532092121986380 + 4.59715801330257*I 
     593        """ 
     594        if not isinstance(z, Expression): 
     595            if is_inexact(z): 
     596                return self._evalf_(n, z, parent=sage_structure_coerce_parent(z)) 
     597            elif n == 0 and z == 0: 
     598                return sage_structure_coerce_parent(z)(0) 
     599        elif n == 0: 
     600            if z.is_trivial_zero(): 
     601                return sage_structure_coerce_parent(z)(0) 
     602            elif (z-const_e).is_trivial_zero(): 
     603                return sage_structure_coerce_parent(z)(1) 
     604            elif (z+1/const_e).is_trivial_zero(): 
     605                return sage_structure_coerce_parent(z)(-1) 
     606        return None 
     607 
     608    def _evalf_(self, n, z, parent=None): 
     609        """ 
     610        EXAMPLES:: 
     611 
     612            sage: N(lambert_w(1)) 
     613            0.567143290409784 
     614            sage: lambert_w(RealField(100)(1)) 
     615            0.56714329040978387299996866221 
     616 
     617        SciPy is used to evaluate for float, RDF, and CDF inputs:: 
     618 
     619            sage: lambert_w(RDF(1)) 
     620            0.56714329041 
     621        """ 
     622        R = parent or sage_structure_coerce_parent(z) 
     623        if R is float or R is complex or R is RDF or R is CDF: 
     624            import scipy.special 
     625            return scipy.special.lambertw(z, n) 
     626        else: 
     627            import mpmath 
     628            return mpmath_utils.call(mpmath.lambertw, z, n, parent=R) 
     629 
     630    def _derivative_(self, n, z, diff_param=None): 
     631        """ 
     632        The derivative of `W_n(x)` is `W_n(x)/(x \cdot W_n(x) + x)`. 
     633 
     634        EXAMPLES:: 
     635 
     636            sage: x = var('x') 
     637            sage: derivative(lambert_w(x), x) 
     638            lambert_w(x)/(x*lambert_w(x) + x) 
     639        """ 
     640        return lambert_w(n, z)/(z*lambert_w(n, z)+z) 
     641 
     642    def _maxima_init_evaled_(self, n, z): 
     643        """ 
     644        EXAMPLES: 
     645 
     646        These are indirect doctests for this function.:: 
     647 
     648            sage: lambert_w(0, x)._maxima_() 
     649            lambert_w(x) 
     650            sage: lambert_w(1, x)._maxima_() 
     651            Traceback (most recent call last): 
     652            ... 
     653            NotImplementedError: Non-principal branch lambert_w[1](x) is not implemented in Maxima 
     654        """ 
     655        if n == 0: 
     656            return "lambert_w(%s)" % z 
     657        else: 
     658            raise NotImplementedError("Non-principal branch lambert_w[%s](%s) is not implemented in Maxima" % (n, z)) 
     659 
     660 
     661    def _print_(self, n, z): 
     662        """ 
     663        Custom _print_ method to avoid printing the branch number if 
     664        it is zero. 
     665 
     666        EXAMPLES:: 
     667 
     668            sage: lambert_w(1) 
     669            lambert_w(1) 
     670            sage: lambert_w(0,x) 
     671            lambert_w(x) 
     672        """ 
     673        if n == 0: 
     674            return "lambert_w(%s)" % z 
     675        else: 
     676            return "lambert_w(%s, %s)" % (n,z) 
     677 
     678    def _print_latex_(self, n, z): 
     679        """ 
     680        Custom _print_latex_ method to avoid printing the branch 
     681        number if it is zero. 
     682 
     683        EXAMPLES:: 
     684 
     685            sage: latex(lambert_w(1)) 
     686            \operatorname{W_0}(1) 
     687            sage: latex(lambert_w(0,x)) 
     688            \operatorname{W_0}(x) 
     689            sage: latex(lambert_w(1,x)) 
     690            \operatorname{W_{1}}(x) 
     691        """ 
     692        if n == 0: 
     693            return r"\operatorname{W_0}(%s)" % z 
     694        else: 
     695            return r"\operatorname{W_{%s}}(%s)" % (n,z) 
     696 
     697lambert_w = Function_lambert_w() 
  • sage/interfaces/maxima_lib.py

    diff --git a/sage/interfaces/maxima_lib.py b/sage/interfaces/maxima_lib.py
    a b  
    10771077    sage.functions.log.exp : "%EXP", 
    10781078    sage.functions.log.ln : "%LOG", 
    10791079    sage.functions.log.log : "%LOG", 
     1080    sage.functions.log.lambert_w : "%LAMBERT_W", 
    10801081    sage.functions.other.factorial : "MFACTORIAL", 
    10811082    sage.functions.other.erf : "%ERF", 
    10821083    sage.functions.other.gamma_inc : "%GAMMA_INCOMPLETE", 
     
    11661167max_array=EclObject("ARRAY") 
    11671168mdiff=EclObject("%DERIVATIVE") 
    11681169max_gamma_incomplete=sage_op_dict[sage.functions.other.gamma_inc] 
     1170max_lambert_w=sage_op_dict[sage.functions.log.lambert_w] 
    11691171 
    11701172def mrat_to_sage(expr): 
    11711173    r""" 
     
    13551357    sage.functions.log.polylog : lambda N,X : [[mqapply],[[max_li, max_array],N],X], 
    13561358    sage.functions.other.psi1 : lambda X : [[mqapply],[[max_psi, max_array],0],X], 
    13571359    sage.functions.other.psi2 : lambda N,X : [[mqapply],[[max_psi, max_array],N],X], 
    1358     sage.functions.other.Ei : lambda X : [[max_gamma_incomplete], 0, X] 
     1360    sage.functions.other.Ei : lambda X : [[max_gamma_incomplete], 0, X], 
     1361    sage.functions.log.lambert_w : lambda N,X : [[max_lambert_w], X] if N==EclObject(0) else [[mqapply],[[max_lambert_w, max_array],N],X] 
    13591362} 
    13601363 
    13611364