def test_QuotientRing(): I = QQ.old_poly_ring(x).ideal(x**2 + 1) R = QQ.old_poly_ring(x) / I assert R == QQ.old_poly_ring(x) / [x**2 + 1] assert R == QQ.old_poly_ring(x) / QQ.old_poly_ring(x).ideal(x**2 + 1) assert R != QQ.old_poly_ring(x) assert R.convert(1) / x == -x + I assert -1 + I == x**2 + I assert R.convert(ZZ(1), ZZ) == 1 + I assert R.convert(R.convert(x), R) == R.convert(x) X = R.convert(x) Y = QQ.old_poly_ring(x).convert(x) assert -1 + I == X**2 + I assert -1 + I == Y**2 + I assert R.to_sympy(X) == x raises(ValueError, lambda: QQ.old_poly_ring(x) / QQ.old_poly_ring(x, y).ideal(x)) R = QQ.old_poly_ring(x, order="ilex") I = R.ideal(x) assert R.convert(1) + I == (R / I).convert(1)
def hermite_normal_form(A, *, D=None, check_rank=False): r""" Compute the Hermite Normal Form of a Matrix *A* of integers. Examples ======== >>> from sympy import Matrix >>> from sympy.matrices.normalforms import hermite_normal_form >>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]]) >>> print(hermite_normal_form(m)) Matrix([[10, 0, 2], [0, 15, 3], [0, 0, 2]]) Parameters ========== A : $m \times n$ ``Matrix`` of integers. D : int, optional Let $W$ be the HNF of *A*. If known in advance, a positive integer *D* being any multiple of $\det(W)$ may be provided. In this case, if *A* also has rank $m$, then we may use an alternative algorithm that works mod *D* in order to prevent coefficient explosion. check_rank : boolean, optional (default=False) The basic assumption is that, if you pass a value for *D*, then you already believe that *A* has rank $m$, so we do not waste time checking it for you. If you do want this to be checked (and the ordinary, non-modulo *D* algorithm to be used if the check fails), then set *check_rank* to ``True``. Returns ======= ``Matrix`` The HNF of matrix *A*. Raises ====== DMDomainError If the domain of the matrix is not :ref:`ZZ`. DMShapeError If the mod *D* algorithm is used but the matrix has more rows than columns. References ========== .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* (See Algorithms 2.4.5 and 2.4.8.) """ # Accept any of Python int, SymPy Integer, and ZZ itself: if D is not None and not ZZ.of_type(D): D = ZZ(int(D)) return _hnf(A._rep, D=D, check_rank=check_rank).to_Matrix()
def test_sub(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = [[ZZ(5), ZZ(4), ZZ(9)], [ZZ(3), ZZ(7), ZZ(1)], [ZZ(12), ZZ(13), ZZ(14)]] c = [[ZZ(12)], [ZZ(17)], [ZZ(21)]] d = [[ZZ(3)], [ZZ(4)], [ZZ(5)]] e = [[ZZ(12), ZZ(78)], [ZZ(56), ZZ(79)]] f = [[ZZ.zero, ZZ.zero], [ZZ.zero, ZZ.zero]] assert sub(a, b, ZZ) == [[ZZ(-2), ZZ(3), ZZ(-5)], [ZZ(-1), ZZ(-3), ZZ(4)], [ZZ(-6), ZZ(-11), ZZ(-11)]] assert sub(c, d, ZZ) == [[ZZ(9)], [ZZ(13)], [ZZ(16)]] assert sub(e, f, ZZ) == e
def test_add(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = [[ZZ(5), ZZ(4), ZZ(9)], [ZZ(3), ZZ(7), ZZ(1)], [ZZ(12), ZZ(13), ZZ(14)]] c = [[ZZ(12)], [ZZ(17)], [ZZ(21)]] d = [[ZZ(3)], [ZZ(4)], [ZZ(5)]] e = [[ZZ(12), ZZ(78)], [ZZ(56), ZZ(79)]] f = [[ZZ.zero, ZZ.zero], [ZZ.zero, ZZ.zero]] assert add(a, b, ZZ) == [[ZZ(8), ZZ(11), ZZ(13)], [ZZ(5), ZZ(11), ZZ(6)], [ZZ(18), ZZ(15), ZZ(17)]] assert add(c, d, ZZ) == [[ZZ(15)], [ZZ(21)], [ZZ(26)]] assert add(e, f, ZZ) == e
def test_trace(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = eye(2, ZZ) assert trace(a, ZZ) == ZZ(10) assert trace(b, ZZ) == ZZ(2)
def test_transpose(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = eye(4, ZZ) assert transpose(a, ZZ) == ([[ZZ(3), ZZ(2), ZZ(6)], [ZZ(7), ZZ(4), ZZ(2)], [ZZ(4), ZZ(5), ZZ(3)]]) assert transpose(b, ZZ) == b
class GaussianIntegerRing(GaussianDomain, Ring): r"""Ring of Gaussian integers ``ZZ_I`` The :ref:`ZZ_I` domain represents the `Gaussian integers`_ `\mathbb{Z}[i]` as a :py:class:`~.Domain` in the domain system (see :ref:`polys-domainsintro`). By default a :py:class:`~.Poly` created from an expression with coefficients that are combinations of integers and ``I`` (`\sqrt{-1}`) will have the domain :ref:`ZZ_I`. >>> from sympy import Poly, Symbol, I >>> x = Symbol('x') >>> p = Poly(x**2 + I) >>> p Poly(x**2 + I, x, domain='ZZ_I') >>> p.domain ZZ_I The :ref:`ZZ_I` domain can be used to factorise polynomials that are reducible over the Gaussian integers. >>> from sympy import factor >>> factor(x**2 + 1) x**2 + 1 >>> factor(x**2 + 1, domain='ZZ_I') (x - I)*(x + I) The corresponding `field of fractions`_ is the domain of the Gaussian rationals :ref:`QQ_I`. Conversely :ref:`ZZ_I` is the `ring of integers`_ of :ref:`QQ_I`. >>> from sympy import ZZ_I, QQ_I >>> ZZ_I.get_field() QQ_I >>> QQ_I.get_ring() ZZ_I When using the domain directly :ref:`ZZ_I` can be used as a constructor. >>> ZZ_I(3, 4) (3 + 4*I) >>> ZZ_I(5) (5 + 0*I) The domain elements of :ref:`ZZ_I` are instances of :py:class:`~.GaussianInteger` which support the rings operations ``+,-,*,**``. >>> z1 = ZZ_I(5, 1) >>> z2 = ZZ_I(2, 3) >>> z1 (5 + 1*I) >>> z2 (2 + 3*I) >>> z1 + z2 (7 + 4*I) >>> z1 * z2 (7 + 17*I) >>> z1 ** 2 (24 + 10*I) Both floor (``//``) and modulo (``%``) division work with :py:class:`~.GaussianInteger` (see the :py:meth:`~.Domain.div` method). >>> z3, z4 = ZZ_I(5), ZZ_I(1, 3) >>> z3 // z4 # floor division (1 + -1*I) >>> z3 % z4 # modulo division (remainder) (1 + -2*I) >>> (z3//z4)*z4 + z3%z4 == z3 True True division (``/``) in :ref:`ZZ_I` gives an element of :ref:`QQ_I`. The :py:meth:`~.Domain.exquo` method can be used to divide in :ref:`ZZ_I` when exact division is possible. >>> z1 / z2 (1 + -1*I) >>> ZZ_I.exquo(z1, z2) (1 + -1*I) >>> z3 / z4 (1/2 + -3/2*I) >>> ZZ_I.exquo(z3, z4) Traceback (most recent call last): ... ExactQuotientFailed: (1 + 3*I) does not divide (5 + 0*I) in ZZ_I The :py:meth:`~.Domain.gcd` method can be used to compute the `gcd`_ of any two elements. >>> ZZ_I.gcd(ZZ_I(10), ZZ_I(2)) (2 + 0*I) >>> ZZ_I.gcd(ZZ_I(5), ZZ_I(2, 1)) (2 + 1*I) .. _Gaussian integers: https://en.wikipedia.org/wiki/Gaussian_integer .. _gcd: https://en.wikipedia.org/wiki/Greatest_common_divisor """ dom = ZZ dtype = GaussianInteger zero = dtype(ZZ(0), ZZ(0)) one = dtype(ZZ(1), ZZ(0)) imag_unit = dtype(ZZ(0), ZZ(1)) units = (one, imag_unit, -one, -imag_unit) # powers of i rep = 'ZZ_I' is_GaussianRing = True is_ZZ_I = True def __init__(self): # override Domain.__init__ """For constructing ZZ_I.""" def get_ring(self): """Returns a ring associated with ``self``. """ return self def get_field(self): """Returns a field associated with ``self``. """ return QQ_I def normalize(self, d, *args): """Return first quadrant element associated with ``d``. Also multiply the other arguments by the same power of i. """ unit = self.canonical_unit(d) d *= unit args = tuple(a * unit for a in args) return (d, ) + args if args else d def gcd(self, a, b): """Greatest common divisor of a and b over ZZ_I.""" while b: a, b = b, a % b return self.normalize(a) def lcm(self, a, b): """Least common multiple of a and b over ZZ_I.""" return (a * b) // self.gcd(a, b) def from_GaussianIntegerRing(K1, a, K0): """Convert a ZZ_I element to ZZ_I.""" return a def from_GaussianRationalField(K1, a, K0): """Convert a QQ_I element to ZZ_I.""" return K1.new(ZZ.convert(a.x), ZZ.convert(a.y))