def decompose_matrix(matrix):
M = numpy.array(matrix, dtype=numpy.float64, copy=True).T<EOL>if abs(M[<NUM_LIT:3>, <NUM_LIT:3>]) < _EPS:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>M /= M[<NUM_LIT:3>, <NUM_LIT:3>]<EOL>P = M.copy()<EOL>P[:, <NUM_LIT:3>] = <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0><EOL>if not numpy.linalg.det(P):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>scale = numpy.zeros((<NUM_LIT:3>, ))<EOL>shear = [<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>]<EOL>angles = [<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>]<EOL>if any(abs(M[:<NUM_LIT:3>, <NUM_LIT:3>]) > _EPS):<EOL><INDENT>perspective = numpy.dot(M[:, <NUM_LIT:3>], numpy.linalg.inv(P.T))<EOL>M[:, <NUM_LIT:3>] = <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0><EOL><DEDENT>else:<EOL><INDENT>perspective = numpy.array([<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>])<EOL><DEDENT>translate = M[<NUM_LIT:3>, :<NUM_LIT:3>].copy()<EOL>M[<NUM_LIT:3>, :<NUM_LIT:3>] = <NUM_LIT:0.0><EOL>row = M[:<NUM_LIT:3>, :<NUM_LIT:3>].copy()<EOL>scale[<NUM_LIT:0>] = vector_norm(row[<NUM_LIT:0>])<EOL>row[<NUM_LIT:0>] /= scale[<NUM_LIT:0>]<EOL>shear[<NUM_LIT:0>] = numpy.dot(row[<NUM_LIT:0>], row[<NUM_LIT:1>])<EOL>row[<NUM_LIT:1>] -= row[<NUM_LIT:0>] * shear[<NUM_LIT:0>]<EOL>scale[<NUM_LIT:1>] = vector_norm(row[<NUM_LIT:1>])<EOL>row[<NUM_LIT:1>] /= scale[<NUM_LIT:1>]<EOL>shear[<NUM_LIT:0>] /= scale[<NUM_LIT:1>]<EOL>shear[<NUM_LIT:1>] = numpy.dot(row[<NUM_LIT:0>], row[<NUM_LIT:2>])<EOL>row[<NUM_LIT:2>] -= row[<NUM_LIT:0>] * shear[<NUM_LIT:1>]<EOL>shear[<NUM_LIT:2>] = numpy.dot(row[<NUM_LIT:1>], row[<NUM_LIT:2>])<EOL>row[<NUM_LIT:2>] -= row[<NUM_LIT:1>] * shear[<NUM_LIT:2>]<EOL>scale[<NUM_LIT:2>] = vector_norm(row[<NUM_LIT:2>])<EOL>row[<NUM_LIT:2>] /= scale[<NUM_LIT:2>]<EOL>shear[<NUM_LIT:1>:] /= scale[<NUM_LIT:2>]<EOL>if numpy.dot(row[<NUM_LIT:0>], numpy.cross(row[<NUM_LIT:1>], row[<NUM_LIT:2>])) < <NUM_LIT:0>:<EOL><INDENT>numpy.negative(scale, scale)<EOL>numpy.negative(row, row)<EOL><DEDENT>angles[<NUM_LIT:1>] = math.asin(-row[<NUM_LIT:0>, <NUM_LIT:2>])<EOL>if math.cos(angles[<NUM_LIT:1>]):<EOL><INDENT>angles[<NUM_LIT:0>] = math.atan2(row[<NUM_LIT:1>, <NUM_LIT:2>], row[<NUM_LIT:2>, <NUM_LIT:2>])<EOL>angles[<NUM_LIT:2>] = math.atan2(row[<NUM_LIT:0>, <NUM_LIT:1>], row[<NUM_LIT:0>, <NUM_LIT:0>])<EOL><DEDENT>else:<EOL><INDENT>angles[<NUM_LIT:0>] = math.atan2(-row[<NUM_LIT:2>, <NUM_LIT:1>], row[<NUM_LIT:1>, <NUM_LIT:1>])<EOL>angles[<NUM_LIT:2>] = <NUM_LIT:0.0><EOL><DEDENT>return scale, shear, angles, translate, perspective<EOL>
Return sequence of transformations from transformation matrix.

    matrix : array_like
        Non-degenerative homogeneous transformation matrix

    Return tuple of:
        scale : vector of 3 scaling factors
        shear : list of shear factors for x-y, x-z, y-z axes
        angles : list of Euler angles about static x, y, z axes
        translate : translation vector along x, y, z axes
        perspective : perspective partition of matrix

    Raise ValueError if matrix is of wrong type or degenerative.

    >>> T0 = translation_matrix([1, 2, 3])
    >>> scale, shear, angles, trans, persp = decompose_matrix(T0)
    >>> T1 = translation_matrix(trans)
    >>> numpy.allclose(T0, T1)
    True
    >>> S = scale_matrix(0.123)
    >>> scale, shear, angles, trans, persp = decompose_matrix(S)
    >>> scale[0]
    0.123
    >>> R0 = euler_matrix(1, 2, 3)
    >>> scale, shear, angles, trans, persp = decompose_matrix(R0)
    >>> R1 = euler_matrix(*angles)
    >>> numpy.allclose(R0, R1)
    True