Multiply some members of an array by independenly drawn random numbers - julia

Suppose that I have a 1D array like so:
julia> myarray = ones(6)
6-element Array{Float64,1}:
1.0
1.0
1.0
1.0
1.0
1.0
I make a mask that will select some elements, the first and second element in this example:
julia> mymask = [true; true; false; false; false; false;]
6-element Array{Bool,1}:
true
true
false
false
false
false
Now I want to multiply only the first and second elements by random numbers drawn from the same distribution, and save the result over the old array. But this will multiply them by the same value:
julia> myarray[mymask] = myarray[mymask] * rand(Normal(20,5))
julia> myarray
6-element Array{Float64,1}:
16.5642
16.5642
1.0
1.0
1.0
1.0
My next thought was to try myarray[mymask] = myarray[mymask] * rand(Normal(20,5),2) but it gives an error.

You can make your multiplication explicitly elementwise:
julia> myarray[mymask] .*= rand(Normal(20,5), size(myarray[mymask]));
julia> myarray
6-element Array{Float64,1}:
24.1747
12.6375
1.0
1.0
1.0
1.0

At the cost of more lines, the following works:
function mularray!(myarray,mymask)
maskpos = find(mymask)
myrand = rand(Normal(20,5),length(maskpos))
for i=1:length(maskpos)
myarray[maskpos[i]] *= myrand[i]
end
end
With the required operation done by
julia> mularray!(myarray,mymask)
julia> myarray
6-element Array{Float64,1}:
22.1761
20.836
1.0
1.0
1.0
1.0
The advantage is in speed (benchmarked at more than 2x the shorter solution), perhaps readability (for some readers), but probably flexibility for other mutating operations.

Because the value of the mask is bool, following method can be used
for i in eachindex(arr)
mask[i] && (arr[i] *= rand(Normal(20,5)))
end
It is equivalent to
for i in eachindex(arr)
if mask[i]
arr[i] *= rand(Normal(20, 5))
end
end
With this method, you can avoid allocation of arr[mask]

Related

How to narrow element type of a Vector or Array in Julia?

Consider a situation where I first create a Vector with eltype of Any incrementally; after that, I want to narrow the element type of it. How can I do that?
julia> vec = Any[1, 2, 3.]
3-element Vector{Any}:
1
2
3.0
I can use something like convert(Vector{Real}, vec). But in this case, I'm specifying the type manually while I want Julia to decide the best suitable eltype for it.
This can be achieved by broadcasting the identity function on each element of the given container (either an Array or a Vector):
julia> narrowed = identity.(vec)
3-element Vector{Real}:
1
2
3.0
Note that this doesn't lead to promoting (or demoting) the type of each individual element of the given container:
julia> typeof(narrowed[1]), typeof(narrowed[3])
(Int64, Float64)
Additional Point
However, in the case of acquainting with related functions in Julia, This can be done verbosely by using the typejoin function to achieve the type join of the container's elements. According to the concise doc of the function:
typejoin(T, S)
Return the closest common ancestor of T and S, i.e. the narrowest type from which they both inherit.
The argument of the typejoin should be a subtype of Core.Type{T} (However, it seems more sensible to define it as typejoin(T...) since it can get an indefinite number of positional arguments, not just two.)
julia> typeof.(vec)
3-element Vector{DataType}:
Int64
Int64
Float64
julia> typejoin(typeof.(vec)...)
Real
julia> convert(Vector{typejoin(typeof.(vec)...)}, vec)
3-element Vector{Real}:
1
2
3.0
Small type unions (such as Union{Int, Float64} are handled in Julia much faster and than abstract types and hence you should avoid vectors of abstract elements such as Vector{Real} in favor of unions of concrete types such as Union{Int, Float64}.
Having that said here is a code that makes such union:
julia> Vector{Union{Set(typeof.(vec))...}}(vec)
3-element Vector{Union{Float64, Int64}}:
1
2
3.0
And here is a simple test that shows that for a 100 element vector the performance difference is 4x:
julia> a1 = Vector{Union{Int, Float64}}(rand(100));
julia> a2 = Vector{Real}(rand(100));
julia> #btime minimum($a1);
428.643 ns (0 allocations: 0 bytes)
julia> #btime minimum($a2);
2.000 μs (102 allocations: 1.59 KiB)
You can use promote like this:
v = Any[1, 2, 3.0]
first.(promote.(v))
3-element Vector{Real}:
1
2
3.0000
v = Any[1, 2, 3.0, 3 + 2im]
first.(promote.(v))
4-element Vector{Number}:
1
2
3.0000
3 + 2im
But, you might be interested more in getting a vector of concrete supertypes of the elements, especially for performance purposes. So, you can use this:
v = Any[1, 2, 3.0]
reduce(vcat, promote(v...))
3-element Vector{Float64}:
1.0
2.0
3.0
v = Any[1, 2, 3.0, 3 + 2im]
reduce(vcat, promote(v...))
4-element Vector{ComplexF64}:
1.0 + 0.0im
2.0 + 0.0im
3.0 + 0.0im
3.0 + 2.0im
Or, simply:
v = Any[1, 2, 3.0];
[v...]
3-element Vector{Float64}:
1.0
2.0
3.0
v = Any[1, 2, 3.0, 3+2im];
[v...]
4-element Vector{ComplexF64}:
1.0 + 0.0im
2.0 + 0.0im
3.0 + 0.0im
3.0 + 2.0im

How to check if two arrays are equal even if they contain NaN values in Julia?

I am trying to compare two arrays. It just so happens that the data for the arrays contains NaN values and when you compare arrays with NaN values, the results are not what I would have expected.
julia> a = [1,2, NaN]
3-element Array{Float64,1}:
1.0
2.0
NaN
julia> b = [1,2, NaN]
3-element Array{Float64,1}:
1.0
2.0
NaN
julia> a == b
false
Is there an elegant way to ignore these Nan's during comparison or replace them efficiently?
Use isequal:
Similar to ==, except for the treatment of floating point numbers and
of missing values. isequal treats all floating-point NaN values as
equal to each other, treats -0.0 as unequal to 0.0, and missing as
equal to missing. Always returns a Bool value.
julia> a = [1,2, NaN]
3-element Array{Float64,1}:
1.0
2.0
NaN
julia> b = [1,2, NaN]
3-element Array{Float64,1}:
1.0
2.0
NaN
julia> isequal(a, b)
true
You probably want to use isequal(a, b) (which also treats missing equal to missing, but -0.0 as unequal to 0.0).
You could filter out the NaN's on each array:
a = [1, 2, NaN]
filteredA = filter(x -> !isnan(x), a)
b = [1, 2, NaN]
filteredB = filter(x -> !isnan(x), b)
print(a == b)
print(filteredA == filteredB)
You could then create a function that does the filtering, and a custom compare function that uses the filtering function on both arguments and compare. Not sure if there is a more Julia-esque way.
Or create a new type. And create a Singleton nan which you use instead of NaN.
struct MyNaN end
nan = MyNaN()
and write a function for replacing NaNs by it.
with_nan(l) = map((x) -> if isnan(x) nan else x end, l)
Then you can wrap your lists using this function.
a = [1, 2, NaN]
b = [1, 2, NaN]
with_nan(a) == with_nan(b)
## true

Perspective warp an image in Julia

I have an image and a 3x3 perspective projection matrix M. How do I apply the transform on the image?
I tried to use the warp(img, tform) function but don't know how to construct the transform object from the matrix.
Tried tform = PerspectiveMap() ∘ inv(LinearMap(M)), no idea if this is a correct to create the transform, but it fails with:
ERROR: Inverse transformation for CoordinateTransformations.PerspectiveMap has not been defined.
There are two components to the answer:
You have to define a transformation that takes a 2-vector to a 2-vector
If the transformation isn't invertible, then you have to specify the range of indices of the final image manually.
For the first, the following suffices:
julia> using StaticArrays, CoordinateTransformations
julia> M = #SMatrix [1 0 0; 0 1 0; -1/1000 0 1] # a 3x3 perspective transformation matrix
3×3 StaticArrays.SArray{Tuple{3,3},Float64,2,9}:
1.0 0.0 0.0
0.0 1.0 0.0
-0.001 0.0 1.0
julia> tform = PerspectiveMap() ∘ inv(LinearMap(M))
(CoordinateTransformations.PerspectiveMap() ∘ LinearMap([1.0 0.0 0.0; -0.0 1.0 0.0; 0.001 -0.0 1.0]))
julia> tform(#SVector([1,1,1])) # this takes a 3-vector as input and returns a 2-vector
2-element SVector{2,Float64}:
0.999001
0.999001
julia> push1(x) = push(x, 1)
push1 (generic function with 1 method)
julia> tform2 = PerspectiveMap() ∘ inv(LinearMap(M)) ∘ push1 # here's one that takes a 2-vector as input (appends 1 to the 2-vector)
(::#55) (generic function with 1 method)
julia> tform2(#SVector([1,1]))
2-element SVector{2,Float64}:
0.999001
0.999001
Now let's try this on an image. We'll create an output image that has the same indices as the input image, although you can choose any indices you want:
julia> using Images, TestImages
julia> img = testimage("lighthouse");
julia> imgw = warp(img, tform2, indices(img)); # 3rd argument sets the indices
julia> using ImageView
julia> imshow(imgw)
img looks like this:
and imgw looks like this:

How to append a vector to Julia matrix as a row?

I have an empty matrix initially:
m = Matrix(0, 3)
and a row that I want to add:
v = [2,3]
I try to do this:
[m v]
But I get an error
ERROR: ArgumentError: number of rows of each array must match
What's the proper way to do this?
That is because your matrix sizes don't match. Specifically v does not contain enough columns to match m. And its transposed
So this doesnt work
m = Matrix(0, 3)
v = [2,3]
m = cat(1, m, v) # or a = [m; v]
>> ERROR: DimensionMismatch("mismatch in dimension 2 (expected 3 got 1)")
whereas this does
m = Matrix(0, 3)
v = [2 3 4]
m = cat(1, m, v) # or m = [m; v]
>> 1x3 Array{Any,2}:
>> 2 3 4
and if you run it again it creates another row
m = cat(1, m, v) # or m = [m; v]
>> 2x3 Array{Any,2}:
>> 2 3 4
>> 2 3 4
Use the vcat (concatenate vertically) function:
help?> vcat
search: vcat hvcat VecOrMat DenseVecOrMat StridedVecOrMat AbstractVecOrMat levicivita is_valid_char #vectorize_2arg
vcat(A...)
Concatenate along dimension 1
Notice you have to transpose the vector v, ie. v', else you get a DimensionMismatch error:
julia> v = zeros(3)
3-element Array{Float64,1}:
0.0
0.0
0.0
julia> m = ones(3, 3)
3x3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
julia> vcat(m, v') # '
4x3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
0.0 0.0 0.0
julia> v' # '
1x3 Array{Float64,2}:
0.0 0.0 0.0
julia> vcat(m, v)
ERROR: DimensionMismatch("mismatch in dimension 2 (expected 3 got 1)")
in cat_t at abstractarray.jl:850
in vcat at abstractarray.jl:887
Note: the comments; # ' are there just to make syntax highlighting work well.
Isn't that Matrix creates a two-dimensional array in Julia? If you try with m =[0, 3], which creates a one-dimensional Vector for you, you can append it by [m; v].
I think using [m v] is create a two-dimensional array as well, from the Julia Document

Concatenate array of arrays

I have an array of arrays in Julia and am trying to find a way to concatenate all of the elements together. If I create the arrays and feed them each individually into hcat(), it performs exactly as I would want. But, if I create the arrays and then feed the array of arrays into hcat(), it fails. I could just write a loop to successfully concatenate one array to another, but I am wondering if there is a better way.
a = ones(2,2);
b = ones(2,2);
c = ones(2,2);
hcat(a,b,c) ## Does what I want by creating a single array. would be impracticable though for large number of objects.
d = Array(Array{Float64,2}, 3);
d[1] = a;
d[2] = b;
d[3] = c;
hcat(d) ## Still leaves me with an array of arrays, like before
[a b c] ## also does what I want
[f for f in d] ## Still leaves me with an array of arrays
julia> hcat(d)
3x1 Array{Array{Float64,2},2}:
2x2 Array{Float64,2}:
1.0 1.0
1.0 1.0
2x2 Array{Float64,2}:
1.0 1.0
1.0 1.0
2x2 Array{Float64,2}:
1.0 1.0
1.0 1.0
julia> hcat(d...)
2x6 Array{Float64,2}:
1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0

Resources