贡献者: addis
Julia 从 Matlab 和 C/C++ 借鉴了不少语法,如果你两种语言都已经会了,那么 Julia 是十分简单的。本章的目的就是为已经学习过类似语言的读者提供一个 Julia 语言的快速入门笔记。
Ubuntu/Debian 安装方法。
sudo apt install julia
# 或者
sudo snap install Julia --classic
如果版本较老,最好还是从官网下载安装包,直接解压即可使用 bin/julia
执行文件。也可以创建软链 sudo ln -s /home/用户名/julia-xxx/bin/julia /usr/bin/julia
另外本地的 Jupyter Notebook 也支持 Julia。在 julia 命令行里面运行 import Pkg
,Pkg.add("IJulia")
。现在打开 Jupyter notebook 就可以新建 julia 文档了。
至于 IDE,Juno 和 JuliaPro 都已经停止更新,当前(2023-3)最热门的 IDE 环境是 Julia 的 VScode 拓展,应该支持逐行调试。
println("hello world")
会自动换行。print
则没有自动换行。
#
,或者 #=一些注释=#
,多行注释也可以和 python 一样用 """..."""
Ctrl + D
退出或者 exit()
退出
ans
变量和 Matlab 一样,用于显示上一次运算的输出结果(结果赋值给变量的除外)
println("$var1 some words $var2")
中 var1, var2
可以是数字、字符串等,这和 println(var1, " some words ", var2)
等效。其实这是字符串的功能而不是 println
特有的。要避免混淆用 $(var)
。
b = 2a
和 c = 2(b+3)
都可以省略乘号。注意 1/2a
相当于 1/(2a)
2/3
返回双精度类型 Float64
而不是整数
2//3
返回 Rational{Int64}
类型,相当于用两个 Int64
整数来表示分数,分数之间的运算没有误差
1 + 2im
,相当于 ComplexF64(0,2)
。又例如 1//2 + (3//4)im
的类型是 Complex{Rational{Int64}}
typeof()
查看某个变量的类型
::类型
限制变量类型
!
可用于变量名或函数名的非首字符。一般来说,在函数名最后加 !
用于表示该函数的参数会被修改。
typemax(Int64)
,typemin(Int64)
BigInt
和 BigFloat
(底层是 GMP)
nothing
,然后运行垃圾回收 GC.gc()
即可。
typeof(Float64)
是 DataType
。
Array{类型,1}
也叫 Vector{类型}
,不区分行和列;Array{类型,2}
也叫 Matrix{类型}
,区分行向量和列向量。
[1, 2]
和 [1; 2]
的类型是 Array{Int64,1}
,但 [1 2]
的类型是 Array{Int64,2}
类型[1,2,3]
可以创建指定类型的数组。
a = [1 2; 3 4]
得到 Array{Float64,2}
注意不能用逗号,但可以不写 ;
而使用换行。
[1, "abc", 1.2]
的类型是 Vector{Any}
。
[2^i for i = 1:10]
可以用通项公式快速生成一个数组。
push!(v, 元素)
可以在 Vector
后面增加一个元素,同时也会返回新的 v
。pop!(v)
移除最后的元素,返回最后一个元素。
splice!(v, 3:5)
可以删除 v[3:5]
A .= 值
或者 fill!(v, 值)
可以把 v
的每个元素赋值。
a[:, j, :]
size(矩阵, 维度)
,元素个数 length()
,isempty()
检查空矩阵,reverse()
元素倒序排序
findmax(), findmin()
找到矩阵的最大最小元素。
Array{Float64,2}(undef, 2, 3)
创建矩阵,矩阵元不初始化。
zeros(整数)
或 zeros(整数, 整数)
分别返回 Array{Float64,1}
和 Array{Float64,2}
。也可以用 zeros(类型, 整数, 整数)
指定类型。
rand(N1, N2, ...)
或者 rand(类型, N1, N2, ...)
。
hash(矩阵)
,类型为 UInt64
。把运算结果的 hash 输出可以保证计算过程不被优化掉。事实上可以作用于任何对象(包括自定义类型)。
Int64
a[:, 1]
或者 a[1, :]
仍然得到 Array{Int64,2}
a[:, 1] = [3; 4]
可以修改 a
的值
a = b
是浅复制,a
改变了 b
也会改变(同一对象)。
a = copy(b)
是真复制,新生成一个对象。
a === b
来判断是否是同一对象。
b = a[:, 1]
也是真复制。
a
作为参数传给函数是 pass by reference,相当于 C 语言传递指针(有例外,见 Julia 的函数)
Float32[1, 4, 5]
。
Any
。例如 ["a", 1.23]
的类型就是 Vector{Any}
即 Array{Any, 1}
函数.(数组)
可以对数组内的每个元素分别作用,返回数组。例如 sin.([1,2,3])
。sin([1,2,3])
是错误的用法。
exp([1 2;3 4])
是矩阵的指数,exp.([1 2;3 4])
是逐个元素做指数。
collect(1:5)
可以把类似 range 的类型变为 Vector{}
类型。
v .+ 标量
可以把数组的每一个元素加上标量。如果用 +
会出错。同理也有 .+=
。其他算符同理。
矩阵 .+ 行向量
可以对每一行都加行向量。
B = [A; A]
可以拼接矩阵
resize!(矢量, N)
可以用于改变矢量长度,已有的元素值不会改变,新增的元素不初始化。
A = reshape(数组, N1, N2, ...)
或者 A = reshape(数组, (N1, N2, ...))
可以改变数组的形状甚至维度。但改变前后元素个数必须不变。注意 A
和 数组
共享内存,改变一个另一个也会变。
A'
是厄密共轭,转置再取共轭,相当于 conj(transpose(A))
maximum(v)
求最大值,maximum(A,2)
求第二个维度的最大值。
argmax(v)
同理,返回 index。
a[:, 1]
作为参数传给函数是 pass by value,如果需要 by reference,使用 view
函数获取 SubArray
类
SubArray
不存数据,可以用来给函数参数 pass by reference
SubArray
类型的 5 个参数 SubArray{标量类,维数,矩阵类,Tuple{各维度索引类型},是否支持快速索引}
view(a, :, 1)
的类型是 SubArray{Int64,1,Matrix{Int64},Tuple{Base.Slice{Base.OneTo{Int64}},Int64},true}
view(a, 1, :)
的类型是 SubArray{Int64,1,Matrix{Int64},Tuple{Int64,Base.Slice{Base.OneTo{Int64}}},true}
view(a, 1:2, 2:3)
的类型是 SubArray{Int64,2,Matrix{Int64},Tuple{UnitRange{Int64},UnitRange{Int64}},false}
SubArray <: AbstractArray{T,Ndim} <: Any
Array{T,Ndim} <: DenseArray{T,Ndim} <: AbstractArray{T,Ndim} <: Any
AbstractArray
,就可以同时接受 Array, SubArray
。
SubArray
的结构
struct SubArray{T,N,P,I,L} <: AbstractArray{T,N}
parent::P
indices::I
offset1::Int # for linear indexing and pointer, only valid when L==true
stride1::Int # used only for linear indexing
...
end
1:5
等效于 range(1,5)
,类型是 UnitRange{Int64}
Vector(3:5)
。
1:3:9
等效于 StepRange(1, 3, 9)
,类型是 StepRange{Int64, Int64}
注意 StepRange
类型的参数只能是整数。StepRange(1, Int8(3), 9)
的类型是 StepRange{Int64, Int8}
1.2:5.1
(等效于 range(1.2,5.1)
)和 1:0.2:4.1
(等效于 1:0.2:4
和 range(1,4,16)
)的类型是 StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
。range(2,4,3)
虽然每个元素都是整数,但类型也是一样的。
LinRange(初始值,终止值,个数)
概念上是等间距数组,相当于 Matlab 的 linspace
。但类型为 LinRange{Float64, Int64}
。
range(1,2,length=3)
等效于 1.0:0.5:2.0
。
AbstractRange <: AbstractVector <: Any
,都可以像数组一样用 size(x, dim)
来获取尺寸,length()
获取元素个数,可以用 x[i]
获取元素。
p = pointer(v)
可以获取一个数组第一个元素的指针,类型是 Ptr{元素类型}
。unsafe_load(p)
可以获得第一个元素的值 p + sizeof(元素类型)
可以获得下一个元素的指针。
unsafe_store!(p, 值)
可以给指针的元素赋值。
tr(A)
,行列式 det(A)
,逆 inv(A)
,本征值 eigvals(A)
,本征矢 eigvecs(A)
,本征对 tmp = eigen(A)
(tmp.vectors, tmp.values
),LU 分解factorize(A)
Symmetric
,Hermitian
,UpperTriangular
,LowerTriangular
,Tridiagonal
,SymTridiagonal
,Bidiagonal
,Diagonal
using SparseArrays
,然后 S = sparse(行标矢量,列标矢量,非零元矢量)
可以创建 CSC 格式的矩阵:SparseMatrixCSC{矩阵元类型, 指标类型}
using LinearAlgebra.BLAS;m=3;n=4;kl=1;ku=1;alpha=1.;beta=0.;A=rand(kl+ku+1,n);x=rand(Float64,n); y=zeros(Float64,m); gbmv!('N', m, kl, ku, alpha, A, x, beta, y)
其中矩阵尺寸为 m
乘 n
,上下子对角线数量 ku, kl
。
geev!(jobvl, jobvr, A)
;对称矩阵本征问题 syev!(jobz, uplo, A)
;对称三对角矩阵本征问题 stev!(job, dv, ev)
julia <file>
运行脚本,用 julia <file> <arg1> <arg2>
给出 arguments
include("/Users/addis/Desktop/main.jl")
(windows 路径不区分大小写),也支持反斜杠,但要转义成 \\
abspath(PROGRAM_FILE) == @__FILE__
第三方画图包 Plots
,无需安装
using Plots
x = 1:10; y = rand(10); # These are the plotting data
plot(x,y)
b = 3;
for a = 1:5
if a < b
println(a, " < ", b)
elseif a > b
println(a, " > ", b)
else
println(a, " = ", b)
end
end
其中 1:5
的类型是 UnitRange{Int64}
。若令 a = 1:5
,可以使用 a[i]
获取 “元素”。类似地,1:2:5
的类型是 StepRange{Int64, Int64}
。
for i in [1,4,0]
if 条件; 命令; end
函数定义
function sphere_vol(r)
return 4/3*pi*r^3
end
定义含名参数如
function greet(name; greeting="Hello")
println("$greeting, $(name)!")
end
time()
try
一些命令
catch y
if isa(y, 错误类型1)
一些命令
elseif isa(y, 错误类型2)
一些命令
end
end
DomainError
(例如 sqrt(-1)
),BoundsError
(数组指标超出范围)。
要把任意变量存到文件,用 using Serialization
,除此之外常用的还有 using JLD2
。
using Serialization
a = randn(100,100)
f = serialize("file1.dat", a)
a1 = deserialize("file1.dat")
println(a == a1)
pwd()
,更改路径 cd()
readdir()
返回当前路径或指定路径中的文件和文件夹
f = open("文件名", "r")
打开文件读取,close(f)
关闭文件。
eof(f)
用于判断是否到达文件末尾
s = readline(f)
读取下一行
s = read(f, String)
整个文件读入字符串
using DelimitedFiles; m = readdlm("文件名")
从文本文件中读取矩阵
write(file, str)
把字符串写入文本文件
using DelimitedFiles; writedlm("文件名", 矩阵)
把矩阵写入文本文件(用空格与回车)
module 模块名; 定义变量、类型、函数; end
。
import 模块名
后,调用函数(或变量)用 模块名.函数名
,但 using 模块名
后,可以省略 模块名.
using
指定内容,用 using 模块名: 函数1, 函数2, 变量3
。
import 模块名: 函数1, 函数2, 变量3
应该和上一条等效。
import 模块名 as 自定义名
和 python 一样。
@edit 命令
可以查看函数的定义代码,例如 1+1
,sin(1)
。
Main
,在最上层定义的名字(变量,函数等)都可以记为 Main.名字
。
macro mymacro()
quote
println("The value of x is $x")
end
end
quote ... end
结构用于把若干命令打包成一个类型为 Expr
的对象。
@mymacro
,如果当前的 x
有定义就会打出它的值。
@macroexpand @mymacro
来查看宏展开后的代码。