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)
您的矩阵类型被定义为的子类型AbstractArray{T, 2}。您需要在Julia的非正式数组接口中为您的类型实现一些方法,以使可以使用的函数和功能AbstractArray{T, 2}也可以在您的自定义类型上使用,即,使您CircularMatrix的可迭代,可索引,完全起作用的矩阵。
实现的方法是
size(M::CircularMatrix)getindex(M::CircularMatrix, i::Int)getindex(M::CircularMatrix, I::Vararg{Int, N})setindex!(M::CircularMatrix, v, i::Int)setindex!(M::CircularMatrix, v, I::Vararg{Int, N})您已经实现了1、2和4,但尚未设置索引样式。如果选择线性索引样式,则可能不需要3和5 。您只需将设置IndexStyle为IndexLinear(),可能需要进行一些修改,然后一切都应适用于您的矩阵。
size(M::CircularMatrix)第一个是size。size(A::CircularMatrix)返回Tuple尺寸为的A。我相信您的矩阵可能类似于以下内容
Base.size(M::CircularMatrix) = size(M.data)
Run Code Online (Sandbox Code Playgroud)
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,我们将首先检查边界,这有望使后续边界检查变得不必要。不过,您可能需要在开发过程中忽略此设置。
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)
setindex!(M::CircularMatrix, v, i::Int)第四个类似于第二个。i如果选择线性索引样式,则此方法应将值设置为线性索引。
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上组织,提供许多有用的定制阵列,包括实现StaticArrays,OffsetArrays等,并且还一个JuliaMatrices组织,提供自定义矩阵类型。您可能想看看它们的实现。
@inline如果使用,则是多余的Base.@propogate_inbounds。
@propagate_inbounds
告诉编译器内联函数,同时保留调用者的入站上下文。
eltype为您的矩阵,因为已经有一个定义,AbstractArray{T, N}它的回报T。| 归档时间: |
|
| 查看次数: |
67 次 |
| 最近记录: |