test__linprog_clean_inputs.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. """
  2. Unit test for Linear Programming via Simplex Algorithm.
  3. """
  4. import numpy as np
  5. from numpy.testing import assert_, assert_allclose, assert_equal
  6. from pytest import raises as assert_raises
  7. from scipy.optimize._linprog_util import _clean_inputs, _LPProblem
  8. from copy import deepcopy
  9. from datetime import date
  10. def test_aliasing():
  11. """
  12. Test for ensuring that no objects referred to by `lp` attributes,
  13. `c`, `A_ub`, `b_ub`, `A_eq`, `b_eq`, `bounds`, have been modified
  14. by `_clean_inputs` as a side effect.
  15. """
  16. lp = _LPProblem(
  17. c=1,
  18. A_ub=[[1]],
  19. b_ub=[1],
  20. A_eq=[[1]],
  21. b_eq=[1],
  22. bounds=(-np.inf, np.inf)
  23. )
  24. lp_copy = deepcopy(lp)
  25. _clean_inputs(lp)
  26. assert_(lp.c == lp_copy.c, "c modified by _clean_inputs")
  27. assert_(lp.A_ub == lp_copy.A_ub, "A_ub modified by _clean_inputs")
  28. assert_(lp.b_ub == lp_copy.b_ub, "b_ub modified by _clean_inputs")
  29. assert_(lp.A_eq == lp_copy.A_eq, "A_eq modified by _clean_inputs")
  30. assert_(lp.b_eq == lp_copy.b_eq, "b_eq modified by _clean_inputs")
  31. assert_(lp.bounds == lp_copy.bounds, "bounds modified by _clean_inputs")
  32. def test_aliasing2():
  33. """
  34. Similar purpose as `test_aliasing` above.
  35. """
  36. lp = _LPProblem(
  37. c=np.array([1, 1]),
  38. A_ub=np.array([[1, 1], [2, 2]]),
  39. b_ub=np.array([[1], [1]]),
  40. A_eq=np.array([[1, 1]]),
  41. b_eq=np.array([1]),
  42. bounds=[(-np.inf, np.inf), (None, 1)]
  43. )
  44. lp_copy = deepcopy(lp)
  45. _clean_inputs(lp)
  46. assert_allclose(lp.c, lp_copy.c, err_msg="c modified by _clean_inputs")
  47. assert_allclose(lp.A_ub, lp_copy.A_ub, err_msg="A_ub modified by _clean_inputs")
  48. assert_allclose(lp.b_ub, lp_copy.b_ub, err_msg="b_ub modified by _clean_inputs")
  49. assert_allclose(lp.A_eq, lp_copy.A_eq, err_msg="A_eq modified by _clean_inputs")
  50. assert_allclose(lp.b_eq, lp_copy.b_eq, err_msg="b_eq modified by _clean_inputs")
  51. assert_(lp.bounds == lp_copy.bounds, "bounds modified by _clean_inputs")
  52. def test_missing_inputs():
  53. c = [1, 2]
  54. A_ub = np.array([[1, 1], [2, 2]])
  55. b_ub = np.array([1, 1])
  56. A_eq = np.array([[1, 1], [2, 2]])
  57. b_eq = np.array([1, 1])
  58. assert_raises(TypeError, _clean_inputs)
  59. assert_raises(TypeError, _clean_inputs, _LPProblem(c=None))
  60. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_ub=A_ub))
  61. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_ub=A_ub, b_ub=None))
  62. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, b_ub=b_ub))
  63. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_ub=None, b_ub=b_ub))
  64. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_eq=A_eq))
  65. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_eq=A_eq, b_eq=None))
  66. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, b_eq=b_eq))
  67. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_eq=None, b_eq=b_eq))
  68. def test_too_many_dimensions():
  69. cb = [1, 2, 3, 4]
  70. A = np.random.rand(4, 4)
  71. bad2D = [[1, 2], [3, 4]]
  72. bad3D = np.random.rand(4, 4, 4)
  73. assert_raises(ValueError, _clean_inputs, _LPProblem(c=bad2D, A_ub=A, b_ub=cb))
  74. assert_raises(ValueError, _clean_inputs, _LPProblem(c=cb, A_ub=bad3D, b_ub=cb))
  75. assert_raises(ValueError, _clean_inputs, _LPProblem(c=cb, A_ub=A, b_ub=bad2D))
  76. assert_raises(ValueError, _clean_inputs, _LPProblem(c=cb, A_eq=bad3D, b_eq=cb))
  77. assert_raises(ValueError, _clean_inputs, _LPProblem(c=cb, A_eq=A, b_eq=bad2D))
  78. def test_too_few_dimensions():
  79. bad = np.random.rand(4, 4).ravel()
  80. cb = np.random.rand(4)
  81. assert_raises(ValueError, _clean_inputs, _LPProblem(c=cb, A_ub=bad, b_ub=cb))
  82. assert_raises(ValueError, _clean_inputs, _LPProblem(c=cb, A_eq=bad, b_eq=cb))
  83. def test_inconsistent_dimensions():
  84. m = 2
  85. n = 4
  86. c = [1, 2, 3, 4]
  87. Agood = np.random.rand(m, n)
  88. Abad = np.random.rand(m, n + 1)
  89. bgood = np.random.rand(m)
  90. bbad = np.random.rand(m + 1)
  91. boundsbad = [(0, 1)] * (n + 1)
  92. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_ub=Abad, b_ub=bgood))
  93. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_ub=Agood, b_ub=bbad))
  94. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_eq=Abad, b_eq=bgood))
  95. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, A_eq=Agood, b_eq=bbad))
  96. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, bounds=boundsbad))
  97. assert_raises(ValueError, _clean_inputs, _LPProblem(c=c, bounds=[[1, 2], [2, 3], [3, 4], [4, 5, 6]]))
  98. def test_type_errors():
  99. lp = _LPProblem(
  100. c=[1, 2],
  101. A_ub=np.array([[1, 1], [2, 2]]),
  102. b_ub=np.array([1, 1]),
  103. A_eq=np.array([[1, 1], [2, 2]]),
  104. b_eq=np.array([1, 1]),
  105. bounds=[(0, 1)]
  106. )
  107. bad = "hello"
  108. assert_raises(TypeError, _clean_inputs, lp._replace(c=bad))
  109. assert_raises(TypeError, _clean_inputs, lp._replace(A_ub=bad))
  110. assert_raises(TypeError, _clean_inputs, lp._replace(b_ub=bad))
  111. assert_raises(TypeError, _clean_inputs, lp._replace(A_eq=bad))
  112. assert_raises(TypeError, _clean_inputs, lp._replace(b_eq=bad))
  113. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=bad))
  114. assert_raises(ValueError, _clean_inputs, lp._replace(bounds="hi"))
  115. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=["hi"]))
  116. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[("hi")]))
  117. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[(1, "")]))
  118. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[(1, 2), (1, "")]))
  119. assert_raises(TypeError, _clean_inputs, lp._replace(bounds=[(1, date(2020, 2, 29))]))
  120. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[[[1, 2]]]))
  121. def test_non_finite_errors():
  122. lp = _LPProblem(
  123. c=[1, 2],
  124. A_ub=np.array([[1, 1], [2, 2]]),
  125. b_ub=np.array([1, 1]),
  126. A_eq=np.array([[1, 1], [2, 2]]),
  127. b_eq=np.array([1, 1]),
  128. bounds=[(0, 1)]
  129. )
  130. assert_raises(ValueError, _clean_inputs, lp._replace(c=[0, None]))
  131. assert_raises(ValueError, _clean_inputs, lp._replace(c=[np.inf, 0]))
  132. assert_raises(ValueError, _clean_inputs, lp._replace(c=[0, -np.inf]))
  133. assert_raises(ValueError, _clean_inputs, lp._replace(c=[np.nan, 0]))
  134. assert_raises(ValueError, _clean_inputs, lp._replace(A_ub=[[1, 2], [None, 1]]))
  135. assert_raises(ValueError, _clean_inputs, lp._replace(b_ub=[np.inf, 1]))
  136. assert_raises(ValueError, _clean_inputs, lp._replace(A_eq=[[1, 2], [1, -np.inf]]))
  137. assert_raises(ValueError, _clean_inputs, lp._replace(b_eq=[1, np.nan]))
  138. def test__clean_inputs1():
  139. lp = _LPProblem(
  140. c=[1, 2],
  141. A_ub=[[1, 1], [2, 2]],
  142. b_ub=[1, 1],
  143. A_eq=[[1, 1], [2, 2]],
  144. b_eq=[1, 1],
  145. bounds=None
  146. )
  147. lp_cleaned = _clean_inputs(lp)
  148. assert_allclose(lp_cleaned.c, np.array(lp.c))
  149. assert_allclose(lp_cleaned.A_ub, np.array(lp.A_ub))
  150. assert_allclose(lp_cleaned.b_ub, np.array(lp.b_ub))
  151. assert_allclose(lp_cleaned.A_eq, np.array(lp.A_eq))
  152. assert_allclose(lp_cleaned.b_eq, np.array(lp.b_eq))
  153. assert_equal(lp_cleaned.bounds, [(0, np.inf)] * 2)
  154. assert_(lp_cleaned.c.shape == (2,), "")
  155. assert_(lp_cleaned.A_ub.shape == (2, 2), "")
  156. assert_(lp_cleaned.b_ub.shape == (2,), "")
  157. assert_(lp_cleaned.A_eq.shape == (2, 2), "")
  158. assert_(lp_cleaned.b_eq.shape == (2,), "")
  159. def test__clean_inputs2():
  160. lp = _LPProblem(
  161. c=1,
  162. A_ub=[[1]],
  163. b_ub=1,
  164. A_eq=[[1]],
  165. b_eq=1,
  166. bounds=(0, 1)
  167. )
  168. lp_cleaned = _clean_inputs(lp)
  169. assert_allclose(lp_cleaned.c, np.array(lp.c))
  170. assert_allclose(lp_cleaned.A_ub, np.array(lp.A_ub))
  171. assert_allclose(lp_cleaned.b_ub, np.array(lp.b_ub))
  172. assert_allclose(lp_cleaned.A_eq, np.array(lp.A_eq))
  173. assert_allclose(lp_cleaned.b_eq, np.array(lp.b_eq))
  174. assert_equal(lp_cleaned.bounds, [(0, 1)])
  175. assert_(lp_cleaned.c.shape == (1,), "")
  176. assert_(lp_cleaned.A_ub.shape == (1, 1), "")
  177. assert_(lp_cleaned.b_ub.shape == (1,), "")
  178. assert_(lp_cleaned.A_eq.shape == (1, 1), "")
  179. assert_(lp_cleaned.b_eq.shape == (1,), "")
  180. def test__clean_inputs3():
  181. lp = _LPProblem(
  182. c=[[1, 2]],
  183. A_ub=np.random.rand(2, 2),
  184. b_ub=[[1], [2]],
  185. A_eq=np.random.rand(2, 2),
  186. b_eq=[[1], [2]],
  187. bounds=[(0, 1)]
  188. )
  189. lp_cleaned = _clean_inputs(lp)
  190. assert_allclose(lp_cleaned.c, np.array([1, 2]))
  191. assert_allclose(lp_cleaned.b_ub, np.array([1, 2]))
  192. assert_allclose(lp_cleaned.b_eq, np.array([1, 2]))
  193. assert_equal(lp_cleaned.bounds, [(0, 1)] * 2)
  194. assert_(lp_cleaned.c.shape == (2,), "")
  195. assert_(lp_cleaned.b_ub.shape == (2,), "")
  196. assert_(lp_cleaned.b_eq.shape == (2,), "")
  197. def test_bad_bounds():
  198. lp = _LPProblem(c=[1, 2])
  199. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=(1, 2, 2)))
  200. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[(1, 2, 2)]))
  201. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[(1, 2), (1, 2, 2)]))
  202. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[(1, 2), (1, 2), (1, 2)]))
  203. lp = _LPProblem(c=[1, 2, 3, 4])
  204. assert_raises(ValueError, _clean_inputs, lp._replace(bounds=[(1, 2, 3, 4), (1, 2, 3, 4)]))
  205. def test_good_bounds():
  206. lp = _LPProblem(c=[1, 2])
  207. lp_cleaned = _clean_inputs(lp) # lp.bounds is None by default
  208. assert_equal(lp_cleaned.bounds, [(0, np.inf)] * 2)
  209. lp_cleaned = _clean_inputs(lp._replace(bounds=[]))
  210. assert_equal(lp_cleaned.bounds, [(0, np.inf)] * 2)
  211. lp_cleaned = _clean_inputs(lp._replace(bounds=[[]]))
  212. assert_equal(lp_cleaned.bounds, [(0, np.inf)] * 2)
  213. lp_cleaned = _clean_inputs(lp._replace(bounds=(1, 2)))
  214. assert_equal(lp_cleaned.bounds, [(1, 2)] * 2)
  215. lp_cleaned = _clean_inputs(lp._replace(bounds=[(1, 2)]))
  216. assert_equal(lp_cleaned.bounds, [(1, 2)] * 2)
  217. lp_cleaned = _clean_inputs(lp._replace(bounds=[(1, None)]))
  218. assert_equal(lp_cleaned.bounds, [(1, np.inf)] * 2)
  219. lp_cleaned = _clean_inputs(lp._replace(bounds=[(None, 1)]))
  220. assert_equal(lp_cleaned.bounds, [(-np.inf, 1)] * 2)
  221. lp_cleaned = _clean_inputs(lp._replace(bounds=[(None, None), (-np.inf, None)]))
  222. assert_equal(lp_cleaned.bounds, [(-np.inf, np.inf)] * 2)
  223. lp = _LPProblem(c=[1, 2, 3, 4])
  224. lp_cleaned = _clean_inputs(lp) # lp.bounds is None by default
  225. assert_equal(lp_cleaned.bounds, [(0, np.inf)] * 4)
  226. lp_cleaned = _clean_inputs(lp._replace(bounds=(1, 2)))
  227. assert_equal(lp_cleaned.bounds, [(1, 2)] * 4)
  228. lp_cleaned = _clean_inputs(lp._replace(bounds=[(1, 2)]))
  229. assert_equal(lp_cleaned.bounds, [(1, 2)] * 4)
  230. lp_cleaned = _clean_inputs(lp._replace(bounds=[(1, None)]))
  231. assert_equal(lp_cleaned.bounds, [(1, np.inf)] * 4)
  232. lp_cleaned = _clean_inputs(lp._replace(bounds=[(None, 1)]))
  233. assert_equal(lp_cleaned.bounds, [(-np.inf, 1)] * 4)
  234. lp_cleaned = _clean_inputs(lp._replace(bounds=[(None, None), (-np.inf, None), (None, np.inf), (-np.inf, np.inf)]))
  235. assert_equal(lp_cleaned.bounds, [(-np.inf, np.inf)] * 4)