简体   繁体   English

Python Sympy 任意近似于任意 Sympy 表达式?

[英]Python Sympy Arbitrary Approximation to Arbitrary Sympy Expression?

I find myself wanting to use approxmations provided as part of the mpmath package, but getting confused on exactly what they are supposed to be doing:我发现自己想使用作为 mpmath 包的一部分提供的近似值,但对它们应该做什么感到困惑:

http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html

What exactly is the difference between a sympy expression and a sympy.mpmath expression ? sympy 表达式和 sympy.mpmath 表达式之间到底有什么区别?

If I want a taylor approximation to a symbolic expression without understanding what mpmath package is doing I can do the following:如果我想要一个符号表达式的泰勒近似而不理解 mpmath 包在做什么,我可以执行以下操作:

#Imports
import sympy
import sympy.parsing
import sympy.parsing.sympy_parser
import Library_TaylorApproximation

#Create a sympy expression to approximate
ExampleStringExpression = 'sin(x)'
ExampleSympyExpression = sympy.parsing.sympy_parser.parse_expr(ExampleStringExpression)


#Create a taylor expantion sympy expression around the point x=0
SympyTaylorApproximation = sympy.series( 
    ExampleSympyExpression,
    sympy.Symbol('x'),
    1, 
    4,
    ).removeO()

#Cast the sympy expressions to python functions which can be evaluated:
VariableNames = [str(var) for var in SympyTaylorApproximation.free_symbols]
PythonFunctionOriginal =  sympy.lambdify(VariableNames, ExampleSympyExpression)
PythonFunctionApproximation = sympy.lambdify(VariableNames, SympyTaylorApproximation)

#Evaluate the approximation and the original at a point:
print PythonFunctionOriginal(2)
print PythonFunctionApproximation(2)

#>>> 0.909297426826
#>>> 0.870987413961

However, if I try to do the same thing with mpmath based on the documentation:但是,如果我尝试根据文档对 mpmath 执行相同的操作:

TaylorCoefficients = sympy.mpmath.taylor(ExampleSympyExpression, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients

#>>> TypeError: 'sin' object is not callable

I can try to cram the python function in there (which is callable):我可以尝试将 python 函数塞入其中(可调用):

TaylorCoefficients = sympy.mpmath.taylor(PythonFunctionOriginal, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients

#>>> TaylorCoefficients [mpf('0.8414709848078965'), mpf('0.0'), mpf('0.0'), mpf('0.0'), mpf('-8.3694689805155739e+57')]

But the above does not make any sense, because I know that derivatives cannot be taken of a python function.但是以上没有任何意义,因为我知道不能对python函数进行导数。

I can call the mpmath function sin :我可以调用 mpmath 函数sin

TaylorCoefficients = sympy.mpmath.taylor(sympy.mpmath.sin, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients
#>>> TaylorCoefficients [mpf('0.8414709848078965'), mpf('0.54030230586813977'), mpf('-0.42073549240394825'), mpf('-0.090050384311356632'), mpf('0.035061291033662352')]

But then I cannot do manipulations on it the way I would want too -> like If I want但是,我也无法按照我想要的方式对其进行操作 -> 喜欢如果我想要

SinTimesCos = sympy.mpmath.sin*sympy.mpmath.cos
TaylorCoefficients = sympy.mpmath.taylor(SinTimesCos, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients
#>>> TypeError: unsupported operand type(s) for *: 'function' and 'function'

Exactly WHAT is an mpmath function ?究竟什么是 mpmath 函数?

It is not a sympy expression, and it is also not a python function.它不是一个 sympy 表达式,也不是一个 python 函数。 How do I do manipulations on arbitrary expressions?如何对任意表达式进行操作?

It would appear that I cannot take approximations of arbitrary sympy expressions in the documentation.看来我不能在文档中对任意 sympy 表达式进行近似处理。 http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html

How do I take arbitrary approximations ( Pade / Cheby Chev / Fourier ) to arbitrary sympy expressions?如何对任意 sympy 表达式进行任意近似(Pade / Cheby Chev / Fourier)?

EDIT:编辑:

So an example of what I am looking for is the following approximation:所以我正在寻找的一个例子是以下近似值:

#Start with a sympy expression of (a, b, x)
expressionString = 'cos(a*x)*sin(b*x)*(x**2)'
expressionSympy = sympy.parsing.sympy_parser.parse_expr(expressionString)

#Do not want to decide on value of `a or b` in advance.
#Do want approximation with respect to x:

wantedSympyExpression = SympyChebyChev( expressionSympy, sympy.Symbol('x') ) 

Result could either be a list of coefficient expressions that are functions of a , and b :结果可能或者是系数表达式是功能的列表a ,和b

wantedSympyExpressionCoefficients = [ Coef0Expression(a,b), Coef1Expression(a,b), ... , CoefNExpression(a,b)]

OR the result could be the entire sympy expression itself (which is itself a function of a , b ):或者结果可能是整个 sympy 表达式本身(它本身是ab的函数):

wantedSympyExpression = Coef0Expression(a,b) + Coef1Expression(a,b) *(x**2) + ... + CoefNExpression(a,b) (x**N)

Note that a and b are not chosen in advance of performing the approximation.请注意, ab不是在执行近似之前选择的。

mpmath functions are ordinary Python functions. mpmath 函数是普通的 Python 函数。 They simply do their math in arbitrary-precision arithmetic.他们只是在任意精度算术中进行数学运算。

But the above does not make any sense, because I know that derivatives cannot be taken of a python function.但是以上没有任何意义,因为我知道不能对python函数进行导数。

You can't take the derivative symbolically , but you can compute an approximation of the derivative by evaluating the function several times and using numerical differentiation techniques.您不能象征性地取导数,但您可以通过多次评估函数并使用数值微分技术来计算导数的近似值。 This is what sympy.mpmath.taylor does.这就是sympy.mpmath.taylor所做的。 Quoting the docs:引用文档:

The coefficients are computed using high-order numerical differentiation.系数是使用高阶数值微分计算的。 The function must be possible to evaluate to arbitrary precision.该函数必须可以评估为任意精度。

If you have a SymPy expression and want to evaluate it to arbitrary precision, use evalf , like如果您有一个 SymPy 表达式并希望将其计算为任意精度,请使用evalf ,例如

sympy.sin(1).evalf(100)

You can use sin(x).evalf(100, subs={x:1}) to replace the x with 1 before evaluating.在评估之前sin(x).evalf(100, subs={x:1})您可以使用sin(x).evalf(100, subs={x:1})x替换为1 evalf uses mpmath under the hood, so this will give you the same result that mpmath would, but without having to use mpmath directly. evalfevalf使用 mpmath,所以这会给你与 mpmath 相同的结果,但不必直接使用 mpmath。

EDIT: Rereading my answer -> I thought I would fill in a few missing pieces as a service to someone someday actually using this.编辑:重读我的答案 -> 我想我会填写一些缺失的部分作为服务,有一天我会真正使用它。 Below I labeled how I named my libraries, and what imports were required.下面我标记了我如何命名我的库,以及需要什么导入。 I don't have the time to be a real contributor to sympy at the moment, but feel this functionality would certainly be used by other math/physics professors/students.我目前没有时间成为 sympy 的真正贡献者,但我觉得这个功能肯定会被其他数学/物理教授/学生使用。

Note for space reasons the following two libraries are omitted, and I will throw a link to my repo at a future date.请注意,出于空间原因,省略了以下两个库,我将在以后的某个日期抛出一个指向我的存储库的链接。

import Library_SympyExpressionToPythonFunction

Creates a python callable function object with the same args ( number and names ) of the free variables in a sympy expression.在 sympy 表达式中创建一个具有相同参数(数字和名称)的自由变量的 python 可调用函数对象。

import Library_SympyExpressionToStringExpression

Literally just does str(SympyExpression)从字面上看只是 str(SympyExpression)

#-------------------------------------------------------------------------------

Library_GenerateChebyShevPolynomial::: Library_GenerateChebyShevPolynomial:::

#-------------------------------------------------------------------------------


import pprint
import Library_SympyExpressionToPythonFunction
import Library_SympyExpressionToStringExpression
import sympy
import sympy.core

def Main(
    ApproximationSymbol = sympy.Symbol('x'),
    ResultType = 'sympy',
    Kind= None,
    Order= None,
    ReturnAll = False,
    CheckArguments = True,
    PrintExtra = False,
    ):

    Result = None

    if (CheckArguments):
        ArgumentErrorMessage = ""

        if (len(ArgumentErrorMessage) > 0 ):
            if(PrintExtra):
                print "ArgumentErrorMessage:\n", ArgumentErrorMessage
            raise Exception(ArgumentErrorMessage)

    ChebyChevPolynomials = []
    ChebyChevPolynomials.append(sympy.sympify(1.))
    ChebyChevPolynomials.append(ApproximationSymbol)

    #Generate the polynomial with sympy:
    for Term in range(Order + 1)[2:]:
        Tn = ChebyChevPolynomials[Term - 1]
        Tnminus1 = ChebyChevPolynomials[Term - 2]
        Tnplus1 = 2*ApproximationSymbol*Tn - Tnminus1

        ChebyChevPolynomials.append(Tnplus1.simplify().expand().trigsimp())

    if(PrintExtra): print 'ChebyChevPolynomials'
    if(PrintExtra): pprint.pprint(ChebyChevPolynomials)


    if (ReturnAll):
        Result = []
        for SympyChebyChevPolynomial in ChebyChevPolynomials:
            if (ResultType == 'python'):
                Result.append(Library_SympyExpressionToPythonFunction.Main(SympyChebyChevPolynomial))
            elif (ResultType == 'string'):
                Result.append(Library_SympyExpressionToStringExpression.Main(SympyChebyChevPolynomial))
            else:
                Result.append(SympyChebyChevPolynomial)

    else:
        SympyExpression = ChebyChevPolynomials[Order] #the last one

        #If the result type is something other than sympy, we can cast it into that type here:
        if (ResultType == 'python'):
            Result = Library_SympyExpressionToPythonFunction.Main(SympyExpression)
        elif (ResultType == 'string'):
            Result = Library_SympyExpressionToStringExpression.Main(SympyExpression)
        else:
            Result = SympyExpression



    return Result 


#-------------------------------------------------------------------------------

Library_SympyChebyShevApproximationOneDimension Library_SympyChebyShevApproximationOneDimension

#-------------------------------------------------------------------------------


import numpy
import sympy
import sympy.mpmath
import pprint
import Library_SympyExpressionToPythonFunction
import Library_GenerateChebyShevPolynomial

def Main(
    SympyExpression= None,
    DomainMinimumPoint= None,
    DomainMaximumPoint= None,
    ApproximationOrder= None,
    CheckArguments = True,
    PrintExtra = False,
    ):

    #Tsymb = sympy.Symbol('t')
    Xsymb = sympy.Symbol('x')
    DomainStart = DomainMinimumPoint[0]
    print 'DomainStart', DomainStart
    DomainEnd = DomainMaximumPoint[0]
    print 'DomainEnd', DomainEnd

    #Transform the coefficients and the result to be on arbitrary inverval instead of from 0 to 1
    DomainWidth = DomainEnd - DomainStart
    DomainCenter = (DomainEnd - DomainStart) / 2.
    t = (Xsymb*(DomainWidth) + DomainStart + DomainEnd) / 2.
    x = (2.*Xsymb - DomainStart - DomainEnd) / (DomainWidth)
    SympyExpression = SympyExpression.subs(Xsymb, t)

    #GET THE COEFFICIENTS:
    Coefficients = []
    for CoefficientNumber in range(ApproximationOrder):
        if(PrintExtra): print 'CoefficientNumber', CoefficientNumber

        Coefficient = 0.0
        for k in range(1, ApproximationOrder + 1):
            if(PrintExtra): print '  k', k

            CoefficientFunctionPart = SympyExpression.subs(Xsymb, sympy.cos( sympy.pi*( float(k) - .5 )/ float(ApproximationOrder) )  )
            if(PrintExtra): print '  CoefficientFunctionPart', CoefficientFunctionPart

            CeofficientCosArg = float(CoefficientNumber)*( float(k) - .5 )/ float( ApproximationOrder)
            if(PrintExtra): print '  ',CoefficientNumber,'*','(',k,'-.5)/(', ApproximationOrder ,') == ', CeofficientCosArg

            CoefficientCosPart      =   sympy.cos( sympy.pi*CeofficientCosArg )
            if(PrintExtra): print '  CoefficientCosPart', CoefficientCosPart

            Coefficient += CoefficientFunctionPart*CoefficientCosPart

        if(PrintExtra): print 'Coefficient==', Coefficient

        Coefficient = (2./ApproximationOrder)*Coefficient.evalf(10)

        if(PrintExtra): print 'Coefficient==', Coefficient

        Coefficients.append(Coefficient)

    print '\n\nCoefficients'
    pprint.pprint( Coefficients )


    #GET THE POLYNOMIALS:
    ChebyShevPolynomials = Library_GenerateChebyShevPolynomial.Main(
        ResultType = 'sympy',
        Kind= 1,
        Order= ApproximationOrder-1,
        ReturnAll = True,
        )

    print '\nChebyShevPolynomials'
    pprint.pprint( ChebyShevPolynomials )


    Result = 0.0 -.5*(Coefficients[0])
    for Coefficient, ChebyShevPolynomial in zip(Coefficients, ChebyShevPolynomials):
        Result += Coefficient*ChebyShevPolynomial

    #Transform the coefficients and the result to be on arbitrary inverval instead of from 0 to 1
    Result = Result.subs(Xsymb, x)

    return Result

------------------------------------------------------------------------------ -------------------------------------------------- -----------------------------

Example_SympyChebyShevApproximationOneDimension: Example_SympyChebyShevApproximationOneDimension:

#------------------------------------------------------------------------------
import sympy
import sympy.mpmath
import matplotlib.pyplot as plt
import json
import pprint




import Library_GenerateBesselFunction
import Library_SympyChebyShevApproximationOneDimension
import Library_SympyExpressionToPythonFunction
import Library_GraphOneDimensionalFunction


ApproximationOrder = 10

#CREATE THE EXAMPLE EXRESSION:
Kind = 1
Order = 2
ExampleSympyExpression = sympy.sin(sympy.Symbol('x'))

"""
Library_GenerateBesselFunction.Main(
    ResultType =  'sympy',
    Kind =  Kind,
    Order =  Order,
    VariableNames = ['x'],
    ) 
"""
PythonOriginalFunction = Library_SympyExpressionToPythonFunction.Main( 
    ExampleSympyExpression ,
    FloatPrecision = 100,
    )

#CREATE THE NATIVE CHEBY APPROXIMATION

ChebyDomainMin = 5.
ChebyDomainMax = 10.
ChebyDomain = [ChebyDomainMin, ChebyDomainMax]
ChebyExpandedPolynomialCoefficients, ChebyError = sympy.mpmath.chebyfit(
    PythonOriginalFunction, 
    ChebyDomain, 
    ApproximationOrder, 
    error=True
    )
print 'ChebyExpandedPolynomialCoefficients'
pprint.pprint( ChebyExpandedPolynomialCoefficients )
def PythonChebyChevApproximation(Point):
    Result = sympy.mpmath.polyval(ChebyExpandedPolynomialCoefficients, Point)
    return Result


#CREATE THE GENERIC ONE DIMENSIONAL CHEBY APPROXIMATION:
SympyChebyApproximation = Library_SympyChebyShevApproximationOneDimension.Main(
    SympyExpression = ExampleSympyExpression*sympy.cos( sympy.Symbol('a') ),
    ApproximationSymbol = sympy.Symbol('x'),
    DomainMinimumPoint = [ChebyDomainMin],
    DomainMaximumPoint = [ChebyDomainMax],
    ApproximationOrder = ApproximationOrder
    )


print 'SympyChebyApproximation', SympyChebyApproximation

SympyChebyApproximation = SympyChebyApproximation.subs(sympy.Symbol('a'), 0.0)

print 'SympyChebyApproximation', SympyChebyApproximation

PythonCastedChebyChevApproximationGeneric = Library_SympyExpressionToPythonFunction.Main( 
    SympyChebyApproximation ,
    FloatPrecision = 100,
    )

print 'PythonCastedChebyChevApproximationGeneric(1)', PythonCastedChebyChevApproximationGeneric(1.)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM