test_solve_toeplitz.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. """Test functions for linalg._solve_toeplitz module
  2. """
  3. from __future__ import division, print_function, absolute_import
  4. import numpy as np
  5. from scipy.linalg._solve_toeplitz import levinson
  6. from scipy.linalg import solve, toeplitz, solve_toeplitz
  7. from numpy.testing import assert_equal, assert_allclose
  8. import pytest
  9. from pytest import raises as assert_raises
  10. def test_solve_equivalence():
  11. # For toeplitz matrices, solve_toeplitz() should be equivalent to solve().
  12. random = np.random.RandomState(1234)
  13. for n in (1, 2, 3, 10):
  14. c = random.randn(n)
  15. if random.rand() < 0.5:
  16. c = c + 1j * random.randn(n)
  17. r = random.randn(n)
  18. if random.rand() < 0.5:
  19. r = r + 1j * random.randn(n)
  20. y = random.randn(n)
  21. if random.rand() < 0.5:
  22. y = y + 1j * random.randn(n)
  23. # Check equivalence when both the column and row are provided.
  24. actual = solve_toeplitz((c,r), y)
  25. desired = solve(toeplitz(c, r=r), y)
  26. assert_allclose(actual, desired)
  27. # Check equivalence when the column is provided but not the row.
  28. actual = solve_toeplitz(c, b=y)
  29. desired = solve(toeplitz(c), y)
  30. assert_allclose(actual, desired)
  31. def test_multiple_rhs():
  32. random = np.random.RandomState(1234)
  33. c = random.randn(4)
  34. r = random.randn(4)
  35. for offset in [0, 1j]:
  36. for yshape in ((4,), (4, 3), (4, 3, 2)):
  37. y = random.randn(*yshape) + offset
  38. actual = solve_toeplitz((c,r), b=y)
  39. desired = solve(toeplitz(c, r=r), y)
  40. assert_equal(actual.shape, yshape)
  41. assert_equal(desired.shape, yshape)
  42. assert_allclose(actual, desired)
  43. def test_native_list_arguments():
  44. c = [1,2,4,7]
  45. r = [1,3,9,12]
  46. y = [5,1,4,2]
  47. actual = solve_toeplitz((c,r), y)
  48. desired = solve(toeplitz(c, r=r), y)
  49. assert_allclose(actual, desired)
  50. def test_zero_diag_error():
  51. # The Levinson-Durbin implementation fails when the diagonal is zero.
  52. random = np.random.RandomState(1234)
  53. n = 4
  54. c = random.randn(n)
  55. r = random.randn(n)
  56. y = random.randn(n)
  57. c[0] = 0
  58. assert_raises(np.linalg.LinAlgError,
  59. solve_toeplitz, (c, r), b=y)
  60. def test_wikipedia_counterexample():
  61. # The Levinson-Durbin implementation also fails in other cases.
  62. # This example is from the talk page of the wikipedia article.
  63. random = np.random.RandomState(1234)
  64. c = [2, 2, 1]
  65. y = random.randn(3)
  66. assert_raises(np.linalg.LinAlgError, solve_toeplitz, c, b=y)
  67. def test_reflection_coeffs():
  68. # check that that the partial solutions are given by the reflection
  69. # coefficients
  70. random = np.random.RandomState(1234)
  71. y_d = random.randn(10)
  72. y_z = random.randn(10) + 1j
  73. reflection_coeffs_d = [1]
  74. reflection_coeffs_z = [1]
  75. for i in range(2, 10):
  76. reflection_coeffs_d.append(solve_toeplitz(y_d[:(i-1)], b=y_d[1:i])[-1])
  77. reflection_coeffs_z.append(solve_toeplitz(y_z[:(i-1)], b=y_z[1:i])[-1])
  78. y_d_concat = np.concatenate((y_d[-2:0:-1], y_d[:-1]))
  79. y_z_concat = np.concatenate((y_z[-2:0:-1].conj(), y_z[:-1]))
  80. _, ref_d = levinson(y_d_concat, b=y_d[1:])
  81. _, ref_z = levinson(y_z_concat, b=y_z[1:])
  82. assert_allclose(reflection_coeffs_d, ref_d[:-1])
  83. assert_allclose(reflection_coeffs_z, ref_z[:-1])
  84. @pytest.mark.xfail(reason='Instability of Levinson iteration')
  85. def test_unstable():
  86. # this is a "Gaussian Toeplitz matrix", as mentioned in Example 2 of
  87. # I. Gohbert, T. Kailath and V. Olshevsky "Fast Gaussian Elimination with
  88. # Partial Pivoting for Matrices with Displacement Structure"
  89. # Mathematics of Computation, 64, 212 (1995), pp 1557-1576
  90. # which can be unstable for levinson recursion.
  91. # other fast toeplitz solvers such as GKO or Burg should be better.
  92. random = np.random.RandomState(1234)
  93. n = 100
  94. c = 0.9 ** (np.arange(n)**2)
  95. y = random.randn(n)
  96. solution1 = solve_toeplitz(c, b=y)
  97. solution2 = solve(toeplitz(c), y)
  98. assert_allclose(solution1, solution2)