-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ndarray: getindex/setindex! linear indexing #294
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -312,6 +312,9 @@ function eltype(arr :: T) where T <: Union{NDArray, MX_NDArrayHandle} | |
end | ||
end | ||
|
||
@inline _first(arr::NDArray) = try_get_shared(arr, sync = :read) |> first | ||
|
||
Base.first(arr::NDArray) = _first(arr) | ||
|
||
""" | ||
slice(arr :: NDArray, start:stop) | ||
|
@@ -341,37 +344,58 @@ function slice(arr :: NDArray, slice::UnitRange{Int}) | |
return NDArray(MX_NDArrayHandle(hdr_ref[]), arr.writable) | ||
end | ||
|
||
function _at(handle::Union{MX_NDArrayHandle, MX_handle}, idx::Integer) | ||
h_ref = Ref{MX_handle}(C_NULL) | ||
@mxcall(:MXNDArrayAt, (MX_handle, MX_uint, Ref{MX_handle}), | ||
handle, idx, h_ref) | ||
h_ref[] | ||
end | ||
|
||
import Base: setindex! | ||
|
||
""" | ||
setindex!(arr :: NDArray, val, idx) | ||
setindex!(arr::NDArray, val, idx) | ||
|
||
Assign values to an `NDArray`. Elementwise assignment is not implemented, only the following | ||
scenarios are supported | ||
Assign values to an `NDArray`. | ||
The following scenarios are supported | ||
|
||
* single value assignment via linear indexing: `arr[42] = 24` | ||
|
||
* `arr[:] = val`: whole array assignment, `val` could be a scalar or an array (Julia `Array` | ||
or `NDArray`) of the same shape. | ||
* `arr[start:stop] = val`: assignment to a *slice*, `val` could be a scalar or an array of | ||
the same shape to the slice. See also [`slice`](@ref). | ||
""" | ||
function setindex!(arr :: NDArray, val :: Real, ::Colon) | ||
@assert(arr.writable) | ||
function setindex!(arr::NDArray, val::Real, idx::Integer) | ||
# linear indexing | ||
@assert arr.writable | ||
_set_value(out=arr[idx], src=val) | ||
end | ||
|
||
function setindex!(arr::NDArray, val::Real, ::Colon) | ||
@assert arr.writable | ||
_set_value(out=arr, src=convert(eltype(arr), val)) | ||
return arr | ||
end | ||
function setindex!(arr :: NDArray, val :: Array{T}, ::Colon) where T<:Real | ||
|
||
function setindex!(arr::NDArray, val::Array{T}, ::Colon) where T<:Real | ||
@assert arr.writable | ||
copy!(arr, val) | ||
end | ||
function setindex!(arr :: NDArray, val :: NDArray, ::Colon) | ||
|
||
function setindex!(arr::NDArray, val::NDArray, ::Colon) | ||
@assert arr.writable | ||
copy!(arr, val) | ||
end | ||
function setindex!(arr :: NDArray, val :: Union{T,Array{T},NDArray}, idx::UnitRange{Int}) where T<:Real | ||
|
||
function setindex!(arr::NDArray, val::Union{T,Array{T},NDArray}, | ||
idx::UnitRange{Int}) where T<:Real | ||
@assert arr.writable | ||
setindex!(slice(arr, idx), val, Colon()) | ||
end | ||
|
||
import Base: getindex | ||
""" | ||
getindex(arr :: NDArray, idx) | ||
getindex(arr::NDArray, idx) | ||
|
||
Shortcut for [`slice`](@ref). A typical use is to write | ||
|
||
|
@@ -396,18 +420,43 @@ which furthur translates into | |
create a **copy** of the sub-array for Julia `Array`, while for `NDArray`, this is | ||
a *slice* that shares the memory. | ||
""" | ||
function getindex(arr :: NDArray, ::Colon) | ||
function getindex(arr::NDArray, ::Colon) | ||
return arr | ||
end | ||
|
||
""" | ||
Shortcut for [`slice`](@ref). **NOTE** the behavior for Julia's built-in index slicing is to create a | ||
copy of the sub-array, while here we simply call `slice`, which shares the underlying memory. | ||
Shortcut for [`slice`](@ref). | ||
**NOTE** the behavior for Julia's built-in index slicing is to create a | ||
copy of the sub-array, while here we simply call `slice`, | ||
which shares the underlying memory. | ||
""" | ||
function getindex(arr :: NDArray, idx::UnitRange{Int}) | ||
function getindex(arr::NDArray, idx::UnitRange{Int}) | ||
slice(arr, idx) | ||
end | ||
|
||
getindex(arr::NDArray) = _first(arr) | ||
|
||
function getindex(arr::NDArray, idx::Integer) | ||
# linear indexing | ||
len = length(arr) | ||
size_ = size(arr) | ||
|
||
if idx <= 0 || idx > len | ||
throw(BoundsError( | ||
"attempt to access $(join(size_, 'x')) NDArray at index $(idx)")) | ||
end | ||
|
||
idx -= 1 | ||
offsets = size_[1:end-1] |> reverse ∘ cumprod ∘ collect | ||
handle = arr.handle | ||
for offset ∈ offsets | ||
handle = _at(handle, idx ÷ offset) | ||
idx %= offset | ||
end | ||
|
||
_at(handle, idx) |> MX_NDArrayHandle |> x -> NDArray(x, arr.writable) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is kinda weird to return a one element array and also not common in Julia. The problem is if we convert it to a Julia value at this point we impose a synchronisation barrier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with the weirdness, Python provide an API looks like this x[42] |> first # do synchronisation and get the value and keep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can send a PR for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 for the BTW: I feel I'm pretty out-dated about the latest Julian things when I see the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
end | ||
|
||
import Base: copy!, copy, convert, deepcopy | ||
|
||
""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#TBD
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(at first I wrote this patch, the issue number was still unknown)
I will send a PR to sort them out for releasing.