© Liashko/Shutterstock.com
Mathematische Aufgaben mit Python berechnen

P-Rechnung


Auf den ersten Blick wirkt Python nicht wie eine Programmiersprache, die für rechenintensive mathematische Aufgaben geeignet ist. Doch der Schein trügt: Zeit, einen Blick auf die vielfältigen Möglichkeiten zu werfen.

Wie so oft im Python-Ökosystem gilt auch hier, dass Bibliotheken des Rätsels Lösung sind. Dank des effizienten nativen Interface kann Python-Code in C oder C++ gehaltene Routinen aufrufen, die (logischerweise) extrem schnell arbeiten. Im Zusammenspiel mit der sehr leistungsstarken Sprache entsteht so ein beinahe optimales Werkzeug zur Bearbeitung mathematischer Probleme.

Versions-Check

Wir beginnen mit einem Versionsabgleich – die folgenden Schritte erfolgen unter einer aktuellen Version von Python 3. Wichtig zu wissen ist, dass NumPy mittlerweile als Mindestversion 3.5 voraussetzt:

t@T18:~$ python3 -V Python 3.6.9

Im nächsten Schritt legen wir ein virtuelles Environment an und laden die NumPy-Bibliothek herunter. NumPy steht für Numerical Python und ist eine Bibliothek, die unseren Programmen diverse Datenstrukturen und Methoden zu ihrer Verarbeitung zur Verfügung stellt:

t@T18:~/pyspace$ python3 -m venv susnumera t@T18:~/pyspace/susnumera/bin$ source activate (susnumera) t@T18:~/pyspace/susnumera/bin$ (susnumera) t@T18:~/pyspace/susnumera/bin$ pip install numpy

Wichtig ist, dass NumPy nicht nur als Stand-Alone-Bibliothek agiert. So gut wie alle fortgeschrittenen Mathematikfunktionen verwenden die in NumPy enthaltenen Datentypen. Von besonderer Wichtigkeit ist der Array-Datentyp, der zur Unterscheidung vom normalen Python-Array auch als ndarray bezeichnet wird. Damit können wir einen ersten Gehversuch wagen, der sich folgendermaßen präsentiert:

import numpy as np np.random.seed(0) x1 = np.random.randint(10, size=6) print (x1)

Dieses kurze Codestück demonstriert einige idiomatische Elemente aus der Welt der NumPy-Programmierung. Erstens wird die Bibliothek im Rahmen des Imports so gut wie immer in NP umbenannt – wenn Sie in Beispielcode oder online verfügbaren Tutorials NP finden, können Sie so gut wie immer von der Verwendung von NumPy ausgehen. Zweitens initialisieren wir den Zufallsgenerator mit einem als Seed (Samen) bezeichneten Wert. So ist – unter Voraussetzung eines konstanten RNG-Algorithmus – sichergestellt, dass auch mehrere hintereinander folgende Programmläufe dieselbe Abfolge numerischer Werte vorgesetzt bekommen.

Was bei der Arbeit mit einem echten Kryptosystem zu massiven Problemen führen würde, hilft beim Debugging durch die Herstellung eines wiederholbaren Programmzustands. Danach verwenden wir den in np enthaltenen Zufallsgenerator, um ein neues eindimensionales Array zu erzeugen. Dieses wandert danach durch Aufruf von Print in die Kommandozeile, was zum in Abbildung 1 gezeigten Verhalten führt.

hanna_rechnen_1.tif_fmt1.jpgAbb. 1: Array am Platz

Die Verwendung von konstant typisierten NumPy-Arrays ist für Entwickler*innen unter anderem deshalb von Vorteil, weil sie mit wesentlich geringerem Speicherbedarf und höherer Performance einhergeht. In Python-Tutorials findet man Beispiele, die für die Erzeugung und/oder Verarbeitung eine Beschleunigung um den Faktor zehn versprechen. Die praktische Erfahrung des Autors ist hier anders – entfällt der Hauptteil des Aufwands auf einen komplexen Berechnungsalgorithmus, ist der Einfluss der Datenstruktur vergleichsweise gering.

Diese nicht unerhebliche Effizienzsteigerung erreicht NumPy dadurch, dass NumPy-Array im Prinzip ein C-Array darstellt – eine Python-Liste ist ja ein Verweis von Pointern auf Python-Objekte, was zu wesentlich geringerer Effizienz führt. Nachteil dieser Vorgehensweise ist allerdings reduzierte Flexibilität. Der Datentyp eines NumPy-Arrays lässt sich folgendermaßen herausfinden: print("dtype:", x1.dtype). Im Fall unseres von np.random.randint erzeugten Beispielarrays bekommen wir hier als Antwort den Wert dtype: int64 zurück. Es ist allerdings auch möglich, andere NumPy-Datentypen zu verwenden. Unter [1] findet sich eine Liste der verschiedenen Typen – da NumPy sowohl auf 32- als auch auf 64-Bittern heimisch ist, ist die Sache zumindest auf den ersten Blick etwas haarig. NumPy ist dabei nicht auf eindimensionale Arrays beschränkt. Eine sehr lustige Sonderfunktion der Bibliothek betrifft die Möglichkeit, Die Gestalt eines Arrays auch zur Laufzeit anzupassen:

x1 = np.random.randint(10, size=6*5) x1.shape=(6,5) print (x1) print("dtype:", x1.dtype)

Der Zufallsgenerator erzeugt im ersten Schritt ein nach wie vor eindimensionales Array, das nun aber statt sechs gleich 30 Elemente eingeschrieben bekommt. Im nächsten Schritt modifizieren wir den Wert von shape – diese Eigenschaft nimmt auf Wunsch ein weiteres Datenfeld entgegen, das die Gestalt beschreibt. Wir befehlen hier die Erzeugung eines zweidimensionalen Arrays, was bei der Programmausführung zum in Abbildung 2 gezeigten Ergebnis führt.

hanna_rechnen_2.tif_fmt1.jpgAbb. 2: Das Array ist nun zweidimensional

Die Cramer’sche Regel

Lineare Gleichungssysteme mögen in der Komplexitätshierarchie der Mathematik nicht besonders hoch stehen. In der Praxis haben Sie es aber immer wieder mit Systemen zu tun, in denen das zu steuernde Gesetz in Form eines Gleichungssystems vorliegt. Das Determinantenverfahren erspart in diesem Fall manuelles Umformen der Gleichungen. Dahinter steht die Idee, dass man das Gleichungssystem als eine Gruppe von Matrizen bzw. Arrays ansieht, und diese danach mit Ergebniswerten dotiert. Lohn der Mühen ist die Möglichkeit, die jeweiligen Ergebnisse durch eine einfache Division zweier Determinanten zu ermitteln.

Außer Frage steht, dass die Determinantenberechnung eines Arrays mit seiner Größe immer aufwendiger wird – ist das Feld allerdings relativ klein, schafft sogar ein antiker Palm IIIc die Berechnung in kurzer Zeit. Für uns ist das in Abbildung 3 beschriebene Determinantenverfahren unter anderem deshalb interessant, weil es einige Aspekte des NumPy-Arrayhandlings demonstriert.

hanna_rechnen_3.tif_fmt1.jpgAbb. 3: Spart in der Praxis Zeit: der Cramer-Prozess [2]

Als Erstes müssen wir Arrays aus Konstanten erzeugen. Sie haben die Aufgabe, die Gleichungsdaten zu laden. Der Autor verwendet in den folgenden Schritten ein Beispielgleichungssystem aus Wikipedia:

factors_raw = ...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang