Fourier series of a box function using sympy - fft

I tried this code but i m getting an error. And If possible pls tell me how to lambdify the defined funct
CODE
from sympy.abc import x
from sympy import *
init_printing()
def func(y):
if y>0:
return 1
elif y<0:
return -1
else:
return 0
s = fourier_series(func(x), (x, -1, 1))
s = s.truncate(n=4)
s
"TypeError: cannot determine truth value of Relational"
this is the error im getting
Please help,
Thank you.

Note that sympy can only work with functions that are fully defined as a sympy expression. To emulate if - elif - else, Piecewise can be used. There is also a special function, Heaviside, that directly corresponds to your given function. Default, Heaviside(0) is undefined. However, the value for 0 can be provided as a second argument.
Using the Heaviside function doesn't seem to work in this case:
from sympy import Heaviside, fourier_series
from sympy.abc import x
s = fourier_series(Heaviside(x, 0), (x, -1, 1))
print(s)
This results in an unevaluated integral with which sympy can't do further operations:
FourierSeries(Heaviside(x, 0), (x, -1, 1), (Integral(Heaviside(x, 0), (x, -1, 1))/2, SeqFormula(cos(_n*pi*x)*Integral(cos(_n*pi*x)*Heaviside(x, 0), (x, -1, 1)), (_n, 1, oo)), SeqFormula(sin(_n*pi*x)*Integral(sin(_n*pi*x)*Heaviside(x, 0), (x, -1, 1)), (_n, 1, oo))))
Fortunately, with Piecewise, everything works as desired:
from sympy import lambdify, Piecewise, fourier_series
from sympy.abc import x
s = fourier_series(Piecewise((1, x > 0), (-1, x < 0), (0, True)), (x, -1, 1))
The function can be lambdified calling lambdify(x, s.truncate(n=4)), and then be used for example to draw curves via matplotlib:
import numpy as np
import matplotlib.pyplot as plt
for k in range(1, 7):
s_np = lambdify(x, s.truncate(n=k))
xs = np.linspace(-1, 1, 500)
plt.plot(xs, s_np(xs), label=f'$n={k}$')
plt.autoscale(enable=True, axis='x', tight=True)
plt.legend()
plt.show()

Related

How to define a piecewise map in sage

I want to define in Sage the following
map. I've attempted to use the following code in Sage:
gamma=function('gamma')
gamma(t)=piecewise([(t>0,(t,0,e^(-1/t^2))),(t==0,(0,0,0)),(t<0,(t,e^(-1/t^2),0))])
This, however, gives me the error TypeError: unable to convert (t, 0, e^(-1/t^2)) to a symbolic expression. How could I change it to create such a type of map?
It seems piecewise does not support vector-valued functions.
Possible workaround: define each coordinate as a piecewise function.
sage: gamma(t) = (t,
....: piecewise([(t <= 0, 0), (t > 0, exp(-t^-2))]),
....: piecewise([(t < 0, exp(-t^-2)), (t > 0, 0)]))
....:
sage: gamma
t |--> (t,
piecewise(t|-->0 on (-oo, 0], t|-->e^(-1/t^2) on (0, +oo); t),
piecewise(t|-->e^(-1/t^2) on (-oo, 0), t|-->0 on (0, +oo); t))
sage: parametric_plot(gamma, (t, -1, 1))
Launched html viewer for Graphics3d Object

Erro in sin function for python

I have a question regarding using the sine function. When I entered the number 4, 8, .., etc., really I supposed to get the number somewhere very close to zero, but not exactly (Ex. 0.001, 0.0003, etc). However, I got the number y = 1.224 when x = 4, and y = -2.449 when x = 8. This should be incorrect. I don’t understand the problem here. Does anyone know what is going on here?
[Photo of my code and a sin graph - Link]
https://ibb.co/6YCWW90
[Code]
import math
import matplotlib.pyplot as plt
import numpy as np
x = [0, 1, 2, 3, 4, 5, 6, 7, 8]
y = [math.sin(0.25 * math.pi * i) for i in x]
print(y)
plt.plot(x, y)
plt.show()
Everything works.
When i is 0, then "0.25 * math.pi * i" is precisely 0 and when you calculate the sine, you get exactly 0.0.
When i is 4, then calculating "0.25 * math.pi * i" results in a number very close to PI, but the accuracy is limited. If you calculate the sine, you get a number which is very, very close to zero, but because of limited accuracy, not exactly zero. The result is 1.2246467991473532e-16. NOTE: it is 0.00000000000000012246467991473532, not 1.224 what your wrote in your question.
Similarly rounding errors result in -2.4492935982947064e-16 for i equal to 8. The argument is not exactly 2 PI and rounding errors result in a value slightly different than 0.0.
Again -2.4492935982947064e-16 is -0.00000000000000024492935982947064 and not -2.449 as you wrote in your question.

Scipy Optimization: Pass a function as a constraint with additional arguments (args)

I have an optimization problem (optimze by changing x[0] and x[1]), where one of the constraints is a function, that uses the same constant variables (a and b) as the optimization function.
min f(x, a, b)
x[0] <= 100
x[1] <= 500
g(x, a, b) >= 0.9
But I am not sure how to realize the connection between function f and g:
x0 = np.array([10, 100])
bnds = ((0, 500), (0, 5000))
arguments = (100, 4) # This are varibles a and b
cons = ({'type': 'ineq', 'fun': lambda x: x[0]},
{'type': 'ineq', 'fun': lambda x: x[1]},
{'type': 'ineq', 'fun': lambda x: g(x, 100, 4)-0.9})
res = minimize(f, x0, args=arguments, method='SLSQP', bounds=bnds, constraints=cons)
print(res.x)
>> x: array([10, 5000])
But using this results function g results in
g(x,a,b)=0.85434
There is an optimal solution with x=[452, 4188], where
g(x,a,b)=0.901839
How do I need to adapt the constraints, that g(x,a,b) is valid.
Edit: Obviously the optimization is not sucessful:
print(res)
>> fun: 1778.86301369863
>> jac: array([1.00019786e+09, 9.31503296e-01])
>> message: 'Inequality constraints incompatible'
>> nfev: 4
>> nit: 1
>> njev: 1
>> status: 4
>> success: False
>> x: array([ 10., 5000.])
Thanks a lot.
UvW
f() and g() are not convex, not smooth and derivates are not available. Nevertheless my questioned aimed for the right syntax (using a function as a constraint). So I tried it with two "simpler" functions (see executeable code below) and it worked. So I assume, that my syntax is right and the problem lies with optimization method "SLSQP".
Is there an optimization method within the SCIPY package (some kind of Evolutionary algorithm) that I can use to solve my problem with g() and f()
not convex,
not smooth and
derivates are not available?
import numpy as np
from scipy.optimize import minimize
def g(x, a, b):
return (x[0]+x[1]+a+b)/100
def f(x, a, b):
return (x[0]*a+x[1]*b)*g(x, a, b)
x0 = np.array([0, 0]) bnds = ((0, 30), (0, 20)) arguments = (2, 3) # This are varibles a and b
cons = ({'type': 'ineq', 'fun': lambda x: x[0]},
{'type': 'ineq', 'fun': lambda x: x[1]},
{'type': 'ineq', 'fun': lambda x: g(x, 2, 3)-0.5}) #<--My question was about the correct syntax of that constraint
res = minimize(f, x0, args=arguments, method='SLSQP', bounds=bnds, constraints=cons)
print(res)
>> fun: 52.50000000000027
>> jac: array([2.05000019, 2.55000019])
>> message: 'Optimization terminated successfully.'
>> nfev: 20
>> nit: 5
>> njev: 5
>> status: 0
>> success: True
>> x: array([30., 15.])

Area of the quarter circle with SymPy Integrate?

I would like to evaluate the following integral using SymPy:
from sympy import *
x = symbols('x')
a = symbols('a', positive=True)
expr = sqrt(a**2 - x**2)
integrate(expr, (x, 0, pi/2))
What I would expect as an outcome is the area of the quarter circle (i.e., a^2*pi/4). Unfortunately, SymPy does not provide this result. When considering
integrate(expr, x)
I obtain the correct indefinite integral but when adding the limits it does not work.
Any ideas what I am doing wrong?
Thanks and all best,
VK88
The limit should be a if that is the radius and you are working in Cartesian coordinates:
from sympy import *
x = symbols('x')
a = symbols('a', positive=True)
expr = sqrt(a**2 - x**2)
integrate(expr, (x, 0, a))
That gives:
2
π⋅a
────
4

Integrating a function with a very large parameter values in Python

I have a function defined as below
\begin{equation}
f(x) = e^{-k1/x}x^{-2}(k1/x+56)^{81}
\end{equation}
Now I want to find integrate the function from 0 to infinite.
\begin{equation}
S = \int^{\inf}_{0} f(x) dx
\end{equation}
And then I want to find the cumulative function defined as below
\begin{equation}
CDF(p) = \int^{p}_{0} \frac{f(x)}{S} dx
\end{equation}
To do so, I wrote a program in Python.
from matplotlib import pyplot as plt
from scipy.integrate import quad
from math import pi, exp
import numpy as np
def func(x, k1, n):
w = -1.8*n+15 # scale the function down.
return (10**w)*exp(-k1/x)*x**(-2)*(k1/x+56)**n
def S(k1, n):
return quad(func, 0, 1e+28, args=(k1, n))[0] + quad(func, 1e+28, 1e+33, args=(k1, n))[0]
def CDF(x, k1, n):
return quad(func, 0, x, args=(k1, n))[0]/S(k1, n)
k1 = 7.7e+27 # When it's <3, CDF does not generate error.
n = 81
print(S(k1, n))
print(CDF(1.1e+27, k1, n))
But unfortunately, the CDF(1.1e+27) throws the error "results out of range".
How could I obtain CDF(1.1e+27)?