def _charpoly(M, x='lambda', simplify=_simplify): """Computes characteristic polynomial det(x*I - M) where I is the identity matrix. A PurePoly is returned, so using different variables for ``x`` does not affect the comparison or the polynomials: Parameters ========== x : string, optional Name for the "lambda" variable, defaults to "lambda". simplify : function, optional Simplification function to use on the characteristic polynomial calculated. Defaults to ``simplify``. Examples ======== >>> from sympy import Matrix >>> from sympy.abc import x, y >>> M = Matrix([[1, 3], [2, 0]]) >>> M.charpoly() PurePoly(lambda**2 - lambda - 6, lambda, domain='ZZ') >>> M.charpoly(x) == M.charpoly(y) True >>> M.charpoly(x) == M.charpoly(y) True Specifying ``x`` is optional; a symbol named ``lambda`` is used by default (which looks good when pretty-printed in unicode): >>> M.charpoly().as_expr() lambda**2 - lambda - 6 And if ``x`` clashes with an existing symbol, underscores will be prepended to the name to make it unique: >>> M = Matrix([[1, 2], [x, 0]]) >>> M.charpoly(x).as_expr() _x**2 - _x - 2*x Whether you pass a symbol or not, the generator can be obtained with the gen attribute since it may not be the same as the symbol that was passed: >>> M.charpoly(x).gen _x >>> M.charpoly(x).gen == x False Notes ===== The Samuelson-Berkowitz algorithm is used to compute the characteristic polynomial efficiently and without any division operations. Thus the characteristic polynomial over any commutative ring without zero divisors can be computed. If the determinant det(x*I - M) can be found out easily as in the case of an upper or a lower triangular matrix, then instead of Samuelson-Berkowitz algorithm, eigenvalues are computed and the characteristic polynomial with their help. See Also ======== det """ if not M.is_square: raise NonSquareMatrixError() if M.is_lower or M.is_upper: diagonal_elements = M.diagonal() x = uniquely_named_symbol(x, diagonal_elements, modify=lambda s: '_' + s) m = 1 for i in diagonal_elements: m = m * (x - simplify(i)) return PurePoly(m, x) berk_vector = _berkowitz_vector(M) x = uniquely_named_symbol(x, berk_vector, modify=lambda s: '_' + s) return PurePoly([simplify(a) for a in berk_vector], x)
def _charpoly(M, x='lambda', simplify=_simplify, dotprodsimp=None): """Computes characteristic polynomial det(x*I - M) where I is the identity matrix. A PurePoly is returned, so using different variables for ``x`` does not affect the comparison or the polynomials: Parameters ========== x : string, optional Name for the "lambda" variable, defaults to "lambda". simplify : function, optional Simplification function to use on the characteristic polynomial calculated. Defaults to ``simplify``, if ``dotprodsimp`` is ``True`` then this is ignored. dotprodsimp : bool, optional Specifies whether intermediate term algebraic simplification is used to control expression blowup during matrix multiplication. If this is true then the simplify function is not used. Examples ======== >>> from sympy import Matrix >>> from sympy.abc import x, y >>> M = Matrix([[1, 3], [2, 0]]) >>> M.charpoly() PurePoly(lambda**2 - lambda - 6, lambda, domain='ZZ') >>> M.charpoly(x) == M.charpoly(y) True >>> M.charpoly(x) == M.charpoly(y) True Specifying ``x`` is optional; a symbol named ``lambda`` is used by default (which looks good when pretty-printed in unicode): >>> M.charpoly().as_expr() lambda**2 - lambda - 6 And if ``x`` clashes with an existing symbol, underscores will be prepended to the name to make it unique: >>> M = Matrix([[1, 2], [x, 0]]) >>> M.charpoly(x).as_expr() _x**2 - _x - 2*x Whether you pass a symbol or not, the generator can be obtained with the gen attribute since it may not be the same as the symbol that was passed: >>> M.charpoly(x).gen _x >>> M.charpoly(x).gen == x False Notes ===== The Samuelson-Berkowitz algorithm is used to compute the characteristic polynomial efficiently and without any division operations. Thus the characteristic polynomial over any commutative ring without zero divisors can be computed. See Also ======== det """ if not M.is_square: raise NonSquareMatrixError() if dotprodsimp: simplify = lambda e: e berk_vector = _berkowitz_vector(M, dotprodsimp=dotprodsimp) x = _uniquely_named_symbol(x, berk_vector) return PurePoly([simplify(a) for a in berk_vector], x)