Python Sympy Произвольное приближение к произвольному выражению Sympy?
Я хочу использовать аппроксимации, предоставляемые как часть пакета mpmath, но не совсем понимаю, что именно они должны делать:
http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html
В чем разница между выражением sympy и выражением sympy.mpmath?
Если я хочу приближение Тейлора к символическому выражению, не понимая, что делает пакет 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
Однако, если я попытаюсь сделать то же самое с mpmath на основе документации:
TaylorCoefficients = sympy.mpmath.taylor(ExampleSympyExpression, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients
#>>> TypeError: 'sin' object is not 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')]
Но вышеупомянутое не имеет никакого смысла, потому что я знаю, что производные не могут быть взяты из функции python.
Я могу вызвать функцию 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')]
Но тогда я не могу делать манипуляции на нем так, как я бы тоже хотел -> например, если я хочу
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'
Что такое функция mpmath?
Это не симпатичное выражение, и это также не функция Python. Как мне делать манипуляции с произвольными выражениями?
Казалось бы, я не могу взять приближения произвольных выражений симпатии в документации. http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html
Как я могу взять произвольные приближения (Паде / Чеби Шев / Фурье) для произвольных выражений симпатий?
РЕДАКТИРОВАТЬ:
Итак, пример того, что я ищу, это следующее приближение:
#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') )
Результатом может быть либо список выражений коэффициентов, которые являются функциями a
, а также b
:
wantedSympyExpressionCoefficients = [ Coef0Expression(a,b), Coef1Expression(a,b), ... , CoefNExpression(a,b)]
ИЛИ результатом может быть само выражение sympy (которое само является функцией a
, b
):
wantedSympyExpression = Coef0Expression(a,b) + Coef1Expression(a,b) *(x**2) + ... + CoefNExpression(a,b) (x**N)
Обратите внимание, что a
а также b
не выбраны заранее выполнения аппроксимации.
3 ответа
РЕДАКТИРОВАТЬ: Перечитывая мой ответ -> Я думал, что я заполню несколько пропущенных частей в качестве услуги для кого-то, кто когда-нибудь на самом деле использует это. Ниже я отметил, как я назвал свои библиотеки, и какой импорт был необходим. У меня нет времени, чтобы стать реальным участником симпати в данный момент, но я чувствую, что эта функция наверняка будет использована другими преподавателями математики / физики / студентами.
Обратите внимание, из-за нехватки места следующие две библиотеки опущены, и я добавлю ссылку на мой репо в будущем.
import Library_SympyExpressionToPythonFunction
Создает объект вызываемой функции Python с теми же аргументами (числом и именами) свободных переменных в выражении sympy.
import Library_SympyExpressionToStringExpression
Буквально просто делает str (SympyExpression)
#-------------------------------------------------------------------------------
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
#-------------------------------------------------------------------------------
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:
#------------------------------------------------------------------------------
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.)
Функции mpmath - это обычные функции Python. Они просто делают математику в произвольной арифметике.
Но вышеупомянутое не имеет никакого смысла, потому что я знаю, что производные не могут быть взяты из функции python.
Вы не можете взять производную символически, но вы можете вычислить аппроксимацию производной, оценив функцию несколько раз и используя методы численного дифференцирования. Это то, что sympy.mpmath.taylor
делает. Цитирование документов:
Коэффициенты вычисляются с использованием численного дифференцирования высокого порядка. Функция должна быть возможна для оценки с произвольной точностью.
Если у вас есть выражение SymPy и вы хотите оценить его с произвольной точностью, используйте evalf
, лайк
sympy.sin(1).evalf(100)
Ты можешь использовать sin(x).evalf(100, subs={x:1})
заменить x
с 1
перед оценкой. evalf
использует mpmath под капотом, так что это даст вам тот же результат, что и mpmath, но без необходимости использовать mpmath напрямую.