Spaces:
Running
Running
from sympy.core.numbers import I | |
from sympy.core.symbol import symbols | |
from sympy.testing.pytest import raises | |
from sympy.matrices import Matrix, zeros, eye | |
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 | |
# Matrix tests | |
def test_row_op(): | |
e = eye(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 = Matrix(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(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 = Matrix(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(3) | |
ident = eye(3) | |
assert zro.is_echelon | |
assert ident.is_echelon | |
a = Matrix(0, 0, []) | |
assert a.is_echelon | |
a = Matrix(2, 3, [3, 2, 1, 0, 0, 6]) | |
assert a.is_echelon | |
a = Matrix(2, 3, [0, 0, 6, 3, 2, 1]) | |
assert not a.is_echelon | |
x = Symbol('x') | |
a = Matrix(3, 1, [x, 0, 0]) | |
assert a.is_echelon | |
a = Matrix(3, 1, [x, x, 0]) | |
assert not a.is_echelon | |
a = Matrix(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(3) | |
e = eye(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 = Matrix(0, 0, []) | |
assert a.echelon_form() == a | |
a = Matrix(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 = Matrix(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 = Matrix(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 = Matrix(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 = Matrix(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 = Matrix(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 = Matrix(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 = Matrix(0, 0, []) | |
assert e.rref(pivots=False) == e | |
e = Matrix(1, 1, [1]) | |
a = Matrix(1, 1, [5]) | |
assert e.rref(pivots=False) == a.rref(pivots=False) == e | |
a = Matrix(3, 1, [1, 2, 3]) | |
assert a.rref(pivots=False) == Matrix([[1], [0], [0]]) | |
a = Matrix(1, 3, [1, 2, 3]) | |
assert a.rref(pivots=False) == Matrix([[1, 2, 3]]) | |
a = Matrix(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 = Matrix(3, 3, [1, 2, 3, 1, 2, 3, 1, 2, 3]) | |
b = Matrix(3, 3, [1, 2, 3, 0, 0, 0, 0, 0, 0]) | |
c = Matrix(3, 3, [0, 0, 0, 1, 2, 3, 0, 0, 0]) | |
d = Matrix(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(3) | |
z = zeros(3) | |
assert e.rref(pivots=False) == e | |
assert z.rref(pivots=False) == z | |
a = Matrix([ | |
[ 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 = Matrix([[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 = Matrix(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_rref_rhs(): | |
a, b, c, d = symbols('a b c d') | |
A = Matrix([[0, 0], [0, 0], [1, 2], [3, 4]]) | |
B = Matrix([a, b, c, d]) | |
assert A.rref_rhs(B) == (Matrix([ | |
[1, 0], | |
[0, 1], | |
[0, 0], | |
[0, 0]]), Matrix([ | |
[ -2*c + d], | |
[3*c/2 - d/2], | |
[ a], | |
[ b]])) | |
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 | |