Geben Sie Python ein, um die algebraische Erweiterung zu implementieren (2) ~ Feld, rationales Zahlenfeld, euklidischer Ring, Ring der Restklasse, endlicher Körper ~

Beim letzten Mal habe ich einen ganzzahligen Ring implementiert, nachdem ich eine abstrakte Basisklasse für Monoide, Gruppen und Ringe erstellt hatte. Dieses Mal implementieren wir nach dem Erstellen der abstrakten Basisklasse des Feldes das rationale Zahlenfeld, den Restklassenring und den endlichen Körper.

Inhaltsverzeichnis

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

Implementierung

Körper

Der Körper ist ein Set, das die folgenden Bedingungen erfüllt

  1. Ein Ring um den Multiplikator $ \ star $ und das Additiv $ \ oplus $
  2. Andere Mengen als das additive Einheitselement $ 0 $ bilden eine Gruppe für den Multiplikator $ \ star $

Wenn Sie dies durch ein bekanntes Wort ersetzen,

  1. Es gibt $ 1 $ und $ 0 $, und Sie können drei Operationen ausführen: Addition, Subtraktion und Multiplikation.
  2. Andere Elemente als $ 0 $ haben eine umgekehrte Multiplikation, dh sie können durch andere als $ 0 $ geteilt werden

Mit anderen Worten, es ist eine Menge, die vier Betriebsregeln ausführen kann (Addition, Subtraktion, Multiplikation und Division).

Erben Sie beim Implementieren einer Klasse die bisher erstellten Gruppen und Ringe und geben Sie "True" zurück, wenn es nur bei der Durchführung des inversen Tests $ 0 $ ist.

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

class Field(Group, Ring):
    def testInverse(self: FieldType) -> bool:
        if self * self.identity() == super().zero():
            return True
        else:
            return super().testInverse()

Rationale Zahl

Lassen Sie uns nun ein rationales Zahlenfeld erstellen. Eine rationale Zahl ist eine Zahl, die in der Form $ \ frac {p} {q} $ mit den beiden ganzen Zahlen $ p $ und $ q $ dargestellt werden kann. Behalten Sie daher diese $ p $ und $ q $ in der Instanz der rationalen Zahlenklasse bei.

Wenn Sie nach gleichen Brüchen suchen, verursacht der einfache Vergleich von $ p $ mit $ q $ Probleme. Dies liegt daran, dass der Nenner je nach Instanz unterschiedlich sein kann, auch wenn die Brüche gleich sind. Es gibt zwei Möglichkeiten, damit umzugehen.

Sie können es reduzieren, indem Sie die später implementierte euklidische Methode der gegenseitigen Teilung verwenden. Hier verwenden wir jedoch die einfache Methode zur Bewertung von $ ps = qr $. Grundsätzlich handelt es sich um die Berechnung von Brüchen, wie sie in der Grund- und Mittelschule gelernt wurden, sodass keine besondere Erklärung erforderlich ist.

class Rational(Field):
    def __init__(self: "Rational", p: Integer, q: Integer = Integer(1)) -> None:
        self.p = p
        self.q = q

    def __repr__(self: "Rational") -> str:
        if self.q == self.q.identity():
            return "%s" % self.p
        return "%s/%s" % (self.p, self.q)

    def __mul__(self: "Rational", x: "Rational") -> "Rational":
        return Rational(self.p * x.p, self.q * x.q)

    def __add__(self: "Rational", x: "Rational") -> "Rational":
        return Rational(self.p * x.q + x.p * self.q, self.q * x.q)

    def __eq__(self, x):
        if not isinstance(x, Rational):
            return NotImplemented
        return self.p * x.q == x.p * self.q

    def __neg__(self: "Rational") -> "Rational":
        return Rational(-self.p, self.q)

    def identity(self: "Rational") -> "Rational":
        return Rational(self.p.identity(), self.p.identity())

    def inverse(self: "Rational") -> "Rational":
        return Rational(self.q, self.p)

    def zero(self: "Rational") -> "Rational":
        return Rational(self.p.zero(), self.p.identity())

Q = Rational

Der Alias für "Rational" ist "Q".

Lassen Sie uns nun die Funktionsweise rationaler Zahlen überprüfen.

a = Q(Z( 8), Z(3))
b = Q(Z(-5), Z(4))
c = Q(Z( 3), Z(7))
y = a * b + c
print(y)
# -> -244/84

print(y.inverse())
# -> 84/-244

Es funktionierte.

Im Moment ist die Reduktion nicht implementiert, kann jedoch zum Zeitpunkt der Anzeige unter Verwendung der später beschriebenen euklidischen Methode der gegenseitigen Teilung reduziert werden.

Tatsächliche rationale Zahlen (Brüche) in Python

Python hat eine Klasse "Fraktionen.Fraktion" zum Ausdrücken von Brüchen. Wenn Sie nur mit Brüchen arbeiten möchten, reicht diese Klasse aus.

from fractions import Fraction

a = 0
for i in range(10):
    a += 1/10
print(a == 1)
# -> False

a = 0
for i in range(10):
    a += Fraction(1, 10)
print(a == 1)
# -> True

Ein Beispiel für Software, die "Fraction" verwendet, ist die Python-Schnittstelle [PyAV] der Videokonvertierungssoftware FFMPEG (https://github.com/mikeboers/PyAV). Wir verwenden Brüche, um die Bildrate zu berechnen.

Euklidischer Ring

Von nun an wird es mehr Möglichkeiten für die Kürzung und den Rest geben. Daher wäre es zweckmäßig, eine abstrakte Basisklasse für den euklidischen Ring als "Ring zu erstellen, der abgeschnitten und geteilt werden kann und der Rest kann erhalten werden".

EuclidianRingType = TypeVar("EuclidianRingType", bound="EuclidianRing")

class EuclidianRing(Ring, metaclass=ABCMeta):
    @abstractmethod
    def __floordiv__(self: EuclidianRingType, x: EuclidianRingType) -> EuclidianRingType:
        pass

    @abstractmethod
    def __mod__(self: EuclidianRingType, x: EuclidianRingType) -> EuclidianRingType:
        pass

Ersetzen Sie dann die übergeordnete Klasse von "Integer" von "Ring" durch "EuclidianRing", um die Kürzungsteilung und den Rest zu definieren.

class Integer(EuclidianRing):

    # ~~ snip ~~

    def __floordiv__(self: "Integer", x: "Integer") -> "Integer":
        return Integer(self.v // x.v)

    def __mod__(self: "Integer", x: "Integer") -> "Integer":
        return Integer(self.v % x.v)

Überschüssiger Ring

Für die ganzen Zahlen $ a $, $ b $ und die natürliche Zahl $ n $ gilt, wenn $ a - b = n \ mathbb {Z} $ ($ \ mathbb {Z} $ ist eine beliebige ganze Zahl) "$ a $ und $ b $ stimmt mit $ n $ als Gesetz überein ", sagt $ a \ equiv b \ pmod n $. Eine Menge, die zwei solcher Zahlen als gleich behandelt, wird als "Überschussring modulo $ n $" bezeichnet.

Lassen Sie uns nun die Restklasse Ringklasse ModRing implementieren.

Eine Instanz der restlichen Ringklasse enthält $ a $ und das Gesetz $ n $. Stellen Sie sicher, dass $ a $ und $ n $ beliebige euklidische Ringe akzeptieren, nicht nur ganze Zahlen. Da $ a $ bei der Anzeige auf dem Bildschirm die kleinste kongruente Zahl von 0 oder mehr sein soll, berechnen wir beim Erstellen der Instanz $ a \ bmod n $.

Als nächstes müssen Sie es unmöglich machen, Zahlen mit verschiedenen Methoden zu berechnen. Aus diesem Grund sollte "ModRing" die Basisklasse für alle Restklassenringe sein, und für jede Methode sollten Unterklassen erstellt werden. Dadurch kann die Typprüfung fehlschlagen, wenn Sie versuchen, Zahlen mit verschiedenen Methoden zu berechnen. Setzen Sie außerdem "init" auf "@ abstractmethod", damit "ModRing" selbst nicht instanziiert werden kann.

ModRingType = TypeVar("ModRingType", bound="ModRing")
ModRingBaseType = TypeVar("ModRingBaseType", bound="EuclidianRing")

class ModRing(Ring, metaclass=ABCMeta):
    @abstractmethod
    def __init__(self: ModRingType, a: ModRingBaseType, n: ModRingBaseType) -> None:
        self.a = a % n
        self.n = n

    def __repr__(self: ModRingType) -> str:
        return "%s (mod %s)" % (str(self.a), str(self.n))

    def __mul__(self: ModRingType, x: ModRingType) -> ModRingType:
        return self.__class__(self.a * x.a)

    def __add__(self: ModRingType, x: ModRingType) -> ModRingType:
        return self.__class__(self.a + x.a)

    def __neg__(self: ModRingType) -> ModRingType:
        return self.__class__(-self.a)

    def __eq__(self, x):
        if not isinstance(x, self.__class__):
            return NotImplemented
        return self.a == x.a

    def identity(self: ModRingType) -> ModRingType:
        return self.__class__(self.a.identity())

    def zero(self: ModRingType) -> ModRingType:
        return self.__class__(self.a.zero())

Durch Festlegen von "self .__ class__" in jeder Methode können Sie auf eine Instanz einer untergeordneten Klasse mit einem Divisor verweisen, nicht auf die Restklasse.

Gehen Sie wie folgt vor, um eine Restringklasse mit einem Divisor von 5 zu erstellen:

class ModRing_5(ModRing):
    def __init__(self, a: Integer) -> None:
        super().__init__(a, Integer(5))

Lassen Sie uns nun die Funktion des Restrings überprüfen.

Erstens ist die Berechnung von Zahlen mit verschiedenen Methoden.

mr_3_5 = ModRing_5(Z(3))
mr_2_4 = ModRing_4(Z(2))
print(mr_3_5 + mr_2_4)
$ mypy ./field_extension.py
field_extension.py:238: error: Unsupported operand types for + ("ModRing_5" and "ModRing_4")

Ich habe einen Fehler in mypy. Wenn die Methode dieselbe ist, tritt kein Fehler auf und die Berechnung kann problemlos durchgeführt werden.

mr_3_5 = ModRing_5(Z(3))
mr_4_5 = ModRing_5(Z(4))
print(mr_3_5 + mr_4_5) # -> 2 (mod 5)

Bedingung, dass der Überschussring ein Körper ist

Von den Ringen haben andere Elemente als $ 0 $ ein inverses Multiplikatorelement, dh dasjenige, das die folgenden Bedingungen erfüllt, wird als Körper bezeichnet.

$ x \ star x ^ {-1} = x ^ {-1} \ star x = e $ existiert $ x ^ {-1} $

Bei Anwendung auf den Restklassenring ist das Finden der Ganzzahl $ p $, die die folgende Gleichung für $ a \ pmod n $ erfüllt, das inverse Element.

a p \equiv 1 \pmod n

Aus der obigen kongruenten Definition unter Verwendung der Ganzzahl $ q $

a p - n q = 1

Die Summe (Differenz) eines Vielfachen von $ a $ und eines Vielfachen von $ n $ ist ein Vielfaches der maximalen Verpflichtung $ GCD (a, n) $ von $ a $ und $ n $. Dies nennt man Bezoos Gleichung. Das heißt, $ GCD (a, n) = 1 $ (elementar zueinander).

Alle $ a $ kleiner als $ n $ und $ n $, die zueinander Primzahlen sind, sind Primzahlen. Wenn also $ n $ eine Primzahl ist, ist der Restklassenring das Feld. Dies wird als endlicher Körper bezeichnet, da es sich um einen Körper handelt, der aus einer endlichen Anzahl von Elementen besteht.

Euklidische Methode der gegenseitigen Teilung

Sie können die euklidische Methode der gegenseitigen Teilung verwenden, um eine Menge von ganzen Zahlen $ p $, $ q $ und $ r $ zu finden, die die Bezu-Gleichung $ a p + b q = r = GCD (a, b) $ erfüllen.

Die euklidische Methode der gegenseitigen Teilung kann innerhalb des euklidischen Rings durchgeführt werden. Aus diesem Grund ist die euklidische Methode der gegenseitigen Teilung in der euklidischen Ringklasse implementiert.

Verwenden Sie im Typhinweis, wenn das Argument oder der Rückgabewert der Funktion ein Taple enthält, typing.Tuple und geben Sie den Typ jedes Elements in eckigen Klammern an.

from typing import Tuple

EuclidianRingType = TypeVar("EuclidianRingType", bound="EuclidianRing")

class EuclidianRing(Ring, metaclass=ABCMeta):
    
    # ~~ snip ~~

    def euclid_gcd(self: EuclidianRingType, b: EuclidianRingType) -> Tuple[EuclidianRingType, EuclidianRingType, EuclidianRingType]:
        a = self
        p = a.zero()
        q = a.identity()
        p_1 = a.identity()
        q_1 = a.zero()
        while True:
            c = a % b
            if c == c.zero():
                break
            p_2 = p_1
            q_2 = q_1
            p_1 = p
            q_1 = q
            p = p_2 - p_1 * (a // b)
            q = q_2 - q_1 * (a // b)
            a = b
            b = c
        return (p, q, b)

Nachdem wir die euklidische Methode der gegenseitigen Teilung implementiert haben, reduzieren wir sie mit der rationalen Zahl "init".

class Rational(Field):
    def __init__(self: "Rational", p: Integer, q: Integer = Integer(1)) -> None:
        _, _, r =  p.euclid_gcd(q)
        self.p = p // r
        self.q = q // r

Begrenzter Körper

Lassen Sie uns nun eine endliche Körperklasse erstellen. Die Finite-Body-Klasse erbt von "ModRing" und definiert die "inverse" Methode. Das endliche $ n $ muss eine Primzahl sein, aber da es schwierig ist, genau zu bestimmen, dass es sich um eine Primzahl handelt, überprüfen wir sie beim Erstellen einer Instanz nicht und überprüfen uns nicht gegenseitig in "invers". Ich werde prüfen, ob es ist.

FiniteFieldType = TypeVar("FiniteFieldType", bound="FiniteField")

class FiniteField(Field, ModRing, metaclass=ABCMeta):
    def inverse(self: FiniteFieldType) -> FiniteFieldType:
        p, q, r = self.a.euclid_gcd(self.n)
        if r == r.identity():
            return self.__class__(p)
        raise Exception("a and n are not co-prime")

Lass es uns testen.

class FiniteField_11(FiniteField):
    def __init__(self, a: Integer) -> None:
        super().__init__(a, Integer(11))

ff_5_11 = FiniteField_11(Z(5))
print(ff_5_11.inverse())
# -> 9 (mod 11)

Da $ 5 \ times 9 = 45 \ equiv 1 \ pmod {11} $ ist, ist die Umkehrung der Multiplikation von $ 5 \ pmod {11} $ sicherlich $ 9 \ pmod {11} $.

Vorschau beim nächsten Mal

Das nächste Mal werden wir einen polymorphen Ring definieren und die Klassen "ModRing" und "FiniteField", die diesmal nur auf ganzen Zahlen basierten, auf Polynome anwenden. Und schließlich werden wir das Feld der rationalen Zahlen erweitern.

Recommended Posts

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 (3) ~ Polygonaler Ring, Restring des Polynoms, Erweiterung des Feldes ~
Geben Sie Python ein, um die algebraische Erweiterung zu implementieren (1) ~ Monoide, Gruppen, Ringe, ganzzahlige Ringe ~
Implementieren Sie die Erweiterung in Python
Implementieren Sie einen deterministischen endlichen Automaten in Python, um Vielfache von 3 zu bestimmen
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 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 möchte Timeout einfach in Python implementieren
So ermitteln Sie die Anzahl der Stellen in Python
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
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
Konvertieren Sie den Webpay-Entitätstyp in den Dict-Typ (rekursiv in Python).