如何从规则矩阵继承

BAR*_*BAR 1 julia

using ShiftedArrays

struct CircularMatrix{T} <: AbstractArray{T,2}
    data::Array{T,2}
    view::CircShiftedArray
    currentIndex::Int
    function CircularMatrix{T}(dims...) where T
        data = zeros(T, dims...)
        CircularMatrix(data, ShiftedArrays.circshift(data, (0, -1)), 1)
    end
end

Base.size(M::CircularMatrix) = size(M.data)
Base.eltype(::Type{CircularMatrix{T}}) where {T} = T

function shift_forward!(M::CircularMatrix)
    M.shift_forward!(1)
end

function shift_forward!(M::CircularMatrix, n)
    # replace the view with a view shifted forwards.
    M.currentIndex += n
    M.view = ShiftedArrays.circshift(M.data, (n, M.currentIndex))
end

@inline Base.@propagate_inbounds function Base.getindex(M::CircularMatrix, i) = M.view[i]
@inline Base.@propagate_inbounds function Base.setindex!(M::CircularMatrix, data, i) = M.view[i] = data

Run Code Online (Sandbox Code Playgroud)

如何使CircularMatrix像常规矩阵一样工作。这样我就可以像访问它

m = CircularMatrix{Int}(4,4)
m[1, 1] = 5
x = view(m, 1, :)
Run Code Online (Sandbox Code Playgroud)

hck*_*ckr 5

您的矩阵类型被定义为的子类型AbstractArray{T, 2}。您需要在Julia的非正式数组接口中为您的类型实现一些方法,以使可以使用的函数和功能AbstractArray{T, 2}也可以在您的自定义类型上使用,即,使您CircularMatrix的可迭代,可索引,完全起作用的矩阵。

实现的方法是

  1. size(M::CircularMatrix)
  2. getindex(M::CircularMatrix, i::Int)
  3. getindex(M::CircularMatrix, I::Vararg{Int, N})
  4. setindex!(M::CircularMatrix, v, i::Int)
  5. setindex!(M::CircularMatrix, v, I::Vararg{Int, N})

您已经实现了1、2和4,但尚未设置索引样式。如果选择线性索引样式,则可能不需要3和5 。您只需将设置IndexStyleIndexLinear(),可能需要进行一些修改,然后一切都应适用于您的矩阵。

1。 size(M::CircularMatrix)

第一个是sizesize(A::CircularMatrix)返回Tuple尺寸为的A。我相信您的矩阵可能类似于以下内容

Base.size(M::CircularMatrix) = size(M.data)
Run Code Online (Sandbox Code Playgroud)

2。 getindex(M::CircularMatrix, i::Int)

如果选择线性索引样式,则需要此方法。getindex(M, i::Int)应该给您线性索引的值i。您已经在代码中实现了它。如果选择线性索引,则需要设置IndexStyle类型,然后只需跳过3和5。Julia将自动将多个索引访问(例如a[3, 5])转换为线性索引访问。

Base.IndexStyle(::Type{<:CircularMatrix}) = IndexLinear()

Base.@propogate_inbounds function Base.getindex(M::CircularMatrix, i::Int)
    @boundscheck checkbounds(M, i)
    @inbounds M.view[i]
end
Run Code Online (Sandbox Code Playgroud)

@inbounds在第二行使用此处可能会更好。如果调用者不使用@inbounds,我们将首先检查边界,这有望使后续边界检查变得不必要。不过,您可能需要在开发过程中忽略此设置。

3。 getindex(M::CircularMatrix, I::Vararg{Int, N})

第三个是笛卡尔索引风格。如果选择此样式,则需要实现此方法。Vararg{Int, N}签名中的“确切N Int参数”代表。在这里N应等于的维数CircularMatrix。由于这是一个矩阵,因此N应该为2。如果选择此样式,则需要定义以下内容

Base.@propogate_inbounds function Base.getindex(A::CircularMatrix, I::Vararg{Int, 2})
    @boundscheck checkbounds(A, I...)
    @inbounds A.view[# convert I[1]` and `I[2]` to a linear index in `view`]
end
Run Code Online (Sandbox Code Playgroud)

或者由于您的维度不是参数化的并且矩阵是2D的,

 Base.@propogate_inbounds function Base.getindex(A::CircularMatrix, i::Int, j::Int)
    @boundscheck checkbounds(A, i, j)
    @inbounds A.view[# convert i` and `j` to a linear index in `view`]
end
Run Code Online (Sandbox Code Playgroud)

4。 setindex!(M::CircularMatrix, v, i::Int)

第四个类似于第二个。i如果选择线性索引样式,则此方法应将值设置为线性索引。

5。 setindex!(M::CircularMatrix, v, I::Vararg{Int, N})

如果选择笛卡尔索引风格,则第五个应该与第三个相似。


在实现1、2和4并设置之后IndexStyle,您应该拥有一个可以正常使用的自定义矩阵类型。

m[1, 1] = 5
x = view(m, 1, :)

for e in 
  ...
end

for i in eachindex(m)
  ...
end

display(m)
println(m)
length(m)
ndims(m)
map(f, A)
....
Run Code Online (Sandbox Code Playgroud)

这些都应该起作用。

一些注意事项

  • 有抽象阵列一个文档界面这里有几个例子。您还可以查看要实施的可选方法

  • 有一个JuliaArray GitHub上组织,提供许多有用的定制阵列,包括实现StaticArraysOffsetArrays等,并且还一个JuliaMatrices组织,提供自定义矩阵类型。您可能想看看它们的实现。

  • @inline如果使用,则是多余的Base.@propogate_inbounds

@propagate_inbounds

告诉编译器内联函数,同时保留调用者的入站上下文。

  • 你并不需要定义eltype为您的矩阵,因为已经有一个定义,AbstractArray{T, N}它的回报T