HyLang : Howto simplest for loop in hy? - hy

I wanna get Hy!
How, In Hylang, do I do the simple Python loop:
for i in range(5):
print(i)

The tutorial provides this example:
(for [x [1 2 3]]
(print x)) ; => 1 2 3
Changing the variable name, and using range in place of a list, we get:
(for [i (range 5)]
(print i))

Related

Multiple iterators in "for", "lfor", etc. with something like "dct.items()"

How could I convert the following to hy?
dct = { 1:2, 3:4 }
print([i*j for i, j in dct.items()])
# => [2, 12]
I'm puzzled by your title, since there's only one iteration clause in your example, but anyway, here's a literal Hy translation:
(setv dct {1 2 3 4})
(print (lfor [i j] (.items dct) (* i j)))
; => [2, 12]
But you could also do this with the shadow multiplication operator:
(import hy.pyops *)
(setv dct {1 2 3 4})
(print #* (map * (.keys dct) (.values dct)))
; => 2 12

N-dimensional Array with Haskell

In Python we can create index a numpy.ndarray with tuples, like
cube = numpy.zeros((3,3,3,))
print(cube[(0,1,2,)])
. However, in Haskell, to index a multi-layered array this can only be done with multiple !!'s which seems pretty adhoc.
I tried foldl:
foldl
(!!)
[[[1, 2, ....], [1, 2, ....], [1, 2, ....]],
[[1, 2, ....], [1, 2, ....], [1, 2, ....]],
[[1, 2, ....], [1, 2, ....], [1, 2, ....]]]
[0, 1, 2]
However foldl can only apply to functions like a -> b -> a, not [a] -> b -> a. Some other information shows hmatrix can do things like numpy in python, but it only applies to matrix and vectors, where the dimension is not adjustable.
This can always be done with C style indexing, i.e. put all data in a 1d list, and index them with multiplications, 0 + 1*3 + 2*9, but it seems rude, losing the information of dimensions and will cause the compiler fail to adjust them in a proper order.
How to do this with a more abstract way?
It is not quite clear to me from the question what you are trying to achieve, but if your question is only about indexing multidimensional arrays in Haskell then I'll try to answer it to best of my ability. Thanks to #leftaroundabout for suggesting massiv in the comments section, being the author of that library I am inclined to agree with his comment.
One thing is for certain, for multiple reasons you do not want to use nested lists for the purpose of arrays. Linear indexing complexity and abysmal performance are only some of those reasons.
Constructing an array
Let's see how we can get it done with massiv. First I'll translate your numpy example:
cube :: Array P Ix3 Float
cube = A.replicate Seq (Sz (3 :> 3 :. 3)) 0
Note because we actually have types in Haskell we need to do some annotations on what type of array we are trying to construct, eg. boxed vs unboxed, mutable vs immutable etc. I recommend reading through library's documentation in order to get more info on those topics. Here I'll focus on indices, since that is what the question is about. In order to get an element from the above 3D array at 0th page, 2nd row and 3rd column (the cube[(0,1,2,)] from numpy example) we can use O(1) time operator ! with an index supplied on its right side:
λ> cube ! (0 :> 1 :. 2)
0.0
Note that indexing operator ! is partial and will result in a runtime exception on out of bounds:
λ> cube ! (10 :> 1 :. 2)
*** Exception: IndexOutOfBoundsException: (10 :> 1 :. 2) is not safe for (Sz (3 :> 3 :. 3))
CallStack (from HasCallStack):
throwEither, called at src/Data/Massiv/Core/Common.hs:807:11 in massiv-1.0.1.0-...
Which can be easily avoid with its safer variant !?:
λ> cube !? (0 :> 1 :. 2) :: Maybe Float
Just 0.0
λ> cube !? (10 :> 1 :. 2) :: Maybe Float
Nothing
Index syntax
Same as with numpy it is possible to use tuples for indexing massiv arrays, but because tuples are polymorphic, it is sometimes trickier for the type checker to infer the right thing, also tuples are supported in massiv only up to 5 dimensions. That's why I will show examples for Ix n type instead, where n is number of dimensions, which can be arbitrary.
When working with flat vectors then regular Int is used for indexing (corresponds to Ix 1):
λ> let vec = makeVectorR P Seq (Sz 10) id
λ> vec
Array P Seq (Sz1 10)
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
λ> vec ! 7
7
For two dimensions there is a special operator :. (corresponds to Ix 2):
λ> let mat = makeArrayR P Seq (Sz (2 :. 10)) $ \(i :. j) -> i + j
λ> mat
Array P Seq (Sz (2 :. 10))
[ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
, [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
]
λ> mat ! (1 :. 3)
4
Index for any dimension larger than 2 is built with :> operator (corresponds to Ix n):
λ> let arr3D = makeArrayR P Seq (Sz (3 :> 2 :. 1)) $ \(i :> j :. k) -> i + j + k
λ> arr3D ! (2 :> 1 :. 0)
3
λ> let arr4D = makeArrayR P Seq (Sz (4 :> 3 :> 2 :. 1)) $ \(h :> i :> j :. k) -> h + i + j + k
λ> arr4D ! (3 :> 2 :> 1 :. 0)
6
More info on indices with examples can be found in the README's #index section.

Julia conditional assignment based on | (or) in multidimensional array

I have a 3D array, and based on the values in one "row" using the or operator "|", I would like to substitute values in a different row. I've attempted to build a mwe, here goes:
# create new array
Pop = fill(Int8(3), 1, 3, 4)
# change values in one row of array
Pop[:,:,2] = [5,6,7]
# change values in second row of array
Pop[:,:,4] = [9,10,11]
# attempt conditional substitution, if element-wise value of Pop[:,:,2] equals either 6 or 7, then substitute the corresponding element wise (across row in dimension 3) for 8
Pop[:,:,2] == 6|7 Pop[:,:,3] .= 8
# to produce this end result
Pop[:,:,3] = [3,8,8]
Pop
I'm missing something in the syntax for the substitution. Thx. J
This works, but requires a temporary variable.
julia> temp = Pop[:,:,3]
1×3 Array{Int8,2}:
3 3 3
julia> temp[(Pop[:,:,2] .== 6) .| (Pop[:,:,2] .== 7)] .= 8
2-element view(::Array{Int8,1}, [2, 3]) with eltype Int8:
8
8
julia> Pop[:,:,3] = temp
1×3 Array{Int8,2}:
3 8 8
I think it's clearer to separate the stages:
julia> Pop = fill(Int8(3), 1, 3, 4);
julia> Pop[:,:,2] .= [5 6 7];
julia> ind = findall(x -> x==6 || x==7, Pop[:,:,2])
2-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 2)
CartesianIndex(1, 3)
julia> Pop[ind, 3] .= 8;
julia> Pop[:, :, 3]
1×3 Matrix{Int8}:
3 8 8
You could also write ind == findall(in((6,7)), #view Pop[:,:,2]). You can write ind_bool = (Pop[:,:,2] .== 6) .| (Pop[:,:,2] .== 7) but I'm not sure Pop[ind_bool, 3] .= 8 will work on all versions of Julia.
Another way is just to write an explicit loop. We could loop separately over for i in axes(Pop,1), j in axes(Pop,2) but we can also use these multi-dimensional CartesianIndex things again:
julia> Pop = fill(Int8(3), 1, 3, 4);
julia> Pop[:,:,2] .= [5 6 7];
julia> for i in CartesianIndices(#view Pop[:,:,2])
x = Pop[i,2]
if x==6 | x==7
Pop[i,3] = 8
end
end
julia> Pop[:, :, 3]
1×3 Matrix{Int8}:
3 3 8
Thanks to help from #mcabbott and #Nathan Boyer, I've got a solution that works, even managed to add more conditions and it seems to work. I'll post the mwe solution.
# create new array
Pop = fill(Int8(3), 1, 3, 4)
# change some values
Pop[:,:,2] = [5,6,7]
Pop[:,:,4] = [9,10,9]
# what does it look like
Pop
# code to check condition values
# create temp array to be altered if conditions met
temp = Pop[:,:,3]
# see which indexes meet conditions, in this case
# array "Pop[:,:,2]" contains either 6 or 7 ... and ...
# array "Pop[:,:,4]" contains values >= 10
temp[(Pop[:,:,2] .== 6) .|
(Pop[:,:,2] .== 7) .&
(Pop[:,:,4] .>= 10)] .= 8
# make changes to original array based on temp
Pop[:,:,3] = temp
# check if it did the job correctly
Pop

View on Julia array using sliding window

What is the most efficient way to create a view on array using, for example, sliding window=2
Let's say we have:
x = collect(1:1:6)
# 1 2 3 4 5 6
And I want to create a view like this:
# 1 2
# 2 3
# 3 4
# 4 5
# 5 6
So far I found only this option, but not sure if it's an optimal one:
y = Array{Float32, 2}(undef, nslides, window)
#inbounds for i in 1:window
y[:, i] = #view x[i:end-(window-i)]
end
One solution with a package (well, with my package) is this:
julia> using Tullio
julia> x = 1:6; window = 2;
julia> #tullio y[r,c] := x[r+c-1] (c in 1:window)
5×2 Matrix{Int64}:
1 2
2 3
3 4
4 5
5 6
The one liner is:
view.(Ref(x), (:).(1:length(x)-1,2:length(x)))
Testing:
julia> x=collect(1:6);
julia> view.(Ref(x), (:).(1:length(x)-1,2:length(x)))
5-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
[1, 2]
[2, 3]
[3, 4]
[4, 5]
[5, 6]
Explanation:
creation of views is vectorized by the dot operator .
we do not want to vectorize on elements of x so use Ref(x) instead
(:) is just a shorter form for UnitRange and again we use the dot operator . to vectorize
I used 2 as the Window size but of course you can write view.(Ref(x), (:).(1:length(x)-(window-1),window:length(x)))
EDIT:
If you want rather a library function this would work for you:
julia> using ImageFiltering
julia> mapwindow(collect, x, 0:1,border=Inner())
5-element OffsetArray(::Array{Array{Int64,1},1}, 1:5) with eltype Array{Int64,1} with indices 1:5:
[1, 2]
[2, 3]
[3, 4]
[4, 5]
[5, 6]
Of course you could put them the function that you want to run on the sliding window rather than just collect.

clojure for loop, store the values in a set or map

This one has been bothering me for a while now,
How should we store a value in a set or map in a for loop?
(let [s #{}]
(for [ i (range 10)
j (range 10) ]
(into s [i j])))
i know this will not work, but i want a functionality similar to this , where the set will finally contain [0 0] [0 1]...[0 9] [1 0]...[9 9]
Thanks
If I understand your question correctly you need to turn your expression inside-out:
(let [s #{}]
(into s (for [i (range 10)
j (range 10)]
[i j])))
The thing to realize here is that for returns a value (a lazy sequence) unlike for-loops in more imperative languages like Java and C.
Is this what you want?
(into #{} (for [i (range 10) j (range 10)]
[i j]))
;-> #{[2 1] [3 2] [4 3] [5 4] [6 5] [7 6] [8 7] [9 8] [1 0]
; [2 2] [3 3] [4 4] [5 5] [6 6]...
And if you just want the list as a set:
(set (for [i (range 10) j (range 10)]
[i j]))
You will end up with a set of pairs.
Generally when you want to return a set or a map or other 'single value' that isn't a seq from a 'repeated' generalized operation on a seq, using reduce is more idiomatic/straightforward than loop/recur, and for always returns a seq (not a set or map).
(reduce conj #{} (for [i (range 10) j (range 10)] [i j]))
note that (for ..) here is only used to produce a seq containing all the values to compile into the single result set. Or, for example:
(reduce + 0 (range 100))
=> 4950
clojure has a several great systems for managing mutable state. in this case you may want an atom containing a set
your other options are:
a ref if more than one change needs to made (coordinated many threads)
a var if this will be single threaded (a var may work just as well here as an atom)
an agent if you wanted to set the value of s asynchronously
of course for returns a sequence already so you may just want
(into #{} (for [ i (range 10)
j (range 10) ]
[i j]))
I think you can also use some transient data structure in this scenario.
(let [s (transient #{})]
(for [ i (range 10)
j (range 10) ]
(assoc! s i j)))
(persistent! s)
Just a code sample, not tested.

Resources