Skip to content
Snippets Groups Projects
Commit 96328c91 authored by Dietrich Gerstenberger's avatar Dietrich Gerstenberger
Browse files

ulam

parent 0b570dc9
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id:2836c33e tags:
# Mathematik Visuell
# Visualisierte Mathematik
%% Cell type:markdown id:4c015b89 tags:
## Die Primzahlen-Spirale
Im Jahre 1963 entdeckte der polnische Mathematiker Stanislaw Marcin Ulam, dass sich Muster ergaben, als er Primzahlen spiralenförmig anordnete. Man spricht daher heute auch von der Ulam-Spirale.
<img src="./pics/ulam-spiral.png" width="200" />
Die Muster sind für die Primzahlen bis 20 aber noch nicht erkennbar, dafür müssen wir den Algorithmus später auf sehr viel mehr Primzahlen ansetzen.
Muster in Primzahlen hätte man vielleicht eher nicht erwartet, sofern bis heute keine Funktion bekannt ist, mit der man diese sehr speziellen Zahlen generieren könnte. Aber im 18. Jahrhundert hat Leonhard Euler die Formel $f(n) = n^{2}+n+17$ entdeckt, it der er für Werte von $n = 0...15$ zumindest die ersten 15 Primzahlen berechnen konnte.
Inzwischen konnte man diese Idee verallgemeinern und weiss, dass für viele Kombinationen aus a,b,c die Formel $f(n) = an^{2}+bn+c$ erstaunlich viele Primzahlen liefern. Werte, die durch diese Formeln berechnet werden können, findet man auf Diagonalen in der besagten SPirale, wodurch es dazu kommt, dass sich in der Primzahl-Spirale viele diagonale Linien andeuten.
Doch dazu später mehr . . .
%% Cell type:markdown id:2401c5e9 tags:
### Konstruieren der Spirale auf unserer Zeichenfläche
todo
<img src="./pics/ulam-spiral-concept.png" width="200" />
todo
<img src="./pics/ulam-spiral-steps.png" width="400" />
%% Cell type:markdown id:af1ae17c tags:
Die Umsetzung in p5.js:
todo
<img src="./pics/ulam-spiral0.png" width="200" />
todo
%% Cell type:markdown id:36c1e6f6 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
var steps = 1;
var number = 1;
var CELLWIDTH = 20;
function setup() {
createCanvas(200, 200);
colorMode(HSB);
background(255);
translate(width/2, height/2);
visualizeCell();
number++;
while (number<44) {
drawSideAndRotate();
drawSideAndRotate();
steps++;
}
}
function draw() {
}
function visualizeCell() {
rectMode(CENTER);
fill(steps*50, 20, 200);
rect(0,0,CELLWIDTH,CELLWIDTH);
stroke(0);
textSize(10);
fill(0);
text(number, -5,3);
}
function drawSideAndRotate() {
for (var i=0; i<steps; i++) {
translate(CELLWIDTH, 0);
visualizeCell();
number++;
}
rotate(radians(-90));
}
```
</div>
</details>
%% Cell type:markdown id:90d6e364 tags:
### Erweiterung zu einer Spirale aus 10000 Zellen
todo
<img src="./pics/ulam-spiral1.png" width="200" />
%% Cell type:markdown id:7ebd64e8 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
var steps = 1;
var number = 1;
var CELLWIDTH = 4;
function setup() {
createCanvas(420, 420);
colorMode(HSB);
background(255);
translate(width/2, height/2);
visualizeCell();
number++;
while (number<10000) {
drawSideAndRotate();
drawSideAndRotate();
steps++;
}
}
function draw() {
}
function visualizeCell() {
var col = (steps*30)%255;
stroke(col, 20, 200);
fill(col, 20, 200);
ellipse(0,0,CELLWIDTH-2,CELLWIDTH-2);
}
function drawSideAndRotate() {
for (var i=0; i<steps; i++) {
translate(CELLWIDTH, 0);
visualizeCell();
number++;
}
rotate(radians(-90));
}
```
</div>
</details>
%% Cell type:markdown id:ada64d62 tags:
### Visualisieren der Primzahlen bis 10000
todo
<img src="./pics/ulam-spiral2.png" width="300" />
%% Cell type:markdown id:60499a61 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
var steps = 1;
var number = 1;
var CELLWIDTH = 4;
var primnumbers = [];
var primIndex = 0;
function preload() {
primnumbers = loadStrings("primzahlen10t.txt");
}
function setup() {
createCanvas(420, 420);
background(255);
translate(width/2, height/2);
visualizeCell();
number++;
while (number<10000) {
drawSideAndRotate();
drawSideAndRotate();
steps++;
}
}
function draw() {
}
function visualizeCell() {
var col=230;
if ( number==int(primnumbers[primIndex]) ) {
primIndex++;
col = 0;
}
stroke(col);
fill(col);
ellipse(0,0,CELLWIDTH-2,CELLWIDTH-2);
}
function drawSideAndRotate() {
for (var i=0; i<steps; i++) {
translate(CELLWIDTH, 0);
visualizeCell();
number++;
}
rotate(radians(-90));
}
```
</div>
</details>
%% Cell type:markdown id:ea2515e6 tags:
## Komplexe Zahlen
## Farbenfrohe Komplexe Zahlen
### Das Komplexe Koordinatensystem
Eine komplexe Zahl ist eine Zahl, die sich in der Form $a + b*i$ ausdrücken lässt, wobei $a$ und $b$ reelle Zahlen sind und $i$ eine Lösung der Gleichung $x^2 = -1$ ist. Da keine reelle Zahl diese Gleichung erfüllt, nennt man i eine imaginäre Zahl.
Bei der komplexen Zahl $a + b*i$ heißt $a$ der *reale* Teil und $b$ der *imaginäre* Teil.
<img src="./pics/complex-number.png" width="250" />
Beginnen wir damit, die Klasse `Complex` zu implementieren, die den Real- und Imaginärteil einer komplexen Zahl verwaltet.
- Implementiere den Konstruktor, der eine komplexe Zahl initialisiert.
- Implementiere die Funktion `printCanvas(x,y)`, die den Realteil und den Imaginärteil als "$[a + bi]$" auf der Zeichenfläche an der Position $(x,y)$ ausgibt.
- Implementiere einen Testfall in `setup()`, in dem Du die komplexe Zahl $[1+2i]$ initialisierst und deren Ausgabe auf die Zeichenfläche schreibst.
``` javascript
class Complex {
// verwaltet die imaginäre Zahl a + b*i
}
void setup(){
}
```
%% Cell type:markdown id:50238d0f tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
class Complex {
// verwaltet die imaginäre Zahl a + b*i
constructor(re, im){
this.a = re;
this.b = im;
}
printCanvas(x, y){
var output = "[" + this.a + " + " + this.b + "i]";
text(output, x, y);
}
}
function setup(){
createCanvas(200,200);
var testValue = new Complex(1,2);
testValue.printCanvas(20,50);
}
function draw() {
}
```
</div>
</details>
%% Cell type:markdown id:afba56f8 tags:
### Komplexe Zahlen addieren
Komplexe Zahlen zu addieren (oder zu subtrahieren) bedeutet, den Realteil und den Imaginärteil getrennt zu betrachten und sie zu addieren (oder zu subtrahieren):
<img src="./pics/complex-number-add.png" width="250"/>
Also z.B.: $[1 + 3i] + [3 + 2i] = [ (1+3) + (3+2)i ] = [4 + 5i]$
Entwickeln wir also eine Funktion `add(u, v)` für die Addition komplexer Zahlen.
Verwende dazu die bestehende Klasse aus der vorherigen Übung und füge die Funktion `add(u, v)` hinzu.
Verwende die komplexen Zahlen $[1 + 3i]$ und $[3 + 2i]$ aus dem Beispiel, implementiere einen neuen Testfall in `setup()` und überprüfen Sie das Ergebnis mittels der Ausgabe auf der Zeichenfläche.
%% Cell type:markdown id:eaa09a37 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
class Complex {
constructor(re, im){
this.a = re;
this.b = im;
}
printCanvas(x, y){
var output = "[" + this.a + " + " + this.b + "i]";
text(output, x, y);
}
static add(u, v) {
return new Complex(u.a+v.a, u.b+v.b);
}
}
function setup(){
createCanvas(200,200);
var testValue1 = new Complex(1,2);
testValue1.printCanvas(20,50);
var testValue2 = new Complex(1,3);
var testValue3 = new Complex(3,2);
var summe = Complex.add(testValue2, testValue3);
text("[1+3𝑖] + [3+2𝑖] = ", 20,75);
summe.printCanvas(110,75);
}
function draw() {
}
```
</div>
</details>
%% Cell type:markdown id:604be702 tags:
### Komplexe Zahlen multiplizieren
Für die Multiplikation zweier komplexer Zahlen muss man lediglich das **Distributivgesetz** kennen:
$(a+b) * (c+d) = (a+b)*c + (a+b)*d = ac + bc + ad + bd$
Machen wir das mit komplexen Zahlen:
$[a+bi] * [c+di] = [(a+bi)*c + (a+bi)*di] = [ac + bic + adi + bidi]$
Mit Hilfe des **Kommutativgesetzes** können wir weiter vereinfachen:
$[ac + bic + adi + bidi] = [ac + bci + adi + bdi^2]$
Erinnern wir uns nun daran, dass $i^2 = -1$ ist und fahren wir fort mit:
$[ac + bci + adi + bdi^2] = [ac + bci + adi - bd] = [ac-bd + (bc+ad)i]$
Erinnere Dich, wo wir angefangen haben:
a: Realteil des ersten Operanden
b: Imaginärteil des ersten Operanden
c: Realteil des zweiten Operanden
d: Imaginärteil des zweiten Operanden
**$[a+bi] * [c+di] = [ac-bd + (bc+ad)i]$**
Nun ist es an Dir, die Funktion `mult(u, v)` zu implementieren.
Verwende die bestehende Klasse aus der vorherigen Übung und füge die Funktion `mult(u,v)` hinzu.
Verwende die komplexen Zahlen $[1 + 3i]$ und $[3 + 2i]$ aus dem Beispiel, implementiere einen neuen Testfall in `setup()` und überprüfe das Ergebnis (es sollte $[-3 + 11i]$ betragen).
%% Cell type:markdown id:ac3ba5da tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
class Complex {
constructor(re, im){
this.a = re;
this.b = im;
}
printCanvas(x, y){
var output = "[" + this.a + " + " + this.b + "i]";
//var output = "real=" + this.a + ", imaginär=" + this.b;
text(output, x, y);
}
static add(u, v) {
return new Complex(u.a+v.a, u.b+v.b);
}
// [𝑎+𝑏𝑖]∗[𝑐+𝑑𝑖]=[𝑎𝑐−𝑏𝑑+(𝑏𝑐+𝑎𝑑)𝑖]
static mult(u, v) {
return new Complex(u.a*v.a-u.b*v.b, u.b*v.a+u.a*v.b);
}
}
function setup(){
createCanvas(200,200);
var testValue1 = new Complex(1,2);
testValue1.printCanvas(20,50);
var testValue2 = new Complex(1,3);
var testValue3 = new Complex(3,2);
var summe = Complex.add(testValue2, testValue3);
text("[1+3𝑖] + [3+2𝑖] = ", 20,75);
summe.printCanvas(110,75);
var produkt = Complex.mult(testValue2, testValue3);
text("[1+3𝑖] * [3+2𝑖] = ", 20,100);
produkt.printCanvas(110,100);
}
function draw() {
}
```
</div>
</details>
%% Cell type:markdown id:151f8902 tags:
Schauen wir uns nun eine einfache Berechnungen an:
$1 * i = $
Nimm das Ergebnis der letzten Berechnung und multipliziere es wieder mit $i$
$1 * i * i = $
<img src="./pics/complex-number-multiply-1.png" width="400" />
$1 * i * i = 1 * i^2 = 1 * -1$
Im komplexen Koordinatensystem führt die Multiplikation einer reellen Zahl mit $-1$ zu einer Drehung um 180 Grad um den Ursprung.
%% Cell type:markdown id:4556dd2a tags:
Bereite jetzt die folgende Berechnung in Deiner `setup()`-Funktion vor und lass uns die Ergebnisse diskutieren.
$[3+2i]$ * i =
<img src="./pics/complex-number-multiply-i.png" width="400" />
Wenn wir eine komplexe Zahl mit $i$ multiplizieren, ist das Ergebnis eine Drehung um 90 Grad um den Ursprung.
Wenn wir das Ergebnis nehmen und wieder mit $i$ multiplizieren, haben wir eine weitere 90-Grad-Drehung.
<img src="./pics/complex-number-multiply-ii.png" width="400" />
%% Cell type:markdown id:9f065899 tags:
### Implementieren der `magnitude` Funktion
Die **Magnitude** oder der **Absolutwert** einer komplexen Zahl gibt an, wie weit die komplexe Zahl vom Ursprung des komplexen Koordinatensystems entfernt ist.
<img src="./pics/complex-number-magnitude.png" width="250" />
Zur Berechnung der **Magnitude** können wir den **Satz des Pythagoras** verwenden.
$magnitude = \sqrt[2]{a^2 + b^2}$
Da der Betrag den (positiven) Abstand zum Ursprung $(0,0)$ anzeigt, wird er auch **Absolutwert** genannt und man findet Formeln wie diese:
$|a + bi| = \sqrt[2]{a^2 + b^2}$
Nun ist es an der Zeit, die Funktion `magnitude(u)` zu implementieren.
- Verwende die bestehende Klasse aus der vorherigen Übung und füge die Funktion `magnitude(. . .)` hinzu.
- Verwende die komplexe Zahl $[2 + 1i]$, um einen neuen Testfall in `setup()` zu implementieren und überprüfe das Ergebnis. Du solltest so etwas wie $2.23606797749979$ erhalten.
%% Cell type:markdown id:a88ae569 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
class Complex {
constructor(re, im){
this.a = re;
this.b = im;
}
printCanvas(x, y){
var output = "[" + this.a + " + " + this.b + "i]";
//var output = "real=" + this.a + ", imaginär=" + this.b;
text(output, x, y);
}
static add(u, v) {
return new Complex(u.a+v.a, u.b+v.b);
}
// [𝑎+𝑏𝑖]∗[𝑐+𝑑𝑖]=[𝑎𝑐−𝑏𝑑+(𝑏𝑐+𝑎𝑑)𝑖]
static mult(u, v) {
return new Complex(u.a*v.a-u.b*v.b, u.b*v.a+u.a*v.b);
}
// |𝑎+𝑏𝑖| = sqrt(𝑎^2+𝑏^2)
static magnitude(u) {
return sqrt(u.a*u.a + u.b*u.b);
}
}
function setup(){
createCanvas(200,200);
var testValue1 = new Complex(1,2);
testValue1.printCanvas(20,50);
var testValue2 = new Complex(1,3);
var testValue3 = new Complex(3,2);
var summe = Complex.add(testValue2, testValue3);
text("[1+3𝑖] + [3+2𝑖] = ", 20,75);
summe.printCanvas(110,75);
var produkt = Complex.mult(testValue2, testValue3);
text("[1+3𝑖] * [3+2𝑖] = ", 20,100);
produkt.printCanvas(110,100);
var testValue4 = new Complex(2,1);
var betrag = Complex.magnitude(testValue4);
text("| 2+1𝑖 | = " + betrag, 20,125);
}
function draw() {
}
```
</div>
</details>
%% Cell type:markdown id:c762b70e tags:
### Visualisieren der Mandelbrot-Menge
Um die Mandelbrot-Menge zu visualisieren, stellen wir jedes Pixel unseres Bildschirms als komplexe Zahl $z$ dar. Dann quadrieren wir den Wert wiederholt und addieren den ursprünglichen Wert $z$.
$z_{n+1} = z_{n}^2 + z$
Dann machen wir dasselbe mit der Ausgabe, und so weiter, und so weiter...
Die Zahlen werden immer größer und wir wählen die Farbe des Pixels (von $z$), die der Anzahl der Iterationen entspricht, die notwendig sind, um eine Größe (Abstand zum Ursprung) zu erhalten, die größer als eine bestimmte Zahl wie 2 ist.
Aus der Multiplikation von $reellen$-Zahlen wissen wir:
- die Multiplikation mit einem größeren Wert macht die Zahl größer
- Multiplikation mit einem kleineren Wert macht die Zahl kleiner
- Beim Multiplizieren mit 1 bleibt die Zahl gleich
Beim Multiplizieren unserer Testfälle haben wir ein ähnliches Muster für komplexe Zahlen gefunden. Würden wir komplexe Zahlen einfach multiplizieren, sähe die Mandelbrot-Menge wie ein Kreis aus.
Aber in der Formel gibt es eine zusätzliche Addition von $z$. Dadurch verwandelt sich der Kreis in eine unendlich komplizierte Figur.
Um die Färbung der Mandelbrot-Menge zu verstehen, probieren wir die Formel in der Funktion `setup()` von Hand aus:
a) Wir beginnen mit $z = [0.25 + 1.5i]$
b) $z_1 = z^2 + z$
c) Schauen wir uns $z1$ und $magnitude(z_1)$ an
%% Cell type:markdown id:edea4746 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
function setup(){
createCanvas(200,200);
var z = new Complex(0.25,1.5);
text("z = ", 20,50);
z.printCanvas(50,50);
text("|z| = " + Complex.magnitude(z), 20,75);
var z1 = Complex.add( Complex.mult(z, z), z);
text("z1 = ", 20,100);
z1.printCanvas(50,100);
text("|z1| = " + Complex.magnitude(z1), 20,125);
}
```
<img src="./pics/mandelbrot-z1.png" width="200" />
</div>
</details>
%% Cell type:markdown id:613d722a tags:
Die Regel war, so lange zu iterieren, bis die *Magnitude* größer als 2 wird.
Unsere erste komplexe Zahl divergiert nach nur 1 Iteration.
Machen wir das Gleiche mit $z = [0,25 + 0,75i]$
%% Cell type:markdown id:6dd252ea tags:
Sie werden feststellen, dass es 4 Iterationen braucht, um diese komplexe Zahl zu divergieren, dann wird der Betrag größer als 2 sein.
In der Debug-Ausgabe können Sie die verschiedenen komplexen Zahlen und ihre Beträge sehen.
<img src="./pics/complex-number-range2.png" width="800" />
### Implementation der Mandelbrot-Funktion
Das war ziemlich mühsam. Als Softwareentwickler sollte man so etwas nicht von Hand machen.
Es hat 4 Iterationen gebraucht, um unsere zweite komplexe Zahl abzuleiten.
Versuchen wir nun, die Funktion `mandelbrot(z, num)` zu implementieren, die diese Aufgabe für uns erledigt.
a) Verwende die bestehende Klasse aus der vorherigen Übung und füge die Funktion `mandelbrot(. . .)` hinzu.
b) Gebe die notwendige Debug-Ausgabe in die Funktion `mandelbrot(. . .)` ein, um eine Ausgabe wie in der vorherigen Übung zu erhalten.
``` javascript
function mandelbrot(z, num){
// schreibe den Eingangsparameter z und dessen Betrag |z|
// auf die Zeichenfläche
.
.
// schreibe z_i and |z_i| von jeder Iteration
// auf die Zeichenfläche
.
.
// schreibe vor dem return die Anzahl der Iterationen
// auf die Zeichenfläche
return num;
}
```
c) Verwende die komplexe Zahl $z = [0.25 + 0.75i]$, um einen neuen Testfall in `setup()` zu implementieren
%% Cell type:markdown id:228c3e2a tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
public static int mandelbrot(Complex z, int num){
print("z = ");
z.consoleOut();
println("|z| = " + Complex.magnitude(z));
int count=0;
Complex z1=z;
while (count<=num){
if ( Complex.magnitude(z1)>2.0){
print("");
println("num = " + count);
return count;
}
z1 = Complex.add( Complex.mult(z1,z1), z);
count += 1;
print("z"+count);
print(" = ");
z1.consoleOut();
print("|z"+count);
println("| = " + Complex.magnitude(z1));
}
print("");
println("num = " + num);
return num;
}
function mandelbrot(z, num) {
var textY = 20;
text("z = ", 20, textY);
z.printCanvas(50, textY);
text("|z| = " + Complex.magnitude(z), 150, textY);
textY += 20;
var count = 0;
var z1 = z;
while (count <= num) {
if (Complex.magnitude(z1) > 2.0) {
text("num = " + count, 20, textY);
return count;
}
z1 = Complex.add(Complex.mult(z1, z1), z);
count += 1;
text("z"+count+" = ", 20, textY);
z1.printCanvas(50, textY);
text("|z"+count+"| = " + Complex.magnitude(z1), 150,textY);
textY += 20;
}
text("num = " + count, 20, textY);
return num;
}
```
</div>
</details>
%% Cell type:markdown id:c596de0d tags:
### Visualisieren der Mandelbrot Menge
Jetzt können wir die Anzahl der Iterationen berechnen, die nötig sind, um für eine gegebene komplexe Zahl festzustellen, dass sie gegen unendlich konvergiert.
Der nächste Schritt besteht darin, diese Anzahl von Iterationen als Farbe für alle komplexen Zahlen aus einem bestimmten Bereich anzuzeigen.
Ein interessanter Bereich, um einen ersten Blick auf die **Mandelbrot-Menge** zu werfen, sind komplexe Zahlen mit Realteil und Imaginärteil im Bereich von -2 bis 2. Wir könnten also mit einigen `globalen` Variablen beginnen:
``` javascript
var xMin = -2;
var xMax = 2;
var yMin = -2;
var yMax = 2;
```
In der Funktion `setup()` geben wir die Anzeigegröße als $400x400$ an.
``` javascript
createCanvas(400, 400);
```
Nun müssen wir einen Algorithmus finden, der die Pixelkoordinaten von der Zeichenfläche in das komplexe Koordinatensystem transformiert.
<img src="./pics/complex-number-coords.png" width="600" />
Für einen gegebenen x-Wert auf unserem Bildschirm im Bereich von 0..400 müssen wir den Realteil im Bereich von -2..2 berechnen.
Für einen gegebenen y-Wert auf unserem Bildschirm im Bereich von 0..400 müssen wir den Imaginärteil im Bereich von -2..2 berechnen.
Dabei ist zu beachten, dass die (0,0)-Bildschirmposition auf der oberen linken Seite liegt, wo wir die komplexe Zahl [-2 + 2i] haben wollen
Die Bildschirmposition (400, 400) befindet sich auf der unteren rechten Seite, wo wir die komplexe Zahl [2 - 2i] haben wollen.
Zum Aufwärmen müssen Sie zwei verschachtelte `for`-Schleifen implementieren.
a) Die äußere Schleife stellt den `yCoord` unseres Bildschirms dar, iteriert von 0 bis Höhe und geht dabei um 100.
b) Die innere Schleife stellt den `xCoord` unseres Bildschirms dar, iteriert von 0 bis width und schreitet um 100.
c) Innerhalb der Schleife berechnen wir die entsprechenden komplexen Zahlen und geben sie in einer Zeile pro y-Schleife aus.
%% Cell type:markdown id:fc146c1b tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
var xMin = -2;
var xMax = 2;
var yMin = -2;
var yMax = 2;
var rangeX = xMax - xMin;
var rangeY = yMax - yMin;
var xScale;
var yScale;
function setup() {
createCanvas(400, 400);
xScale = rangeX / width;
yScale = rangeY / height;
var textX = 20;
var textY = 20;
for (var y = 0; y <= height; y += 100) {
for (var x = 0; x <= width; x += 100) {
var z = new Complex(xMin + x * xScale, yMax - y * yScale);
text("[" + z.a + ", " + z.b + "i]", textX, textY);
textX += 50;
}
textX = 20;
textY += 20;
}
}
```
</div>
</details>
%% Cell type:markdown id:baa64fa8 tags:
### Anzeigen der Mandelbrot Menge in schwarz/weiss
Die Umwandlung von Bildschirmkoordinaten in komplexe Koordinaten ist abgeschlossen.
Nun können wir für jede komplexe Zahl unseres Koordinatensystems die Funktion `mandelbrot()` aufrufen und das entsprechende Pixel in der angegebenen Farbe ausmalen.
a) Ab jetzt müssen die `for`-Schleifen um 1 erhöht werden, da wir für jedes Pixel unseres Bildschirms eine Farbe berechnen wollen
b) in der Schleife rufen wir die Funktion `mandelbrot()` auf und setzen die Farbe vorerst auf $schwarz$ wenn die Iterationen $100$ überschreiten und auf $weiß$ in allen anderen Fällen
c) wir benutzen die Funktionen `noStroke()` und `rect(x, y, 1, 1)` um ein 1x1 Rect mit der angegebenen Farbe zu zeichnen
<img src="./pics/mandelbrot-sw.png" width="300" />
%% Cell type:markdown id:0bcbc794 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
var xMin = -2;
var xMax = 2;
var yMin = -2;
var yMax = 2;
var rangeX = xMax - xMin;
var rangeY = yMax - yMin;
var xScale;
var yScale;
function setup() {
createCanvas(400, 400);
noStroke();
xScale = rangeX / width;
yScale = rangeY / height;
for (var y = 0; y <= height; y++) {
for (var x = 0; x <= width; x++) {
var z = new Complex(xMin + x * xScale, yMax - y * yScale);
var col = mandelbrot(z, 100);
if (col == 100) {
fill(0); // black
} else {
fill(255); // white
}
rect(x, y, 1, 1);
}
}
}
```
</div>
</details>
%% Cell type:markdown id:b8f81937 tags:
### Hinzufügen von Farbe
Jetzt wollen wir eine Reihe von verschiedenen Farben durchlaufen. Im "HSB"-Modus können wir dies tun, indem wir nur einen Parameter (den "Farbton") ändern. Lass uns diesen HSB-Farbmodus ausprobieren.
a) Wir wollen einen Bereich von 300 Farben haben. Wir können einfach den HSB-Modus mit Farbton/Sättigung/Helligkeit im Bereich von 0..300 initialisieren, indem wir `colorMode(HSB, 300)` aufrufen
b) Initialisiere eine $300x300$ Anzeige, um ein Rechteck jeder Farbe zu zeichnen
c) Implementiere eine `for`-Schleife, die die $300$ Farben durchläuft und gefüllte Rechtecke auf dem Bildschirm zeichnet. Du hast den HSB-Modus mit dem Wert $300$ initialisiert. Um 'brillante' Farben zu erhalten, müssen Sie _Sättigung_ und _Helligkeit_ auf den Maximalwert von 300 setzen (Beispiel: `fill(hue, 300, 300)`.
%% Cell type:markdown id:2261900b tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
```
</div>
</details>
%% Cell type:markdown id:c047b099 tags:
Und nun werden wir diese 300 Farben in unsere Mandelbrot-Menge einfügen.
a) Kopiere Deinen Code aus der Schwarz-Weiß Übung.
b) Setze die Farbe auf schwarz, wenn die Iteration 100 überschreitet.
c) Ordne die Anzahl der Berechnungen (0..99) den 300 Farben zu.
d) Genieße die farbenprächtige Mandelbrot-Menge
<img src="./pics/mandelbrot-color.png" width="300" />
%% Cell type:markdown id:12f460ff tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
var xMin = -2;
var xMax = 2;
var yMin = -2;
var yMax = 2;
var rangeX = xMax - xMin;
var rangeY = yMax - yMin;
var xScale;
var yScale;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 300);
noStroke();
xScale = rangeX / width;
yScale = rangeY / height;
for (var y = 0; y <= height; y++) {
for (var x = 0; x <= width; x++) {
var z = new Complex(xMin + x * xScale, yMax - y * yScale);
var col = mandelbrot(z, 100);
if (col == 100) {
fill(0); // black
} else {
fill(3*col, 300, 300); // color
}
rect(x, y, 1, 1);
}
}
}
```
</div>
</details>
%% Cell type:markdown id:0d2df9ae tags:
### Erkunden der Mandelbrot-Menge
Sieht nett aus, aber was ist mit all den winzig kleinen Figuren in dem größeren Bild.
Vielleicht sollten wir uns das genauer ansehen.
Erinnere Dich an unser komplexes Koordinatensystem und finde eine Region, die für Dich von Interesse ist. Vielleicht diese hier:
``` javascript
float xMin = -1;
float xMax = 0;
float yMin = -0;
float yMax = 1;
```
<img src="./pics/mandelbrot-diffstart.png" width="300" />
%% Cell type:markdown id:93ef1b95 tags:
### Auswählen einer Region in der Mandelbrot-Menge
Ok, jetzt können wir die interessanten Punkte herausfinden, den Code ändern und die Szene genießen, aber auch diese handgemachten Änderungen sind nicht das, was Softwareentwickler gerne tun.
Wir sollten versuchen, eine Region zur Laufzeit auszuwählen und automatisch anzuzeigen!
- Bei jedem Aufruf der draw() Funktion zeichnen wir jetzt zunächst die Mandelbrot-Menge
- Als linke obere Ecke des Auswahl-Rechtecks merken wir uns die aktuelle Mausposition.
- Um es einfach zu machen, wählen wir als neue Breite und Höhe des Rechtecks `width/4` und `height/4`.
- Jetzt zeichnen wir den grauen Rahmen des Rechtecks an der Mausposition
- In der Funktion `mousePressed()` fangen wir den Druck der Maustaste ab und bereiten uns schon mal mental darauf vor den sichtbaren Bereich unserer Mandelbrot-Menge anpassen zu müssen.
%% Cell type:markdown id:6ac7e901 tags:
<hr>
%% Cell type:markdown id:606e3670 tags:
Der nächste Schritt besteht darin, die komplexen Koordinaten des Bereichs aus unserer rechteckigen Auswahl des Bildschirms zu berechnen.
- Schaue Dir die Berechnung von Bildschirmpixeln in komplexe Koordinaten an.
- Füge den notwendigen Code in `mousePressed()` hinzu.
- Du hast jetzt `xMin,xMax` und `yMin,yMax` neu berechnet. Im bisherigen Code kannst Du aber sehen, dass aber auch `rangeX,rangeY` und `xScale,yScale` aus diesen Werten berechnet wurden. Auch dieser Code gehört jetzt noch in die Funktion `mousePressed()`
%% Cell type:code id:5572a396 tags:
``` python
%%html
<iframe src="https://vircadiavr.cs.upb.de/uploads/intro-processing/sketch_mandelbrot_explore/" width="400" height="400"></iframe>
```
%% Output
%% Cell type:markdown id:6421c8ba tags:
## Ein Ausflug zur Julia-Menge
In der Mandelbrot-Menge gibt es Millionen interessanter Bereiche zu erforschen. Und all dies basiert auf dieser einfachen Formel: $z_{n+1} = z_{n}^2 + z$
Bei jeder Iteration fügen wir die ursprüngliche Zahl $z$ hinzu. Das bedeutet, dass die Mandelbrot-Formel auch von der Ausgangszahl $z$ abhängt.
Lassen Sie uns eine einfache, aber wirkungsvolle Änderung an dieser Formel vornehmen: $z_{n+1} = z_{n}^2 + c$
Jetzt haben wir zwei Parameter für unsere Formel. Wir beginnen mit dem komplexen Wert $z$ und fügen in jeder Iteration eine konstante komplexe Zahl $c$ hinzu, die eine Variation in unsere Berechnungen bringen wird.
Passen Sie Ihren Mandelbrot-Code an und beginnen Sie Ihre Erkundungen mit $c=[-0.8, 0.156i]$
<img src="./pics/julia.png" width="300" />
%% Cell type:markdown id:a8a16a57 tags:
<details>
<summary><i><b>Musterlösung</b></i></summary>
<div>
``` javascript
```
</div>
</details>
%% Cell type:code id:e8278bbd tags:
``` python
%%html
<iframe id="p5.js web editor embed" title="p5.js web editor embed" width="800" height="600" src="https://editor.p5js.org/"></iframe>
```
%% Output
......
pics/ulam-spiral-concept.png

38 KiB

pics/ulam-spiral-steps.png

128 KiB

pics/ulam-spiral.png

33.8 KiB

pics/ulam-spiral0.png

56.3 KiB

pics/ulam-spiral1.png

254 KiB

pics/ulam-spiral2.png

111 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment