SHA-256 in 256 Zeilen

Programmiersprachen muss man üben, um sie zu lernen und um sie nicht wieder zu vergessen. Ich habe also meine Zeit damit vertrieben einen SHA-256 zu schreiben — eine kryptographische Hash Funktion. Die Spezifikation ist glücklicherweise sehr sehr verständlich. Und auch wenn es tausende andere Implementationen gibt, die schneller sind, alle Grenzfälle beachten (ich befürchte, dass mein Programm Probleme auf Big Endian Systemen bekommt), und sogar Schaltkreise, die hochoptimiert nur diese Operation beherrschen (Stichwort: Bitcoin ASIC), ist meiner dennoch sehenswert, da er SHA-256 in 256 Zeilen darstellt.

Der Code ist als Gist auf GitHub, da er in seinen 256 Zeilen ansonsten den Lesefluss stören würde.

In Python ist es übrigens etwas kürzer.

print(hashlib.sha256(b"Hallo Welt!").hexdigest())

DGLshow

Nachdem ich so vielen Differenzialgleichungssystemen [1, 2, 3, 4] begegnet bin, die sich nicht analytisch lösen lassen, habe ich mir ein Programm zur numerischen Lösung und Visualisierung derselben geschrieben.

Die grundlegende Idee zur numerischen Lösung von Differentialgleichungen ist es, die Zeit in diskreten Schritten \(\tau\) vergehen zu lassen. Nach jedem Schritt wird der Zustand so geändert, als ob sich während des Zeitschrittes nichts geändert hätte und die „Kräfte“ werden entsprechend der Bewegungsgleichungen neu berechnet. Für infinitesimal kleine \(\tau \to \mathrm{d}t\) ist diese Methode schließlich exakt.

Im einfachsten Fall, dem Euler Verfahren, sähe das für ein einfaches Fadenpendel nach \(k\) Zeitschritten so aus

\begin{align*} \ddot\vartheta_{k+1} &= - mgl \sin(\vartheta_k)\\ \dot\vartheta_{k+1} &= \tau \ddot\vartheta_{k} + \dot\vartheta_{k}\\ \vartheta_{k+1} &= \tau \dot\vartheta_{k} + \vartheta_{k} \end{align*}

Unglücklicherweise hat dieses Verfahren ernsthafte Probleme mit der Energieerhaltung und braucht sehr kleine \(\tau\) für brauchbare Ergebnisse. Es gibt deutlich ausgefeiltere Methoden, wie den klassischen Runge-Kutta Algorithmus. Es gibt Methoden, den Zeitschritt \(\tau\) während der Simulation adaptiv anzupassen, um nur wenig Rechenaufwand in den wenig fehleranfälligen Phasen zu verbringen. Es gibt spezialisierte Methoden, die sehr gut für bestimmte Bewegungsgleichungen funktionieren, wie Velocity-Verlet, der oft für Molekulardynamiksimulationen eingesetzt wird.

Chaotische Systeme haben in der Regel etwas kompliziertere Bewegungsgleichungen. Das oben abgebildete Doppelpendel etwa wird, wie ich in einem anderen Post beschrieben habe durch folgendes Ungetüm beschrieben.

\begin{align*} \ddot\theta_1 &= \frac{m_2 \cos(\theta_1 - \theta_2) (l_1 \sin(\theta_1 - \theta_2) \dot\theta_1^2 - g \sin(\theta_2)) + m_2 l_2 \sin(\theta_1 - \theta_2) \dot\theta_2^2 + (m_1 + m_2) g \sin(\theta_1)}{m_2 l_1 \cos^2(\theta_1 - \theta_2) - (m_1+m_2) l_1} \\ \ddot\theta_2 &= \frac{m_2 l_2 \cos(\theta_1 - \theta_2) \sin(\theta_1 - \theta_2) \dot\theta_2^2 + (m_1+m_2) l_1 \sin(\theta_1 - \theta_2) \dot\theta_1^2 + (m_1+m_2) g \cos(\theta_1 - \theta_2) \sin(\theta_1) - (m_1+m_2) g \sin(\theta_2)}{(m_1+m_2) l_2 - m_2 l_2 \cos^2(\theta_1 - \theta_2)} \end{align*}

Anfangs empfiehlt es sich also etwas einfacheres und vertrauteres zu lösen, wie den Lorenz-Attraktor

\begin{align*} \dot{X} &= a(Y - X) \\ \dot{Y} &= X(b - Z) - Y \\ \dot{Z} &= XY - cZ \\ \end{align*}

Oder das Dreikörperproblem

\begin{align*} \ddot{\vec{x}_1} &= -\frac{Gm_2}{\left(x_1 - x_2\right)^3} (\vec{x}_1 - \vec{x}_2) - \frac{Gm_3}{\left(x_1 - x_3\right)^3} (\vec{x}_1 - \vec{x}_3)\\ \ddot{\vec{x}_2} &= -\frac{Gm_1}{\left(x_2 - x_1\right)^3} (\vec{x}_2 - \vec{x}_1) - \frac{Gm_3}{\left(x_2 - x_3\right)^3} (\vec{x}_2 - \vec{x}_3)\\ \ddot{\vec{x}_3} &= -\frac{Gm_1}{\left(x_3 - x_1\right)^3} (\vec{x}_3 - \vec{x}_1) - \frac{Gm_2}{\left(x_3 - x_2\right)^3} (\vec{x}_3 - \vec{x}_2)\\ \end{align*}

Da man das 3-Körperproblem trivial auf ein \(N\)-Körperproblem erweitern kann, habe ich hier ein „Sonnensystem“ bzw. Bohrsches „Atom“-modell simuliert.

Sonnensystem

Um die obigen (bewegten) Bilder zu erzeugen und um ein bewegtes Doppelpendel für meinen Schreibtisch zu haben, — wennauch nur auf einem Bildschirm — habe ich in C++ einen adaptiven Runge-Kutta-4 Löser geschrieben, der mit den Qt Zeichenprimitiven animiert wird.

Auch wenn der Code nicht sehr aufgeräumt ist und Startwerte im Quellcode angepasst werden müssen, sind die Quellen auf GitHub: github.com/surt91/DGLshow.

Ising Modell zur Bildentrauschung

Eines der bekanntesten Modelle der statistischen Physik ist das Ising-Modell. Es besteht aus (klassischen) Spins auf einem Gitter im Wärmebad und soll magnetische Eigenschaften von Festkörpern modellieren. Es zeigt nämlich in 2D und 3D (und 4D … ) einen Phasenübergang zweiter Ordnung von „magnetisch“ zu „nicht magnetisch“, so wie ferromagnetische Materialien, die oberhalb der Curie Temperatur nicht mehr ferromagnetisch sind.

In einfachen Worten: Die Spins des Ising-Modells richten sich so aus wie ihre Nachbarn und die Temperatur bringt sie wieder durcheinander.

Aber es wäre natürlich langweilig das Modell so zu benutzen, wie alle anderen auch. Deshalb stelle ich hier eine Anwendung aus Pattern Recgonition and Machine Learning vor, die nichts mehr mit Magneten zu tun hat: Rauschunterdrückung in Bildern.

Andererseits bin ich Physiker und darf deshalb nichts machen, was direkt nützlich wäre, also beschränke ich mich auf schwarz-weiße Bilder, die man direkt auf das „spin up“-„spin down“ des Ising-Modells abbilden kann.

Die Idee ist, das jeder Spin einem Pixel \(x_i\) entspricht. Dann koppelt man die Spins des Ising-Modells \(x_i\) an die Pixel \(y_i\) des verrauschten Bildes über einen zusätzlichen Energie-Term

$$\mathcal{H} = - \beta \sum_{\left< i,j \right>} x_i x_j - \eta \sum_i x_i y_i.$$

Dabei bedeutet \(\left< i,j \right>\), dass man über alle Nachbarn von \(i\) summiert.

Von diesem Modell kann man dann per Simulated Annealing den Grundzustand suchen oder man macht es sich einfach equilibriert bei \(T=0\).

Ising-Modell

Das Schema dazu wurde bereits in diesem Post gezeigt. Graue Knoten entsprechen den Pixeln des verrauschten Bilds \(y_i\) und weiße Knoten den Ising-Spins \(x_i\), die am Ende als Pixel des entrauschten Bilds interpretiert werden.

Genug der Theorie. Es wird Zeit für pixelige Bilder. Leider hatte ich kein verrauschtes Bild, also habe ich ein beliebiges Bild gemalt und 10% aller Pixel invertiert.

Vorher-Nachher Vergleich

Links das verrauschte Bild und rechts das entrauschte. Ja, nicht perfekt. Und in dem zitierten Buch wird auf der gleichen Seite noch eine sehr viel bessere Methode angesprochen. Aber die hatte nichts mit dem Ising-Modell zu tun. Und man sieht ja auch eine Verbesserung. Oder?

Nebenbei bemerkt, kann man das Ising-Modell auch als zellulären Automaten mit zufälligem Element betrachten, denn jeder Spin ist eine Zelle, die nur lokal von seinen Nachbarn und zufällig durch die Temperatur beeinflusst wird.

Der Code ist als Gist auf Github.