How to iterate over whole array when I need i, j, k? - julia

Given A is a multi-dimensional array, can I collapse iteration through every element into one for statement if I need i,j,k,etc.? In other words, I am looking for a more compact version of the following:
for k in 1:size(A,3)
for j in 1:size(A,2)
for i in 1:size(A,1)
# Do something with A[i+1,j,k], A[i,j+1,k], A[i,j,k+1], etc.
end
end
end
I think the solution is with axes or CartesianIndices, but I can't get the syntax right. Failed attempts:
julia> for (i,j,k) in axes(A)
println(i)
end
1
1
1
julia> for (i,j,k) in CartesianIndices(A)
println(i)
end
ERROR: iteration is deliberately unsupported for CartesianIndex. Use `I` rather than `I...`, or use `Tuple(I)...`
It would be great if in addition to a solution which defines i,j,k, you could also provide a solution that works regardless of the number of dimensions in A.

You are almost there. Read the message carefully:
ERROR: iteration is deliberately unsupported for CartesianIndex.
It is the "pattern matching" in (i,j,k) in CartesianIndices(...) that fails, not the approach in general (I made the same mistake when reproducing the problem!). You have to convert the individual CartesianIndexes to tuples first:
julia> for ix in CartesianIndices(A)
println(Tuple(ix))
end
(1, 1, 1)
(2, 1, 1)
(3, 1, 1)
(1, 2, 1)
(2, 2, 1)
(3, 2, 1)
...

or using axes:
for (i,j,k) in Iterators.product(axes(x)...)
println([i,j,k]) # or whatever else you want
end

Related

Isn't there a nicer way to combine multiple `Union{T, Nothing}`

I'm very new to Julia but I've got a some background in Scheme/Rust/F#.
Today I wanted to make yesterday's AoC nicer without an explicit number of nested loops.
I arrived at this working solution, but I don't like the last if. In the languages mentioned above I would call a function (or use a computation expression) that gives me the first result that is not None. For Julia, I expected something to do that. It does, but unexpectedly in an eager fashion.
So When I tried return something(find(r, n, start + 1, which), find(r, n - 1, start + 1, extended)), that also evaluated the second argument when the first already had a result—and thus crashed.
Is there a macro/lazy version or something that I didn't find? How are you supposed to handle a case like that?
I also thought about (short-circuited) or'ing them together, but I guess Julia's strictness in that matter spoils that.
using DataStructures
function find(r::Array{Int}, n, start = 1, which = nil())::Union{Int,Nothing}
if start <= length(r)
extended = cons(start, which)
with_current = sum(i -> r[i], extended)
if with_current == 2020 && n == 1
return prod(i -> r[i], extended)
else
# Unfortunately no :(
#return something(find(r, n, start + 1, which), find(r, n - 1, start + 1, extended))
re = find(r, n, start + 1, which)
if isnothing(re)
return find(r, n - 1, start + 1, extended)
else
re
end
end
end
end
Let me comment more on it why it is not possible given the discussion in the comments.
In Julia function arguments are evaluated eagerly, so Julia evaluates both find(r, n, start + 1, which) and find(r, n - 1, start + 1, extended) before passing them to something function.
Now, with macros you have (I am not writing in a fully general case for simplicity and I hope I got the hygiene right :)):
julia> macro something(x, y)
quote
local vx = $(esc(x))
isnothing(vx) ? $(esc(y)) : vx
end
end
#something (macro with 1 method)
julia> #something 1 2
1
julia> #something nothing 2
2
julia> #something 1 sqrt(-1)
1
julia> #something nothing sqrt(-1)
ERROR: DomainError with -1.0:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
(in a full-blown version of the macro varargs and Some should be handled to replicate something exactly)
Piqued by Bogumił's answer I wanted to write my first Julia macro. It took some time and numerous attempts to figure out syntax, hygiene and escaping but I'm quite happy now.
I thought it might be worth sharing and provide opportunity for suggestions/improvements.
A lazy #something analog to Base.something
function _something_impl(thing)
:(something($(esc(thing))))
end
function _something_impl(thing, rest...)
quote
local evalued = $(esc(thing))
if isnothing(evalued)
$(_something_impl(rest...))
else
something(evalued)
end
end
end
macro something(things...)
_something_impl(things...)
end
Version without exceptions
As I found exceptions raised from a macro like this not quite suitable, I also made a version that falls back to nothing.
function _something_nothing_impl(thing)
quote
local evaluated = $(esc(thing))
if isa(evaluated, Some)
evaluated.value
else
evaluated
end
end
end
function _something_nothing_impl(thing, rest...)
quote
local evalued = $(esc(thing))
if isnothing(evalued)
$(_something_nothing_impl(rest...))
else
something(evalued)
end
end
end
macro something_nothing(things...)
_something_nothing_impl(things...)
end
Now I guess the recursive middle function could also generated by a macro. :)

Robot in a Grid - how to get all possible paths

I'm trying to solve this problem:
There is a grid with with r rows and c columns. A robot sitting in top left cell can only move in 2 directions, right and down. But certain cells have to be avoided and the robot cannot step on them. Find a path for the robot from the top left to the bottom right.
The problem specifically asks for a single path, and that seems straight forward:
Having the grid as boolean[][], the pseudocode I have is
List<String> path = new ArrayList<String>()
boolean found = false
void getPath(r, c){
if (!found) {
if ( (r or c is outofbounds) || (!grid[r][c]) )
return
if (r==0 AND c==0) // we reached
found = true
getPath(r-1, c)
getPath(r, c-1)
String cell = "(" + r + ", " + c + ")"
path.add(cell)
}
}
Though I was wondering how can I get all the possible paths (NOT just the count, but the path values as well). Note that it has r rows and c columns, so its not a nxn grid. I'm trying to think of a DP/recursive solution but unable to come up with any and stuck. It's hard to think when the recursion goes in two ways.
Any pointers? And also any general help on how to "think" about such problems would be appreciated :).
Any pointers? And also any general help on how to "think" about such problems would be appreciated :).
Approach to the problem:
Mentally construct graph G of the problem. In this case the vertices are cells in the grid and directed edges are created where a valid robot move exist.
Search for properties of G. In this case G is a DAG (Directed Acyclic Graph).
Use such properties to come up with a solution. In this case (G is a DAG) its common to use topological sort and dynamic programming to find the amount of valid paths.
Actually you don't need to construct the graph since the set of edges is pretty clear or to do topological sort as usual iteration of the matrix (incremental row index and incremental column index) is a topological sort of this implicit graph.
The dynamic programming part can be solved by storing in each cell [x][y] the amount of valid paths from [0][0] to [x][y] and checking where to move next.
Recurrence:
After computations the answer is stored in dp[n - 1][m - 1] where n is amount of rows and m is amount of columns. Overall runtime is O(nm).
How about find all possible valid paths:
Usual backtracking works and we can speed it up by applying early pruning. In fact, if we calculate dp matrix and then we do backtracking from cell [n - 1][m - 1] we can avoid invalid paths as soon the robot enters at a cell whose dp value is zero.
Python code with dp matrix calculated beforehand:
n, m = 3, 4
bad = [[False, False, False, False],
[ True, True, False, False],
[False, False, False, False]]
dp = [[1, 1, 1, 1],
[0, 0, 1, 2],
[0, 0, 1, 3]]
paths = []
curpath = []
def getPath(r, c):
if dp[r][c] == 0 or r < 0 or c < 0:
return
curpath.append((r, c))
if r == 0 and c == 0:
paths.append(list(reversed(curpath)))
getPath(r - 1, c)
getPath(r, c - 1)
curpath.pop()
getPath(n - 1, m - 1)
print(paths)
# valid paths are [[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3)],
# [(0, 0), (0, 1), (0, 2), (1, 2), (1, 3), (2, 3)],
# [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 3)]]
Notice that is very similar to your code, there is a need to store all valid paths together and take care that appended lists are a copy of curpath to avoid ending up with an list of empty lists.
Runtime: O((n + m) * (amount of valid paths)) since simulated robot moves belong to valid paths or first step into an invalid path detected using foresight (dp). Warning: This method is exponential as amount of valid paths can be .

Get a number from an array of digits

To split a number into digits in a given base, Julia has the digits() function:
julia> digits(36, base = 4)
3-element Array{Int64,1}:
0
1
2
What's the reverse operation? If you have an array of digits and the base, is there a built-in way to convert that to a number? I could print the array to a string and use parse(), but that sounds inefficient, and also wouldn't work for bases > 10.
The previous answers are correct, but there is also the matter of efficiency:
sum([x[k]*base^(k-1) for k=1:length(x)])
collects the numbers into an array before summing, which causes unnecessary allocations. Skip the brackets to get better performance:
sum(x[k]*base^(k-1) for k in 1:length(x))
This also allocates an array before summing: sum(d.*4 .^(0:(length(d)-1)))
If you really want good performance, though, write a loop and avoid repeated exponentiation:
function undigit(d; base=10)
s = zero(eltype(d))
mult = one(eltype(d))
for val in d
s += val * mult
mult *= base
end
return s
end
This has one extra unnecessary multiplication, you could try to figure out some way of skipping that. But the performance is 10-15x better than the other approaches in my tests, and has zero allocations.
Edit: There's actually a slight risk to the type handling above. If the input vector and base have different integer types, you can get a type instability. This code should behave better:
function undigits(d; base=10)
(s, b) = promote(zero(eltype(d)), base)
mult = one(s)
for val in d
s += val * mult
mult *= b
end
return s
end
The answer seems to be written directly within the documentation of digits:
help?> digits
search: digits digits! ndigits isdigit isxdigit disable_sigint
digits([T<:Integer], n::Integer; base::T = 10, pad::Integer = 1)
Return an array with element type T (default Int) of the digits of n in the given base,
optionally padded with zeros to a specified size. More significant digits are at higher
indices, such that n == sum([digits[k]*base^(k-1) for k=1:length(digits)]).
So for your case this will work:
julia> d = digits(36, base = 4);
julia> sum([d[k]*4^(k-1) for k=1:length(d)])
36
And the above code can be shortened with the dot operator:
julia> sum(d.*4 .^(0:(length(d)-1)))
36
Using foldr and muladd for maximum conciseness and efficiency
undigits(d; base = 10) = foldr((a, b) -> muladd(base, b, a), d, init=0)

Julia list comprehension changes the type

Suppose we have a Vector of tuples (Int64, Int64) in julia:
In [1] xx = [(1, 2), (3, 4), (5, 6)]
typeof(xx) == Vector{(Int64, Int64)}
Out[1] true
Now I want to construct a new vector of the first indices of the tuples.
In [2] indices = [x[1] for x in xx]
typeof(indices)
Out[2] Array{Any, 1}
I expect it to be an Array{Int64, 1} type. How can I fix this?
edit: I am using 0.3.9.
function f()
xx = [(1, 2), (3, 4), (5, 6)]
inds = [ x[1] for x in xx ]
return(inds)
end
y = f()
typeof(y)
The last line of code returns Array{Int64, 1}.
The problem here is that you are working in global scope. For Julia's type inference to be able to do its magic, you need to work in a local scope. In other words, wrap all your code in functions. This rule is very, very, important, but, having come from a MatLab background myself, I can see why people forget it. Just remember, 90% of questions saying "Why is my Julia code slow?" occur because the user was working in global scope, not local scope.
ps, even in local scope, type inference of loop comprehensions can stumble in particularly complex cases. This is a known issue and is being worked on. If you want to provide the compiler with some "help" you can do something like:
inds = Int[ x[1] for x in xx ]
You can also use map and preserve the type:
#passing a lambda that takes the 1st element, and the iterable
inds = map( (x)-> x[1], xx)

How to make recursive nested loops which use loop variables inside?

I need to make a nested loop with an arbitrary depth. Recursive loops seem the right way, but I don't know how to use the loop variables in side the loop. For example, once I specify the depth to 3, it should work like
count = 1
for i=1, Nmax-2
for j=i+1, Nmax-1
for k=j+1,Nmax
function(i,j,k,0,0,0,0....) // a function having Nmax arguments
count += 1
end
end
end
I want to make a subroutine which takes the depth of the loops as an argument.
UPDATE:
I implemented the scheme proposed by Zoltan. I wrote it in python for simplicity.
count = 0;
def f(CurrentDepth, ArgSoFar, MaxDepth, Nmax):
global count;
if CurrentDepth > MaxDepth:
count += 1;
print count, ArgSoFar;
else:
if CurrentDepth == 1:
for i in range(1, Nmax + 2 - MaxDepth):
NewArgs = ArgSoFar;
NewArgs[1-1] = i;
f(2, NewArgs, MaxDepth, Nmax);
else:
for i in range(ArgSoFar[CurrentDepth-1-1] + 1, Nmax + CurrentDepth - MaxDepth +1):
NewArgs = ArgSoFar;
NewArgs[CurrentDepth-1] = i;
f(CurrentDepth + 1, NewArgs, MaxDepth, Nmax);
f(1,[0,0,0,0,0],3,5)
and the results are
1 [1, 2, 3, 0, 0]
2 [1, 2, 4, 0, 0]
3 [1, 2, 5, 0, 0]
4 [1, 3, 4, 0, 0]
5 [1, 3, 5, 0, 0]
6 [1, 4, 5, 0, 0]
7 [2, 3, 4, 0, 0]
8 [2, 3, 5, 0, 0]
9 [2, 4, 5, 0, 0]
10 [3, 4, 5, 0, 0]
There may be a better way to do this, but so far this one works fine. It seems easy to do this in fortran. Thank you so much for your help!!!
Here's one way you could do what you want. This is pseudo-code, I haven't written enough to compile and test it but you should get the picture.
Define a function, let's call it fun1 which takes inter alia an integer array argument, perhaps like this
<type> function fun1(indices, other_arguments)
integer, dimension(:), intent(in) :: indices
...
which you might call like this
fun1([4,5,6],...)
and the interpretation of this is that the function is to use a loop-nest 3 levels deep like this:
do ix = 1,4
do jx = 1,5
do kx = 1,6
...
Of course, you can't write a loop nest whose depth is determined at run-time (not in Fortran anyway) so you would flatten this into a single loop along the lines of
do ix = 1, product(indices)
If you need the values of the individual indices inside the loop you'll need to unflatten the linearised index. Note that all you are doing is writing the code to transform array indices from N-D into 1-D and vice versa; this is what the compiler does for you when you can specify the rank of an array at compile time. If the inner loops aren't to run over the whole range of the indices you'll have to do something more complicated, careful coding required but not difficult.
Depending on what you are actually trying to do this may or may not be either a good or even satisfactory approach. If you are trying to write a function to compute a value at each element in an array whose rank is not known when you write the function then the preceding suggestion is dead flat wrong, in this case you would want to write an elemental function. Update your question if you want further information.
you can define your function to have a List argument, which is initially empty
void f(int num,List argumentsSoFar){
// call f() for num+1..Nmax
for(i = num+1 ; i < Nmax ; i++){
List newArgs=argumentsSoFar.clone();
newArgs.add(i);
f(i,newArgs);
}
if (num+1==Nmax){
// do the work with your argument list...i think you wanted to arrive here ;)
}
}
caveat: the stack should be able to handle Nmax depth function calls
Yet another way to achieve what you desire is based on the answer by High Performance Mark, but can be made more general:
subroutine nestedLoop(indicesIn)
! Input indices, of arbitrary rank
integer,dimension(:),intent(in) :: indicesIn
! Internal indices, here set to length 5 for brevity, but set as many as you'd like
integer,dimension(5) :: indices = 0
integer :: i1,i2,i3,i4,i5
indices(1:size(indicesIn)) = indicesIn
do i1 = 0,indices(1)
do i2 = 0,indices(2)
do i3 = 0,indices(3)
do i4 = 0,indices(4)
do i5 = 0,indices(5)
! Do calculations here:
! myFunc(i1,i2,i3,i4,i5)
enddo
enddo
enddo
enddo
enddo
endsubroutine nestedLoop
You now have nested loops explicitly coded, but these are 1-trip loops unless otherwise desired. Note that if you intend to construct arrays of rank that depends on the nested loop depth, you can go up to rank of 7, or 15 if you have a compiler that supports it (Fortran 2008). You can now try:
call nestedLoop([1])
call nestedLoop([2,3])
call nestedLoop([1,2,3,2,1])
You can modify this routine to your liking and desired applicability, add exception handling etc.
From an OOP approach, each loop could be represented by a "Loop" object - this object would have the ability to be constructed while containing another instance of itself. You could then theoretically nest these as deep as you need to.
Loop1 would execute Loop2 would execute Loop3.. and onwards.

Resources