运筹系列41:Julia入门

参考 https://zhuanlan.zhihu.com/p/41953244
还有这篇教程:https://zhuanlan.zhihu.com/p/60889456
详见julia中文文档:http://cn.julialang.org/JuliaZH.jl/latest/

1. 介绍

1.1 背景

Julia是麻省理工学院计算机科学和人工智能实验室(Csil)开发和孵化的一种免费开放源码语言,于2012年发布,目标是结合C的速度与Python的可用性、Ruby的动态性、MATLAB的数学能力和R的统计能力。麻省理工学院说Julia是“petaflop club“中唯一的高级动态语言,在世界第10大超级计算机Cori上被用来模拟1.88亿颗恒星、星系和其他天体,模拟运行只需14.6分钟,使用650000Knights Landing Xeon Phi 核,有1.5千兆秒的运算(每秒四万亿次浮点运算)。
总的来说,目前还是MIT的老师和学生在推Julia。Julia开发都通过GitHub进行(社区驱动),现在上面的代码贡献者有200名左右,稳定的、高度活跃的贡献者约有30名。目前Julia主要用在科学计算上,另外Julia足以胜任的领域之一是教育。下一代学生可以直接跨过现有的技术。IJulia图形化的Notebook集成(运行Julia的IPython Notebook)使之对于教学极具魅力。研究者、算法开发者和库作者也在采用Julia,因为Julia使工作更高效。

1.2 特性

Julia能将工作负载分散到数十万个处理器核,这导致它从机器学习到大规模超级计算机模拟等各个方面的应用。
Julia采用即时编译的策略,底层通过LLVM实现,可以为多个平台编译高效的本地代码。在某些情况下,Julia 可以接近甚至达到 C 语言的速度。我们在下一篇文章会介绍julia的性能提升秘诀。
从本质上来说,Julia更倾向于是一种编译型语言,而不是解释型语言。
Julia的多分派dispatch范式是指允许函数重名,并会在调用时自动根据传入的参数类型进行分派,非常像java/C++中的函数重载,区别在于,C++/Java是在编译时完成分派,而Julia是在运行时完成这一工作。使用它的多分派dispatch范式能表达许多面向对象和函数编程范式,它还有一个非常适合数学运算的语法,有许多数字数据类型和内置的并行支持。
Julia和numpy一样,支持广播机制,可以在GPU和其它向量化硬件上实现高效的优化计算。
Julia 的 Base 包和标准库都是由 Julia 语言编写的。这包括像整数运算那样的基本操作。也就是说,Julia 实现了一定程度的自举。

1.3 安装软件

mac上安装很简单,brew cask install julia即可。如果你已经安装了jupyter notebook的话,直接输入jupyter notebook启动即可。
linux上安装,到julia官网下载julia,然后解压,配置到环境变量中,sudo vim .bashrc,在环境变量中加上这句,注意这里要写你的julia的bin的路径:export PATH="/myapp/julia/bin:$PATH",然后执行终端输入 julia 顺利执行到julia交互界面,到这里就安装成功了,如果想要安装julia notebook环境,就往下看

在julia 交互界面执行

using Pkg
Pkg.add("IJulia")
using IJulia; notebook(detached=true)

然后就安装成功了。

启动julia时有一系列可配置参数:

  • -e:用于直接对跟在后面的表达式进行求值。例如,我们可以输入julia -e 'a = 5 * 8; println(a)'并回车。这时,julia会对单引号内的表达式进行逐一求值。多个表达式之间需要以英文分号;分隔。第二个表达式println(a)在被求值时会在计算机的标准输出上打印40。当所有求值都完成后,julia命令会直接退出(返回命令行提示符)。
  • -E:与-e的功能很类似。但不同的是,追加该参数的julia命令在退出之前还会在标准输出上打印出最后一个表达式的求值结果。上面的第二个表达式println(a)的求值结果会是nothing,表示没有结果值。
  • -p:指定用于处理并行任务的工作进程的数量。跟在它后面的值必须是一个大于 0 的整数,或者为auto(指代当前计算机的 CPU 逻辑核心数)。例如,如果我们输入的命令是julia -p 5,那么工作进程的总数就会是6。这是因为 REPL 环境本身还会占用一个工作进程。如果不追加参数-p,那么 Julia 就不会产生额外的工作进程。
  • -i:用于以交互模式运行命令。这意味着,命令执行后将进入 REPL(Read–eval–print loop)环境。简单来说,这个 REPL 环境就是一个可以与 Julia 的运行时系统进行即时交互的界面。比如,你在这个环境中输入println(“abc”)并回车,它立马就会回显独占一行的abc和一个空行。从字面上我们也可以了解到,该环境会读取你输入的表达式、对读到的表达式进行求值、显示表达式的求值结果,然后再次等待读取。如此循环往复。如果我们在输入julia命令的时候没有追加任何源码文件,那么它就会以交互模式运行。

1.4 安装包

julia的包以xx.jl的方式命名,文件里面用module、end包住。自定义的julia包首先要使用activate命令激活,然后就可以使用import xx或者using导入。当然也可以托管到github上,然后add到本地。
输入julia进入julia PERL,然后输入Pkg.add(“PackageName”)安装包;也可以按 ] 键进入pkg模式。接着就可以使用using或者import来调用包了:

julia> using IJulia
[ Info: Precompiling IJulia [7073ff75-c697-5162-941a-fcdaad2a7d2a]
julia> notebook()

Julia目前所有包均可在https://juliapackages.com/上找到。常用包介绍如下:

基本数据结构:DataFrames
交互:CSV, JSON, XLSX
随机数:Random,StatsFuns
微分方程:DifferentialEquations
线性代数:LinearAlgebra,IterativeSolvers
统计:Turing(贝叶斯),Distributions,StatsBase,Regression,MixedModels,CurveFit,Interpolations,MultivariateAnalysis,HypothesisTests,POMDPs(马尔科夫决策过程模拟),HMMBase,TimeSeries
凸优化:JuMP(建模)、Convex(凸优化)、GeneticAlgorithms(遗传算法)
绘图:Gadfly(科学绘图)、Plots(可视化),注意这个包的依赖比较大,国内要改一下下载代码:https://zhuanlan.zhihu.com/p/115118883
图论:LightGraphs
机器学习:Flux
深度学习:Knet
写作:Latexify

1.5 各种小技巧

  • 各种模式:输入;可以进入shell模式,相当于ipython下的!号;输入 ] 键进入pkg模式。
  • 注释:单行注释类似python,用#;多行注释用#=和=#;也可以用markdown注释方式,前后都用"""围起来即可
  • 快捷键:除了Ctrl+c之外,Julia 的 REPL 环境还支持不少的快捷键。在 macOS 操作系统中,最常用的快捷键有:
    Option+←:将光标移动到左边最近的单词开始处。
    Option+→:将光标移动到右边最近的单词末尾处之后。
    Ctrl+d:退出julia命令,回到原始的命令行。
    Ctrl+e:将光标移动到当前行的末尾处之后。
    Ctrl+a:将光标移动到当前行的开始处。
    Ctrl+l:清除当前界面中的历史命令,或称清屏。
    Ctrl+r:向后搜索历史命令。
    Ctrl+s:向前搜索历史命令。
  • 多进程:使用-p n起n个进程
  • 分布式:使用--machine-file file会对file中的每一行启动一个worker。
  • 传参:使用PROGRAM_FILE获取文件名,使用ARGS获取参数列表
$ echo 'println(PROGRAM_FILE); for x in ARGS; println(x); end' > script.jl
$ julia script.jl foo bar
script.jl
foo
bar
  • 列举变量:varinfo()方法会列出所有当前存储的变量和模块。
  • 上次结果:用ans表示
julia> x = 1
1
julia> ans + 1
2
  • 特殊字符:可以输入`+符号名称的方式来输入更多的Unicode数学字符,如\alpha后按tab键就会出现α的字符。
  • 类型的最大最小值:typemin和typemax
(typemin(Int32), typemax(Int32))
>>(-2147483648, 2147483647)
typemax(Int64)+1
>>-9223372036854775808

2. 数据结构

2.1 变量和常量

Julia 是一种可选类型化的编程语言。Julia 代码中的任何值都是有类型的。而一个区别在于,一个值的类型是由我们显式指定的,还是由 Julia 在自行推断之后附加上的。例如:

julia> typeof(2020)
Int64

在 Julia 中,变量的类型也是可以改变的,只有值才有类型。但为了描述方便,我们仍然会说“变量的类型”。虽然 Julia 允许我们随意改变一个变量的类型,但是这样做往往会对程序的性能造成不小的负面影响。我们可以在编程的时候用附加类型标识符的方式让变量的类型固定下来,比如:y::Int64操作符::可以将类型标识符附加到程序中的变量和表达式之后。下面是它的两个重要用途:

  1. 它可以用于类型标注,为编译器提供额外的类型信息,从而在某些情况下提高程序的性能。当用于类型标注时,操作符::及其右侧的类型标识符就意味着这个变量将永远是某个类型的。
  2. 它可以用于类型断言,判断某个值或者某个表达式的结果是否是某个类型的.

我们可以使用关键字const来定义一个常量。在 Julia 中,常量是一种特殊的变量:const A = 2020
下面是一些规范:变量名尽量小写;类型和模块名首字母大写,单词间使用驼峰式分隔;一般不鼓励使用下划线;函数名和宏名使用小写字母,不使用下划线。

关于变量作用域,变量默认都是local的,使用global可以突破限制。注意下面的1:5是UnitRange类型,如果是1:2:5,则是StepRange类型。
在这里插入图片描述

2.2 数值类型

Julia 属于动态类型语言。在Julia的类型图中,Any是一个唯一的顶层类型,union是唯一一个底层类型。Julia 中具体的数值类型一共有 19 个。罗列如下:
布尔类型:Bool
有符号整数类型:BigInt、Int8、Int16、Int32、Int64和Int128
无符号整数类型:UInt8、UInt16、UInt32、UInt64和UInt128
浮点数类型:BigFloat、Float16、Float32和Float64
复数类型:Complex
有理数类型:Rational
无理数类型:Irrational
在这里插入图片描述
抽象类型不能被实例化,而Int64/Float64等都是抽象类型的具体类型,抽象类型不能直接使用,类似于C++中的抽象类。抽象类型有:

abstract type Number end
abstract type Real     <: Number end
abstract type AbstractFloat <: Real end
abstract type Integer  <: Real end
abstract type Signed   <: Integer end
abstract type Unsigned <: Integer end

2.3 复合类型

也叫自定义类型,类的替代物。
在这里插入图片描述

2.4 参数化类型

初学者看懂julia的代码,这段是关键。
参数化(parametric)允许类型自身包含参数,并使得一个这样的类型就可以代表整个类型族群,类似于c++中的template。像Ref{T}这样的参数化类型,我们可以用任何一个类型的名称替换掉T,从而表示一种确定的类型,如Ref{String},这样我们就用一个表达式,涵盖了所有的数据类型:
在这里插入图片描述

Julia 已经预定义了不少的参数化类型,对它们的进一步说明如下:

  • Ref{T}:它是专门用来做引用的类型。要想让它成为某一个类型的引用类型,我们就需要在其花括号中填入那个类型的名称。例如,Ref{UInt32}就表示针对UInt32类型的引用类型。
  • Union{Types…}:这个类型的花括号中可以有多个类型名称,叫做类型共用体。这使它可以表示为针对那些类型的联合类型,从而让那些类型的值都成为这个联合类型的实例。例如,Union{Integer, AbstractString}就联合了Integer类型和AbstractString类型,从而使整数值和字符串值都变成了它的实例。
    在这里插入图片描述
  • Complex{T<:Real}:代表复数的的类型。因为复数的实部和虚部都必须是实数,所以Complex类型的参数一定要是Real类型的子类型。
  • SubString{T<:AbstractString}:代表子字符串的类型。由于子字符串值只能基于字符串值创建,因此SubString类型的参数必须继承自AbstractString。

在类型定义中,操作符<:用于表示当前类型直接继承自哪一个抽象类型,可以在定义和声明中使用:

julia> abstract type Jewelry end
julia> struct Necklace <: Jewelry end
julia> struct Ring <: Jewelry end
julia> mutable struct JewelryShop{T<:Jewelry}
           showcase1::Showcase{Necklace}
           showcase2::Showcase{Ring}
           showcase3::Showcase{Jewelry}
           showcase4::Showcase{T}
       end

最后是UnionAll类型,用于对参数的类型进行界定:
在这里插入图片描述

2.5 元组

元组(tuple)是一种很简单的容器。它可以包含若干个任意类型的元素值。

julia> Drawer{Necklace} <: Drawer{Jewelry}, Drawer{Ring} <: Drawer{Jewelry}
(false, false)

julia> typeof(ans)
Tuple{Bool,Bool}

简单的结构体可以用括号来表示,本质上是一个元组,叫namedTuple,使用.进行调用。
在这里插入图片描述
collect()可以将 tuple 转换为 array:

julia> collect((1,2,3))
3-element Array{Int64,1}:
 1
 2
 3

元组类型的最后一个参数可以是Vararg,表示后面可以跟任意多个参数:
在这里插入图片描述

2.6 字典

字典使用关键字Dict定义,并且用=>进行赋值,中间这种=>叫做pair,pair数组可以强制转换为dict。字典使用[ ]进行调用:

julia> d = Dict("a"=>1, "b"=>2, "c"=>3);
julia> a = Dict([(1, "a"), (2, "b"), (3, "c")])
Dict{Int64,String} with 3 entries:
  2 => "b"
  3 => "c"
  1 => "a"
julia> a[1]
"a"
julia> links = Tuple((s[i],e[i]) for i in 1:N) #其中s和e是两个列表
julia> Dict(links .=> c) #其中links和c是key和value的列表。

使用value可以获得包含所有值的迭代器。

2.7 字符串

首先是一些基础知识:

  • ASCII:美国标准代码-信息交换。
  • Unicode 是一个针对书面字符和文本的通用字符编码标准。它定义了多语言文本数据在国际间交换的统一方式,并为全球化软件创建了基础。Unicode 编码标准以 ASCII 编码集作为出发点,并突破了 ASCII 只能对拉丁字母进行编码的限制。在 Unicode 编码标准中,代码空间由从0到10FFFF的十六进制整数组成。这就意味着,有 1114112 个代码点可以用于表示抽象字符。Unicode 编码标准的惯用法是使用十六进制形式来表示代码点的数值,并使用U+作为前缀。比如,英文字母字符’a’的 Unicode 代码点就是U+0061。在 Unicode 编码标准的模型中,编码格式用于确定怎样将代码空间中的每一个整数(或者说代码点)都表示成包含若干个代码单元的序列。
  • Unicode 编码标准中存在多种编码格式。其中有一种编码格式叫做 UTF-8。UTF 是 Unicode Transformation Format 的缩写。

对于字符和字符串,Julia 通常都会采用 UTF-8 编码格式将它们转换成二进制数并进行存储。

julia> 'a'
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
julia> '\u4e2d'
'中': Unicode U+4e2d (category Lo: Letter, other)

然后是字符串基本操作:

  • 搜索:用findfirst、findprev、findnext
  • 拼接:可以直接用逗号,可以用*拼接(注意和python用+不一样),可以用cmd里面的$(变量索引):
    在这里插入图片描述
  • 替换、分割、合并:replace用=>,split默认用空格,使用join合并数组
    在这里插入图片描述

2.8 向量、矩阵

在julia中,数组和矩阵都是Array格式,和numpy不一样。高于二维的数组,需要使用reshape的方式定义。

  • 向量:定义为Array{T}(undef, dims) ,undef是UndefInitializer()的缩写
    列向量:[1;2;3]
    行向量:[1 2 3]
    显式声明:p = Array{Float64}(undef, 3, 1)
    向量的元素可以是tuple:pairs = Array{Tuple{Int64,Int64}}(undef, 3),或者这样声明:pairs = [(2,3),(1,2),(3,4)]
    如果要初始化,则用fill:fill(1.0, (2,3))

  • 矩阵:其实就是二维向量,比如[1 2 3;4 5 6]
    下标访问:A[1,2]
    转置:transpose(A)或A’
    函数和numpy基本一致

使用[:]的方式进行数组/矩阵拷贝。
在这里插入图片描述

再来看矩阵拼接中的三种方式:

  • , :相当于np.array([a,b])
  • ;:相当于np.vstack([a,b])
    • 空格:相当于np.hstack([a,b])

在这里插入图片描述
矩阵运算分两种,逐点计算和矩阵计算:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果还是不会用,就使用numpy吧:
在这里插入图片描述

2.9 range和循环

注意在julia中,array和range的下标从1开始!。python中的range(N)在julia中用1:N表示,数据类型为UnitRange或者StepRange
julia的循环使用end结束,没有:并且不需要缩进,和python不一样

julia> tuple3 = (10, 20, 30, 40, 50);

julia> for e in tuple3
           println(e)
       end
10
20
30
40
50

2.10 常用数学函数

# 比较运算,支持链式比较```1 <= 2 <= 3 == 3 <=5 >4 >=2```
# 进位函数
round(x)        #四舍五入
floor(x)        #向下取整
ceil(x)         #向上取整
trunc(x)        #trunc是直接砍掉小数,在正数的时候trunc跟floor一样,负数时跟ceil一样
# 除法函数
div(x,y)        #取模
fld(x,y)        #取小于结果的最大整数
cld(x,y)        #取大于结果的最小整数
rem(x,y)        #取余
mod(x,y)        
mod1(x,y1)      #如果x是y的整数倍,则返回y,不会返回余数
mod2pi(x)       #对2pi取余
divrem(x,y)     #返回取模的值和取余的值
fldmod(x,y)     #返回取小于x的最大整数和取余的值
gcd(x,y...)     #最大公约数
lcm(x,y...)     #最小公倍数
# 符号函数
abs(x)          #求模
abs2(x)         #求平方
sign(x)         #取符号
signbit(x)      #正数返回false,负数返回true
copysign(x,y)   #返回x * sign(y)
flipsign(x,y)   #返回x * sign(y) * -1
# 开根号 log
sqrt(x)         #开根号
cbrt(x)         #开三次根
hypot(x,y)      #sqrt(x^2 + y^2)
exp(x)          #e^x
expm1(x)        #e^-x
ldexp(x,n)      #x^n
log(x)          #loge(x)
log(b,x)        #logb(x)
log2(x)         #log2(x)     
log10(x)        #log10(x)
log1p(x)        #loge(1+x)
# 三角函数
sin    cos    tan    cot    sec    csc
sinh   cosh   tanh   coth   sech   csch
asin   acos   atan   acot   asec   acsc
asinh  acosh  atanh  acoth  asech  acsch
sinc   cosc

3. 函数

3.1 声明

使用function...end定义函数,用两个冒号::来断言具体变量类型(注意不是声明!julia的变量没有类型)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
使用@doc funcname可以看到函数前面的注释。
local变量可以强制转类型,需要先声明再赋值。注意字符串转数字要用parse。
在这里插入图片描述

3.2 调用

修改参数的函数结尾使用!,这样的函数被称为mutating functions或in-place functions
函数可以用于map和reduce中,也可以加在管道后面
在这里插入图片描述
下面是个使用管道的网红自动问答系统:
在这里插入图片描述

Julia 预定义了非常丰富的数学函数。一些常用的函数如下:

  • 数值类型转换: 主要有T(x)和convert(T, x)。其中,T代表目的类型,x代表源值。
  • 数值特殊性判断: 有isequal、isfinite、isinf和isnan。
  • 舍入: 有四舍五入的round(T, x)、向正无穷舍入的ceil(T, x)、向负无穷舍入的floor(T, x),以及总是向0舍入的trunc(T, x)。
  • 除法: 有cld(x, y)、fld(x, y)和div(x, y),它们分别会将商向正无穷、负无穷和0做舍入。其中的x代表被除数,y代表除数。另外,与之相关的还有取余函数rem(x, y)和取模函数mod(x, y),等等。
  • 公约数与公倍数: 函数gcd(x, y…)用于求取最大正公约数,而函数lcm(x, y…)则用于求取最小正公倍数。圆括号中的…的意思是,除了x和y,函数还允许传入更多的数值。但要注意,这里的数值都应该是整数。
  • 符号获取: 函数sign(x)和signbit(x)都用于获取一个数值的符号。但不同的是,前者对于正整数、0和负整数会分别返回1、0和-1,而后者会分别返回false、false和true。
  • 绝对值获取: 用于获取绝对值的函数是abs(x)。一个相关的函数是,用于求平方的abs2(x)。
  • 求根: 函数sqrt(x)用于求取x的平方根,而函数cbrt(x)则用于求取x的立方根。
  • 求指数: 函数exp(x)会求取x的自然指数。另外还有expm1(x),为接近0的x计算exp(x)-1。
  • 求对数: log(x)会求取x的自然对数,log(b, x)会求以b为底的x的对数,而log2(x)和log10(x)则会分别以2和10为底求对数。另外还有log1p(x),为接近0的x计算log(1+x)。

3.3 匿名函数、多返回值、可变参数

用->表示匿名函数,用…表示多参数
在这里插入图片描述

3.4 方法重载

在这里插入图片描述
在这里插入图片描述
注意这里x…表示将数组元素拆开:
在这里插入图片描述
在这里插入图片描述

3.5 多重分派

分派就是指根据变量的类型选择相应的方法,单分派指的是指根据第一个参数类型去选择方法。

下面我们举一个Python中的例子来做解释,Python因为在函数定义时是不知道参数类型的,所以一般没有单分派;但Python中提供了单分派的修饰符,可以实现单分派的功能。

from functools import singledispatch

@singledispatch
def func(arg, verbose=False):
    print('initial...\n')

@func.register(int)
def _(arg, verbose=False):
    print(arg)

func(1)
>>1
func(2.3)
>>initial...

3.6 控制流

复合表达式 : begin(;)
条件求值 : if-elseif-else?: (ternary operator)
短路求值 : &&,||chained comparisons
重复求值: whilefor
异常处理 : try-catcherrorthrow
任务(也称为协程) : yieldto
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.7 表达式

在这里插入图片描述
使用dump来查看symbol,使用eval来解析symbol:
在这里插入图片描述

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
运筹优化Python是使用Python编程语言进行运筹优化问题建模和求解的过程。运筹优化是一种数学方法,用于优化决策问题,例如最大化利润或最小化成本。Python是一种功能强大的编程语言,具有丰富的库和工具,可以帮助我们在运筹优化中进行问题建模和求解。 通过使用Python,您可以使用线性规划库来解决线性规划问题。这些库包装了本机求解器,可以提供解决方案状态、决策变量值、松弛变量、目标函数等结果信息。一些常用的Python线性规划库包括GLPK、LP Solve、CBC、CVXOPT、SciPy等。 此外,还有一些商业求解器提供了Python API,如Gurobi Optimization。Gurobi是一家提供快速商业求解器的公司,他们还提供关于线性规划和混合整数线性规划的宝贵资源,包括基础知识、教程和如何选择数学规划求解器的指南。 总之,运筹优化Python是指使用Python编程语言进行运筹优化问题建模和求解的过程,可以通过使用线性规划库或商业求解器的Python API来解决问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [运筹优化学习26:Python求解线性规划问题入门手册](https://blog.csdn.net/m1m2m3mmm/article/details/112579384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值