1'''Functions returning normal forms of matrices''' 2 3from sympy.polys.polytools import Poly 4from sympy.polys.matrices import DomainMatrix 5from sympy.polys.matrices.normalforms import ( 6 smith_normal_form as _snf, 7 invariant_factors as _invf, 8 ) 9 10 11def _to_domain(m, domain=None): 12 """Convert Matrix to DomainMatrix""" 13 # XXX: deprecated support for RawMatrix: 14 ring = getattr(m, "ring", None) 15 m = m.applyfunc(lambda e: e.as_expr() if isinstance(e, Poly) else e) 16 17 dM = DomainMatrix.from_Matrix(m) 18 19 domain = domain or ring 20 if domain is not None: 21 dM = dM.convert_to(domain) 22 return dM 23 24 25def smith_normal_form(m, domain=None): 26 ''' 27 Return the Smith Normal Form of a matrix `m` over the ring `domain`. 28 This will only work if the ring is a principal ideal domain. 29 30 Examples 31 ======== 32 33 >>> from sympy import Matrix, ZZ 34 >>> from sympy.matrices.normalforms import smith_normal_form 35 >>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]]) 36 >>> print(smith_normal_form(m, domain=ZZ)) 37 Matrix([[1, 0, 0], [0, 10, 0], [0, 0, -30]]) 38 39 ''' 40 dM = _to_domain(m, domain) 41 return _snf(dM).to_Matrix() 42 43 44def invariant_factors(m, domain=None): 45 ''' 46 Return the tuple of abelian invariants for a matrix `m` 47 (as in the Smith-Normal form) 48 49 References 50 ========== 51 52 [1] https://en.wikipedia.org/wiki/Smith_normal_form#Algorithm 53 [2] http://sierra.nmsu.edu/morandi/notes/SmithNormalForm.pdf 54 55 ''' 56 dM = _to_domain(m, domain) 57 factors = _invf(dM) 58 factors = tuple(dM.domain.to_sympy(f) for f in factors) 59 # XXX: deprecated. 60 if hasattr(m, "ring"): 61 if m.ring.is_PolynomialRing: 62 K = m.ring 63 to_poly = lambda f: Poly(f, K.symbols, domain=K.domain) 64 factors = tuple(to_poly(f) for f in factors) 65 return factors 66