"""Minimal univariate rational functions over Q using python-flint.""" import flint from flint import fmpq_poly, fmpq class RF: __slots__ = ("n", "d") def __init__(self, n, d=None, norm=True): if not isinstance(n, fmpq_poly): n = fmpq_poly([n]) if d is None: d = fmpq_poly([1]) elif not isinstance(d, fmpq_poly): d = fmpq_poly([d]) if norm: if n == 0: d = fmpq_poly([1]) else: g = n.gcd(d) if g.degree() > 0: n = n // g d = d // g lc = d.coeffs()[-1] if lc != 1: n = n / lc d = d / lc self.n, self.d = n, d @staticmethod def gen(): return RF(fmpq_poly([0, 1])) def _c(self, o): return o if isinstance(o, RF) else RF(o) def __add__(self, o): o = self._c(o) if self.d == o.d: return RF(self.n + o.n, self.d) return RF(self.n * o.d + o.n * self.d, self.d * o.d) __radd__ = __add__ def __neg__(self): return RF(-self.n, self.d, norm=False) def __sub__(self, o): return self + (-self._c(o)) def __rsub__(self, o): return self._c(o) - self def __mul__(self, o): o = self._c(o) if self.n == 0 or o.n == 0: return RF(0) return RF(self.n * o.n, self.d * o.d) __rmul__ = __mul__ def __truediv__(self, o): o = self._c(o) if o.n == 0: raise ZeroDivisionError return RF(self.n * o.d, self.d * o.n) def __rtruediv__(self, o): return self._c(o) / self def __pow__(self, k): if k == 0: return RF(1) if k < 0: return RF(1) / (self ** (-k)) return RF(self.n ** k, self.d ** k) def __eq__(self, o): o = self._c(o) return self.n == o.n and self.d == o.d def __ne__(self, o): return not self.__eq__(o) def __hash__(self): return hash((str(self.n), str(self.d))) def __repr__(self): if self.d == 1: return f"({self.n})" return f"({self.n})/({self.d})" def __call__(self, x): return self.n(x) / self.d(x)