123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- from sympy.core.numbers import I
- from sympy.core.symbol import symbols
- from sympy.matrices.common import _MinimalMatrix, _CastableMatrix
- from sympy.matrices.matrices import MatrixReductions
- from sympy.testing.pytest import raises
- from sympy.matrices import Matrix, zeros
- from sympy.core.symbol import Symbol
- from sympy.core.numbers import Rational
- from sympy.functions.elementary.miscellaneous import sqrt
- from sympy.simplify.simplify import simplify
- from sympy.abc import x
- class ReductionsOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixReductions):
- pass
- def eye_Reductions(n):
- return ReductionsOnlyMatrix(n, n, lambda i, j: int(i == j))
- def zeros_Reductions(n):
- return ReductionsOnlyMatrix(n, n, lambda i, j: 0)
- # ReductionsOnlyMatrix tests
- def test_row_op():
- e = eye_Reductions(3)
- raises(ValueError, lambda: e.elementary_row_op("abc"))
- raises(ValueError, lambda: e.elementary_row_op())
- raises(ValueError, lambda: e.elementary_row_op('n->kn', row=5, k=5))
- raises(ValueError, lambda: e.elementary_row_op('n->kn', row=-5, k=5))
- raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=1, row2=5))
- raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=5, row2=1))
- raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=-5, row2=1))
- raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=1, row2=-5))
- raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=1, row2=5, k=5))
- raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=5, row2=1, k=5))
- raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=-5, row2=1, k=5))
- raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=1, row2=-5, k=5))
- raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=1, row2=1, k=5))
- # test various ways to set arguments
- assert e.elementary_row_op("n->kn", 0, 5) == Matrix([[5, 0, 0], [0, 1, 0], [0, 0, 1]])
- assert e.elementary_row_op("n->kn", 1, 5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]])
- assert e.elementary_row_op("n->kn", row=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]])
- assert e.elementary_row_op("n->kn", row1=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]])
- assert e.elementary_row_op("n<->m", 0, 1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
- assert e.elementary_row_op("n<->m", row1=0, row2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
- assert e.elementary_row_op("n<->m", row=0, row2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
- assert e.elementary_row_op("n->n+km", 0, 5, 1) == Matrix([[1, 5, 0], [0, 1, 0], [0, 0, 1]])
- assert e.elementary_row_op("n->n+km", row=0, k=5, row2=1) == Matrix([[1, 5, 0], [0, 1, 0], [0, 0, 1]])
- assert e.elementary_row_op("n->n+km", row1=0, k=5, row2=1) == Matrix([[1, 5, 0], [0, 1, 0], [0, 0, 1]])
- # make sure the matrix doesn't change size
- a = ReductionsOnlyMatrix(2, 3, [0]*6)
- assert a.elementary_row_op("n->kn", 1, 5) == Matrix(2, 3, [0]*6)
- assert a.elementary_row_op("n<->m", 0, 1) == Matrix(2, 3, [0]*6)
- assert a.elementary_row_op("n->n+km", 0, 5, 1) == Matrix(2, 3, [0]*6)
- def test_col_op():
- e = eye_Reductions(3)
- raises(ValueError, lambda: e.elementary_col_op("abc"))
- raises(ValueError, lambda: e.elementary_col_op())
- raises(ValueError, lambda: e.elementary_col_op('n->kn', col=5, k=5))
- raises(ValueError, lambda: e.elementary_col_op('n->kn', col=-5, k=5))
- raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=1, col2=5))
- raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=5, col2=1))
- raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=-5, col2=1))
- raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=1, col2=-5))
- raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=1, col2=5, k=5))
- raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=5, col2=1, k=5))
- raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=-5, col2=1, k=5))
- raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=1, col2=-5, k=5))
- raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=1, col2=1, k=5))
- # test various ways to set arguments
- assert e.elementary_col_op("n->kn", 0, 5) == Matrix([[5, 0, 0], [0, 1, 0], [0, 0, 1]])
- assert e.elementary_col_op("n->kn", 1, 5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]])
- assert e.elementary_col_op("n->kn", col=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]])
- assert e.elementary_col_op("n->kn", col1=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]])
- assert e.elementary_col_op("n<->m", 0, 1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
- assert e.elementary_col_op("n<->m", col1=0, col2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
- assert e.elementary_col_op("n<->m", col=0, col2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
- assert e.elementary_col_op("n->n+km", 0, 5, 1) == Matrix([[1, 0, 0], [5, 1, 0], [0, 0, 1]])
- assert e.elementary_col_op("n->n+km", col=0, k=5, col2=1) == Matrix([[1, 0, 0], [5, 1, 0], [0, 0, 1]])
- assert e.elementary_col_op("n->n+km", col1=0, k=5, col2=1) == Matrix([[1, 0, 0], [5, 1, 0], [0, 0, 1]])
- # make sure the matrix doesn't change size
- a = ReductionsOnlyMatrix(2, 3, [0]*6)
- assert a.elementary_col_op("n->kn", 1, 5) == Matrix(2, 3, [0]*6)
- assert a.elementary_col_op("n<->m", 0, 1) == Matrix(2, 3, [0]*6)
- assert a.elementary_col_op("n->n+km", 0, 5, 1) == Matrix(2, 3, [0]*6)
- def test_is_echelon():
- zro = zeros_Reductions(3)
- ident = eye_Reductions(3)
- assert zro.is_echelon
- assert ident.is_echelon
- a = ReductionsOnlyMatrix(0, 0, [])
- assert a.is_echelon
- a = ReductionsOnlyMatrix(2, 3, [3, 2, 1, 0, 0, 6])
- assert a.is_echelon
- a = ReductionsOnlyMatrix(2, 3, [0, 0, 6, 3, 2, 1])
- assert not a.is_echelon
- x = Symbol('x')
- a = ReductionsOnlyMatrix(3, 1, [x, 0, 0])
- assert a.is_echelon
- a = ReductionsOnlyMatrix(3, 1, [x, x, 0])
- assert not a.is_echelon
- a = ReductionsOnlyMatrix(3, 3, [0, 0, 0, 1, 2, 3, 0, 0, 0])
- assert not a.is_echelon
- def test_echelon_form():
- # echelon form is not unique, but the result
- # must be row-equivalent to the original matrix
- # and it must be in echelon form.
- a = zeros_Reductions(3)
- e = eye_Reductions(3)
- # we can assume the zero matrix and the identity matrix shouldn't change
- assert a.echelon_form() == a
- assert e.echelon_form() == e
- a = ReductionsOnlyMatrix(0, 0, [])
- assert a.echelon_form() == a
- a = ReductionsOnlyMatrix(1, 1, [5])
- assert a.echelon_form() == a
- # now we get to the real tests
- def verify_row_null_space(mat, rows, nulls):
- for v in nulls:
- assert all(t.is_zero for t in a_echelon*v)
- for v in rows:
- if not all(t.is_zero for t in v):
- assert not all(t.is_zero for t in a_echelon*v.transpose())
- a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])
- nulls = [Matrix([
- [ 1],
- [-2],
- [ 1]])]
- rows = [a[i, :] for i in range(a.rows)]
- a_echelon = a.echelon_form()
- assert a_echelon.is_echelon
- verify_row_null_space(a, rows, nulls)
- a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 8])
- nulls = []
- rows = [a[i, :] for i in range(a.rows)]
- a_echelon = a.echelon_form()
- assert a_echelon.is_echelon
- verify_row_null_space(a, rows, nulls)
- a = ReductionsOnlyMatrix(3, 3, [2, 1, 3, 0, 0, 0, 2, 1, 3])
- nulls = [Matrix([
- [Rational(-1, 2)],
- [ 1],
- [ 0]]),
- Matrix([
- [Rational(-3, 2)],
- [ 0],
- [ 1]])]
- rows = [a[i, :] for i in range(a.rows)]
- a_echelon = a.echelon_form()
- assert a_echelon.is_echelon
- verify_row_null_space(a, rows, nulls)
- # this one requires a row swap
- a = ReductionsOnlyMatrix(3, 3, [2, 1, 3, 0, 0, 0, 1, 1, 3])
- nulls = [Matrix([
- [ 0],
- [ -3],
- [ 1]])]
- rows = [a[i, :] for i in range(a.rows)]
- a_echelon = a.echelon_form()
- assert a_echelon.is_echelon
- verify_row_null_space(a, rows, nulls)
- a = ReductionsOnlyMatrix(3, 3, [0, 3, 3, 0, 2, 2, 0, 1, 1])
- nulls = [Matrix([
- [1],
- [0],
- [0]]),
- Matrix([
- [ 0],
- [-1],
- [ 1]])]
- rows = [a[i, :] for i in range(a.rows)]
- a_echelon = a.echelon_form()
- assert a_echelon.is_echelon
- verify_row_null_space(a, rows, nulls)
- a = ReductionsOnlyMatrix(2, 3, [2, 2, 3, 3, 3, 0])
- nulls = [Matrix([
- [-1],
- [1],
- [0]])]
- rows = [a[i, :] for i in range(a.rows)]
- a_echelon = a.echelon_form()
- assert a_echelon.is_echelon
- verify_row_null_space(a, rows, nulls)
- def test_rref():
- e = ReductionsOnlyMatrix(0, 0, [])
- assert e.rref(pivots=False) == e
- e = ReductionsOnlyMatrix(1, 1, [1])
- a = ReductionsOnlyMatrix(1, 1, [5])
- assert e.rref(pivots=False) == a.rref(pivots=False) == e
- a = ReductionsOnlyMatrix(3, 1, [1, 2, 3])
- assert a.rref(pivots=False) == Matrix([[1], [0], [0]])
- a = ReductionsOnlyMatrix(1, 3, [1, 2, 3])
- assert a.rref(pivots=False) == Matrix([[1, 2, 3]])
- a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])
- assert a.rref(pivots=False) == Matrix([
- [1, 0, -1],
- [0, 1, 2],
- [0, 0, 0]])
- a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 1, 2, 3, 1, 2, 3])
- b = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 0, 0, 0, 0, 0, 0])
- c = ReductionsOnlyMatrix(3, 3, [0, 0, 0, 1, 2, 3, 0, 0, 0])
- d = ReductionsOnlyMatrix(3, 3, [0, 0, 0, 0, 0, 0, 1, 2, 3])
- assert a.rref(pivots=False) == \
- b.rref(pivots=False) == \
- c.rref(pivots=False) == \
- d.rref(pivots=False) == b
- e = eye_Reductions(3)
- z = zeros_Reductions(3)
- assert e.rref(pivots=False) == e
- assert z.rref(pivots=False) == z
- a = ReductionsOnlyMatrix([
- [ 0, 0, 1, 2, 2, -5, 3],
- [-1, 5, 2, 2, 1, -7, 5],
- [ 0, 0, -2, -3, -3, 8, -5],
- [-1, 5, 0, -1, -2, 1, 0]])
- mat, pivot_offsets = a.rref()
- assert mat == Matrix([
- [1, -5, 0, 0, 1, 1, -1],
- [0, 0, 1, 0, 0, -1, 1],
- [0, 0, 0, 1, 1, -2, 1],
- [0, 0, 0, 0, 0, 0, 0]])
- assert pivot_offsets == (0, 2, 3)
- a = ReductionsOnlyMatrix([[Rational(1, 19), Rational(1, 5), 2, 3],
- [ 4, 5, 6, 7],
- [ 8, 9, 10, 11],
- [ 12, 13, 14, 15]])
- assert a.rref(pivots=False) == Matrix([
- [1, 0, 0, Rational(-76, 157)],
- [0, 1, 0, Rational(-5, 157)],
- [0, 0, 1, Rational(238, 157)],
- [0, 0, 0, 0]])
- x = Symbol('x')
- a = ReductionsOnlyMatrix(2, 3, [x, 1, 1, sqrt(x), x, 1])
- for i, j in zip(a.rref(pivots=False),
- [1, 0, sqrt(x)*(-x + 1)/(-x**Rational(5, 2) + x),
- 0, 1, 1/(sqrt(x) + x + 1)]):
- assert simplify(i - j).is_zero
- def test_issue_17827():
- C = Matrix([
- [3, 4, -1, 1],
- [9, 12, -3, 3],
- [0, 2, 1, 3],
- [2, 3, 0, -2],
- [0, 3, 3, -5],
- [8, 15, 0, 6]
- ])
- # Tests for row/col within valid range
- D = C.elementary_row_op('n<->m', row1=2, row2=5)
- E = C.elementary_row_op('n->n+km', row1=5, row2=3, k=-4)
- F = C.elementary_row_op('n->kn', row=5, k=2)
- assert(D[5, :] == Matrix([[0, 2, 1, 3]]))
- assert(E[5, :] == Matrix([[0, 3, 0, 14]]))
- assert(F[5, :] == Matrix([[16, 30, 0, 12]]))
- # Tests for row/col out of range
- raises(ValueError, lambda: C.elementary_row_op('n<->m', row1=2, row2=6))
- raises(ValueError, lambda: C.elementary_row_op('n->kn', row=7, k=2))
- raises(ValueError, lambda: C.elementary_row_op('n->n+km', row1=-1, row2=5, k=2))
- def test_rank():
- m = Matrix([[1, 2], [x, 1 - 1/x]])
- assert m.rank() == 2
- n = Matrix(3, 3, range(1, 10))
- assert n.rank() == 2
- p = zeros(3)
- assert p.rank() == 0
- def test_issue_11434():
- ax, ay, bx, by, cx, cy, dx, dy, ex, ey, t0, t1 = \
- symbols('a_x a_y b_x b_y c_x c_y d_x d_y e_x e_y t_0 t_1')
- M = Matrix([[ax, ay, ax*t0, ay*t0, 0],
- [bx, by, bx*t0, by*t0, 0],
- [cx, cy, cx*t0, cy*t0, 1],
- [dx, dy, dx*t0, dy*t0, 1],
- [ex, ey, 2*ex*t1 - ex*t0, 2*ey*t1 - ey*t0, 0]])
- assert M.rank() == 4
- def test_rank_regression_from_so():
- # see:
- # https://stackoverflow.com/questions/19072700/why-does-sympy-give-me-the-wrong-answer-when-i-row-reduce-a-symbolic-matrix
- nu, lamb = symbols('nu, lambda')
- A = Matrix([[-3*nu, 1, 0, 0],
- [ 3*nu, -2*nu - 1, 2, 0],
- [ 0, 2*nu, (-1*nu) - lamb - 2, 3],
- [ 0, 0, nu + lamb, -3]])
- expected_reduced = Matrix([[1, 0, 0, 1/(nu**2*(-lamb - nu))],
- [0, 1, 0, 3/(nu*(-lamb - nu))],
- [0, 0, 1, 3/(-lamb - nu)],
- [0, 0, 0, 0]])
- expected_pivots = (0, 1, 2)
- reduced, pivots = A.rref()
- assert simplify(expected_reduced - reduced) == zeros(*A.shape)
- assert pivots == expected_pivots
- def test_issue_15872():
- A = Matrix([[1, 1, 1, 0], [-2, -1, 0, -1], [0, 0, -1, -1], [0, 0, 2, 1]])
- B = A - Matrix.eye(4) * I
- assert B.rank() == 3
- assert (B**2).rank() == 2
- assert (B**3).rank() == 2
|