Files
2026-07-13 12:32:53 +08:00

279 lines
11 KiB
Python

import pytest
from mpmath import (arange, chebyfit, cos, cosm, differint, e, euler, exp,
expm, fourier, fourierval, inf, invertlaplace, j, limit,
log, matrix, mp, mpf, norm, pade, pi, polyroots, polyval,
sin, sinm, sqrt, logm)
def test_approximation():
f = lambda x: cos(2-2*x)/x
p, err = chebyfit(f, [2, 4], 8, error=True)
assert err < 1e-5
for i in range(10):
x = 2 + i/5.
assert abs(polyval(p, x) - f(x)) < err
def test_chebyfit():
f = lambda x: cos(2-2*x)/x
p, err = chebyfit(f, [2, 4], 8, error=True, asc=False)
assert err < 1e-5
p = p[::-1]
for i in range(10):
x = 2 + i/5.
assert abs(polyval(p, x) - f(x)) < err
def test_chebyfit_nonpositive_N():
with pytest.raises(ValueError):
chebyfit(sin, [-1, 1], 0)
def test_limits():
assert limit(lambda x: (x-sin(x))/x**3, 0).ae(mpf(1)/6)
assert limit(lambda n: (1+1/n)**n, inf).ae(e)
def test_polyval():
assert polyval([], 3) == 0
assert polyval([0], 3) == 0
assert polyval([5], 3) == 5
# 4x^3 - 2x + 5
p = [5, -2, 0, 4]
assert polyval(p, 4) == 253
assert polyval(p, 4, derivative=True) == (253, 190)
assert polyval([1, 2, 3], 2, asc=False) == 11
assert polyval(list(reversed(p)), 4, asc=False) == 253
def test_polyroots():
p = polyroots([-4,1])
assert p[0].ae(4)
p, q = polyroots([3,2,1])
assert p.ae(-1 - sqrt(2)*j)
assert q.ae(-1 + sqrt(2)*j)
#this is not a real test, it only tests a specific case
assert polyroots([1]) == []
pytest.raises(ValueError, lambda: polyroots([0]))
p, q = polyroots([1,2,3], asc=False)
assert p.ae(-1 - sqrt(2)*j)
assert q.ae(-1 + sqrt(2)*j)
def test_polyroots_legendre():
n = 64
coeffs = [916312070471295267, 0, -1905929106580294155360, 0,
659769125727878493447120, 0, -91048139350447232095702560, 0,
6695289961520387531608984680, 0, -304114948474392713657972548576,
0, 9330799555464321896324157740400, 0,
-205277590220215081719131470288800, 0,
3378527005707706553294038781836500, 0,
-42927166660756742088912492757452000, 0,
431305058712550634988073414073557200, 0,
-3491517141958743235617737161547844000, 0,
23112325428835593809686977515028663000, 0,
-126584428502545713788439446082310831200, 0,
579006552594977616773047095969088431600, 0,
-2228176940331017311443863996901733412640, 0,
7255051932731034189479516844750603752850, 0,
-20071017111583894941305187420771723751200, 0,
47310254620162038075933656063247634556400, 0,
-95158890516229191805647495979277603503200, 0,
163356095386193445933028201431093219347160, 0,
-239057700565161140389797367947941296605600, 0,
297432255354328395601259515935229287637200, 0,
-313237834141273382807123548182995095192800, 0,
277415422258095841688223780704620656114900, 0,
-204721258548015217049921875719981284186016, 0,
124284021969194758465450309166353645376880, 0,
-60969520211303089058522793175947071316960, 0,
23556405536185284408974715545252277554280, 0,
-6897338342113537600691931230430793911840, 0,
1437919688271127330313741595496589239248, 0,
-190100434726484311252477736051902332000, 0,
11975573020964041433067793888190275875]
with mp.workdps(3):
with pytest.raises(mp.NoConvergence):
polyroots(coeffs, maxsteps=5, cleanup=True, error=False,
extraprec=n*10)
roots = polyroots(coeffs, maxsteps=50, cleanup=True, error=False,
extraprec=n*10)
roots = [str(r) for r in roots]
assert roots == \
['-0.999', '-0.996', '-0.991', '-0.983', '-0.973', '-0.961',
'-0.946', '-0.93', '-0.911', '-0.889', '-0.866', '-0.841',
'-0.813', '-0.784', '-0.753', '-0.72', '-0.685', '-0.649',
'-0.611', '-0.572', '-0.531', '-0.489', '-0.446', '-0.402',
'-0.357', '-0.311', '-0.265', '-0.217', '-0.17', '-0.121',
'-0.073', '-0.0243', '0.0243', '0.073', '0.121', '0.17', '0.217',
'0.265', '0.311', '0.357', '0.402', '0.446', '0.489', '0.531',
'0.572', '0.611', '0.649', '0.685', '0.72', '0.753', '0.784',
'0.813', '0.841', '0.866', '0.889', '0.911', '0.93', '0.946',
'0.961', '0.973', '0.983', '0.991', '0.996', '0.999']
def test_polyroots_legendre_init():
extra_prec = 100
coeffs = [916312070471295267, 0, -1905929106580294155360, 0,
659769125727878493447120, 0, -91048139350447232095702560, 0,
6695289961520387531608984680, 0, -304114948474392713657972548576,
0, 9330799555464321896324157740400, 0,
-205277590220215081719131470288800, 0,
3378527005707706553294038781836500, 0,
-42927166660756742088912492757452000, 0,
431305058712550634988073414073557200, 0,
-3491517141958743235617737161547844000, 0,
23112325428835593809686977515028663000, 0,
-126584428502545713788439446082310831200, 0,
579006552594977616773047095969088431600, 0,
-2228176940331017311443863996901733412640, 0,
7255051932731034189479516844750603752850, 0,
-20071017111583894941305187420771723751200, 0,
47310254620162038075933656063247634556400, 0,
-95158890516229191805647495979277603503200, 0,
163356095386193445933028201431093219347160, 0,
-239057700565161140389797367947941296605600, 0,
297432255354328395601259515935229287637200, 0,
-313237834141273382807123548182995095192800, 0,
277415422258095841688223780704620656114900, 0,
-204721258548015217049921875719981284186016, 0,
124284021969194758465450309166353645376880, 0,
-60969520211303089058522793175947071316960, 0,
23556405536185284408974715545252277554280, 0,
-6897338342113537600691931230430793911840, 0,
1437919688271127330313741595496589239248, 0,
-190100434726484311252477736051902332000, 0,
11975573020964041433067793888190275875]
roots_init = matrix(['-0.999', '-0.996', '-0.991', '-0.983', '-0.973',
'-0.961', '-0.946', '-0.93', '-0.911', '-0.889',
'-0.866', '-0.841', '-0.813', '-0.784', '-0.753',
'-0.72', '-0.685', '-0.649', '-0.611', '-0.572',
'-0.531', '-0.489', '-0.446', '-0.402', '-0.357',
'-0.311', '-0.265', '-0.217', '-0.17', '-0.121',
'-0.073', '-0.0243', '0.0243', '0.073', '0.121',
'0.17', '0.217', '0.265', ' 0.311', '0.357',
'0.402', '0.446', '0.489', '0.531', '0.572',
'0.611', '0.649', '0.685', '0.72', '0.753',
'0.784', '0.813', '0.841', '0.866', '0.889',
'0.911', '0.93', '0.946', '0.961', '0.973',
'0.983', '0.991', '0.996', '0.999', '1.0'])
with mp.workdps(2*mp.dps):
roots_exact = polyroots(coeffs, maxsteps=50, cleanup=True, error=False,
extraprec=2*extra_prec)
with pytest.raises(mp.NoConvergence):
polyroots(coeffs, maxsteps=5, cleanup=True, error=False,
extraprec=extra_prec)
roots,err = polyroots(coeffs, maxsteps=5, cleanup=True, error=True,
extraprec=extra_prec,roots_init=roots_init)
assert max(matrix(roots_exact)-matrix(roots).apply(abs)) < err
roots1,err1 = polyroots(coeffs, maxsteps=25, cleanup=True, error=True,
extraprec=extra_prec,roots_init=roots_init[:60])
assert max(matrix(roots_exact)-matrix(roots1).apply(abs)) < err1
def test_pade():
one = mpf(1)
mp.dps = 20
N = 10
a = [one]
k = 1
for i in range(1, N+1):
k *= i
a.append(one/k)
p, q = pade(a, N//2, N//2)
for x in arange(0, 1, 0.1):
r = polyval(p, x)/polyval(q, x)
assert r.ae(exp(x), 1.0e-10)
def test_fourier():
c, s = fourier(lambda x: x+1, [-1, 2], 2)
#plot([lambda x: x+1, lambda x: fourierval((c, s), [-1, 2], x)], [-1, 2])
assert c[0].ae(1.5)
assert c[1].ae(-3*sqrt(3)/(2*pi))
assert c[2].ae(3*sqrt(3)/(4*pi))
assert s[0] == 0
assert s[1].ae(3/(2*pi))
assert s[2].ae(3/(4*pi))
assert fourierval((c, s), [-1, 2], 1).ae(1.9134966715663442)
def test_differint():
assert differint(lambda t: t, 2, -0.5).ae(8*sqrt(2/pi)/3)
def test_invlap():
t = 0.01
fp = lambda p: 1/(p+1)**2
ft = lambda t: t*exp(-t)
ftt = ft(t)
assert invertlaplace(fp,t,method='talbot').ae(ftt)
assert invertlaplace(fp,t,method='stehfest').ae(ftt)
assert invertlaplace(fp,t,method='dehoog').ae(ftt)
assert invertlaplace(fp,t,method='cohen').ae(ftt)
t = 1.0
ftt = ft(t)
assert invertlaplace(fp,t,method='talbot').ae(ftt)
assert invertlaplace(fp,t,method='stehfest').ae(ftt)
assert invertlaplace(fp,t,method='dehoog').ae(ftt)
assert invertlaplace(fp,t,method='cohen').ae(ftt)
t = 0.01
fp = lambda p: log(p)/p
ft = lambda t: -euler-log(t)
ftt = ft(t)
assert invertlaplace(fp,t,method='talbot').ae(ftt)
assert invertlaplace(fp,t,method='stehfest').ae(ftt)
assert invertlaplace(fp,t,method='dehoog').ae(ftt)
assert invertlaplace(fp,t,method='cohen').ae(ftt)
t = 1.0
ftt = ft(t)
assert invertlaplace(fp,t,method='talbot').ae(ftt)
assert invertlaplace(fp,t,method='stehfest').ae(ftt)
assert invertlaplace(fp,t,method='dehoog').ae(ftt)
assert invertlaplace(fp,t,method='cohen').ae(ftt)
def test_expm():
# Simple tests with known exact results
A = matrix([[2, 0], [0, 1]])
A = expm(A)
B = matrix([[e**2, 0], [0, e]])
assert norm(A-B, inf) < 1e-15
A = matrix([[0, -pi], [pi, 0]])
A = expm(A)
B = matrix([[-1, 0], [0, -1]])
assert norm(A-B, inf) < 1e-15
# Test with input as list of lists
A = [[1, 0], [0, 2]]
A = expm(A)
B = matrix([[e, 0], [0, e**2]])
assert norm(A-B, inf) < 1e-15
# Test non-square matrix input
A = [[1, 0], [0, 1], [0, 0]]
pytest.raises(ValueError, lambda: expm(A))
def test_cosm_sinm():
# Simple test with known exact result
A = matrix([[-pi, 0], [0, pi]])
C = cosm(A)
S = sinm(A)
C_exact = matrix([[cos(-pi), 0], [0, cos(pi)]])
S_exact = matrix([[0, 0], [0, 0]])
assert norm(C-C_exact, inf) < 1e-15
assert norm(S-S_exact, inf) < 1e-15
# Test with input as list of lists
A = [[-pi, 0], [0, pi]]
C = cosm(A)
S = sinm(A)
C_exact = matrix([[cos(-pi), 0], [0, cos(pi)]])
S_exact = matrix([[0, 0], [0, 0]])
assert norm(C-C_exact, inf) < 1e-15
assert norm(S-S_exact, inf) < 1e-15
# Test non-square matrix input
A = [[1, 0], [0, 1], [0, 0]]
pytest.raises(ValueError, lambda: cosm(A))
pytest.raises(ValueError, lambda: sinm(A))
def test_logm():
# Test for zero matrix
A = [[0, 0], [0, 0]]
pytest.raises(ValueError, lambda: logm(A))