How can I use map! with a function using vector variables in julia?
Codes below did not work.
Perhaps, there might be a simple solution of below codes,
but I want to use map! in this problem.
a1 = ones(100, 2)
a2 = ones(100, 2)
a3 = ones(100, 2)
function expe1(v1,v2,v3)
v1 + v2 + v3
end
dest = [zeros(100) for i in 1:2]
map!(expe1, dest, eachcol(a1), eachcol(a2), eachcol(a3))
Error:
ERROR: MethodError: no method matching map!(::typeof(expe1), ::Vector{Vector{Float64}}, ::Base.Generator{Base.OneTo{Int64}, Base.var"#242#243"{Matrix{Float64}}}, ::Base.Generator{Base.OneTo{Int64}, Base.var"#242#243"{Matrix{Float64}}}, ::Base.Generator{Base.OneTo{Int64}, Base.var"#242#243"{Matrix{Float64}}})
Closest candidates are:
map!(::F, ::AbstractArray, ::AbstractArray) where F at abstractarray.jl:2924
map!(::F, ::AbstractArray, ::AbstractArray, ::AbstractArray) where F at abstractarray.jl:2967
map!(::F, ::AbstractArray, ::AbstractArray...) where F at abstractarray.jl:3024
...
Stacktrace:
[1] top-level scope
# REPL[8]:1
There is no method of map! for non-array iterables, because it insists on all arguments being AbstractArrays having the same shape.
To write the result into a destination array without intermediate allocation, you could broadcast-assign it a generator:
julia> dest .= Base.Generator(expe1, eachcol(a1), eachcol(a2), eachcol(a3))
2-element Vector{Vector{Float64}}:
[3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0 … 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
[3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0 … 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
Something like this should also work:
function my_map!(f::F, dest::AbstractArray, As...) where F
for (i, a...) in zip(eachindex(dest), As...)
val = f(a...)
#inbounds dest[i] = val
end
return dest
end
Please check with latest Julia, it works fine with Julia 1.9.0-DEV:
map!(expe1, dest, eachcol(a1), eachcol(a2), eachcol(a3))
2-element Vector{Vector{Float64}}:
[3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0 … 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
[3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0 … 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
julia> VERSION
v"1.9.0-DEV.1332"
And you could just do:
expe1(eachcol(a1), eachcol(a2), eachcol(a3))
2-element Vector{Vector{Float64}}:
[3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0 … 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
[3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0 … 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
Related
I have a vector containing an unknown number of vectors, which all have the same length. For example, like this:
julia> a
4-element Vector{Vector{Int64}}:
[1, 5]
[2, 6]
[3, 7]
[4, 8]
And I want to pivot it into a vector of tuples, exactly the way you would with zip(), like this:
julia> collect(zip(a...))
2-element Vector{NTuple{4, Int64}}:
(1, 2, 3, 4)
(5, 6, 7, 8)
However, I want to do this without using the splat (...) in there, since the splat will end up happening at compile-time if I understand correctly. I want something like reduce(zip, a), but that's obviously not right:
julia> collect(reduce(zip, a))
2-element Vector{Tuple{Tuple{Tuple{Int64, Int64}, Int64}, Int64}}:
(((1, 2), 3), 4)
(((5, 6), 7), 8)
So I guess I have two questions:
Am I correct that this use of splat is not performant?
What is the right way to do this operation performantly?
Thank you!
For reference, here is a performance characterization of the current approach. It actually appears surprisingly performant (though maybe it would be worse in-situ?):
julia> a = Any[collect(1:1_000_000), [2.0 for _ in 1:1_000_000]]
2-element Vector{Any}:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 … 999991, 999992, 999993, 999994, 999995, 999996, 999997, 999998, 999999, 1000000]
[2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0 … 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
julia> #time collect(zip(a...))
0.003288 seconds (4 allocations: 15.259 MiB)
1000000-element Vector{Tuple{Int64, Float64}}:
(1, 2.0)
(2, 2.0)
(3, 2.0)
(4, 2.0)
(5, 2.0)
(6, 2.0)
⋮
(999996, 2.0)
(999997, 2.0)
(999998, 2.0)
(999999, 2.0)
(1000000, 2.0)
You can use the invert function from SplitApplyCombine.jl
julia> invert(a)
2-element Vector{Vector{Int64}}:
[1, 2, 3, 4]
[5, 6, 7, 8]
julia> Tuple.(invert(a))
2-element Vector{NTuple{4, Int64}}:
(1, 2, 3, 4)
(5, 6, 7, 8)
The second version broadcasts Tuple over the result to get a vector of tuples instead of a vector of vectors. The first version is the faster among the two, but both versions are faster than the collect(zip(...)) method in my benchmarks.
How to round away from zero in Julia?
I have seen the documentation here:
https://docs.julialang.org/en/v1/base/math/#Base.Rounding.RoundNearestTiesAway
How to use this in Julia?
Can it be used along with round ?
-1.5 gives -2
1.5 gives 2
Pass rounding mode as an argument to round. By default ties are rounded to even number:
julia> tuple.(x, round.(-4.5:4.5))
10-element Vector{Tuple{Float64, Float64}}:
(-4.5, -4.0)
(-3.5, -4.0)
(-2.5, -2.0)
(-1.5, -2.0)
(-0.5, -0.0)
(0.5, 0.0)
(1.5, 2.0)
(2.5, 2.0)
(3.5, 4.0)
(4.5, 4.0)
but if you want to round ties away from zero use:
julia> tuple.(x, round.(-4.5:4.5, RoundNearestTiesAway))
10-element Vector{Tuple{Float64, Float64}}:
(-4.5, -5.0)
(-3.5, -4.0)
(-2.5, -3.0)
(-1.5, -2.0)
(-0.5, -1.0)
(0.5, 1.0)
(1.5, 2.0)
(2.5, 3.0)
(3.5, 4.0)
(4.5, 5.0)
As you can see for 1.5 and -1.5 there is no difference between default rounding mode and the rounding mode you want. But for 2.5 and -2.5 there is a difference.
How do I make the following code into nested list comprehension?
node_x = 5
node_y = 5
node_z = 5
xyz = Matrix(undef, node_x*node_y*node_z,3)
ii = 0
dx = 1.0
for k in 0:node_z-1
for j in 0:node_y-1
for i in 0:node_x-1
x = i * dx
y = j * dx
z = k * dx
ii += 1
#println([x, y, z])
xyz[ii, 1] = x
xyz[ii, 2] = y
xyz[ii, 3] = z
end
end
end
In python and numpy, I can write such as following codes.
xyz = np.array([[i*dx, j*dx, k*dx] for k in range(node_z) for j in range(node_y) for i in range(node_x)])
Comprehensions can be nested just the same, it's just range that is a bit different, but in your case there is the start:end syntactic sugar:
julia> [[i*dx, j*dx, k*dx] for k in 1:node_z for j in 1:node_y for i in 1:node_x]
125-element Vector{Vector{Float64}}:
[1.0, 1.0, 1.0]
[2.0, 1.0, 1.0]
⋮
[4.0, 5.0, 5.0]
[5.0, 5.0, 5.0]
To get the same array as your Python example, you'd have to permute the dimensions of the 3-element vectors and concatenate the list:
julia> vcat(([i*dx j*dx k*dx] for k in 1:node_z for j in 1:node_y for i in 1:node_x)...)
125×3 Matrix{Float64}:
1.0 1.0 1.0
2.0 1.0 1.0
⋮
4.0 5.0 5.0
5.0 5.0 5.0
I have 2 arrays of tuples and I have a loop asking if one element is in the other.
At each step I ask if the tuple contained in the coord array is in the Y array. The loop works fine except for one element which I cant explain why. Here is what I have :
Y[55:65] # This is the array I want to check at each step if my state is in or not.
11-element Array{Any,1}: (2.0, 1.0) (3.0, 1.0) (4.0, 1.0) (5.0,
1.0) (6.0, 1.0) (7.0, 1.0) (8.0, 1.0) (9.0, 1.0) (10.0, 1.0) (11.0, 1.0) (12.0, 1.0)
coord[i-1] # this is one element of coord that is in Y
0-dimensional Array{Tuple{Float64,Float64},0}: (6.0, 1.0)
coord[i] # this is an other element of coord that is in Y
0-dimensional Array{Tuple{Float64,Float64},0}: (7.0, 1.0)
But then when I test when they are in Y:
in(coord[i],Y[55:65]) # testing if coord[i] is in Y
false
in(coord[i-1],Y[55:65]) # testing if coord[i-1] is in Y
true
I dont understand: they are both represented in the same way in Y, they have the same type, why do I get from using in() that one is in and not the other?
I use Julia version 0.6.3.
Thanks in advance for the help!
How did you get coord and Y? If you get them by calculations rather than direct assignments, they may not be exactly equal even if they are displayed so. For example:
julia> p1 = fill((6.0, 1.0))
0-dimensional Array{Tuple{Float64,Float64},0}:
(6.0, 1.0)
julia> p2 = fill((7.0 + 3eps(), 1.0))
0-dimensional Array{Tuple{Float64,Float64},0}:
(7.000000000000001, 1.0)
julia> Y = [p1, p2]
2-element Array{Array{Tuple{Float64,Float64},0},1}:
(6.0, 1.0)
(7.0, 1.0) # NOTE that it get truncated in display but the content did not changed!
julia> x = fill((6.0, 1.0))
0-dimensional Array{Tuple{Float64,Float64},0}:
(6.0, 1.0)
julia> x in Y
true
julia> x = fill((7.0, 1.0))
0-dimensional Array{Tuple{Float64,Float64},0}:
(7.0, 1.0)
julia> x in Y
false
If this is the case, you can either round them before comparing or write the in function mannually using isapprox (or the ≈ operator, typed in Julia by \approx + Tab)
I can see from this link that R's equivalent of seq is n:m in (http://www.johnmyleswhite.com/notebook/2012/04/09/comparing-julia-and-rs-vocabularies/).
But the case of seq(a,b, length.out = n) is not covered.
For example seq(1, 6, length.out=3) gives c(1.0, 3.5, 6.0). It is a really nice way to specify the number of outputs.
What's its equivalent in Julia?
As of Julia 1.0:
linspace has been deprecated. You can still use range:
julia> range(0, stop = 5, length = 3)
0.0:2.5:5.0
As #TasosPapastylianou noted, if you want this to be a vector of values, you can use collect:
julia> collect( range(0, stop = 5, length = 3) )
3-element Array{Float64,1}:
0.0
2.5
5.0
You are looking for the linspace function. Note this is synonymous to the equivalent function in matlab / octave.
Also note that this returns a "steprange" type object:
julia> a = linspace(1,5,9)
1.0:0.5:5.0
julia> typeof(a)
StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}
julia> collect(a)
9-element Array{Float64,1}:
1.0
1.5
2.0
2.5
3.0
3.5
4.0
4.5
5.0
PS: similarly, there exists a range function which is equivalent to the start:step:stop syntax, similar to the seq(from=, to=, by=) syntax in R.