Skip to content

quadraticelement2

__all__ = ('QuadraticElement2',) module-attribute

QuadraticElement2 dataclass

Element of the quadratic rationals \(\mathbb{K}\left(\sqrt{2}\right)\).

An instance represents an exact rational of the form

\[ a+b\sqrt{2} \qquad a, b\in\mathbb{K} \]

where currently \(\mathbb{K}\) is \(\mathbb{Z}\) (int) or \(\mathbb{Q}\) (fractions.Fraction).

The immutable class supports exact conversion, ordering, algebraic conjugation, norm computation and arithmetic.

Addition, subtraction & multiplication is closed, mixed coefficients are promoted. Inversion is closed for integers for a norm of \(\pm1\), otherwise it is promoted to rationals. Division is more often than necessary promoted to rationals.

Parameters:

  • a (int or Fraction, default: 0 ) –

    Coefficient of \(1\).

  • b (int or Fraction, default: 0 ) –

    Coefficient of \(\sqrt{2}\).

References
Source code in radicalfield\quadraticelement2.py
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
@total_ordering
@dataclass(eq=False, frozen=True, slots=True) #make slots, immutability & repr
class QuadraticElement2:
    r"""Element of the quadratic rationals $\mathbb{K}\left(\sqrt{2}\right)$.

    An instance represents an exact rational of the form

    $$
        a+b\sqrt{2} \qquad a, b\in\mathbb{K}
    $$

    where currently $\mathbb{K}$ is $\mathbb{Z}$ (`int`)
    or $\mathbb{Q}$ (`fractions.Fraction`).

    The immutable class supports exact conversion, ordering,
    algebraic conjugation, norm computation and arithmetic.

    Addition, subtraction & multiplication is closed,
    mixed coefficients are promoted.
    Inversion is closed for integers for a norm of $\pm1$,
    otherwise it is promoted to rationals.
    Division is more often than necessary promoted to rationals.

    Parameters
    ----------
    a : int or Fraction, default 0
        Coefficient of $1$.
    b : int or Fraction, default 0
        Coefficient of $\sqrt{2}$.

    References
    ----------
    - [Wikipedia - Quadratic integers](https://en.wikipedia.org/wiki/Quadratic_integer)
    """
    a:Final[int|Fraction] = 0
    b:Final[int|Fraction] = 0
    SQRT2:ClassVar[float] = sqrt(2)



    @staticmethod
    def from_expr(e:sp.Expr) -> 'QuadraticElement2':
        r"""Construct a `QuadraticElement2` from a `sympy.Expr`.

        Parameters
        ----------
        e
            Expression to convert.

        Returns
        -------
        QuadraticElement2
            Expression as `QuadraticElement2`.

        Raises
        ------
        ValueError
            If the expression is not an element of
            $\mathbb{K}\left(\sqrt{2}\right)$.
        """
        if not isinstance(e, sp.Expr):
            raise TypeError('e must be a sympy.Expr')

        SPSQRT2 = sp.sqrt(2)
        e:sp.Expr = sp.nsimplify(e, [SPSQRT2])

        a:sp.Expr = sp.simplify(e.subs(SPSQRT2, 0))
        b:sp.Expr = sp.simplify((e - a) / SPSQRT2)

        if sp.simplify(a + b*SPSQRT2 - e) != 0:
            raise ValueError('expression not exactly representable in 𝕂(√2)')

        if not (isinstance(a, sp.Rational) and isinstance(b, sp.Rational)):
            raise ValueError(f'not in 𝕂(√2): {e} (a={a}, b={b})')

        def rat_to_int_or_frac(r:sp.Integer|sp.Rational) -> int|Fraction:
            if isinstance(r, sp.Integer):
                return int(r)
            else:
                return Fraction(int(r.p), int(r.q))

        return QuadraticElement2(rat_to_int_or_frac(a), rat_to_int_or_frac(b))


    def __post_init__(self) -> None:
        if not (isinstance(self.a, (int, Fraction)) \
                and isinstance(self.b, (int, Fraction))):
            raise TypeError('a and b must be integers or fractions')



    #conversion
    def __bool__(self) -> bool:
        """Return whether this element is unequal zero.

        Returns
        -------
        bool
            Whether this element is unequal zero.
        """
        return bool(self.a) or bool(self.b)

    def is_rational(self) -> bool:
        r"""Return whether this element has no $\sqrt{2}$ component.

        Notes
        -----
        Not a property to be consistent with `fractions.Fraction.is_integer()`.

        Returns
        -------
        bool
            Whether this element has no $\sqrt{2}$ component.
        """
        return not bool(self.b)

    def as_fraction(self) -> Fraction:
        """Return this element as a fraction.

        Returns
        -------
        Fraction
            This element as a fraction.

        Raises
        ------
        ValueError
            If this element is not a fraction.
        """
        if not self.is_rational():
            raise ValueError('not a fraction (b != 0)')
        return Fraction(self.a)

    def is_integer(self) -> bool:
        """Return whether this element is an integer.

        Notes
        -----
        Not a property to be consistent with `fractions.Fraction.is_integer()`.

        Returns
        -------
        bool
            Whether this element is an integer.
        """
        return (isinstance(self.a, int) or self.a.is_integer()) and self.b==0

    def __int__(self) -> int:
        """Return this element as an integer.

        Returns
        -------
        int
            This element as an integer.

        Raises
        ------
        ValueError
            If this element is not an integer.
        """
        if not self.is_integer():
            raise ValueError('not an integer')
        return int(self.a)

    def __float__(self) -> float:
        """Return this element as a float.

        Returns
        -------
        float
            This element as a float.
        """
        return float(self.a) + QuadraticElement2.SQRT2*float(self.b)

    def _sympy_(self) -> sp.Expr:
        return self.a + sp.sqrt(2)*self.b

    def __hash__(self) -> int:
        #https://docs.python.org/3/library/numbers.html#notes-for-type-implementers
        if self.is_rational():
            return hash(self.a)
        else:
            return hash((self.a, self.b))



    #ordering
    @overload
    def __eq__(self, other:Self) -> bool: ...
    @overload
    def __eq__(self, other:int) -> bool: ...
    @overload
    def __eq__(self, other:Fraction) -> bool: ...
    def __eq__(self, other:Any) -> bool|NotImplementedType:
        if isinstance(other, QuadraticElement2):
            return self.a==other.a and self.b==other.b
        elif isinstance(other, (int, Fraction)):
            return self.a==other and self.b==0
        return NotImplemented

    @overload
    def __lt__(self, other:Self) -> bool: ...
    @overload
    def __lt__(self, other:int) -> bool: ...
    @overload
    def __lt__(self, other:Fraction) -> bool: ...
    def __lt__(self, other:Any) -> bool|NotImplementedType:
        r"""Return whether this element is less than the other.

        $$
            \begin{aligned}
                a+b\sqrt{2} &\overset{?}{<} c+d\sqrt{2} &&\mid -a-d\sqrt{2} \\
                (b-d)\sqrt{2} &\overset{?}{<} (c-a)\sqrt{2} &&\mid \cdot^2 \\
                2(b-d)|b-d| &\overset{?}{<} (c-a)|c-a|
            \end{aligned}
        $$

        Parameters
        ----------
        other: QuadraticElement2 or int or Fraction
            Operand to compare to.

        Returns
        -------
        bool
            Whether this element is less than the other.
        """
        if isinstance(other, QuadraticElement2):
            l:int|Fraction = self.b - other.b
            r:int|Fraction = other.a - self.a
            #https://math.stackexchange.com/a/2347212
            return 2*l*abs(l) < r*abs(r)
        elif isinstance(other, (int, Fraction)):
            r:int|Fraction = other - self.a
            return 2*self.b*abs(self.b) < r*abs(r)
        return NotImplemented

    def __abs__(self) -> Self:
        return +self if self>=0 else -self



    #arithmetic
    #make all following methods non-recursive/leaves,
    #except inversion as it is otherwise to complicated
    def norm(self) -> int|Fraction:
        r"""Return the algebraic norm.

        $$
            N\left(a+b\sqrt{2}\right)
            = \left(\overline{a+b\sqrt{2}}\right)\left(a+b\sqrt{2}\right)
            = a^2-2b^2
        $$

        Returns
        -------
        int or Fraction
            The algebraic norm.

        References
        ----------
        [Wikipedia - Quadratic integers - Norm and conjugation](https://en.wikipedia.org/wiki/Quadratic_integer#Norm_and_conjugation)
        """
        return self.a*self.a - 2*self.b*self.b

    def conj(self) -> Self:
        """Return the algebraic conjugate.

        See also
        --------
        Alias for [`conjugate`][radicalfield.quadraticelement2.QuadraticElement2.conjugate].
        """
        return self.conjugate()

    def conjugate(self) -> Self:
        r"""Return the algebraic conjugation.

        $$
            \overline{a+b\sqrt{2}} = a-b\sqrt{2}
        $$

        Returns
        -------
        QuadraticElement2
            The algebraic conjugation.

        References
        ----------
        [Wikipedia - Quadratic integers - Norm and conjugation](https://en.wikipedia.org/wiki/Quadratic_integer#Norm_and_conjugation)
        """
        return QuadraticElement2(self.a, -self.b)


    def __pos__(self) -> Self:
        r"""Return itself.

        $$
            +\left(a+b\sqrt{2}\right)
        $$

        Returns
        -------
        QuadraticElement2
            Itself.
        """
        return QuadraticElement2(+self.a, +self.b)

    def __neg__(self) -> Self:
        r"""Return the negation.

        $$
            -\left(a+b\sqrt{2}\right)
        $$

        Returns
        -------
        QuadraticElement2
            The negation.
        """
        return QuadraticElement2(-self.a, -self.b)


    @overload
    def __add__(self, other:Self) -> Self: ...
    @overload
    def __add__(self, other:int) -> Self: ...
    @overload
    def __add__(self, other:Fraction) -> Self: ...
    def __add__(self, other:Any) -> Self|NotImplementedType:
        r"""Return the sum.

        $$
            \left(a+b\sqrt{2}\right) + \left(c+d\sqrt{2}\right)
            = \left(a+c\right) + \left(b+d\right)\sqrt{2}
        $$

        Parameters
        ----------
        other: QuadraticElement2 or int or Fraction
            Other summand.

        Returns
        -------
        QuadraticElement2
            The sum.
        """
        if isinstance(other, QuadraticElement2):
            return QuadraticElement2(self.a+other.a, self.b+other.b)
        elif isinstance(other, (int, Fraction)):
            return QuadraticElement2(self.a+other, self.b)
        return NotImplemented

    @overload
    def __radd__(self, other:int) -> Self: ...
    @overload
    def __radd__(self, other:Fraction) -> Self: ...
    def __radd__(self, other:Any) -> Self|NotImplementedType:
        if isinstance(other, (int, Fraction)):
            return QuadraticElement2(other+self.a, self.b)
        return NotImplemented


    @overload
    def __sub__(self, other:Self) -> Self: ...
    @overload
    def __sub__(self, other:int) -> Self: ...
    @overload
    def __sub__(self, other:Fraction) -> Self: ...
    def __sub__(self, other:Any) -> Self|NotImplementedType:
        r"""Return the difference.

        $$
            \left(a+b\sqrt{2}\right) - \left(c+d\sqrt{2}\right)
            = \left(a-c\right) + \left(b-d\right)\sqrt{2}
        $$

        Parameters
        ----------
        other: QuadraticElement2 or int or Fraction
            The subtrahend.

        Returns
        -------
        QuadraticElement2
            The difference.
        """
        if isinstance(other, QuadraticElement2):
            return QuadraticElement2(self.a-other.a, self.b-other.b)
        elif isinstance(other, (int, Fraction)):
            return QuadraticElement2(self.a-other, self.b)
        return NotImplemented

    @overload
    def __rsub__(self, other:int) -> Self: ...
    @overload
    def __rsub__(self, other:Fraction) -> Self: ...
    def __rsub__(self, other:Any) -> Self|NotImplementedType:
        if isinstance(other, (int, Fraction)):
            return QuadraticElement2(other-self.a, -self.b)
        return NotImplemented


    @overload
    def __mul__(self, other:Self) -> Self: ...
    @overload
    def __mul__(self, other:int) -> Self: ...
    @overload
    def __mul__(self, other:Fraction) -> Self: ...
    def __mul__(self, other:Any) -> Self|NotImplementedType:
        r"""Return the product.

        $$
            \left(a+b\sqrt{2}\right) \cdot \left(c+d\sqrt{2}\right)
            = \left(ac+2bd\right) + \left(ad+bc\right)\sqrt{2}
        $$

        Parameters
        ----------
        other: QuadraticElement2 or int or Fraction
            The other factor.

        Returns
        -------
        QuadraticElement2
            The product.
        """
        if isinstance(other, QuadraticElement2):
            return QuadraticElement2(
                    self.a*other.a + 2*self.b*other.b,
                    self.a*other.b + self.b*other.a
            )
        elif isinstance(other, (int, Fraction)):
            return QuadraticElement2(self.a*other, self.b*other)
        return NotImplemented

    @overload
    def __rmul__(self, other:int) -> Self: ...
    @overload
    def __rmul__(self, other:Fraction) -> Self: ...
    def __rmul__(self, other:Any) -> Self|NotImplementedType:
        if isinstance(other, (int, Fraction)):
            return QuadraticElement2(other*self.a, other*self.b)
        return NotImplemented


    #NOT PERFECTLY TYPED ZONE BEGIN
    def inv(self) -> Self:
        r"""Return the multiplicative inverse in $\mathbb{K}\left(\sqrt{2}\right)$.

        $$
            \frac{1}{a+b\sqrt{2}}
            = \frac{a-b\sqrt{2}}{\left(a+b\sqrt{2}\right)\left(a-b\sqrt{2}\right)}
            = \frac{a-b\sqrt{2}}{a^2-2b^2}
            = \frac{a-b\sqrt{2}}{N\left(a+b\sqrt{2}\right)}
        $$

        `QuadraticElement2` with integer coefficients and norm Β±1 stays integer,
        otherwise promoted to rational.

        Returns
        -------
        QuadraticElement2
            The multiplicative inverse element.

        Raises
        ------
        ZeroDivisionError
            If the norm is zero.

        See also
        --------
        [`QuadraticElement2.norm`][radicalfield.quadraticelement2.QuadraticElement2.norm]
        """
        n:Fraction = Fraction(self.norm())
        if n == 0:
            raise ZeroDivisionError('division by zero in 𝕂(√2)')
        elif n == +1:
            return QuadraticElement2(self.a, -self.b)
        elif n == -1:
            return QuadraticElement2(-self.a, self.b)
        return QuadraticElement2(self.a/n, -self.b/n)

    @overload
    def __truediv__(self, other:Self) -> Self: ...
    @overload
    def __truediv__(self, other:int) -> Self: ...
    @overload
    def __truediv__(self, other:Fraction) -> Self: ...
    def __truediv__(self, other:Any) -> Self|NotImplementedType:
        r"""Return the quotient.

        $$
            \frac{\left(a+b\sqrt{2}\right)}{\left(c+d\sqrt{2}\right)}
            = \frac{\left(a+b\sqrt{2}\right)\left(c-d\sqrt{2}\right)}{\left(c+d\sqrt{2}\right)\left(c-d\sqrt{2}\right)}
            = \frac{\left(ac-2bd\right)+\left(bc-ad\right)\sqrt{2}}{c^2-2d^2}
        $$

        More often than necessary promoted to rationals.

        Parameters
        ----------
        other: QuadraticElement2 or int or Fraction
            The denominator.

        Returns
        -------
        QuadraticElement2
            The quotient.

        Raises
        ------
        ZeroDivisionError
            If the norm of the denominator is zero.
        """
        if isinstance(other, QuadraticElement2):
            return self * other.inv()
        elif isinstance(other, (int, Fraction)):
            other:Fraction = Fraction(other)
            return QuadraticElement2(self.a/other, self.b/other)
        return NotImplemented

    @overload
    def __rtruediv__(self, other:int) -> Self: ...
    @overload
    def __rtruediv__(self, other:Fraction) -> Self: ...
    def __rtruediv__(self, other:Any) -> Self|NotImplementedType:
        if isinstance(other, (int, Fraction)):
            return other * self.inv()
        return NotImplemented
    #NOT PERFECTLY TYPED ZONE END



    #IO
    def __str__(self) -> str:
        return f'{self.a}{self.b:+}√2'

    def _repr_latex_(self) -> str:
        return f'{self.a}{self.b:+}\\sqrt{{2}}'

__init__(a=0, b=0)

a = 0 class-attribute instance-attribute

b = 0 class-attribute instance-attribute

SQRT2 = sqrt(2) class-attribute

from_expr(e) staticmethod

Construct a QuadraticElement2 from a sympy.Expr.

Parameters:

  • e (Expr) –

    Expression to convert.

Returns:

Raises:

  • ValueError –

    If the expression is not an element of \(\mathbb{K}\left(\sqrt{2}\right)\).

Source code in radicalfield\quadraticelement2.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
@staticmethod
def from_expr(e:sp.Expr) -> 'QuadraticElement2':
    r"""Construct a `QuadraticElement2` from a `sympy.Expr`.

    Parameters
    ----------
    e
        Expression to convert.

    Returns
    -------
    QuadraticElement2
        Expression as `QuadraticElement2`.

    Raises
    ------
    ValueError
        If the expression is not an element of
        $\mathbb{K}\left(\sqrt{2}\right)$.
    """
    if not isinstance(e, sp.Expr):
        raise TypeError('e must be a sympy.Expr')

    SPSQRT2 = sp.sqrt(2)
    e:sp.Expr = sp.nsimplify(e, [SPSQRT2])

    a:sp.Expr = sp.simplify(e.subs(SPSQRT2, 0))
    b:sp.Expr = sp.simplify((e - a) / SPSQRT2)

    if sp.simplify(a + b*SPSQRT2 - e) != 0:
        raise ValueError('expression not exactly representable in 𝕂(√2)')

    if not (isinstance(a, sp.Rational) and isinstance(b, sp.Rational)):
        raise ValueError(f'not in 𝕂(√2): {e} (a={a}, b={b})')

    def rat_to_int_or_frac(r:sp.Integer|sp.Rational) -> int|Fraction:
        if isinstance(r, sp.Integer):
            return int(r)
        else:
            return Fraction(int(r.p), int(r.q))

    return QuadraticElement2(rat_to_int_or_frac(a), rat_to_int_or_frac(b))

__post_init__()

Source code in radicalfield\quadraticelement2.py
 99
100
101
102
def __post_init__(self) -> None:
    if not (isinstance(self.a, (int, Fraction)) \
            and isinstance(self.b, (int, Fraction))):
        raise TypeError('a and b must be integers or fractions')

__bool__()

Return whether this element is unequal zero.

Returns:

  • bool –

    Whether this element is unequal zero.

Source code in radicalfield\quadraticelement2.py
107
108
109
110
111
112
113
114
115
def __bool__(self) -> bool:
    """Return whether this element is unequal zero.

    Returns
    -------
    bool
        Whether this element is unequal zero.
    """
    return bool(self.a) or bool(self.b)

is_rational()

Return whether this element has no \(\sqrt{2}\) component.

Notes

Not a property to be consistent with fractions.Fraction.is_integer().

Returns:

  • bool –

    Whether this element has no \(\sqrt{2}\) component.

Source code in radicalfield\quadraticelement2.py
117
118
119
120
121
122
123
124
125
126
127
128
129
def is_rational(self) -> bool:
    r"""Return whether this element has no $\sqrt{2}$ component.

    Notes
    -----
    Not a property to be consistent with `fractions.Fraction.is_integer()`.

    Returns
    -------
    bool
        Whether this element has no $\sqrt{2}$ component.
    """
    return not bool(self.b)

as_fraction()

Return this element as a fraction.

Returns:

  • Fraction –

    This element as a fraction.

Raises:

  • ValueError –

    If this element is not a fraction.

Source code in radicalfield\quadraticelement2.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def as_fraction(self) -> Fraction:
    """Return this element as a fraction.

    Returns
    -------
    Fraction
        This element as a fraction.

    Raises
    ------
    ValueError
        If this element is not a fraction.
    """
    if not self.is_rational():
        raise ValueError('not a fraction (b != 0)')
    return Fraction(self.a)

is_integer()

Return whether this element is an integer.

Notes

Not a property to be consistent with fractions.Fraction.is_integer().

Returns:

  • bool –

    Whether this element is an integer.

Source code in radicalfield\quadraticelement2.py
148
149
150
151
152
153
154
155
156
157
158
159
160
def is_integer(self) -> bool:
    """Return whether this element is an integer.

    Notes
    -----
    Not a property to be consistent with `fractions.Fraction.is_integer()`.

    Returns
    -------
    bool
        Whether this element is an integer.
    """
    return (isinstance(self.a, int) or self.a.is_integer()) and self.b==0

__int__()

Return this element as an integer.

Returns:

  • int –

    This element as an integer.

Raises:

  • ValueError –

    If this element is not an integer.

Source code in radicalfield\quadraticelement2.py
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
def __int__(self) -> int:
    """Return this element as an integer.

    Returns
    -------
    int
        This element as an integer.

    Raises
    ------
    ValueError
        If this element is not an integer.
    """
    if not self.is_integer():
        raise ValueError('not an integer')
    return int(self.a)

__float__()

Return this element as a float.

Returns:

  • float –

    This element as a float.

Source code in radicalfield\quadraticelement2.py
179
180
181
182
183
184
185
186
187
def __float__(self) -> float:
    """Return this element as a float.

    Returns
    -------
    float
        This element as a float.
    """
    return float(self.a) + QuadraticElement2.SQRT2*float(self.b)

__hash__()

Source code in radicalfield\quadraticelement2.py
192
193
194
195
196
197
def __hash__(self) -> int:
    #https://docs.python.org/3/library/numbers.html#notes-for-type-implementers
    if self.is_rational():
        return hash(self.a)
    else:
        return hash((self.a, self.b))

__eq__(other)

__eq__(other: Self) -> bool
__eq__(other: int) -> bool
__eq__(other: Fraction) -> bool
Source code in radicalfield\quadraticelement2.py
208
209
210
211
212
213
def __eq__(self, other:Any) -> bool|NotImplementedType:
    if isinstance(other, QuadraticElement2):
        return self.a==other.a and self.b==other.b
    elif isinstance(other, (int, Fraction)):
        return self.a==other and self.b==0
    return NotImplemented

__lt__(other)

__lt__(other: Self) -> bool
__lt__(other: int) -> bool
__lt__(other: Fraction) -> bool

Return whether this element is less than the other.

\[ \begin{aligned} a+b\sqrt{2} &\overset{?}{<} c+d\sqrt{2} &&\mid -a-d\sqrt{2} \\ (b-d)\sqrt{2} &\overset{?}{<} (c-a)\sqrt{2} &&\mid \cdot^2 \\ 2(b-d)|b-d| &\overset{?}{<} (c-a)|c-a| \end{aligned} \]

Parameters:

  • other (Any) –

    Operand to compare to.

Returns:

  • bool –

    Whether this element is less than the other.

Source code in radicalfield\quadraticelement2.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
def __lt__(self, other:Any) -> bool|NotImplementedType:
    r"""Return whether this element is less than the other.

    $$
        \begin{aligned}
            a+b\sqrt{2} &\overset{?}{<} c+d\sqrt{2} &&\mid -a-d\sqrt{2} \\
            (b-d)\sqrt{2} &\overset{?}{<} (c-a)\sqrt{2} &&\mid \cdot^2 \\
            2(b-d)|b-d| &\overset{?}{<} (c-a)|c-a|
        \end{aligned}
    $$

    Parameters
    ----------
    other: QuadraticElement2 or int or Fraction
        Operand to compare to.

    Returns
    -------
    bool
        Whether this element is less than the other.
    """
    if isinstance(other, QuadraticElement2):
        l:int|Fraction = self.b - other.b
        r:int|Fraction = other.a - self.a
        #https://math.stackexchange.com/a/2347212
        return 2*l*abs(l) < r*abs(r)
    elif isinstance(other, (int, Fraction)):
        r:int|Fraction = other - self.a
        return 2*self.b*abs(self.b) < r*abs(r)
    return NotImplemented

__abs__()

Source code in radicalfield\quadraticelement2.py
252
253
def __abs__(self) -> Self:
    return +self if self>=0 else -self

norm()

Return the algebraic norm.

\[ N\left(a+b\sqrt{2}\right) = \left(\overline{a+b\sqrt{2}}\right)\left(a+b\sqrt{2}\right) = a^2-2b^2 \]

Returns:

  • int or Fraction –

    The algebraic norm.

References

Wikipedia - Quadratic integers - Norm and conjugation

Source code in radicalfield\quadraticelement2.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
def norm(self) -> int|Fraction:
    r"""Return the algebraic norm.

    $$
        N\left(a+b\sqrt{2}\right)
        = \left(\overline{a+b\sqrt{2}}\right)\left(a+b\sqrt{2}\right)
        = a^2-2b^2
    $$

    Returns
    -------
    int or Fraction
        The algebraic norm.

    References
    ----------
    [Wikipedia - Quadratic integers - Norm and conjugation](https://en.wikipedia.org/wiki/Quadratic_integer#Norm_and_conjugation)
    """
    return self.a*self.a - 2*self.b*self.b

conj()

Return the algebraic conjugate.

See also

Alias for conjugate.

Source code in radicalfield\quadraticelement2.py
280
281
282
283
284
285
286
287
def conj(self) -> Self:
    """Return the algebraic conjugate.

    See also
    --------
    Alias for [`conjugate`][radicalfield.quadraticelement2.QuadraticElement2.conjugate].
    """
    return self.conjugate()

conjugate()

Return the algebraic conjugation.

\[ \overline{a+b\sqrt{2}} = a-b\sqrt{2} \]

Returns:

References

Wikipedia - Quadratic integers - Norm and conjugation

Source code in radicalfield\quadraticelement2.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
def conjugate(self) -> Self:
    r"""Return the algebraic conjugation.

    $$
        \overline{a+b\sqrt{2}} = a-b\sqrt{2}
    $$

    Returns
    -------
    QuadraticElement2
        The algebraic conjugation.

    References
    ----------
    [Wikipedia - Quadratic integers - Norm and conjugation](https://en.wikipedia.org/wiki/Quadratic_integer#Norm_and_conjugation)
    """
    return QuadraticElement2(self.a, -self.b)

__pos__()

Return itself.

\[ +\left(a+b\sqrt{2}\right) \]

Returns:

Source code in radicalfield\quadraticelement2.py
308
309
310
311
312
313
314
315
316
317
318
319
320
def __pos__(self) -> Self:
    r"""Return itself.

    $$
        +\left(a+b\sqrt{2}\right)
    $$

    Returns
    -------
    QuadraticElement2
        Itself.
    """
    return QuadraticElement2(+self.a, +self.b)

__neg__()

Return the negation.

\[ -\left(a+b\sqrt{2}\right) \]

Returns:

Source code in radicalfield\quadraticelement2.py
322
323
324
325
326
327
328
329
330
331
332
333
334
def __neg__(self) -> Self:
    r"""Return the negation.

    $$
        -\left(a+b\sqrt{2}\right)
    $$

    Returns
    -------
    QuadraticElement2
        The negation.
    """
    return QuadraticElement2(-self.a, -self.b)

__add__(other)

__add__(other: Self) -> Self
__add__(other: int) -> Self
__add__(other: Fraction) -> Self

Return the sum.

\[ \left(a+b\sqrt{2}\right) + \left(c+d\sqrt{2}\right) = \left(a+c\right) + \left(b+d\right)\sqrt{2} \]

Parameters:

  • other (Any) –

    Other summand.

Returns:

Source code in radicalfield\quadraticelement2.py
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
def __add__(self, other:Any) -> Self|NotImplementedType:
    r"""Return the sum.

    $$
        \left(a+b\sqrt{2}\right) + \left(c+d\sqrt{2}\right)
        = \left(a+c\right) + \left(b+d\right)\sqrt{2}
    $$

    Parameters
    ----------
    other: QuadraticElement2 or int or Fraction
        Other summand.

    Returns
    -------
    QuadraticElement2
        The sum.
    """
    if isinstance(other, QuadraticElement2):
        return QuadraticElement2(self.a+other.a, self.b+other.b)
    elif isinstance(other, (int, Fraction)):
        return QuadraticElement2(self.a+other, self.b)
    return NotImplemented

__radd__(other)

__radd__(other: int) -> Self
__radd__(other: Fraction) -> Self
Source code in radicalfield\quadraticelement2.py
371
372
373
374
def __radd__(self, other:Any) -> Self|NotImplementedType:
    if isinstance(other, (int, Fraction)):
        return QuadraticElement2(other+self.a, self.b)
    return NotImplemented

__sub__(other)

__sub__(other: Self) -> Self
__sub__(other: int) -> Self
__sub__(other: Fraction) -> Self

Return the difference.

\[ \left(a+b\sqrt{2}\right) - \left(c+d\sqrt{2}\right) = \left(a-c\right) + \left(b-d\right)\sqrt{2} \]

Parameters:

  • other (Any) –

    The subtrahend.

Returns:

Source code in radicalfield\quadraticelement2.py
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
def __sub__(self, other:Any) -> Self|NotImplementedType:
    r"""Return the difference.

    $$
        \left(a+b\sqrt{2}\right) - \left(c+d\sqrt{2}\right)
        = \left(a-c\right) + \left(b-d\right)\sqrt{2}
    $$

    Parameters
    ----------
    other: QuadraticElement2 or int or Fraction
        The subtrahend.

    Returns
    -------
    QuadraticElement2
        The difference.
    """
    if isinstance(other, QuadraticElement2):
        return QuadraticElement2(self.a-other.a, self.b-other.b)
    elif isinstance(other, (int, Fraction)):
        return QuadraticElement2(self.a-other, self.b)
    return NotImplemented

__rsub__(other)

__rsub__(other: int) -> Self
__rsub__(other: Fraction) -> Self
Source code in radicalfield\quadraticelement2.py
411
412
413
414
def __rsub__(self, other:Any) -> Self|NotImplementedType:
    if isinstance(other, (int, Fraction)):
        return QuadraticElement2(other-self.a, -self.b)
    return NotImplemented

__mul__(other)

__mul__(other: Self) -> Self
__mul__(other: int) -> Self
__mul__(other: Fraction) -> Self

Return the product.

\[ \left(a+b\sqrt{2}\right) \cdot \left(c+d\sqrt{2}\right) = \left(ac+2bd\right) + \left(ad+bc\right)\sqrt{2} \]

Parameters:

  • other (Any) –

    The other factor.

Returns:

Source code in radicalfield\quadraticelement2.py
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
def __mul__(self, other:Any) -> Self|NotImplementedType:
    r"""Return the product.

    $$
        \left(a+b\sqrt{2}\right) \cdot \left(c+d\sqrt{2}\right)
        = \left(ac+2bd\right) + \left(ad+bc\right)\sqrt{2}
    $$

    Parameters
    ----------
    other: QuadraticElement2 or int or Fraction
        The other factor.

    Returns
    -------
    QuadraticElement2
        The product.
    """
    if isinstance(other, QuadraticElement2):
        return QuadraticElement2(
                self.a*other.a + 2*self.b*other.b,
                self.a*other.b + self.b*other.a
        )
    elif isinstance(other, (int, Fraction)):
        return QuadraticElement2(self.a*other, self.b*other)
    return NotImplemented

__rmul__(other)

__rmul__(other: int) -> Self
__rmul__(other: Fraction) -> Self
Source code in radicalfield\quadraticelement2.py
454
455
456
457
def __rmul__(self, other:Any) -> Self|NotImplementedType:
    if isinstance(other, (int, Fraction)):
        return QuadraticElement2(other*self.a, other*self.b)
    return NotImplemented

inv()

Return the multiplicative inverse in \(\mathbb{K}\left(\sqrt{2}\right)\).

\[ \frac{1}{a+b\sqrt{2}} = \frac{a-b\sqrt{2}}{\left(a+b\sqrt{2}\right)\left(a-b\sqrt{2}\right)} = \frac{a-b\sqrt{2}}{a^2-2b^2} = \frac{a-b\sqrt{2}}{N\left(a+b\sqrt{2}\right)} \]

QuadraticElement2 with integer coefficients and norm Β±1 stays integer, otherwise promoted to rational.

Returns:

Raises:

  • ZeroDivisionError –

    If the norm is zero.

See also

QuadraticElement2.norm

Source code in radicalfield\quadraticelement2.py
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
def inv(self) -> Self:
    r"""Return the multiplicative inverse in $\mathbb{K}\left(\sqrt{2}\right)$.

    $$
        \frac{1}{a+b\sqrt{2}}
        = \frac{a-b\sqrt{2}}{\left(a+b\sqrt{2}\right)\left(a-b\sqrt{2}\right)}
        = \frac{a-b\sqrt{2}}{a^2-2b^2}
        = \frac{a-b\sqrt{2}}{N\left(a+b\sqrt{2}\right)}
    $$

    `QuadraticElement2` with integer coefficients and norm Β±1 stays integer,
    otherwise promoted to rational.

    Returns
    -------
    QuadraticElement2
        The multiplicative inverse element.

    Raises
    ------
    ZeroDivisionError
        If the norm is zero.

    See also
    --------
    [`QuadraticElement2.norm`][radicalfield.quadraticelement2.QuadraticElement2.norm]
    """
    n:Fraction = Fraction(self.norm())
    if n == 0:
        raise ZeroDivisionError('division by zero in 𝕂(√2)')
    elif n == +1:
        return QuadraticElement2(self.a, -self.b)
    elif n == -1:
        return QuadraticElement2(-self.a, self.b)
    return QuadraticElement2(self.a/n, -self.b/n)

__truediv__(other)

__truediv__(other: Self) -> Self
__truediv__(other: int) -> Self
__truediv__(other: Fraction) -> Self

Return the quotient.

\[ \frac{\left(a+b\sqrt{2}\right)}{\left(c+d\sqrt{2}\right)} = \frac{\left(a+b\sqrt{2}\right)\left(c-d\sqrt{2}\right)}{\left(c+d\sqrt{2}\right)\left(c-d\sqrt{2}\right)} = \frac{\left(ac-2bd\right)+\left(bc-ad\right)\sqrt{2}}{c^2-2d^2} \]

More often than necessary promoted to rationals.

Parameters:

  • other (Any) –

    The denominator.

Returns:

Raises:

  • ZeroDivisionError –

    If the norm of the denominator is zero.

Source code in radicalfield\quadraticelement2.py
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
def __truediv__(self, other:Any) -> Self|NotImplementedType:
    r"""Return the quotient.

    $$
        \frac{\left(a+b\sqrt{2}\right)}{\left(c+d\sqrt{2}\right)}
        = \frac{\left(a+b\sqrt{2}\right)\left(c-d\sqrt{2}\right)}{\left(c+d\sqrt{2}\right)\left(c-d\sqrt{2}\right)}
        = \frac{\left(ac-2bd\right)+\left(bc-ad\right)\sqrt{2}}{c^2-2d^2}
    $$

    More often than necessary promoted to rationals.

    Parameters
    ----------
    other: QuadraticElement2 or int or Fraction
        The denominator.

    Returns
    -------
    QuadraticElement2
        The quotient.

    Raises
    ------
    ZeroDivisionError
        If the norm of the denominator is zero.
    """
    if isinstance(other, QuadraticElement2):
        return self * other.inv()
    elif isinstance(other, (int, Fraction)):
        other:Fraction = Fraction(other)
        return QuadraticElement2(self.a/other, self.b/other)
    return NotImplemented

__rtruediv__(other)

__rtruediv__(other: int) -> Self
__rtruediv__(other: Fraction) -> Self
Source code in radicalfield\quadraticelement2.py
540
541
542
543
def __rtruediv__(self, other:Any) -> Self|NotImplementedType:
    if isinstance(other, (int, Fraction)):
        return other * self.inv()
    return NotImplemented

__str__()

Source code in radicalfield\quadraticelement2.py
549
550
def __str__(self) -> str:
    return f'{self.a}{self.b:+}√2'