There's still a simple model: the indices are the *key* of the entry. Think
about an array as a very special Dict. You could create a Dict with integer
keys, let's say from -2:5. Presumably you wouldn't be exactly happy if
there were some magical way that the number you originally stored as `d[-1]
= 3.2` were alternatively accessible as `d[2]`, simply because the smallest
index was -2 and therefore 3.2 is the "second" entry?

Like a Dict, for an array the value always goes with the key (the indices).
Perhaps this will help:
```
julia> using OffsetArrays

julia> a = OffsetArray(rand(11), -5:5)
OffsetArrays.OffsetArray{Float64,1,Array{Float64,1}} with indices -5:5:
 0.815289
 0.0043941
 0.00403153
 0.478065
 0.150709
 0.256156
 0.934703
 0.672495
 0.428721
 0.242469
 0.43742

julia> idx = OffsetArray(-1:1, -1:1)
OffsetArrays.OffsetArray{Int64,1,UnitRange{Int64}} with indices -1:1:
 -1
  0
  1

julia> b = a[idx]
OffsetArrays.OffsetArray{Float64,1,Array{Float64,1}} with indices -1:1:
 0.150709
 0.256156
 0.934703

julia> a[-1]
0.15070935766983662

julia> b[-1]
0.15070935766983662
```
So indexing `b = a[idx]` means that `b[j] = a[idx[j]]`. Does that help?

Best,
--Tim

On Tue, Nov 1, 2016 at 3:36 PM, Bob Portmann <bobportm...@gmail.com> wrote:

> Like I said, no real practical experience yet. The increase in complexity
> that I fear is the loss of, e.g., writing arr[2,3] and having it not be the
> element in the 2nd row and third column (i.e., the loss of a simple model
> of how things are laid out). Maybe my fears are unfounded. Others don't
> seem concerned it would seem.
>
> I'll check out those packages that you mention.
>
> Thanks,
> Bob
>
> On Sun, Oct 30, 2016 at 2:29 PM, Tim Holy <tim.h...@gmail.com> wrote:
>
>> I'm afraid I still don't understand the claimed big increment in
>> complexity. First, let's distinguish "generic offset arrays" from the
>> OffsetArrays.jl package. If you're happy using OffsetArrays, you don't have
>> to write your own offset-array type. Being able to use an established &
>> tested package reduces your burden a lot, and you can ignore the second
>> half of the devdocs page entirely.
>>
>> If you just want to *use* OffsetArrays.jl, the basic changes in coding
>> style for writing indices-aware code are:
>>
>> - any place you used to call `size`, you probably want to call `indices`
>> instead (and likely make minor adjustments elsewhere, since `incides`
>> returns a tuple-of-ranges---but such changes tend to be very obvious);
>> - check all uses of `similar`; some will stay as-is, other will migrate
>> to `similar(f, inds)` style.
>>
>> In my experience, that's just about it. The devdocs goes into quite a lot
>> of detail to explain the rationale, but really the actual changes are quite
>> small. While you can't quite do it via `grep` and `sed`, to me that just
>> doesn't seem complicated.
>>
>> Where the pain comes is that if you're converting old code, you sometimes
>> have to think your way through it again---"hmm, what do I really mean by
>> this index"? If your code had complicated indexing the first time you wrote
>> it, unfortunately you're going to have to think about it carefully again;
>> so in some cases, "porting" code is almost as bad as writing it the first
>> time. However, if you write indices-aware code in the first place, in my
>> experience the added burden is almost negligible, and in quite a few cases
>> the ability to offset array indices makes things *easier* (e.g., "padding"
>> an array on its edges is oh-so-much-clearer than it used to be, it's like a
>> different world). That's the whole reason I implemented this facility in
>> julia-0.5: to make life easier, not to make it harder. (Personally I think
>> the whole argument over 0-based and 1-based indexing is stupid; it's the
>> ability to use arbitrary indices that I find interesting & useful, and it
>> makes most of my code prettier.)
>>
>> For examples of packages that use OffsetArrays, check the following:
>> - CatIndices
>> - FFTViews
>> - ImageFiltering
>>
>> ImageFiltering is a mixed bag: there's a small performance penalty in a
>> few cases (even if you use @unsafe) because that LLVM doesn't always
>> optimize code as well as it could in principle (maybe @polly will help
>> someday...). Because image filtering is an extraordinarily
>> performance-sensitive operation, there are a few places where I had to make
>> some yucky hand optimizations.
>>
>> Again, I'm very happy to continue this conversation---I'd really like to
>> understand your concern, but without a concrete example I confess I'm lost.
>>
>> Best,
>> --Tim
>>
>>
>> On Sat, Oct 29, 2016 at 8:44 PM, Bob Portmann <bobportm...@gmail.com>
>> wrote:
>>
>>> Thanks for the thoughtful response. I hope you'll tolerate one reply in
>>> the "abstract".
>>>
>>> I am resisting the big change that occurred in 0.5. In 0.4 and earlier
>>> if one declares an array as an `AbstractArray` in a function then one knew
>>> that the indices were one based (a nice simple model, even if it is hated
>>> by many). In 0.5, if one wants to write general code, then one has to
>>> assume that arrays can have ANY indices. And one needs to write code using
>>> more abstract tools. This seems to me to be a large cost in complexity for
>>> the small subset of cases where offset indices are helpful. This is the
>>> core issue to me.
>>>
>>> One way around this, it would seem, is to declare arrays as `::Array`
>>> and not `::AbstractArray` in functions (if one want to be sure they are
>>> `OneTo`). But then one gives up accepting many types of arrays that would
>>> pose no problem (e.g, DistributedArrays with OneTo indices). Thus, I'm
>>> proposing to have a high level abstract type that would capture all arrays
>>> types that can be assumed to be `OneTo`. Then one can write library
>>> functions against that type. This alone would help I think.
>>>
>>> The auto-conversion is an extra step that I thought might work since it
>>> is (I think) low cost to convert an `OffsetArray` to a `OneTo` array . Thus
>>> if you passed an OffsetArray to a function that takes the abstract OneTo
>>> type (I kept its name AbstractArray above but that need not be its name)
>>> you expect that if it returned a `similar` array it would be of `OneTo`
>>> type. You would then have to convert it back to an OffsetArray type. It
>>> would probably be easy to write one line functions to do this for you. If
>>> it was sparse I assume it would remain so. It would be up to the writer of
>>> the new OffsetArray type to declare what type it would convert to in the
>>> OneTo array abstract tree.
>>>
>>> Does this help?
>>>
>>> Bob
>>>
>>> ps I don't have any concrete examples yet because OffsetArrays are so
>>> scarce in the julia ecosystem. I'm just looking ahead to a world where it
>>> will no longer be possible to assume AbstractArrays are OneTo. This seems
>>> more painful than telling the 0-based crowd to code against 1-based arrays.
>>>
>>>
>>> On Sat, Oct 29, 2016 at 10:40 AM, Tim Holy <tim.h...@gmail.com> wrote:
>>>
>>>> I should add, abstract discussions are all well and good, but I fully
>>>> recognize you may have something very specific in mind and my answer
>>>> simply
>>>> fails to understand your concern. If you can give one or more concrete
>>>> examples of where the current system is either bug-prone or a pain in
>>>> the
>>>> neck, I'd love to see what you mean.
>>>>
>>>> Best,
>>>> --Tim
>>>>
>>>> On Thursday, October 27, 2016 5:21:26 PM CDT Bob Portmann wrote:
>>>> > TL;DR I think the type system should take care of converting between
>>>> > different types of arrays and thus free the user to code against the
>>>> type
>>>> > of array they want (OneTo, ZeroTo, Offset, etc).
>>>> >
>>>> > Maybe I have a deep mis-understanding of how the new generalized
>>>> offset
>>>> > arrays are suppose to work in Julia. If so I'd be happy to be set
>>>> straight.
>>>> > If not then I think the present system will lead to unnecessary
>>>> complexity
>>>> > and bug-ridden code. In the present system one can define array types
>>>> that
>>>> > are not one-based but can have arbitrary offsets. This is a great
>>>> idea but
>>>> > to make it work a very general system for indexing relative to the
>>>> ends of
>>>> > the array has been devised. If one writes a function that accepts an
>>>> > `AbstractArray` then one MUST use this more general system or produce
>>>> bugs
>>>> > when e.g. a `ZeroToArray` is passed in. This puts a large burden on
>>>> writers
>>>> > of library code that works on arrays and I think is an unnecessary
>>>> > complexity.
>>>> >
>>>> > Since Fortran arrays are a nice example let look at the situation in
>>>> > Fortran. If I define an array in a function `real arr(-10:10)` then I
>>>> would
>>>> > index it using indices that range from -10 to 10. If I pass this into
>>>> > another function that declared the array using its total size (usually
>>>> > passed in separately or in a parameter statement) `real arr(21)` then
>>>> in
>>>> > that subroutine one would index the array using "normal" indices that
>>>> range
>>>> > from 1 to 21. I.E., you state in the function how you want to treat
>>>> the
>>>> > array and are not forced to work with in offset form unless you want
>>>> to. In
>>>> > my opinion, this is what makes using offset arrays in Fortran sane
>>>> and is
>>>> > the key thing that Julia should try to emulate.
>>>> >
>>>> > One way to get this behavior in Julia would be to use the type system
>>>> and
>>>> > `convert`. Since `AbstractArray` has meant until 0.5 a `OneTo` array I
>>>> > think it is wise that it remain that way so that all old code will
>>>> work
>>>> > unchanged (even with the new array types). Thus, I propose adding a
>>>> new
>>>> > top-level type above AbstractArray type to capture all arrays
>>>> something
>>>> > like:
>>>> >
>>>> > ```
>>>> > Array{T,N} <: DenseArray{T,N} <: AbstractArray{T,N} <:
>>>> > AbstractAllArray{T,N} <: Any
>>>> > ```
>>>> >
>>>> > And the offset arrays would be subtypes of `AbstractAllArrays` on a
>>>> > different branch
>>>> >
>>>> > ```
>>>> > OffsetArray{T,N} <: AbstractOffsetArray{T,N} <: AbstractAllArray{T,N}
>>>> <: Any
>>>> > ```
>>>> >
>>>> > And similarly for `ZeroToArray`.
>>>> >
>>>> > Then, if one declares an Array as
>>>> >
>>>> > ```
>>>> > function func(arr::AbstractArray)
>>>> > ```
>>>> >
>>>> > one can safely assume it is a 1-based Array inside `func`. If an
>>>> offset
>>>> > array is passed into `func` then it is automatically converted to a
>>>> `OneTo`
>>>> > array inside `func`. This is the key point of this proposal and is
>>>> similar
>>>> > to the auto-conversion of, e.g., Int to Floats in a function call.
>>>> > Similarly if one declares an array as a `ZeroToArray` in a function
>>>> and
>>>> > passes in an `Array` then it will be converted to a `ZeroToArray` in
>>>> the
>>>> > function. Some conversions would need more information and thus would
>>>> be
>>>> > disallowed (e.g., `Array` to `OffsetArray`). I think this system
>>>> would go a
>>>> > long way towards making `ZeroToArray`s and `OffsetArray`s simple to
>>>> use in
>>>> > Julia w/o using the generalized indexing techniques introduced in
>>>> Julia
>>>> > 0.5. Note that it would still be possible to use the
>>>> `AbstractAllArray`
>>>> > type and accept all arrays w/o conversion and use the generalized
>>>> indexing
>>>> > techniques.
>>>> >
>>>> > I'm curious what people think about this.
>>>> >
>>>> > Bob
>>>> >
>>>> > ps Paste into github to see in formatted form. I'm not sure how to
>>>> get that
>>>> > in an email.
>>>>
>>>>
>>>>
>>>
>>
>

Reply via email to