Julia 定义行为类似于堆叠阵列的类型

Julia 定义行为类似于堆叠阵列的类型,julia,Julia,我有一个由多个数组组成的类型 type VectorWrapper{T} x::Vector{T} y::Vector{T} end 我想要向量函数(比如说sumabs2,norm,scale!,copy!,fill!,axpy!,map!,reduce)对这种类型起作用,就好像它是一个叠加向量一样。例如,我想要以下内容: sumabs2(a) <-> sumabs2(a.x) + sumabs2(a.y) copy!(a1, a2) <-> copy!(

我有一个由多个数组组成的类型

type VectorWrapper{T}
   x::Vector{T}
   y::Vector{T}
end
我想要向量函数(比如说
sumabs2
norm
scale!
copy!
fill!
axpy!
map!
reduce
)对这种类型起作用,就好像它是一个叠加向量一样。例如,我想要以下内容:

sumabs2(a) <-> sumabs2(a.x) + sumabs2(a.y)
copy!(a1, a2) <->  copy!(a1.x, a2.x) ; copy !(a1.y, a2.y)
但这并没有表现得那么好:

a = VectorWrapper(rand(10_000_000), rand(10_000_000))
@time sumabs2(a)
# 0.091090 seconds (7 allocations: 208 bytes)
@time sumabs2(a.x) + sumabs2(a.y)
# 0.010433 seconds (7 allocations: 208 bytes)
我猜
sumabs2(a)
sumabs2(a.x)+sumabs2(a.y)
慢,这是因为
getindex
中添加了操作、绑定检查以及缺少SIMD矢量化


是否有一种将1的性能与2的简洁性结合起来的解决方案?

如何定义堆叠阵列
v
作为主要组件,并将
x
y
作为其阵列视图。。。?例如:

type VecWrap{T} <: AbstractVector{T}
    v::Vector{T}
    x::Vector{T}
    y::Vector{T}

    function VecWrap{T}( x_in::Vector{T}, y_in::Vector{T} )
        ( nx, ny ) = ( length( x_in ), length( y_in ) )
        v = Vector{T}( nx + ny )
        v[ 1      : nx      ] = x_in
        v[ (nx+1) : (nx+ny) ] = y_in

        x = pointer_to_array( pointer( v ),       (nx,) )
        y = pointer_to_array( pointer( v, nx+1 ), (ny,) )
        return new( v, x, y )
    end
end

Base.getindex( a::VecWrap, i::Int ) = a.v[ i ]
Base.setindex!( a::VecWrap, val, i::Int ) = ( a.v[ i ] = val )
Base.size( a::VecWrap ) = size( a.v )
Base.copy( a::VecWrap ) = VecWrap{Float64}( a.x, a.y )
Base.copy!( b::VecWrap, a::VecWrap ) = copy!( b.v, a.v )

function test()
    n = 10_000_000
    a = VecWrap{Float64}( rand( n ), rand( n ) )
    for loop = 1:3
        println( "loop = $loop" )
        @time sumabs2( a )
        @time sumabs2( a.x ) + sumabs2( a.y )
        @time sumabs2( a.v )
    end
end

加油!()etc似乎没有问题(尽管没有得到充分证实)。将x和y定义为子阵列似乎也能以几乎相同的效率(0.009-0.011秒)工作。

map
目前可能是一个性能陷阱,您是否尝试过在没有它的情况下编写
size
方法

还有,你看到了吗?它似乎已经在做你想要的事情了

type VecWrap{T} <: AbstractVector{T}
    v::Vector{T}
    x::Vector{T}
    y::Vector{T}

    function VecWrap{T}( x_in::Vector{T}, y_in::Vector{T} )
        ( nx, ny ) = ( length( x_in ), length( y_in ) )
        v = Vector{T}( nx + ny )
        v[ 1      : nx      ] = x_in
        v[ (nx+1) : (nx+ny) ] = y_in

        x = pointer_to_array( pointer( v ),       (nx,) )
        y = pointer_to_array( pointer( v, nx+1 ), (ny,) )
        return new( v, x, y )
    end
end

Base.getindex( a::VecWrap, i::Int ) = a.v[ i ]
Base.setindex!( a::VecWrap, val, i::Int ) = ( a.v[ i ] = val )
Base.size( a::VecWrap ) = size( a.v )
Base.copy( a::VecWrap ) = VecWrap{Float64}( a.x, a.y )
Base.copy!( b::VecWrap, a::VecWrap ) = copy!( b.v, a.v )

function test()
    n = 10_000_000
    a = VecWrap{Float64}( rand( n ), rand( n ) )
    for loop = 1:3
        println( "loop = $loop" )
        @time sumabs2( a )
        @time sumabs2( a.x ) + sumabs2( a.y )
        @time sumabs2( a.v )
    end
end
loop = 1
  0.012153 seconds
  0.009812 seconds
  0.009667 seconds
loop = 2
  0.011365 seconds
  0.009657 seconds
  0.009641 seconds
loop = 3
  0.011350 seconds
  0.009658 seconds
  0.009665 seconds