Qi – Gaussian Rationals

Gaussian rational (Qi) class: a + bi with a, b in Q, represented exactly as fractions.Fraction.

Qi is integrated with Zi (Gaussian integers): constructing a Qi whose real and imaginary parts both happen to be whole numbers transparently yields a Zi instead of a Qi (see __new__). This means Qi(4, 6) is actually a Zi(4, 6), while Qi(4, ‘2/3’) is a genuine Qi.

Examples:

>>> from gint import Zi, Qi
>>>
>>> Zi(11, 3) / Zi(1, 8)
>>> # ==> Qi('7/13', '-17/13')
>>>
>>> print(Zi(11, 3) / Zi(1, 8))
>>> # ==> (7/13-17/13j)
>>>
>>> Qi(2.25, -3.6)
>>> # ==> Qi('9/4', '-18/5')
>>>
>>> Qi(2.0, 4)
>>> # ==> Zi(2, 4)
class gint.qi.Qi(real=None, imag=None)[source]

Bases: Complex

A class that represents a Gaussian rational: a + bi with a, b in Q, the set of all rational numbers.

__init__(real=None, imag=None) → None[source]
property real: Fraction

Retrieve the real component of this number.

This should subclass Real.

property imag: Fraction

Retrieve the imaginary component of this number.

This should subclass Real.

conjugate()[source]

(x+y*i).conjugate() returns (x-y*i).

property norm
__add__(other)[source]

self + other

__sub__(other)[source]

self - other

__mul__(other)[source]

self * other

__truediv__(other)[source]

self / other: Should promote to float when necessary.

inverse()[source]

Returns the exact multiplicative inverse of this Gaussian rational.

to_array()[source]

Returns a two-element array representation of this Gaussian rational.

static from_array(arr)[source]

Returns a Gaussian rational, given a two-element array.

classmethod get_unit_symbol()[source]

Forwards to Zi.get_unit_symbol(), the single source of truth (see the note by __slots__ above).

classmethod set_unit_symbol(symbol)[source]

Forwards to Zi.set_unit_symbol(); setting it on either class affects both, since they share the same underlying setting.

classmethod get_max_denominator()[source]
classmethod set_max_denominator(value)[source]
limit_denominator(max_denominator=None)[source]

Return a new Qi (or Zi, if both parts become whole numbers) with each component approximated by the closest fraction whose denominator does not exceed max_denominator (defaults to Qi.get_max_denominator()).

static gcd(a, b)[source]

Greatest common divisor of two Gaussian rationals, generalizing the classic rational-number identity

gcd(p1/q1, p2/q2) == gcd(p1, p2) / lcm(q1, q2)

to Q(i): clear denominators down to Zi numerators, take Zi.gcd of those, and divide by the lcm of the original denominators. The defining property – the one this is tested against – is that a/g and b/g both come out as exact Zi values.

Like Zi.gcd, the result is only defined up to a unit factor. gcd(0, 0) returns 0, matching Zi.gcd’s convention.

static congruent_modulo(a, b, c)[source]

True iff a is congruent to b modulo c over the Gaussian rationals Q(i): i.e., iff (a - b) / c is an exact Gaussian integer. This generalizes Zi.congruent_modulo to inputs drawn from all of Q(i), not just Z[i] – and agrees with it exactly when a, b, c all happen to be Gaussian integers.

Raises ZeroDivisionError if c == 0.

static crt(residues, moduli)[source]

Chinese Remainder Theorem, exposed on Qi purely as an input-flexibility convenience over Zi.crt – it does NOT generalize the theorem itself to fractional values.

Q(i) is a field: it has no proper nonzero ideals, so there’s no ring Q(i)/(m) for a nonzero m to generalize the classical Z[i]/(m) statement to. And it isn’t just a matter of finding the right formula, either – unlike congruent_modulo (which only ever checks a candidate x someone already has in hand), crt constructs a solution, and coprime moduli alone stop being enough to guarantee one exists once residues are allowed to be fractional: e.g. no x satisfies both (x-1/2) in Z[i] and (x-1/3) in Z[i], regardless of what moduli those residues are paired with, since a single x can’t simultaneously have two different fractional parts.

So every residue and modulus passed here must still be Gaussian-integer-valued – each argument must itself be, or coerce via Qi’s usual type handling to, a Zi (so int, complex, Fraction, Zi, and integer-valued Qi are all fine; a genuinely fractional Qi or Fraction is not). That’s the actual generalization on offer: passing e.g. Fraction(6, 1) or 3+0j instead of only a bare Zi. Raises ValueError if any residue or modulus is fractional. Everything else – pairwise coprimality, zero moduli, mismatched/empty input – is Zi.crt’s to enforce; see its docstring for the algorithm. Returns a Zi, same as Zi.crt.