Ing Mathematik: Julia

Aus Wikibooks


Hallo Welt und allgemeine Hinweise[Bearbeiten]

Was ist Julia[Bearbeiten]

  • Julia ist eine höhere Programmiersprache, die vor allem für numerisches und wissenschaftliches Rechnen entwickelt wurde.
  • Julia ist Open-Source (MIT-Lizenz).
  • Julia ist schnell (JIT-Compiler).
  • Julia ist für wichtige Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
  • Julia als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
Wikipedia hat einen Artikel zum Thema:

.

Julia installieren[Bearbeiten]

MS Windows[Bearbeiten]

Laden Sie das aktuelle Julia-Paket von der Webseite [1] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.

Julia starten[Bearbeiten]

MS Windows[Bearbeiten]

Das Icon für das Julia-Programm doppelklicken. Und schon startet das Programm.

Das Julia-System präsentiert sich dann folgendermaßen (interaktives Kommandozeilenprogramm REPL [Read–eval–print loop]):

Ein paar Worte zur Erklärung[Bearbeiten]

Getestet wurden die Beispiele unter dem Betriebssystem MS Windows 10 mit den Julia-Versionen 1.9.4 und 1.10.2. An Beliebtheit rangiert Julia mit Stand November 2023 mit einem Rating von 0,44% an 34. Stelle (lt. TPCI - TIOBE Programming Community Index).

Ein erstes Programm[Bearbeiten]

Kommentare werden in Julia mit der Raute (#) eingeleitet. Sie werden vom Julia-Interpreter ignoriert. Text kann mit der print- oder println-Funktion ausgegeben werden. Starten Sie Julia und geben sie folgende Anweisungen zeilenweise ein (die Anweisungen sind jeweils mit der Return-Taste abzuschließen)

julia> # Das ist ein Kommentar
julia> print("Hallo Welt!")

Als Ergebnis erhalten Sie

Hallo Welt!

Der Prompt (julia>) ist selbstverständlich nicht einzutippen, sondern wird vom Julia-System geliefert.

Strings sind in Julia in Anführungszeichen (") zu setzen. Zwischen dem Befehl print und der öffnenden Klammer ( darf kein Leerzeichen gesetzt werden.

Julia als Taschenrechner[Bearbeiten]

Allgemeines[Bearbeiten]

Wir wollen 3 * 5 berechnen. Dazu starten wir Julia. Geben Sie dann die Formel

julia> 3 * 5

ein, drücken die Taste ENTER/RETURN und erhalten als Ergebnis

15

Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck berechnen :

julia> sin(sqrt(15))
-0.6679052983383519

Mit dieser Zahl kann unmittelbar weitergerechnet werden, z.B.

julia> ans * 2
-1.3358105966767038

"ans" steht übrigens für den Begriff "answer" (auf Deutsch "Antwort").

Das Mal-Zeichen (*) kann übrigens eingespart werden. ans * 2 ist dasselbe wie 2ans. Man beachte aber, dass in der Kurzform kein Leerzeichen zwischen 2 und ans stehen darf.

Beenden lässt sich das Julia-Programm durch Eingabe von exit() (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken). Beachten Sie wieder, dass zwischen der Funktion exit und der öffnenden Klammer kein Leerzeichen stehen darf.

Die Hilfefunktion von Julia[Bearbeiten]

Bei Eingabe eines Fragezeichens (?) springt Julia in das Hilfesystem.

Eingabe:

?

Eingabe:

help?> sin

Ausgabe:

 sin
search: sin sinh sind sinc sinpi sincos sincosd sincospi asin using isinf asinh asind isinteger isinteractive thisind

  sin(x)

  Compute sine of x, where x is in radians.

  See also sind, sinpi, sincos, cis, asin.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> round.(sin.(range(0, 2pi, length=9)'), digits=3)
  ...
  ...
  ...
    0.454649  0.454649

Für die komplette Julia-Dokumentation siehe [2].

Aufgaben[Bearbeiten]

  • Erkunden Sie die Tangensfunktion "tan" mittels Julia-Hilfe.
  • Berechnen Sie mit Julia den Ausdruck . Siehe für die Exponentialfunktion im Julia-Hilfesystem auch den Befehl exp(). Potenzieren kann man bei Julia mit dem ^-Operator (z.B. 2^3 = 8)
  • Berechnen Sie mit Julia den Ausdruck . Anmerkung: cosd erwartet den Parameter im Gradmaß (d für "degree"), sin erwartet den Parameter im Bogenmaß.

Julia als Scriptsprache[Bearbeiten]

Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.jl

# Das ist ein Kommentar
print("Hallo Welt!")

Julia-Dateien werden mit der Dateiendung .jl versehen.

Danach bringen Sie die Skriptdatei test1.jl (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:

1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ die Windows PowerShell). Das sieht dann etwa so aus:

Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.

C:\Users\xyz>
Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell den Eintrag "Windows PowerShell"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort cmd ein und mit "OK" wird das Ganze bestätigt.

2) Wechseln Sie mittels cd c:\tmp in das Verzeichnis c:\tmp

3) Angenommen, Sie haben Julia unter dem Pfad c:\devel\Julia-1.9.4\ installiert. Starten Sie das Programm so (der Prompt c:\tmp>ist natürlich nicht mit einzutippen):

c:\tmp>c:\devel\Julia-1.9.4\bin\julia.exe test1.jl

4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm

Hallo Welt!

Variablen[Bearbeiten]

Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9), Underscores (_) und etlichen Unicode-Zeichen bestehen, dürfen aber nicht mit einer Zahl beginnen.

Gültige Variablenbezeichner wären also:

xyz
x1
_wert
name_anzahl
a₂
γπΩ

Wie kann man eigentlich die griechischen Zeichen im vorhergehenden Beispiel eingeben? Auf einer deutschen oder englischen Tastatur sind sie jedenfalls nicht zu finden. Des Rätsels Lösung kann folgendermaßen aussehen (wird am Beispiel des Omega-Zeichens (Ω) vorgeführt):

1) Starten Sie das Julia-System (z.B. mittels Doppelklick auf das Julia-Icon oder in der Eingabeaufforderung durch direkte Eingabe von julia.exe (ggf. mit dem entsprechenden Programmpfad).

2) geben Sie \Omega ein (ohne den Befehl mit Return abzuschließen)

julia> \Omega

3 Tippen Sie auf die Tabulatortaste und schon erscheint das Ω.

4) Dieses Zeichen können Sie dann mittels Zwischenablage z.B. auch in eine jl.-Datei einfügen (ggf. unter Verwendung eines geeigneten Text-Editors, z.B. Geany)

Ähnliches gilt für tiefgestellte Indizes, z.B. a\_2 gefolgt von einem Tabulator ergibt a₂.

Da Julia case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:

xyz
XYZ
xYz

Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.jl gespeichert.

x = 5
y = 10
z = x*y
print(z)

Bringen Sie die Datei test1.jl zur Ausführung, so erhalten Sie folgende Bildschirmausgabe

50

Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben.

x = 5; y = 10; z = x*y
print(z)

Ausgabe:

50

Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.

x = 5;
println(x)
# x = x - 2
x -= 2
println(x)

Bildschirmausgabe:

5
3

Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Die Verwendung von Prä-/Postfix-Operatoren (++, --) wie unter C/C++ oder Java ist in Julia nicht erlaubt, sondern liefert nur eine Fehlermeldung.

Soll eine Anweisung auf mehrere Zeilen verteilt werden, z.B. weil sie zu lang ist, so kann dies geschehen, wie nachfolgend dargestellt.

x = 5;
y = 1000 * x + 
    sin(x/2)
print(y)    

Ausgabe:

5000.598472144104

Beachten Sie, dass die Zeilentrennung nach einem Operator erfolgt! Folgendes würde ein falsches Resultat liefern:

x = 5;
y = 1000 * x 
    + sin(x/2)
print(y)    

Ausgabe:

5000

Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Julia problemlos möglich:

wert = 10
println(wert)
wert = 35.5
println(wert)
wert = "Hallo"
println(wert)
wert = pi
println(wert)

Ausgabe:

10
35.5
Hallo
π

Hexadezimale, oktale und binäre Zahlen[Bearbeiten]

# Hexadezimale Zahl
println(0xABC)

# Oktale Zahl
println(0o56)

# Binäre Zahl
println( 0b1000011 )

Ausgabe (als Dezimalzahlen):

2748
46
67

Julia kann auch dezimale in binäre Zahlen etc. umwandeln:

Eingabe:

b = bitstring(30)
println(b) 

Ausgabe:

0000000000000000000000000000000000000000000000000000000000011110

Ein anderes Beispiel (hexadezimal nach binär):

# hexadezimal -> binär
s = string(0xF, base=2)
print(s) 

Ausgabe:

1111

Verzweigungen[Bearbeiten]

if[Bearbeiten]

Die IF-Verzweigung ist aus anderen Programmiersprachen bereits bekannt. In Pseudocode lässt sie sich folgendermaßen darstellen:

WENN bedingung TRUE
  führe block1 aus
SONST
  führe block2 aus
ENDE 

Die test1.jl-Datei laute also wie folgt:

x = 5;

if x < 4
  println("x ist kleiner als 4");
else
  println("Der else-Zweig wird ausgefuehrt");
  println("x ist groesser oder gleich 4");  
end

Ausgabe:

Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4

Julia kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:

  • <, <= ... kleiner (gleich)
  • >, >= ... größer (gleich)
  • == ... gleich
  • != ... ungleich
  • &, && ... AND
  • |, || ... OR

Beispielsweise:

a = 5;
b = 9;

if a<=10 & b!=7
  println("OK");
else
  println("Nicht OK");
end

Ausgabe:

OK

Erweiterung der if-else-end-Verzweigung - ein Beispiel mit elseif:

a = 5

if a==10
    println("OK")
elseif a==5
    println("Nicht OK")
    println("a = 5")
elseif a==6
    println("Auch nicht OK")
else
    println("Weiß nicht")
end

Ausgabe:

Nicht OK
a = 5

Ternärer Operator[Bearbeiten]

Eingabedatei:

a = 5
a >= 6 ? println("größer gleich 6") : println("kleiner 6")

Ausgabe:

kleiner 6

Schleifen[Bearbeiten]

while[Bearbeiten]

Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert nicht ganz so wie aus anderen Programmiersprachen bekannt.

In Pseudocode:

SOLANGE bedingung TRUE
  führe block aus
ENDE

In Julia:

x = 0

while x <= 10
  println(x)
  global x += 1
end

Ausgabe:

0
1
2
3
4
5
6
7
8
9
10

Außerhalb von Funktionen muss das Schlüsselwort global verwendet werden. Ansonsten gibt es eine Warnung und eine Fehlermeldung. Innerhalb einer Funktion benötigt man das global nicht.

for[Bearbeiten]

for x = 0 : 2 : 10
  println(x);
end

Ausgabe:

0
2
4
6
8
10

Der FOR-Schleifenkopf ist in Form einer Zahlenkolonne folgendermaßen aufgebaut:

for variable = startwert : schrittweite : endwert

Alternativ findet man in der Literatur auch folgende for-Schleifenaufbauten.

for x in 0 : 2 : 10
  println(x);
end
for x ∈ 0 : 2 : 10
  println(x);
end

Achtung: Das ∈ ist kein \epsilon, sondern ein \in.

Die unterschiedlichen for-Schleifen liefern jeweils das gleiche Ergebnis.

break und continue[Bearbeiten]

Zum Abbrechen einer Schleife gibt es den Befehl "break".

for var = 0 : 1 : 100
  println(var)
  if var == 5
    break;
  end
end

Ausgabe:

0
1
2
3
4
5

"continue" setzt mit dem nächsten Schleifendurchlauf fort, z.B.

for var = 0 : 1 : 10
   if var == 5
     continue;
   end
   println(var);
 end

Ausgabe:

0
1
2 
3
4
6
7
8
9
10

Eingabe via Tastatur[Bearbeiten]

Datei c:\tmp\test1.jl:

print("Geben Sie eine Zahl ein: ")

# Einlesen als String
str = readline(stdin)
print("Die Zahl lautet ")
println(str)

# Umwandeln in einen Float
zahl = parse(Float64, str)
print("Die Zahl lautet ")
println(zahl)

Eingabe der Zahl via Tastatur:

67.8

Mit der RETURN-Taste bestätigen.

Ausgabe:

Die Zahl lautet 67.8
Die Zahl lautet 67.8

In diesem Fall wird, wie gezeigt, zweimal Die Zahl lautet 67.8 ausgegeben. Gibt man aber z.B. Eins ein, so wird einmal Die Zahl lautet Eins ausgegeben. Das ist klar, da Eins ein gültiger String ist. Danach folgt aber eine Fehlermeldung, weil Eins nicht in eine Fließkommazahl umgewandelt werden kann.

Grafiken zeichnen[Bearbeiten]

Es gibt in Julia mehrere Möglichkeiten Grafiken zu zeichnen. Hier wird eine Einführung in das Package Plots gegeben.

Plots installieren[Bearbeiten]

Im Julia-REPL die schließende eckige Klammer ] eintippen. Damit springt man in das Package-System, angezeigt wird das mit dem Prompt (@v1.9) pkg>.

Das Plots-Package zum Julia-System hinzufügen:

(@v1.9) pkg> add Plots

Mit STRG-C kann das Package-System wieder verlassen werden.

2D[Bearbeiten]

Graph einer Funktion[Bearbeiten]

Es soll die cosh-Funktion im Intervall gezeichnet werden. Der Programmcode lautet in der einfachsten Form:

using Plots

x = -3 : .1 : 3 
y = cosh.(x) 

p = plot(x, y)
gui()

while(true)
end

Ausgabe:

Der Code ist quasi selbsterklärend. Das Plots-Package wird importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plot" ist der Zeichenbefehl. "gui" ist notwendig, um das Fenster mit der Grafik anzuzeigen. Es folgt eine Endlossschleife. Diese ist notwendig, weil das Fenster mit der Grafik sonst nur kurz aufblinkt und das Programm danach beendet wird. Das Gesagte gilt, wenn man die test1.jl-Datei direkt ausführt. Im REPL kann man sich den Befehl "gui" und die Endlosschleife sparen.

Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen.

Hinweise:

  • Bis das Fenster mit dem cosh-Graphen erscheint, kann es einige Sekunden dauern.
  • Beenden kann man die Endlosschleife, indem man STRG-C drückt (STRG ist die Steuerungs- oder Control-Taste)
  • Beachten Sie den Punkt (.) bei der cosh-Funktion. Vergessen Sie diesen, so wird eine Fehlermeldung ausgegeben.

Ein etwas komplexeres Beispiel ist folgendes

using Plots

x = -3 : .1: 3
y = cosh.(x) + 2 .^x

plot(x,y)
gui()

while true
end

Man beachte die Punkte bei der Funktion y. Vergisst man die Punkte, dann erhält man eine Fehlermeldung. Weiters beachte man das Leerzeichen und die Position desselben bei 2 .^x. Setzt man das Leerzeichen an die falsche Stelle oder vergisst es ganz, so ist das auch ein Fehler.

Ausgabe:

Graphen mehrerer Funktionen und weiteres[Bearbeiten]

Mehrere Graphen lassen sich folgendermaßen in ein Fenster zeichnen (es werden auch Titel und Labels gesetzt):

using Plots

x = -3 : .1: 3
y1 = cosh.(x) + 2 .^x
y2 = sin.(x) .* cos.(x)

plot(x, [y1, y2],  title="Screenshot", label=["cosh(x) + 2^x" "sin(x) + cos(x)"], 
    xlabel="x", ylabel="y")

gui()

while true
end

Will man mehrere Graphen in ein Fenster zeichnen, aber nicht alles in einen plot-Befehl quetschen, so kann die "plot!"-Anweisung die Lösung des Problems sein. Auch die Linienstile sollen nun etwas individueller gestaltet werden:

using Plots

x = -3 : .1: 3
y1 = cosh.(x) + 2 .^x
y2 = sin.(x) .* cos.(x)

plot(x, y1, linestyle=:dot, label="cosh ...", linewidth=5)
plot!(x, y2, ls=:dot, label="sin ...", lw=3)
title!("Funktionsgraphen")
xlabel!("x")
ylabel!("y")

gui()

while true
end

Funktion in Parameterdarstellung[Bearbeiten]

Es soll die archimedische Spirale im Intervall gezeichnet werden.

using Plots

t = 0 : .1: 6*pi
x = t .* cos.(t)
y = t .* sin.(t)
plot(x, y, lw=5)

gui()

while true
end

Der Graph erscheint in der obigen Darstellung verzerrt. Will man das nicht, so setze man das aspect_ratio auf :equal:

using Plots

t = 0 : .1: 6*pi
x = t .* cos.(t)
y = t .* sin.(t)
plot(x, y, lw=5, aspect_ratio = :equal)

gui()

while true
end

Logarithmische Achsenskalierung[Bearbeiten]

using Plots

f(x) = 10^x

p1 = plot(f, 1, 5, lw=2, title="kartesische Koordinaten")
p2 = plot(f, 1, 5, yscale=:log10, lw=2, title="Semilog")
p3 = plot(f, 1, 5, xscale=:log10, yscale=:log10, lw=2, title="LogLog")

plot(p1, p2, p3, layout=(3,1))

gui()
while true
end

Ausgabe:

Aufgaben[Bearbeiten]

  • Zeichnen Sie die Strophoide . Das Ganze sollte in etwa so aussehen wie folgende Grafik:

  • Zeichnen Sie die verschlungene Hypozykloide . Das Ganze sollte in etwa so aussehen wie folgende Grafik:

  • Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.

3D[Bearbeiten]

Räumliche Kurven[Bearbeiten]

Mittels "plot3d" lassen sich Raumkurven zeichnen.

using Plots

t = 0 : .1: 6*pi
x = t .* cos.(t)
y = t .* sin.(t)
z = t

plot3d(x, y, z)

gui()

while true
end

Flächen[Bearbeiten]

using Plots

x = 0 : .1 : 10;
y = 0 : .1 : 10;
z(x,y) = sin(x) + 3*cos(y);

surface(x,y,z)

gui()

while true
end

Das Ganze in Netzdarstellung läßt sich so programmieren:

using Plots

x = 0 : .5 : 10
y = 0 : .5 : 10
z(x,y) = sin(x) + 3*cos(y)
 
wireframe(x, y, z)

gui()

while true
end

Die Kameraposition lässt sich verändern:

using Plots

x = 0 : .1 : 10
y = 0 : .1 : 10
z(x,y) = sin(x) + 3*cos(y)

# Kamerawinkel in Grad (Azimut, Altitude)
surface(x,y,z, camera = (75, 60)) 

gui()

while true
end

Wikipedia hat einen Artikel zum Thema:


Höhenlinien[Bearbeiten]

using Plots

x = 0 : .1 : 10
y = 0 : .1 : 10
z(x,y) = sin(x) + 3*cos(y)

contour(x,y,z)

gui() 

while true
end

Etwas abgewandelt sind das so aus:

using Plots

x = 0 : .1 : 10
y = 0 : .1 : 10
z(x,y) = sin(x) + 3*cos(y)

contour(x, y, z, levels=10, clabels=true, cbar=false)

gui()

while true
end

Und noch eine Variante sei gezeigt.

using Plots

x = 0 : .1 : 10
y = 0 : .1 : 10
z(x,y) = sin(x) + 3*cos(y)

contourf(x, y, z)

gui()

while true
end

Aufgaben[Bearbeiten]

  • Zeichnen Sie die räumliche Kurve , , , .
  • Zeichnen Sie die Fläche .

Animationen[Bearbeiten]

using Plots

anim = Animation()
	
for i = 1:100
    plt = plot(sin, 0, i*2pi/10, ylims = (-1., 1.), lab="")
    frame(anim, plt)
end
	
gif(anim, "c:/tmp/Julia_anim1.gif",fps=10)

Dieses Programm schreibt ein animiertes  GIF in die Datei c:/tmp/Julia_anim1.gif.

Vektoren und Matrizen[Bearbeiten]

Vektoren[Bearbeiten]

Vektoren sollten jedem aus der Linearen Algebra bekannt sein.

Spalten- und Zeilenvektoren[Bearbeiten]

Starten Sie die Julia-REPL. Geben Sie folgenden Befehl ein, um einen Spaltenvektor zu erstellen:

julia> v1 = [1, 2, 3]

Ausgabe:

3-element Vector{Int64}:
 1
 2
 3

Geben Sie folgenden Befehl ein, um einen Zeilenvektor (oder genauer eine 1x3-Matrix) zu erstellen:

julia> v1 = [1 2 3]

Ausgabe:

1×3 Matrix{Int64}:
 1  2  3

Zugriff auf Vektorelemente[Bearbeiten]

Nachfolgend seien Zugriffsmöglichkeiten auf die Vektorelemente erläutert.

Auf ein einzelnes Element kann via Index zugegriffen werden. Der Index startet bei 1:

v1 = [1, 2, 3]
println(v1[2])

Ausgabe:

2

Mehrere Elemente werden folgendermaßen angesprochen:

v1 = [1 2 4 8 16]
print(v1[3:4])

Ausgabe:

[4, 8]

Liefere den Teilvektor von einem gegebenen Index bis zum letzten Element:

v1 = [1 2 4 8 16]
print(v1[3:end])

Ausgabe:

[4, 8, 16]

Addition und Subtraktion von Vektoren[Bearbeiten]

v1 = [1, 2, 3]
v2 = [5, 7, 9]

println(v1 + v2)
println(v1 - v2)

Ausgabe:

[6, 9, 12]
[-4, -5, -6]

Multiplikation mit Skalaren[Bearbeiten]

faktor = 3;
v = [1, 2, 3];

println(v * faktor)

Ausgabe:

[3, 6, 9]

Skalarprodukt[Bearbeiten]

Das Skalarprodukt ist bekanntermaßen als definiert. In Julia sieht das so aus:

using LinearAlgebra

v1 = [1, 2, 3]
v2 = [2, 5, 10]

println(LinearAlgebra.dot(v1, v2)) 

Ausgabe:

42

Hinweis: Wenn das LinearAlgebra-Paket noch nicht installiert ist, so muss dies eventuell nachgeholt werden. Wie das prinzipiell funktioniert, wurde im Kapitel "Grafiken zeichnen" am Beispiel des Plots-Pakets vorgeführt.

Vektorprodukt[Bearbeiten]

Julia-Code:

using LinearAlgebra

v1 = [1, 2, 3]
v2 = [2, 5, 10]

println(LinearAlgebra.cross(v1, v2))

Ausgabe:

[5, -4, 1]

Transponierter Vektor[Bearbeiten]

using LinearAlgebra
v = [1, 2, 3]
println(LinearAlgebra.transpose(v))

Ausgabe:

[1 2 3]

Einige weitere Vektorfunktionen[Bearbeiten]

Die euklidische Norm in Julia:

using LinearAlgebra
v = [1 2 3]
println(norm(v))

Ausgabe:

3.7416573867739413

Beispiel:

# 1 + 2 + 3
v = [1 2 3]
println(sum(v))

Ausgabe:

6

Beispiel:

# 1 * 2 * 3 * 4
v = [1 2 3 4]
println(prod(v))

Ausgabe:

24

Matrizen[Bearbeiten]

Starten Sie die Julia-REPL. Geben Sie folgenden Befehl ein, um eine 2x3-Matrix zu erstellen:

julia> [1 2 3; 4 5 6]

Ausgabe:

2×3 Matrix{Int64}:
 1  2  3
 4  5  6

Damit verlassen wir die Julia-REPL wieder und arbeiten im Folgenden mit der test1.jl-Datei weiter.

Zugriff auf Matrizenelemente[Bearbeiten]

m = [1 2 3; 4 5 6]

# Element aus Zeile 2 und Spalte 3
println(m[2,3])

Ausgabe:

6

Eine andere Zugriffsmöglichkeit ist diese:

m = [1 2 3; 4 5 6]

# Auf das Element an Position 5 soll zugegriffen werden
println(m[5])

Ausgabe:

3

Die Matrix wird also spaltenweise durchlaufen (nicht zeilenweise). Dies ist vielleicht auf den ersten Blick etwas ungewöhnlich, wird aber z.B. auch in Fortran oder Octave so gehandhabt.

Addition und Subtraktion von Matrizen[Bearbeiten]

m1 = [1 2 3; 4 5 6]
m2 = [-4 -2 0; 2 4 6]
println(m1 + m2)
println(m1 - m2)

Ausgabe:

[-3 0 3; 6 9 12]
[5 4 3; 2 1 0]

Transponierte Matrix[Bearbeiten]

m = [1 2 3; 4 5 6]
println(m')

Ausgabe:

[1 4; 2 5; 3 6]

Rang einer Matrix[Bearbeiten]

using LinearAlgebra
m1 = [1 2 3; 4 5 6]
m2 = [1 2 3; 2 4 6]
println(LinearAlgebra.rank(m1))
println(LinearAlgebra.rank(m2))

Ausgabe:

2
1

Inverse Matrix[Bearbeiten]

using LinearAlgebra
m = [1 3; 0 -5 ]
println(LinearAlgebra.inv(m))

Ausgabe:

[1.0 0.6000000000000001; 0.0 -0.2]

Determinate einer Matrix[Bearbeiten]

using LinearAlgebra
m1 = [1 3; 0 -5 ]
m2 = [1 2; 2 4]
println(LinearAlgebra.det(m1))
println(LinearAlgebra.det(m2))

Ausgabe:

-5.0
0.0

m1 ist regulär, m2 ist singulär. Determinanten können nur von quadratischen Matrizen gebildet werden.

Multiplikation von Matrizen (falksches Schema)[Bearbeiten]

m1 = [1 3 4; 0 -5 1]
m2 = [1 2; 2 3; 0 2]
println(m1 * m2)

Ausgabe:

[7 19; -10 -13]

Teilmatrizen[Bearbeiten]

m = [1 2 3; 0 5 1]

# Die Matrix in einen Spaltenvektor umwandeln
println(m[:])

# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
println(m[1,2])

# Erste Zeile extrahieren
println(m[1, 1:3])
println(m[1, :])

# Zweite Spalte extrahieren
println(m[1:2, 2])
println(m[:, 2])

Ausgabe:

[1, 0, 2, 5, 3, 1]
2
[1, 2, 3]
[1, 2, 3]
[2, 5]
[2, 5]

Eigenwerte und Eigenvektoren[Bearbeiten]

using LinearAlgebra

A = [5 8; 1 3] 

# Eigenvektoren und Eigenwerte 
println(eigvals(A))
println(eigvecs(A))

Ausgabe:

[1.0, 7.0]
[-0.8944271909999159 0.9701425001453319; 0.447213595499958 0.24253562503633297]

LR-Zerlegung einer Matrix[Bearbeiten]

Führen Sie die LR-Faktorisierung (LR ... links/rechts bzw. LU ... left/upper) einer Matrix m aus. Dazu springen wir wieder in die REPL und geben folgende Befehle ein:

julia> using LinearAlgebra

julia> m=[1 0 5; -1 1 -2; 0 0 3]
  3×3 Matrix{Int64}:
     1  0   5
     -1  1  -2
     0  0   3

julia> f = factorize(m)
  LU{Float64, Matrix{Float64}, Vector{Int64}}
  L factor:
  3×3 Matrix{Float64}:
    1.0  0.0  0.0
    -1.0  1.0  0.0
    0.0  0.0  1.0
  U factor:
  3×3 Matrix{Float64}:
    1.0  0.0  5.0
    0.0  1.0  3.0
    0.0  0.0  3.0

Schwach besetzte Matrizen[Bearbeiten]

In der Technik treten häufig große Matrizen auf, die aber nur relativ wenige von Null verschiedene Werte mit Bandstruktur besitzen. Für diese ist es ineffizient, alle Matrizenelemente zu speichern. Effizienter ist es, nur die von Null verschiedenen Elemente zu speichern. Zu diesem Zwecke gibt es das SparseArrays-Paket.

julia> using SparseArrays
julia> ms = sparse([1, 2, 3, 3, 4, 5, 5], [2, 4, 1, 4, 3, 4, 5], [1, 3, 4, 2, 1, 1, 7])

Ausgabe:

⋅  1  ⋅  ⋅  ⋅
⋅  ⋅  ⋅  3  ⋅
4  ⋅  ⋅  2  ⋅
⋅  ⋅  1  ⋅  ⋅
⋅  ⋅  ⋅  1  7

Spezielle Matrizen[Bearbeiten]

Nachfolgend sollen eine Nullmatrix und eine Matrix mit lauter Einsen generiert werden. Dazu starten wir wieder die Julia-REPL, geben die entsprechenden Befehle ein und erhalten:

julia> zeros(3,2)
3×2 Matrix{Float64}:
 0.0  0.0
 0.0  0.0
 0.0  0.0  

julia> ones(3,2)
3×2 Matrix{Float64}:
 1.0  1.0
 1.0  1.0
 1.0  1.0

Insbesondere für Testzwecke kann es manchmal sinnvoll sein größere Matrizen mit Zufallswerten zu bilden. Dazu stellt Julia den rand-Befehl zur Verfügung.

julia> m = rand(5,6)
5×6 Matrix{Float64}:
 0.554722   0.7314     0.571432  0.804651   0.192327  0.912537
 0.684459   0.748819   0.642302  0.552636   0.671043  0.250012
 0.624424   0.722093   0.125511  0.342248   0.398071  0.820795
 0.0894763  0.0514967  0.310389  0.96167    0.382739  0.0181225
 0.957162   0.365172   0.50859   0.0742012  0.555778  0.512406

Einheitsmatrizen: Man beachte das I nach der Zahl 1. Die Matrix muss quadratisch sein.

julia> using LinearAlgebra
julia> M = 1I + zeros(4,4)
4×4 Matrix{Float64}:
 1.0  0.0  0.0  0.0
 0.0  1.0  0.0  0.0
 0.0  0.0  1.0  0.0
 0.0  0.0  0.0  1.0

Alternativ:

julia> using LinearAlgebra
julia> M = 1I(4)
4×4 Diagonal{Int64, Vector{Int64}}:
 1  ⋅  ⋅  ⋅
 ⋅  1  ⋅  ⋅
 ⋅  ⋅  1  ⋅
 ⋅  ⋅  ⋅  1

Diagonalmatrizen, z.B.:

julia> using LinearAlgebra
julia> M = 3I + zeros(4,4)
4×4 Matrix{Float64}:
 3.0  0.0  0.0  0.0
 0.0  3.0  0.0  0.0
 0.0  0.0  3.0  0.0
 0.0  0.0  0.0  3.0

Und damit verlassen wir die REPL wieder.

Komplexe Zahlen[Bearbeiten]

Die imaginäre Einheit wird in Julia durch die Buchstabenkombination im symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:

  • Kartesische Darstellung
  • Polardarstellungen

Die konjugiert komplexe Zahl ist

Mit komplexen Zahlen rechnen[Bearbeiten]

z1 = 2 + 5im        # kartesische Darstellung
z2 = 3 * exp(3im)   # Polardarstellung

# Addition
res = z1 + z2
println("z1 + z2 = ", res)

# Multiplikation
res = z1 * z2
println("z1 * z2 = ", res)

# Realteil
res = real(z2)
println("Realteil von z2 = ", res)

# Imaginärteil
res = imag(z2)
println("Imaginaerteil von z2 = ", res)

# Betrag
res = abs(z1)
println("Betrag von z1 = ", res)

# Argument
res = angle(z1)
println("Argument von z1 = ", res)

# Konjugiert komplexe Zahl
res = conj(z1)
println("Konjugiert komplexe Zahl von z1 = ", res)

Ausgabe:

z1 + z2 = -0.9699774898013365 + 5.423360024179601im
z1 * z2 = -8.05675510050068 - 14.003167400647481im
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = 2 - 5im

Funktionen[Bearbeiten]

Um Programme zu strukturieren und einfacher zu gestalten können Programmteile in Funktionen ausgelagert werden. Eingebaute Funktionen haben wir schon kennengelernt (z.B. die Sinus-Funktion sin). Nun wollen wir sehen, wie man selbst solche Funktionen schreiben kann.

Eine einfache Funktion schreiben[Bearbeiten]

f(a, b) = a + b
println(f(2, 3))

Ausgabe:

5

function[Bearbeiten]

Datei c:\tmp\func.jl:

function add(a,b)
  println(a + b)
end

Datei c:\tmp\test1.jl:

include("func.jl")
add(5, 11)

Folgendes wird ausgegeben, wenn wir die test1.jl-Datei ausführen

16

Anonyme Funktionen[Bearbeiten]

println(map(a ->  5a + 10, [2, 3]))

Ausgabe:

[20, 25]

return[Bearbeiten]

Datei c:\tmp\func.jl:

function add(a,b)
  return a + b
end

Datei c:\tmp\test1.jl:

include("func.jl")
println(add(5, 11))

Folgendes wird ausgegeben, wenn wir die test1.jl-Datei ausführen

16

Auch die Rückgabe mehrerer Werte ist möglich.

Datei c:\tmp\func.jl:

function add(a, b)
  return a + b, "Addition"   
end

Datei c:\tmp\test1.jl:

include("func.jl")
x, y = add(10, 20)
println(x)
println(y)

Ausgabe:

30
Addition

Optionale Argumente[Bearbeiten]

Datei c:\tmp\func.jl:

function add(a, b = 100)
  return a + b
end

Datei c:\tmp\test1.jl:

include("func.jl")
println(add(5, 11))
println(add(5))

Folgendes wird ausgegeben, wenn wir die test1.jl-Datei ausführen

16
105

Schlüsselwort-Argumente[Bearbeiten]

Datei c:\tmp\func.jl:

function add(a; b = 100)
  return a + b
end

Man beachte, dass hier zwischen den Argumenten a und b kein Beistrich, sondern ein Semikolon steht.

Datei c:\tmp\test1.jl:

include("func.jl")

println(add(b=16, 5))
println(add(5, b=16))
println(add(5))

Ausgabe:

21
21
105

Polynome[Bearbeiten]

Sofern noch nicht geschehen, fügen Sie das Paket Polynomials zum Julia-System hinzu.

Ein erstes einfaches Beispiel[Bearbeiten]

using Polynomials
println(Polynomial([1, 0, 5, 7]))

Ausgabe:

1 + 5*x^2 + 7*x^3

Einzelne Polynomwerte berechnen[Bearbeiten]

using Polynomials

p = Polynomial([1, 0, 5, 7]);
println(p(1.5))

Ausgabe:

35.875

Polynome integrieren und differenzieren[Bearbeiten]

using Polynomials

p = Polynomial([1, 0, 5, 7]);
i = integrate(p)
d = derivative(p)
println(i)
println(d)

Ausgabe:

1.0*x + 1.66667*x^3 + 1.75*x^4
10*x + 21*x^2

Nullstellen bestimmen[Bearbeiten]

using Polynomials

p = Polynomial([4, 0, 5, 2]);
r = roots(p)
println(r)

Ausgabe:

ComplexF64[-2.7621427020576714 + 0.0im, 0.13107135102883646 - 0.8407709868482356im, 0.13107135102883646 + 0.8407709868482356im]

Aufgaben[Bearbeiten]

  • Berechnen Sie den Wert für x = 3 des Polynoms .
  • Differenzieren und integrieren Sie das Polynom .
  • Berechnen Sie die Nullstellen von .

Lineare Gleichungssysteme[Bearbeiten]

Sei ein lineares Gleichungssystem. sei die Koeffizientenmatrix, der Lösungsvektor und ein bekannter Vektor.

Beispiel:

A = [5 1; 0 2]
b = [1, 2] 
x = A \ b
println(x)

Ausgabe:

[0.0, 1.0]

Interpolation[Bearbeiten]

Als erstes muss das Interpolations-Paket installiert werden. Wenn Sie nicht wissen, wie man das macht, so sehen Sie unter dem Abschnitt "Grafiken zeichnen" den Absatz "Plots installieren". Dort wird die Vorgehensweise detailliert beschrieben.

Datei "c:\tmp\test1.jl":

using Interpolations
using Plots

# Stützpunkte
xp = 1 : 1 : 5
yp = [0; -5; 2; 7; 6]

# Interpolationsfunktionen
lspl = LinearInterpolation(xp, yp, extrapolation_bc = Line())
cspl = CubicSplineInterpolation(xp, yp, extrapolation_bc = Line())

# Stützpunkte zeichnen
plot(xp,yp,marker=4,linetype=:scatter, label = "Data", title = "Interpolation")

# Interpolierende zeichnen
x = 1 : .1 : 5
plot!(x, lspl(x), label="Linearer Spline")
plot!(x, cspl(x), label="Kubischer Spline")

gui()

while true
end

Ausgabe:

Differenzialrechnung[Bearbeiten]

Symbolische Differenziation[Bearbeiten]

julia> using Calculus
julia> differentiate("sin(x)", :x)

Ausgabe:

:(1 * cos(x))

Auswertung:

julia> x = pi/2;
julia> round(eval(differentiate("sin(x)", :x)))

Ausgabe:

0.0

Numerische Differenziation[Bearbeiten]

julia> using Calculus
julia> derivative("sin", pi/2)

Ausgabe:

0.0

Integralrechnung[Bearbeiten]

julia> using QuadGK
julia> integral, err = quadgk(x -> sin(x), 0, pi/2, rtol=1e-8)

Ausgabe:

(0.9999999999999999, 1.1102230246251565e-16)

Im Rahmen der Näherung ist das Resultat richtig (exakt sollte (1.0, 0.0) rauskommen).

Gewöhnliche Differenzialgleichungen[Bearbeiten]

Das Paket DifferentialEquations ist, wie so viele andere, umfangreich. Hier sei nur ein einfaches Beispiel dargestellt. Für weiterführende Studien sei auf die entsprechenden Weblinks verwiesen.

Folgende Differentialgleichung sei gegeben: .

using DifferentialEquations
using Plots

f(y, p, x) = x^2 + y^3
problem = ODEProblem(f, 0.0, (0.0, 1.0))
s = solve(problem, Tsit5(), reltol = 1e-8, abstol = 1e-8)

plot(s, title = "ODE")
gui()

while true
end

Ausgabe:

Ein- und Ausgabe[Bearbeiten]

Dateien lesen[Bearbeiten]

# Textdatei im aktuellen Verzeichnis öffnen
f = open("test1.jl")

# Lesen aus Datei
lines = readlines(f)

# Zeilenweise Ausgabe am Bildschirm
for l in lines
   println("$l")
end

# Datei schließen
close(f)

Als Ausgabe erscheint exakt obiger Source-Code im Terminal.

Dateien schreiben[Bearbeiten]

open("test.txt", "w") do f
   write(f, "Schreibe eine Zeile in Textdatei\n")
end

Der Inhalt der Datei "test.txt" ist dann:

Schreibe eine Zeile in Textdatei

Benutzeroberflächen erstellen[Bearbeiten]

Hier wird nur eine (sehr) kurze Einführung in das Thema GUI mit Gtk (Gimp toolkit, [3]) gegeben. Nähere Details siehe die Gtk.jl-Dokumentation ([4]). Nachfolgend wird ein gegenüber der offiziellen Dokumentation abgewandeltes Beispiel gezeigt. Das ist nötig, um Gtk.jl unter Windows 10 zum Laufen (bzw. um ein Fenster angezeigt) zu bekommen. Das Problem scheint schon seit Langem bekannt zu sein, siehe Gtk.jl, Julia Bindings for Gtk: Gtk Window is not displayed outside the REPL.

using Gtk

win = GtkWindow("Hallo Welt", 400, 200)

b = GtkButton("Push the button")
push!(win,b)

c = Condition()
endit(w) = notify(c)
signal_connect(endit, win, :destroy)
showall(win)
wait(c)

Ausgabe:

Ein etwas komplizierteres (aber zugegebenerweise noch nicht sehr schönes) Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.

using Gtk

win = GtkWindow("Stringverknüpfung")
hbox = GtkBox(:h)
push!(win, hbox)

e1 = GtkEntry() 
l1 = GtkLabel("verknüpfe mit")
e2 = GtkEntry()
b  = GtkButton("=")
l2 = GtkLabel("   ")
push!(hbox, e1)
push!(hbox, l1)
push!(hbox, e2)
push!(hbox, b)
push!(hbox, l2)

function on_button_clicked(b)
  GAccessor.text(l2, get_gtk_property(e1, :text, String) * get_gtk_property(e2, :text, String))
end
signal_connect(on_button_clicked, b, "clicked")

c = Condition()
endit(w) = notify(c)
signal_connect(endit, win, :destroy)
showall(win)
wait(c)

Ausgabe (vor der Eingabe der Teilstrings):

Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):

Ausblick[Bearbeiten]

Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Julia. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks und die Julia-Hilfefunktion verwiesen. Julia kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Pakete fast beliebig erweiterbar.

Weblinks[Bearbeiten]