Julia Inconsistent bounds check for slices - julia

I was writing some code that makes use of array views and slices, but encountered some inconsistencies.
Why does the following not cause an exception:
a = [1,2]
#show a[3:end]
#show a[4:end]
The above all return empty arrays as expected
But this causes a BoundsError
a = [1,2]
#show a[2:3]
Why is the first index of the slice allowed to be larger than the size of the array itself, but Julia seems to have a problem with the last index being larger than the size?
Julia version: 1.3.1

x[c:end] is syntax for getindex(x, UnitRange(c, lastindex(x))).
Any range a:b with a > b is empty. Indexing an array with an empty range will result in an empty array by definition of getindex.
You index an array with an empty range in your first set of examples. In your second set of examples, you index with an out-of-bounds range, which errors as expected.

Related

How to add all arrays from all .fits files in a directory?

I have a directory on my computer with several .fits files that I am trying to work with in IDL. For some reason I am unable to add all of the arrays together correctly, as I'm getting negative numbers in the totaled array when all of the individual elements in all files are positive.
In IDL, I tried the following code:
flatsfiles = file_search(Vflats, filter)
addedflats = make_array(1530,1020,value=0)
FOREACH element, flatsfiles DO BEGIN
flatsarray = readfits(element)
addedflats = [addedflats + flatsarray]
ENDFOREACH
Pretty simple code, yet the values in addedflats are negative, while all the arrays have ONLY positive elements on the order of 10^4. Can anyone see where I'm going wrong, or have a different way of doing this?
I've also tried adding the arrays one by one to see where it goes wrong:
array = readfits(flatsfiles[0])
addedflats = [addedflats + array]
array2 = readfits(flatsfiles[1])
addedflats = [addedflats + array2]
Here, the first addedflats array shows the same thing as array, which is expected since it's just being added to an array of 0's. The second addedflats, however, gives negative numbers again. For reference, the first element of array is 25189, the first element of array2 is 24030, but the first element of addedflats is -16317 rather than the expected 49219. TIA!!
Be careful of integer types that might not be able to hold the sum. Your example is probably 16-bit signed integers (the default integers in IDL):
IDL> print, 25189 + 24030
-16317
To fix, declare at least one of the arrays that you are adding to be an integer type that is big enough to hold there result. Here, 32-bit longs are sufficient (just doing scalars for simplicity, but the same works for arrays):
IDL> print, 25189L + 24030L
49219

Octave: How to assign the right dimensionality to an existing cell array to avoid "error: =: nonconformant arguments (op1 is 2x2x2, op2 is 2x2x2)"?

I am a beginner at Octave, that is why I will share something too obvious for the most.
cell_arr = cell(2,2,2);
cell_arr(2,2,2) = cell(2,2,2);
error: =: nonconformant arguments (op1 is 2x2x2, op2 is 2x2x2)
I am assigning an array of the same dimensionality as the cell_array, and it is not accepted. What should I change?
This is a spin-off from Please Explain Octave-Error : operator /: nonconformant arguments (op1 is 1x1, op2 is 1x10) and Error: nonconformant arguments (op1 is 1x3, op2 is 1x2) which both do not deal with cell arrays.
It's not clear what you're trying to do, but your understanding of cells seems to be a bit confused.
To make matters worse, I think you are coming across a bug: https://savannah.gnu.org/bugs/?func=detailitem&item_id=59637
I don't want to get too technical and confuse you even more, but what is happening here is this. We usually introduce cell arrays by saying this little story:
"There are two kinds of arrays: normal arrays, and cell arrays. Normal arrays always need to be 'rectangular', and contain elements of the same type. Cell arrays on the other hand, can contain elements of different types."
However, this isn't exactly true. It's a simplification. In reality, a 'cell' is simply a special kind of object; a container if you like. And a cell array then, is simply a normal array, whose elements are all 'cell objects'. In fact, the cell command is simply a shortcut way for creating an array of empty cells, nothing more.
More generally, cell arrays are indexed using {}, which opens up the cell object, and gives you its contents.
However, since they can also be thought of as normal arrays of 'cell objects', you can also index it with () like a normal array, and return the 'cell object' itself (as opposed to its contents).
E.g.
a = cell(1,2) # this is equivalent to a = { [], [] }
a{1} # returns an empty numerical array, which is what the first cell contains.
a(1) # returns a cell object, which happens to contain an empty numerical array.
Regarding the bug you're coming across, octave seems to report the wrong size for the elements you're trying to access when it comes to multidimensional cell arrays. This has been reported. What you should have been getting was something like
Error: op1 is 1x1, op2 is 2x2x2
In other words: "you are trying to cram a 2x2x2 array (whose elements happen to be cell objects) into a space that only fits a single element (i.e. at position 2,2,2)."
The reason for the error is that a new cell array can only be assigned to an existing cell array if the dimensions are exactly the same.
cell_arr = cell(2,2,2);
x = cell(2,2,2);
cell_arr(2,2,2) = x;
The last line causes an error, since cell_arr(2,2,2) chooses just the second item of each dimension, and not the 2 items of each dimension. Instead, only the initialisation of cell(2,2,2) builds a cell array of 2 items for each dimension.
It is thus important on which side you are, and whether you initiate or re-use a cell array.
The following works:
cell_arr(:,:,:) = x;
cell_arr(1:2,1:2,1:2) = x;
cell_arr(1:end,1:end,1:end) = x;
cell_arr(:,:,:) = x(1:2,1:2,1:2);
cell_arr(:,:,:) = x(:,:,:);
cell_arr(:,:,:) = x(1:end,1:end,1:end);
Of course, a directly initiated cell array can also be assigned:
cell_arr(:,:,:) = cell(1:2,1:2,1:2);
and this does not work with "end", since it does not exist till then:
cell_arr(1:end,1:end,1:end) = cell(1:end,1:end,1:end);
error: invalid use of 'end': may only be used to index existing value
Thus the solution is as follows, if you want to assign something to cell_arr(2,2,2):
Right: Two cell arrays of 2x2x2 are created.
cell_arr = cell(2,2,2);
x = cell(2,2,2);
And then:
Left: Only the 2nd item of each dim is chosen = 1x1. Right: Thus, only one item can be chosen per dim, for example the first item as follows:
cell_arr(2,2,2) = x(1,1,1);

Return 1-Element Array as Element Type

If I create a Vector of integers
a = Vector(1:3)
and I index one element it has the type of the element
typeof(a[3])
Int64
but if I index one element with a range object it has the type Array
typeof(a[3:3])
Vector{Int64}
How can I make sure that in case of only one element, the element is returned and not the array. The reason is that I want to send the indexed Vector to a function and depending on the type a different method is called.
Why is this happening?
So here's the problem, when you call a[3]
you're actually calling getindex(a, 3)
which has the signature getindex(::AbstractArray, ::Integer).
Your second example is dispatched to a different function, though- getindex(::AbstractArray, ::UnitRange). The behavior of these two functions is different- although they both give what I would expect to see out.
For contrast, both python lists and numpy arrays have the exact same behavior, but it works easier for numpy because numpy doesn't enforce an equal number of dimensions for broadcasting.
What can you do?
First idea: conditional branching using length
a = # ...
return length(a) == 1 ? func(a[1]) : func(a)
Note you can use only(a) instead of a[1] if you're on at least Julia 1.3.
Second idea: if you're programmatically indexing into vector, you could check if the two indices are equal
i = # ... the first index
j = # ... the second index
return i == j ? func(a[i]) : func(a[i:j])
I'm not sure I understand your question correctly, but are you maybe looking for eltype?
julia> eltype(a[3])
Int64
julia> eltype(a[3:3])
Int64
EDIT: Reading #Miles Lucas's answer I see a different interpretation of your question. In this case, the only function might be helpful:
julia> only(a[3])
3
julia> only(a[3:3])
3
Note that this errors if you index with a range longer than 1.

Boolean (BitArray) multidimensional array indexing or masking in Julia?

As part of a larger algorithm, I need to produce the residuals of an array relative to a specified limit. In other words, I need to produce an array which, given someArray, comprises elements which encode the amount by which the corresponding element of someArray exceeds a limit value. My initial inclination was to use a distributed comparison to determine when a value has exceeded the threshold. As follows:
# Generate some test data.
residualLimit = 1
someArray = 2.1.*(rand(10,10,3).-0.5)
# Determine the residuals.
someArrayResiduals = (residualLimit-someArray)[(residualLimit-someArray.<0)]
The problem is that the someArrayResiduals is a one-dimensional vector containing the residual values, rather than a mask of (residualLimit-someArray). If you check [(residualLimit-someArray.<0)] you'll find that it is behaving as expected; it's producing a BitArray. The question is, why doesn't Julia allow to use this BitArray to mask someArray?
Casting the Bools in the BitArray to Ints using int() and distributing using .*produces the desired result, but is a bit inelegant... See the following:
# Generate some test data.
residualLimit = 1
someArray = 2.1.*(rand(10,10,3).-0.5)
# Determine the residuals.
someArrayResiduals = (residualLimit-someArray).*int(residualLimit-someArray.<0)
# This array should be (and is) limited at residualLimit. This is correct...
someArrayLimited = someArray + someArrayResiduals
Anyone know why a BitArray can't be used to mask an array? Or, any way that this entire process can be simplified?
Thanks, all!
Indexing with a logical array simply selects the elements at indices where the logical array is true. You can think of it as transforming the logical index array with find before doing the indexing expression. Note that this can be used in both array indexing and indexed assignment. These logical arrays are often themselves called masks, but indexing is more like a "selection" operation than a clamping operation.
The suggestions in the comments are good, but you can also solve your problem using logical indexing with indexed assignment:
overLimitMask = someArray .> residualLimit
someArray[overLimitMask] = residualLimit
In this case, though, I think the most readable way to solve this problem is with min or clamp: min(someArray, residualLimit) or clamp(someArray, -residualLimit, residualLimit)

Returning a variable-sized matrix from a function in Ada

I'm trying to learn Ada for a course at the University, and I'm having a lot of problems wrapping my head around some of the ideas in it.
My current stumbling block: Let's say I have a function which takes a Matrix (just a 2-dimensional array of Integers), and returns a new, smaller matrix (strips out the first row and first column).
I declare the matrix and function like this:
type MATRIX is array(INTEGER range <>, INTEGER range <>) of INTEGER;
function RemoveFirstRowCol (InMatrix: in MATRIX) return MATRIX is
Then I decide on the size of the Matrix to return:
Result_matrix: MATRIX (InMatrix'First(1) .. InMatrix'Length(1) - 1, InMatrix'First(2) .. InMatrix'Length(2) - 1);
Then I do the calculations and return the Result_matrix.
So here's my problem: when running this, I discovered that if I try to return the result of this function into anything that's not a Matrix declared with the exact proper size, I get an exception at runtime.
My question is, am I doing this right? It seems to me like I shouldn't have to know ahead of time what the function will return in terms of size. Even with a declared Matrix bigger than the one I get back, I still get an error. Then again, the whole idea of Ada is strong typing, so maybe this makes sense (I should know exactly the return type).
Anyways, am I doing this correctly, and is there really no way to use this function without knowing in advance the size of the returned matrix?
Thanks,
Edan
You don't need to know the size of the returned matrix in advance, nor do you need to use an access (pointer) type. Just invoke your function in the declarative part of a unit or block and the bounds will be set automatically:
procedure Call_The_Matrix_Reduction_Function (Rows, Cols : Integer) is
Source_Matrix : Matrix(1 .. Rows, 1 .. Cols);
begin
-- Populate the source matrix
-- ...
declare
Result : Matrix := RemoveFirstRowCol (Source_Matrix)
-- Result matrix is automatically sized, can also be declared constant
-- if appropriate.
begin
-- Process the result matrix
-- ...
end;
end Call_The_Matrix_Reduction_Function;
Caveat: Since the result matrix is being allocated on the stack, you could have a problem if the numbers of rows and columns are large.
Because your MATRIX type is declared with unbound indexes, the type is incomplete. This means that it can be returned by a function. In this case, this acts as it were pointer. Of course the compiler does not know the exact indexes in compile time, the result matrix will always be allocated in heap.
Your solution should be working. The only problem is when you create the result matrix is, that it will work only if the original matrix index starts with 0.
m:MATRIX(11..15,11..20);
In this case m'first(1) is 11, m'length(1) is 5! So you get:
Result_matrix:MATRIX(11..4,11..9);
which is CONSTRAINT_ERROR...
Use the last attribute instead. Even if you usually use with 0 index.
But remember, you do not need to use pointer to the MATRIX because the MATRIX is also incomplete, and that's why it can be used to be returned by a function.
The caller knows the dimensions of the matrix it passes to your function, so the caller can define the type of the variable it stores the function's return value in in terms of those dimensions. Does that really not work?
your function cannot know the size of the result matrix in compile time
you need to return a pointer to the new matrix :
type Matrix is array (Positive range <>, Positive range <>) of Integer;
type Matrix_Ptr is access Matrix;
-- chop the 1'th row and column
function Chopmatrix (
Inputmatrix : in Matrix )
return Matrix_Ptr is
Returnmatrixptr : Matrix_Ptr;
begin
-- create a new matrix with is one row and column smaller
Returnmatrixptr := new Matrix(2 .. Inputmatrix'Last, 2.. Inputmatrix'Last(2) );
for Row in Inputmatrix'First+1 .. Inputmatrix'Last loop
for Col in Inputmatrix'First+1 .. Inputmatrix'Last(2) loop
Returnmatrixptr.All(Row,Col) := Inputmatrix(Row,Col);
end loop;
end loop;
return Returnmatrixptr;
end Chopmatrix ;

Resources