朱莉娅:为特定大小的向量制作类型

时间:2018-07-06 21:49:03

标签: vector types julia

我正在尝试在Julia中为具有三个元素的向量定义类型(结构?)。我认为我找到的最接近Optimally passing dimensions of fixed size array in juliaDeclare the size of an array attribute in a type definition的东西,但是它们是0.6之前的版本,因为不可变不再是一回事。而且,这似乎是错误的。

用例是我知道函数要使用的向量的大小

function myFunc(v::threeVec,u::threeVec)
    Do stuff to u and v
end

进一步的搜索使我想到了构造函数。 https://docs.julialang.org/en/stable/manual/constructors/ 我特别看到了例子

struct OrderedPair
           x::Real
           y::Real
           OrderedPair(x,y) = x > y ? error("out of order") : new(x,y)
       end

但是,这是一个单独的对象,即使这样,我也不确定如何将类似的东西传递给函数。我考虑改用三元组,因为它们的类型为Tuple(Int,Int,Int),但是我要对u和v进行矢量/矩阵算术运算,所以我不必转换它们。

我可以在函数内部检查向量的长度,但是我读到一些提示,由于调度程序的原因,它首选使用类型。对于此特定功能,在这种情况下,这是一种合理的实现方式,但是在其他用例中,这可能不是一个好主意,因此我现在想以“正确的方式”来实现。

1 个答案:

答案 0 :(得分:2)

有很多方法可以处理这种情况;我将根据您提供的想法在下面概述其中一些。

选项1:StaticArrays

StaticArrays.jl软件包提供对定长数组的支持。

using StaticArrays
const ThreeVec{T} = SVector{3,T}

function myFunc(u::ThreeVec, v::ThreeVec)
    u .+ v  # example functionality
end

仅当两个参数的长度均为3的myFunc时,此实现才允许调用SVector

julia> myFunc(SVector(1, 2, 3), SVector(4, 5, 6))
3-element SArray{Tuple{3},Int64,1,3}:
 5
 7
 9

julia> myFunc(SVector(1, 2, 3), SVector(4, 5))
ERROR: MethodError: no method matching myFunc(::SArray{Tuple{3},Int64,1,3}, ::SArray{Tuple{2},Int64,1,2})
Closest candidates are:
  myFunc(::SArray{Tuple{3},T,1,3} where T, ::SArray{Tuple{3},T,1,3} where T) at REPL[13]:2

还可以使用内部构造函数定义自定义类型,以断言长度正确。但是,除了潜在的低效率之外,这还要求您重载各种方法来支持StaticArrays已处理的自定义类型。

选项2:元组

取决于您计划执行的向量/矩阵算术运算,元组可能已经可以通过广播原生支持该功能。例如,尽管不能添加元组,但是可以在其元素上广播添加。

julia> u = (1, 2, 3);
       v = (4, 5, 6);

julia> u + v  # not allowed
ERROR: MethodError: no method matching +(::Tuple{Int64,Int64,Int64}, ::Tuple{Int64,Int64,Int64})
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
Stacktrace:
 [1] top-level scope at none:0

julia> u .+ v  # element-wise broadcasting
(5, 7, 9)

选项3:运行时错误

如果您想对内置Vector类型进行操作,则只要输入无效就可以抛出错误,将错误处理从编译转移到运行时。

function myFunc(u::Vector, v::Vector)
    length(u) == 3 || throw(ArgumentError("Invalid length of (u = $u), should be 3"))
    length(v) == 3 || throw(ArgumentError("Invalid length of (v = $v), should be 3"))
    u .+ v  # example functionality
end