123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- """
- test_pythonmpq.py
- Test the PythonMPQ class for consistency with gmpy2's mpq type. If gmpy2 is
- installed run the same tests for both.
- """
- from fractions import Fraction
- from decimal import Decimal
- import pickle
- from typing import Callable, List, Tuple, Type
- from sympy.testing.pytest import raises
- from sympy.external.pythonmpq import PythonMPQ
- #
- # If gmpy2 is installed then run the tests for both mpq and PythonMPQ.
- # That should ensure consistency between the implementation here and mpq.
- #
- rational_types: List[Tuple[Callable, Type, Callable, Type]]
- rational_types = [(PythonMPQ, PythonMPQ, int, int)]
- try:
- from gmpy2 import mpq, mpz
- rational_types.append((mpq, type(mpq(1)), mpz, type(mpz(1))))
- except ImportError:
- pass
- def test_PythonMPQ():
- #
- # Test PythonMPQ and also mpq if gmpy/gmpy2 is installed.
- #
- for Q, TQ, Z, TZ in rational_types:
- def check_Q(q):
- assert isinstance(q, TQ)
- assert isinstance(q.numerator, TZ)
- assert isinstance(q.denominator, TZ)
- return q.numerator, q.denominator
- # Check construction from different types
- assert check_Q(Q(3)) == (3, 1)
- assert check_Q(Q(3, 5)) == (3, 5)
- assert check_Q(Q(Q(3, 5))) == (3, 5)
- assert check_Q(Q(0.5)) == (1, 2)
- assert check_Q(Q('0.5')) == (1, 2)
- assert check_Q(Q(Fraction(3, 5))) == (3, 5)
- # https://github.com/aleaxit/gmpy/issues/327
- if Q is PythonMPQ:
- assert check_Q(Q(Decimal('0.6'))) == (3, 5)
- # Invalid types
- raises(TypeError, lambda: Q([]))
- raises(TypeError, lambda: Q([], []))
- # Check normalisation of signs
- assert check_Q(Q(2, 3)) == (2, 3)
- assert check_Q(Q(-2, 3)) == (-2, 3)
- assert check_Q(Q(2, -3)) == (-2, 3)
- assert check_Q(Q(-2, -3)) == (2, 3)
- # Check gcd calculation
- assert check_Q(Q(12, 8)) == (3, 2)
- # __int__/__float__
- assert int(Q(5, 3)) == 1
- assert int(Q(-5, 3)) == -1
- assert float(Q(5, 2)) == 2.5
- assert float(Q(-5, 2)) == -2.5
- # __str__/__repr__
- assert str(Q(2, 1)) == "2"
- assert str(Q(1, 2)) == "1/2"
- if Q is PythonMPQ:
- assert repr(Q(2, 1)) == "MPQ(2,1)"
- assert repr(Q(1, 2)) == "MPQ(1,2)"
- else:
- assert repr(Q(2, 1)) == "mpq(2,1)"
- assert repr(Q(1, 2)) == "mpq(1,2)"
- # __bool__
- assert bool(Q(1, 2)) is True
- assert bool(Q(0)) is False
- # __eq__/__ne__
- assert (Q(2, 3) == Q(2, 3)) is True
- assert (Q(2, 3) == Q(2, 5)) is False
- assert (Q(2, 3) != Q(2, 3)) is False
- assert (Q(2, 3) != Q(2, 5)) is True
- # __hash__
- assert hash(Q(3, 5)) == hash(Fraction(3, 5))
- # __reduce__
- q = Q(2, 3)
- assert pickle.loads(pickle.dumps(q)) == q
- # __ge__/__gt__/__le__/__lt__
- assert (Q(1, 3) < Q(2, 3)) is True
- assert (Q(2, 3) < Q(2, 3)) is False
- assert (Q(2, 3) < Q(1, 3)) is False
- assert (Q(-2, 3) < Q(1, 3)) is True
- assert (Q(1, 3) < Q(-2, 3)) is False
- assert (Q(1, 3) <= Q(2, 3)) is True
- assert (Q(2, 3) <= Q(2, 3)) is True
- assert (Q(2, 3) <= Q(1, 3)) is False
- assert (Q(-2, 3) <= Q(1, 3)) is True
- assert (Q(1, 3) <= Q(-2, 3)) is False
- assert (Q(1, 3) > Q(2, 3)) is False
- assert (Q(2, 3) > Q(2, 3)) is False
- assert (Q(2, 3) > Q(1, 3)) is True
- assert (Q(-2, 3) > Q(1, 3)) is False
- assert (Q(1, 3) > Q(-2, 3)) is True
- assert (Q(1, 3) >= Q(2, 3)) is False
- assert (Q(2, 3) >= Q(2, 3)) is True
- assert (Q(2, 3) >= Q(1, 3)) is True
- assert (Q(-2, 3) >= Q(1, 3)) is False
- assert (Q(1, 3) >= Q(-2, 3)) is True
- # __abs__/__pos__/__neg__
- assert abs(Q(2, 3)) == abs(Q(-2, 3)) == Q(2, 3)
- assert +Q(2, 3) == Q(2, 3)
- assert -Q(2, 3) == Q(-2, 3)
- # __add__/__radd__
- assert Q(2, 3) + Q(5, 7) == Q(29, 21)
- assert Q(2, 3) + 1 == Q(5, 3)
- assert 1 + Q(2, 3) == Q(5, 3)
- raises(TypeError, lambda: [] + Q(1))
- raises(TypeError, lambda: Q(1) + [])
- # __sub__/__rsub__
- assert Q(2, 3) - Q(5, 7) == Q(-1, 21)
- assert Q(2, 3) - 1 == Q(-1, 3)
- assert 1 - Q(2, 3) == Q(1, 3)
- raises(TypeError, lambda: [] - Q(1))
- raises(TypeError, lambda: Q(1) - [])
- # __mul__/__rmul__
- assert Q(2, 3) * Q(5, 7) == Q(10, 21)
- assert Q(2, 3) * 1 == Q(2, 3)
- assert 1 * Q(2, 3) == Q(2, 3)
- raises(TypeError, lambda: [] * Q(1))
- raises(TypeError, lambda: Q(1) * [])
- # __pow__/__rpow__
- assert Q(2, 3) ** 2 == Q(4, 9)
- assert Q(2, 3) ** 1 == Q(2, 3)
- assert Q(-2, 3) ** 2 == Q(4, 9)
- assert Q(-2, 3) ** -1 == Q(-3, 2)
- if Q is PythonMPQ:
- raises(TypeError, lambda: 1 ** Q(2, 3))
- raises(TypeError, lambda: Q(1, 4) ** Q(1, 2))
- raises(TypeError, lambda: [] ** Q(1))
- raises(TypeError, lambda: Q(1) ** [])
- # __div__/__rdiv__
- assert Q(2, 3) / Q(5, 7) == Q(14, 15)
- assert Q(2, 3) / 1 == Q(2, 3)
- assert 1 / Q(2, 3) == Q(3, 2)
- raises(TypeError, lambda: [] / Q(1))
- raises(TypeError, lambda: Q(1) / [])
- raises(ZeroDivisionError, lambda: Q(1, 2) / Q(0))
- # __divmod__
- if Q is PythonMPQ:
- raises(TypeError, lambda: Q(2, 3) // Q(1, 3))
- raises(TypeError, lambda: Q(2, 3) % Q(1, 3))
- raises(TypeError, lambda: 1 // Q(1, 3))
- raises(TypeError, lambda: 1 % Q(1, 3))
- raises(TypeError, lambda: Q(2, 3) // 1)
- raises(TypeError, lambda: Q(2, 3) % 1)
|