Geben Sie Python ein, um die algebraische Erweiterung zu implementieren (3) ~ Polygonaler Ring, Restring des Polynoms, Erweiterung des Feldes ~

Dies ist das Finale der 3er Serie.

Bis zum letzten Mal habe ich verschiedene Klassen im Bereich von ganzen Zahlen und rationalen Zahlen erstellt.

Dieses Mal erstellen wir zuerst eine Klasse, die Polynome der Ordnung $ n $ behandelt, und dann Polynome mit der Ringklasse der restlichen Klasse, die wir zuletzt erstellt haben. Und schließlich werden wir das Feld der rationalen Zahlen erweitern.

Inhaltsverzeichnis

  1. Monoid / Group / Ring / Integer Ring
  2. Feld, rationales Zahlenfeld, euklidischer Ring, Restring, endlicher Körper
  3. Polygonring, Restring des Polypolys, Feldausdehnung

Implementierung

Polygonring

Um eine algebraische Expansion durchzuführen, müssen Polynome behandelt werden. Daher definieren wir hier eine Klasse, die Polynome mit einem Grad von $ n $ (** polymorpher Ring **) behandelt und die endgültigen Vorbereitungen für die algebraische Expansion trifft.

Das $ n $ -Ordnungspolypoly besteht aus $ n + 1 $ -Koeffizienten und der Variablen $ x $ einschließlich des konstanten Terms.

\sum_{k=0}^n a_k x^k

Daher wird im polymorphen Ring der Koeffizient $ a_k $ in Form einer Liste gehalten.

Es ist ersichtlich, dass Addition, Multiplikation und Subtraktion (zusätzliche inverse Elemente) immer für Polynome berechnet werden können, aber sie sind nicht immer teilbar, wenn sie durch Polynome geteilt werden, was zu einem ** Ring ** führt. Da Sie die Kürzungsteilung und den Rest definieren können, können Sie auch sehen, dass es sich um den ** euklidischen Ring ** handelt, der beim letzten Mal aufgetreten ist.

Die hier definierte Klasse "Polynom" erbt von "EuclidianRing" und gleichzeitig von "Generic [PolynomialBaseType]". Wenn Sie dies erben, wird "Polynom" als generische Klasse behandelt, und wenn Sie es in Form von "Polynom [T]" in den Code schreiben, wird der im Teil von "T" beschriebene Typ "PolynomialBaseType" zugewiesen. Wird aktiviert (ähnlich einer C ++ - Vorlage).

from typing import Generic, List
from itertools import dropwhile, zip_longest

PolynomialBaseType = TypeVar("PolynomialBaseType", bound=Field)

class Polynomial(EuclidianRing, Generic[PolynomialBaseType]):
    def __init__(self: "Polynomial[PolynomialBaseType]", *args: PolynomialBaseType) -> None:
        self.coeffs = list(dropwhile(lambda x: x == x.zero(), args))
        if not self.coeffs:
            self.coeffs = [args[0].zero()]

    @staticmethod
    def _mul_poly(a: List[PolynomialBaseType], b: List[PolynomialBaseType]) -> List[PolynomialBaseType]:
        c = [a[0].zero() for i in range(len(a) + len(b) - 1)]
        for i, aa in enumerate(reversed(a)):
            for j, bb in enumerate(reversed(b)):
                c[i + j] += aa * bb
        return list(reversed(c))

    @staticmethod
    def _div_poly(a: List[PolynomialBaseType], b: List[PolynomialBaseType]) -> Tuple[List[PolynomialBaseType], List[PolynomialBaseType]]:
        q = [a[0].zero() for i in range(max(len(a) - len(b) + 1, 0))]
        r = a[:]
        for i in range(len(q)):
            q[i] = r[i] / b[0]
            for k in range(len(b)):
                r[i + k] -= b[k] * q[i]
        return ([a[0].zero()] + q, r)

    def __repr__(self: "Polynomial") -> str:
        s = " " + " + ".join("%s x ^ %d" % (repr(c), len(self.coeffs) - i - 1) for i, c in enumerate(self.coeffs) if c != c.zero()) + " "
        s = s.replace(" + -", " - ")
        s = s.replace(" x ^ 0 ", " ")
        s = s.replace(" x ^ 1 ", " x ")
        s = s.replace(" 1 x ", " x ")
        return s.strip()

    def __floordiv__(self: "Polynomial[PolynomialBaseType]", x: "Polynomial[PolynomialBaseType]") -> "Polynomial[PolynomialBaseType]":
        q, r = Polynomial._div_poly(self.coeffs, x.coeffs)
        return Polynomial[PolynomialBaseType](*q)

    def __mod__(self: "Polynomial[PolynomialBaseType]", x: "Polynomial[PolynomialBaseType]") -> "Polynomial[PolynomialBaseType]":
        q, r = Polynomial._div_poly(self.coeffs, x.coeffs)
        return Polynomial[PolynomialBaseType](*r)

    def __mul__(self: "Polynomial[PolynomialBaseType]", x: "Polynomial[PolynomialBaseType]") -> "Polynomial[PolynomialBaseType]":
        y = Polynomial._mul_poly(self.coeffs, x.coeffs)
        return Polynomial[PolynomialBaseType](*y)

    def __add__(self: "Polynomial[PolynomialBaseType]", x: "Polynomial[PolynomialBaseType]") -> "Polynomial[PolynomialBaseType]":
        y = list(a + b for a, b in zip_longest(reversed(self.coeffs), reversed(x.coeffs), fillvalue=self.coeffs[0].zero()))
        y.reverse()
        return Polynomial[PolynomialBaseType](*y)

    def __neg__(self: "Polynomial[PolynomialBaseType]") -> "Polynomial[PolynomialBaseType]":
        return Polynomial[PolynomialBaseType](*(-aforainself.coeffs))

    def __eq__(self, x):
        if not isinstance(x, Polynomial):
            return NotImplemented
        return self.coeffs == x.coeffs

    def identity(self: "Polynomial[PolynomialBaseType]") -> "Polynomial[PolynomialBaseType]":
        return Polynomial[PolynomialBaseType](self.coeffs[0].identity())

    def zero(self: "Polynomial[PolynomialBaseType]") -> "Polynomial[PolynomialBaseType]":
        return Polynomial[PolynomialBaseType](self.coeffs[0].zero())

    def euclid_gcd(self: "Polynomial[PolynomialBaseType]", b: "Polynomial[PolynomialBaseType]") -> Tuple["Polynomial[PolynomialBaseType]", "Polynomial[PolynomialBaseType]", "Polynomial[PolynomialBaseType]"]:
        p, q, r = super().euclid_gcd(b)
        r.coeffs = [x / r.coeffs[0] for x in r.coeffs]
        return (p, q, r)

Hier wird die euklidische Methode der gegenseitigen Teilung "euclid_gcd" überschrieben, und die Verarbeitung der Division des maximalen Versprechens durch den Koeffizienten höchster Ordnung wird eingeschlossen. Dies ermöglicht es, monische Polynome zu erhalten, wenn die maximalen Versprechen zwischen Polynomen berechnet werden.

Der Code ist lang, also testen wir ihn einmal.

f = Polynomial[Q](Q(Z(1)),Q(Z(1)))  # x + 1
g = Polynomial[Q](Q(Z(1)),-Q(Z(1))) # x - 1
print(f * g) # -> x ^ 2 - 1

x = Polynomial[Q](Q(Z(2)),Q(Z(1)),Q(Z(-3)),Q(Z(2))) # 2 x ^ 3 + x ^ 2 - 3 x + 2
y = Polynomial[Q](Q(Z(1)),Q(Z(0)),Q(Z(1))) # x ^ 2 + 1
print(x // y) # -> 2 x + 1
print(x % y)  # -> -5 x + 1

Da $ 2 x ^ 3 + x ^ 2-3 x + 2 = (2 x + 1) (x ^ 2 + 1) + (-5 x + 1) $, stimmten der Quotient und der Rest sicher überein.

Stellen Sie außerdem sicher, dass "Generic" funktioniert. Versuchen Sie, die eckigen Klammern [] durch den entsprechenden Körper zu ersetzen.

f = Polynomial[FiniteField_11](Q(Z(1)),Q(Z(1)))

Wenn ich es mit mypy überprüfe, erhalte ich die Fehlermeldung, dass es sich nicht um den erwarteten Typ handelt.

field_extension.py:347: error: Argument 1 to "Polynomial" has incompatible type "Rational"; expected "FiniteField_11"
field_extension.py:347: error: Argument 2 to "Polynomial" has incompatible type "Rational"; expected "FiniteField_11"

Restring der Polypolyse

Der Restring war $ a \ pmod n $, und $ a $ und $ n $ waren euklidische Ringe. Da der polymorphe Ring auch ein euklidischer Ring ist, können Sie einen Ring erstellen, indem Sie sich auf den Rest konzentrieren.

Um einen Polynomrestring für einen bestimmten Divisor zu erstellen, ersetzen Sie einfach die im Restklassenring angegebene "Ganzzahl" durch ein "Polynom [Q]".

class MR_x2_1(ModRing): # (mod x ^ 2 + 1)
    def __init__(self: "MR_x2_1", a: Polynomial[Q]) -> None:                                          
        super().__init__(a, Polynomial[Q](Q(Z(1)),Q(Z(0)),Q(Z(1))))                                
                                    
u = MR_x2_1(Polynomial[Q](Q(Z(2)),Q(Z(1)),Q(Z(-3)),Q(Z(2))))
print(u) # -> -5 x + 1 (mod x ^ 2 + 1)

Multiplikator invers zum Restring des Polypolys

Wenn im Fall eines Restklassenrings von ganzen Zahlen der Divisor eine "Primzahl" ist, die nicht mehr in Primfaktoren zerlegt werden kann, ist er ein endliches Feld.

Selbst im Fall von Polynomen gibt es im Restring des Polynoms immer ein inverses Element, wenn das Divisor-Polynom ein ** irreduzibles Polynom ** ist, das innerhalb eines bestimmten Feldbereichs nicht weiter faktorisiert werden kann.

Zum Beispiel kann im Bereich rationaler Zahlen $ x ^ 2 -1 $ wie $ (x + 1) (x -1) $ berücksichtigt werden, aber $ x ^ 2-1 $ kann nicht berücksichtigt werden. Wenn es jedoch auf den realen Bereich erweitert wird, kann es in $ (x + \ sqrt 2) (x- \ sqrt 2) $ zerlegt werden. Mit anderen Worten, $ x ^ 2 - 2 $ ist ein irreduzibles Polymorph im Bereich rationaler Zahlen, aber kein irreduzibles Polymorph im Bereich reeller Zahlen.

Wenden wir nun "Polynom [Q]" auf das zuvor erstellte "FiniteField" an.

class F_x2_n2(FiniteField): # (mod x ^ 2 - 2)
    def __init__(self: "F_x2_n2", a: Polynomial[Q]) -> None:
        super().__init__(a, Polynomial[Q](Q(Z(1)),Q(Z(0)),Q(Z(-2))))

v = F_x2_n2(Polynomial[Q](Q(Z(1)),Q(Z(1)))) # x + 1 (mod x ^ 2 - 2)
print(v.inverse()) # -> x - 1 (mod x ^ 2 - 2)

Lass uns nachsehen.

$ (x + 1) (x - 1) = x ^ 2 - 1 = (x ^ 2 - 2) + 1 $ ist mit Sicherheit $ x + 1 \ pmod {x ^ 2 - 2} $ $ x - 1 \ pmod {x ^ 2 - 2} $.

Erweiterung der Algebra des Körpers

$ N $ Ordnungspolymorphismus $ f (x) = a_0 + a_1 x + a_2 x ^ 2 + \ cdots + a_n x ^ n $ root $ x $ mit $ K $ als Element eines Feldes $ K $ Betrachten Sie den Fall, in dem es nicht existiert. Unter Berücksichtigung der quadratischen Gleichung des rationalen Koeffizienten $ f (x) = x ^ 2 - 2 = 0 $ existiert die Lösung $ x $ beispielsweise nicht im Bereich der rationalen Zahlen.

In diesem Fall wird die Betrachtung eines neuen $ x $, das diese Gleichung erfüllt, und das Hinzufügen zum Feld $ K $, um ein neues Feld $ L $ zu erstellen, als ** algebraische Erweiterung ** bezeichnet.

Dieses $ L $ kann leicht mit dem Restring des Polypolys ausgedrückt werden.

Darstellung der algebraischen Expansion unter Verwendung des Restrings eines Polypolys

Hier haben wir ein Polynom $ g (x) $ und ein irreduzibles Polypoly $ f (x) $ und betrachten den Rest $ r (x) $, der durch Teilen von $ g (x) $ durch $ f (x) $ erhalten wird. Dann gilt die folgende Gleichung.

g(x) = h(x) f(x) + r(x)

Wenn Sie $ x $ durch $ a $, die Wurzel von $ f (x) $, ersetzen, erhalten Sie $ g (a) = r (a) $ aus $ f (a) = 0 $.

Mit anderen Worten, das Ersetzen der Wurzel des a priori-Polynoms $ f (x) $ durch das Polynom $ g (x) $ ist der Rest von $ g (x) $ geteilt durch $ f (x) $. Es ist nichts anderes als eine Operation zu finden.

f(a) = 0 \land g(a) = r(a) \longleftrightarrow g(x) \bmod f(x) = r(x)

Schauen wir uns ein Beispiel für das Hinzufügen der Wurzel von $ x ^ 2 - 2 $ zum rationalen Zahlenfeld $ Q $ an.

class L(FiniteField): # Q(√2)
    def __init__(self: "L", a: Polynomial[Q]) -> None:
        super().__init__(a, Polynomial[Q](Q(Z(1)),Q(Z(0)),Q(Z(-2)))) # x^2 - 2

a = L(Polynomial[Q](Q(Z(1)),Q(Z(0))))
print(a * a) # -> 2 (mod x ^ 2 - 2)

Zuerst haben wir das Feld $ L $ erstellt, indem wir die Wurzeln von $ x ^ 2 - 2 $ zum Feld $ Q $ mit rationalen Zahlen hinzugefügt und der Variablen a $ x $ auf $ L $ zugewiesen haben. Wenn Sie dieses $ x $ quadrieren, können Sie sehen, dass es "2" ist.

Mit anderen Worten, a ist $ \ pm \ sqrt 2 $. Daher wird dieser Körper $ L $ auch als $ Q (\ sqrt 2) $ geschrieben.

Fügen wir die Wurzel von $ x ^ 2-3 $ hinzu, um den Körper $ M $ zu machen (dh $ Q (\ sqrt 2, \ sqrt 3) $). Hierbei ist zu beachten, dass die Koeffizienten des Polypolys aus $ L $ extrahiert werden müssen.

L_1 = L(Polynomial[Q](Q(Z(1))))#1inQ(√2)
L_3 = L(Polynomial[Q](Q(Z(3))))#3inQ(√2)
L_0 = L(Polynomial[Q](Q(Z(0))))#0inQ(√2)

class M(FiniteField): # Q(√2, √3)
    def __init__(self, a: Polynomial[L]) -> None:
        super().__init__(a, Polynomial[L](L_1,L_0,-L_3))
        #Unten ist ein Fehler
        #super().__init__(a, Polynomial[L](Q(Z(1)),Q(Z(0)),-Q(Z(3))))

b = M(Polynomial[L](a))
print(b * b) # -> 2 (mod x ^ 2 - 2) (mod 1 (mod x ^ 2 - 2) x ^ 2 - 3 (mod x ^ 2 - 2))

c = M(Polynomial[L](L_1,L_0))
print(c * c) # -> 3 (mod x ^ 2 - 2) (mod 1 (mod x ^ 2 - 2) x ^ 2 - 3 (mod x ^ 2 - 2))

Die Ausgabe ist chaotisch, aber ich konnte die Entsprechungen von $ \ pm \ sqrt {2} $ und $ \ pm \ sqrt {3} $ in derselben Klasse erstellen.

Natürlich können Sie auch $ \ pm \ sqrt {6} $ erstellen.

d = b * c
print(d * d) # -> 6 (mod x ^ 2 - 2) (mod 1 (mod x ^ 2 - 2) x ^ 2 - 3 (mod x ^ 2 - 2))

Hierbei ist zu beachten, dass die in der algebraischen Erweiterung hinzugefügten Zahlen eine andere Dimension aufweisen als die ursprünglichen Körperelemente.

Daher können beispielsweise $ \ pm \ sqrt {2} $, $ \ pm \ sqrt {3} $ und $ \ pm \ sqrt {6} $ jeweils nach Quadrat verglichen werden, aber $ \ Es ist nicht möglich herauszufinden, welche größer sind, pm \ sqrt {2} $ oder $ \ pm \ sqrt {3} $, wie sie sind.

Zusammenfassung

Bevor ich den Typ-Hinweis gab, als ich $ \ sqrt {3} $ zu $ Q (\ sqrt {2}) $ hinzufügte, bekam ich den folgenden Fehler und war besorgt, weil ich die Ursache nicht verstehen konnte, selbst wenn ich sie las.

Traceback (most recent call last):
  File "./field_extension.py", line 370, in <module>
    print(c * c) # -> 3 (mod x ^ 2 - 2) (mod 1 (mod x ^ 2 - 2) x ^ 2 - 3 (mod x ^ 2 - 2))
  File "./field_extension.py", line 214, in __mul__
    return self.__class__(self.a * x.a)
  File "./field_extension.py", line 364, in __init__
    super().__init__(a, Polynomial(Q(Z(1)),Q(Z(0)),-Q(Z(3))))
  File "./field_extension.py", line 207, in __init__
    self.a = a % n
  File "./field_extension.py", line 283, in __mod__
    q, r = Polynomial._div_poly(self.coeffs, x.coeffs)
  File "./field_extension.py", line 265, in _div_poly
    q[i] = r[i] / b[0]
  File "./field_extension.py", line 37, in __truediv__
    return self * x.inverse()
  File "./field_extension.py", line 214, in __mul__
    return self.__class__(self.a * x.a)
AttributeError: 'Rational' object has no attribute 'a'

Als ich ihm jedoch einen Tipp gab und ihn mit mypy überprüfte, erhielt ich eine sehr leicht verständliche Nachricht wie die folgende.

field_extension.py:364: error: Argument 1 to "Polynomial" has incompatible type "Rational"; expected "L"
field_extension.py:364: error: Argument 2 to "Polynomial" has incompatible type "Rational"; expected "L"
field_extension.py:364: error: Argument 3 to "Polynomial" has incompatible type "Rational"; expected "L"

Apropos, es ist ein natürlicher Fehler, aber als ich Ihnen den Fehler zum ersten Mal erzählte, dachte ich: "Oh, ich verstehe."

Mypy ist ein Tool, das auf Missverständnisse und Fehler hinweist, die sich aus der Komplexität von Programmen ergeben.

Recommended Posts

Geben Sie Python ein, um die algebraische Erweiterung zu implementieren (3) ~ Polygonaler Ring, Restring des Polynoms, Erweiterung des Feldes ~
Geben Sie Python ein, um die algebraische Erweiterung zu implementieren (2) ~ Feld, rationales Zahlenfeld, euklidischer Ring, Ring der Restklasse, endlicher Körper ~
Geben Sie Python ein, um die algebraische Erweiterung zu implementieren (1) ~ Monoide, Gruppen, Ringe, ganzzahlige Ringe ~
Implementieren Sie die Erweiterung in Python
Ich habe versucht, PLSA in Python zu implementieren
Ich habe versucht, Permutation in Python zu implementieren
Ich habe versucht, PLSA in Python 2 zu implementieren
Ich habe versucht, ADALINE in Python zu implementieren
Ich habe versucht, PPO in Python zu implementieren
Versuchen Sie, Oni Mai Tsuji Miserable mit Python zu implementieren
So vereinfachen Sie die eingeschränkte Polypoly-Anpassung in Python
So implementieren Sie Shared Memory in Python (mmap.mmap)
Ich habe versucht, TOPIC MODEL in Python zu implementieren
Ich habe versucht, eine selektive Sortierung in Python zu implementieren
Wie man mit dem Datum / Uhrzeit-Typ in Pythons SQLite3 umgeht
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
Implementieren Sie XENO mit Python
Ich habe versucht, Drakues Poker in Python zu implementieren
Implementieren Sie die Lösung der Riccati-Algebra in Python
Ich habe versucht, GA (genetischer Algorithmus) in Python zu implementieren
Implementieren Sie sum in Python
Konvertieren Sie den Webpay-Entitätstyp in den Dict-Typ (rekursiv in Python).
Implementieren Sie Traceroute in Python 3
So implementieren Sie Python EXE für Windows mit Docker-Container
Ich habe versucht, die Mail-Sendefunktion in Python zu implementieren
Eine Geschichte über den Versuch, private Variablen in Python zu implementieren.
Ich habe versucht, das Blackjack of Trump-Spiel mit Python zu implementieren
So löschen Sie stdout in Python
Melden Sie sich auf der Website in Python an
Implementieren Sie Naive Bayes in Python 3.3
Implementieren Sie alte Chiffren in Python
Implementieren Sie Redis Mutex in Python
Sprechen mit Python [Text zu Sprache]
Implementieren Sie schnelles RPC in Python
Implementieren Sie den Dijkstra-Algorithmus in Python
Implementieren Sie den Slack Chat Bot in Python
Wie man in Python entwickelt
Post an Slack in Python
Zeitzonenspezifikation beim Konvertieren einer Zeichenfolge in einen Datums- / Uhrzeittyp mit Python
Ich habe eine Funktion zum Laden des Git-Erweiterungsskripts in Python geschrieben
Implementieren Sie einen deterministischen endlichen Automaten in Python, um Vielfache von 3 zu bestimmen
Ich habe versucht, ein missverstandenes Gefangenendilemma in Python zu implementieren
Was tun, wenn der Werttyp in Python nicht eindeutig ist?
Implementieren Sie das Stacking-Lernen in Python [Kaggle]
[Python] Wie man PCA mit Python macht
Implementieren Sie die Funktion power.prop.test von R in Python
Definition des Funktionsargumenttyps in Python
Trainieren! !! Einführung in Python Type (Type Hints)
So sammeln Sie Bilder in Python
Verwendung von SQLite in Python
Laden Sie JSON-Typen dynamisch mit Python
Im Python-Befehl zeigt Python auf Python3.8
Implementieren Sie das Singleton-Muster in Python
Versuchen Sie, Trace in Python zu berechnen
Typ in Python angegeben. Ausnahmen auslösen