] status
5 Arbeit mit Julia: REPL, Pakete, Introspection
5.1 Dokumentation
Die offizielle Julia-Dokumentation https://docs.julialang.org/ enthält zahlreiche Übersichten, darunter:
- https://docs.julialang.org/en/v1/base/punctuation/ Verzeichnis der Symbole
- https://docs.julialang.org/en/v1/manual/unicode-input/ Verzeichnis spezieller Unicode-Symbole und deren Eingabe in Julia via Tab-Vervollständigung
- https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions Liste mathematischer Funktionen
5.2 Julia REPL (Read - Eval - Print - Loop)
Nach dem Start von Julia in einem Terminal kann man neben Julia-Code auch verschiedene Kommandos eingeben
Kommando | Wirkung |
---|---|
exit() oder Ctrl-d |
exit Julia |
Ctrl-c |
interrupt |
Ctrl-l |
clear screen |
Kommando mit ; beenden |
Ausgabe unterdrückt |
include("filename.jl") |
Datei mit Julia-Code einlesen und ausführen |
Der REPL hat verschiedene Modi:
Modus | Prompt | Modus starten | Modus verlassen |
---|---|---|---|
default | julia> |
Ctrl-d (beendet Julia) |
|
Package manager | pkg> |
] |
backspace |
Help | help?> |
? |
backspace |
Shell | shell> |
; |
backspace |
5.3 Jupyter-Notebooks (IJulia)
In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Input-Zelle nutzbar:
- ein Kommando des Paket-Managers:
- eine Help-Abfrage:
?sin
- Ein Shell-Kommando:
;ls
5.4 Der Paketmanager
Wichtiger Teil des Julia Ecosystems sind die zahlreichen Pakete, die Julia erweitern.
- Einige Pakete sind Teil jeder Julia-Installation und müssen nur mit einer
using Paketname
-Anweisung aktiviert werden.- Sie bilden die sogenannte Standard Library und dazu gehören
LinearAlgebra
,Statistics
,SparseArrays
,Printf
,Pkg
und andere.
- Über 9000 Pakete sind offiziell registriert, siehe https://julialang.org/packages/.
- Diese können mit wenigen Tastendrücken heruntergeladen und installiert werden.
- Dazu dient der package manager
Pkg
. - Man kann ihn auf zwei Arten verwenden:
- als normale Julia-Anweisungen, die auch in einer
.jl
-Programmdatei stehen können:
using Pkg Pkg.add("PaketXY")
- im speziellen pkg-Modus des Julia-REPLs:
] add PaketXY
- als normale Julia-Anweisungen, die auch in einer
- Anschließend kann das Paket mit
using PaketXY
verwendet werden.
- Man kann auch Pakete aus anderen Quellen und selbstgeschriebene Pakete installieren.
5.4.1 Einige Funktionen des Paketmanagers
Funktion | pkg - Mode |
Erklärung |
---|---|---|
Pkg.add("MyPack") |
pkg> add MyPack |
add MyPack.jl to current environment |
Pkg.rm("MyPack") |
pkg> remove MyPack |
remove MyPack.jl from current environment |
Pkg.update() |
pkg> update |
update packages in current environment |
Pkg.activate("mydir") |
pkg> activate mydir |
activate directory as current environment |
Pkg.status() |
pkg> status |
list packages |
Pkg.instantiate() |
pg> instantiate |
install all packages according to Project.toml |
5.4.2 Installierte Pakete und Environments
- Julia und der Paketmanager verwalten
- eine Liste der mit dem Kommando
Pkg.add()
bzw.]add
explizit installierten Pakete mit genauer Versionsbezeichnung in einer DateiProject.toml
und - eine Liste aller dabei auch als implizite Abhängigkeiten installierten Pakete in der Datei
Manifest.toml
.
- eine Liste der mit dem Kommando
- Das Verzeichnis, in dem diese Dateien stehen, ist das
environment
und wird mitPkg.status()
bzw.]status
angezeigt. - Im Normalfall sieht das so aus:
(@v1.10) pkg> status
Status `~/.julia/environments/v1.10/Project.toml`
[6e4b80f9] BenchmarkTools v1.5.0
[5fb14364] OhMyREPL v0.5.24
[91a5bcdd] Plots v1.40.4
[295af30f] Revise v3.5.14
- Man kann für verschiedene Projekte eigene
environments
benutzen. Dazu kann man entweder Julia mit
julia --project=path/to/myproject
starten oder in Julia das environment mit Pkg.activate("path/to/myproject")
aktivieren. Dann werden Project.toml, Manifest.toml
dort angelegt und verwaltet. (Die Installation der Paketdateien erfolgt weiterhin irgendwo unter $HOME/.julia
)
5.4.3 Zum Installieren von Paketen auf unserem Jupyter-Server misun103
:
- Es gibt ein zentrales Repository, in dem alle in diesem Kurs erwähnten Pakete bereits installiert sind.
- Dort haben Sie keine Schreibrechte.
- Sie können aber zusätzliche Pakete in Ihrem
HOME
installieren. Dazu ist als erster Befehl nötig, das aktuelle Verzeichnis zu aktivieren:
] activate .
(Man beachte den Punkt!)
Danach können Sie mit add
im Pkg-Modus auch Pakete installieren:
] add PaketXY
Achtung! Das kann dauern! Viele Pakete haben komplexe Abhängigkeiten und lösen die Installation von weiteren Paketen aus. Viele Pakete werden beim Installieren vorkompiliert. Im REPL sieht man den Installationsfortschritt, im Jupyter-Notebook leider nicht.
5.5 Der Julia JIT (just in time) Compiler: Introspection
Julia baut auf die Werkzeuge des LLVM Compiler Infrastructure Projects auf.
Stages of Compilation
stage & result | introspection command |
---|---|
Parse \(\Longrightarrow\) Abstract Syntax Tree (AST) | Meta.parse() |
Lowering: transform AST \(\Longrightarrow\) Static Single Assignment (SSA) form | @code_lowered |
Type Inference | @code_warntype , @code_typed |
Generate LLVM intermediate representation | @code_llvm |
Generate native machine code | @code_native |
function f(x,y)
= x^2 + log(y)
z return 2z
end
f (generic function with 1 method)
= Meta.parse( "function f(x,y); z=x^2+log(y); return 2x; end ") p
:(function f(x, y)
#= none:1 =#
#= none:1 =#
z = x ^ 2 + log(y)
#= none:1 =#
return 2x
end)
using TreeView
walk_tree(p)
@code_lowered f(2,4)
CodeInfo(
1 ─ %1 = Main.Notebook.:+
│ %2 = Main.Notebook.:^
│ %3 = Core.apply_type(Base.Val, 2)
│ %4 = (%3)()
│ %5 = Base.literal_pow(%2, x, %4)
│ %6 = Main.Notebook.log
│ %7 = (%6)(y)
│ z = (%1)(%5, %7)
│ %9 = Main.Notebook.:*
│ %10 = z
│ %11 = (%9)(2, %10)
└── return %11
)
@code_warntype f(2,4)
MethodInstance for Main.Notebook.f(::Int64, ::Int64)
from f(x, y) @ Main.Notebook ~/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd:196
Arguments
#self#::Core.Const(Main.Notebook.f)
x::Int64
y::Int64
Locals
z::Float64
Body::Float64
1 ─ %1 = Main.Notebook.:+::Core.Const(+)
│ %2 = Main.Notebook.:^::Core.Const(^)
│ %3 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│ %4 = (%3)()::Core.Const(Val{2}())
│ %5 = Base.literal_pow(%2, x, %4)::Int64
│ %6 = Main.Notebook.log::Core.Const(log)
│ %7 = (%6)(y)::Float64
│ (z = (%1)(%5, %7))
│ %9 = Main.Notebook.:*::Core.Const(*)
│ %10 = z::Float64
│ %11 = (%9)(2, %10)::Float64
└── return %11
@code_typed f(2,4)
CodeInfo(
1 ─ %1 = Base.mul_int(x, x)::Int64
│ %2 = Base.sitofp(Float64, y)::Float64
│ %3 = invoke Base.Math.log(%2::Float64)::Float64
│ %4 = Base.sitofp(Float64, %1)::Float64
│ %5 = Base.add_float(%4, %3)::Float64
│ %6 = Base.mul_float(2.0, %5)::Float64
└── return %6
) => Float64
@code_llvm f(2,4)
; Function Signature: f(Int64, Int64)
; @ /home/hellmund/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd:196 within `f`
define double @julia_f_16465(i64 signext %"x::Int64", i64 signext %"y::Int64") #0 {
top:
; @ /home/hellmund/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd:197 within `f`
; ┌ @ intfuncs.jl:370 within `literal_pow`
; │┌ @ int.jl:88 within `*`
%0 = mul i64 %"x::Int64", %"x::Int64"
; └└
; ┌ @ math.jl:1529 within `log`
; │┌ @ float.jl:374 within `float`
; ││┌ @ float.jl:348 within `AbstractFloat`
; │││┌ @ float.jl:239 within `Float64`
%1 = sitofp i64 %"y::Int64" to double
; │└└└
; │ @ math.jl:1531 within `log`
%2 = call double @j_log_16471(double %1)
; └
; ┌ @ promotion.jl:429 within `+`
; │┌ @ promotion.jl:400 within `promote`
; ││┌ @ promotion.jl:375 within `_promote`
; │││┌ @ number.jl:7 within `convert`
; ││││┌ @ float.jl:239 within `Float64`
%3 = sitofp i64 %0 to double
; │└└└└
; │ @ promotion.jl:429 within `+` @ float.jl:491
%4 = fadd double %2, %3
; └
; @ /home/hellmund/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd:198 within `f`
; ┌ @ promotion.jl:430 within `*` @ float.jl:493
%5 = fmul double %4, 2.000000e+00
; └
ret double %5
}
@code_native f(2,4)
.text
.file "f"
.globl julia_f_16642 # -- Begin function julia_f_16642
.p2align 4, 0x90
.type julia_f_16642,@function
julia_f_16642: # @julia_f_16642
; Function Signature: f(Int64, Int64)
; ┌ @ /home/hellmund/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd:196 within `f`
# %bb.0: # %top
; │ @ /home/hellmund/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd within `f`
#DEBUG_VALUE: f:x <- $rdi
#DEBUG_VALUE: f:y <- $rsi
push rbp
mov rbp, rsp
push rbx
push rax
mov rbx, rdi
; │ @ /home/hellmund/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd:197 within `f`
; │┌ @ intfuncs.jl:370 within `literal_pow`
; ││┌ @ int.jl:88 within `*`
imul rbx, rdi
; │└└
; │┌ @ math.jl:1529 within `log`
; ││┌ @ float.jl:374 within `float`
; │││┌ @ float.jl:348 within `AbstractFloat`
; ││││┌ @ float.jl:239 within `Float64`
vcvtsi2sd xmm0, xmm0, rsi
; ││└└└
; ││ @ math.jl:1531 within `log`
movabs rax, offset j_log_16648
call rax
; │└
; │┌ @ promotion.jl:429 within `+`
; ││┌ @ promotion.jl:400 within `promote`
; │││┌ @ promotion.jl:375 within `_promote`
; ││││┌ @ number.jl:7 within `convert`
; │││││┌ @ float.jl:239 within `Float64`
vcvtsi2sd xmm1, xmm1, rbx
; ││└└└└
; ││ @ promotion.jl:429 within `+` @ float.jl:491
vaddsd xmm0, xmm0, xmm1
; │└
; │ @ /home/hellmund/Julia/23/Book-ansipatch/chapters/5_TricksHelp.qmd:198 within `f`
; │┌ @ promotion.jl:430 within `*` @ float.jl:493
vaddsd xmm0, xmm0, xmm0
; │└
add rsp, 8
pop rbx
pop rbp
ret
.Lfunc_end0:
.size julia_f_16642, .Lfunc_end0-julia_f_16642
; └
# -- End function
.type ".L+Core.Float64#16644",@object # @"+Core.Float64#16644"
.section .rodata,"a",@progbits
.p2align 3, 0x0
".L+Core.Float64#16644":
.quad ".L+Core.Float64#16644.jit"
.size ".L+Core.Float64#16644", 8
.set ".L+Core.Float64#16644.jit", 128627131790624
.size ".L+Core.Float64#16644.jit", 8
.section ".note.GNU-stack","",@progbits