Cos, Acos with complex numbers - julia

In Matlab I can write:
real(cos(kron(acos(-1.25),[0:4])))
and get:
1.0000 -1.2506 2.1282 -4.0725 8.0583
How to do the same in Julia. acos does not work with numbers less than -1.0. Even if I write:
r = max(-1.25,-1)
v = collect(0:4).';
cc =kron(acos(r),v)
I get only this:
1.0 -1.0 1.0 -1.0 1.0
It seems that I need to make cos/acos work with complex numbers.

Is this what you are looking for?
julia> real(cos.(kron(acos(complex(-1.25)),(0:4)')))
1×5 RowVector{Float64,Array{Float64,1}}:
1.0 -1.25 2.125 -4.0625 8.03125
or
julia> real(cos.(kron(acos(complex(-1.25)),0:4)))
5-element Array{Float64,1}:
1.0
-1.25
2.125
-4.0625
8.03125
Looks like Julia's acos requires a complex argument for a complex output.

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

Julia equivalent of Python numpy "arange"

In Python, I can create an array of evenly spaced values using
xi2 = np.arange(0, np.sqrt(6), 1e-3)
How do I write this in Julia? I tried,
xi2 = range(0,sqrt(6),step=1e-3)
but this returns 0.0:0.001:2.449
The result, 0.0:0.001:2.449 is indeed a range of evenly spaced values, and can be indexed, sliced, broadcasted on, and generally used just like any other AbstractArray. For example:
julia> xi2 = range(0,sqrt(6),step=1e-3)
0.0:0.001:2.449
julia> xi2[1]
0.0
julia> xi2[100]
0.099
julia> length(xi2)
2450
julia> isa(xi2, AbstractArray)
true
julia> sin.(xi2)
2450-element Vector{Float64}:
0.0
0.0009999998333333417
0.0019999986666669333
0.002999995500002025
⋮
0.6408405168240852
0.6400725224915994
0.6393038880866445
0.6385346143778549
If for any reason you want to turn xi2 into a full Array preemptively, you can do that with collect
julia> collect(xi2)
2450-element Vector{Float64}:
0.0
0.001
0.002
0.003
⋮
2.446
2.447
2.448
2.449
which will "materialize" the range, so to speak. This uses a lot more memory than the Range though, and is less often necessary than you might expect.

Julia - console behaving differently than include("myfile.jl")

I would like to execute the following code, which works perfectly well when I type every line into my Julia console on Windows 10, but throws an error because of the mismatching type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} (my subsequent code expects Array{Float64,2}).
This is the code:
x = [0.2, 0.1, 0.2]
y = [-0.5 0.0 0.5]
fx = x * y
fy = fx'
return fx::Array{Float64,2}, fy::Array{Float64,2}
There is a TypeError, because fy seems to be of type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} instead of Array{Float64,2}.
How can I do a transpose and get a "normal" Array{Float64,2} object ?
And why does this work when I type every line into my Julia console, but does not when I run the file via include("myfile.jl") ?
Use collect to have a copy of actual data rather than a transformed view of the original (note that this rule applies to many other similar situations):
julia> x = [0.2, 0.1, 0.2];
julia> y = [-0.5 0.0 0.5];
julia> fx = x * y
3×3 Array{Float64,2}:
-0.1 0.0 0.1
-0.05 0.0 0.05
-0.1 0.0 0.1
julia> fy = fx'
3×3 LinearAlgebra.Adjoint{Float64,Array{Float64,2}}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
julia> fy = collect(fx')
3×3 Array{Float64,2}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
To get a normal Matrix{Float64} use:
fy = permutedims(fx)
or
fy = Matrix(fx')
Those two are not 100% equivalent in general as fx' is a recursive adjoint operation (conjugate transpose), while permutedims is a non-recursive transpose, but in your case they will give the same result.
What does recursive adjoint mean exactly?
recursive: the conjugate transpose is applied recursively to all entries of the array (in your case you have array of numbers and transpose of a number is the same number so this does not change anything);
adjoint: if you would have complex numbers then the operation would return their complex conjugates (in your case you have real numbers so this does not change anything);
Here is an example when both things matter:
julia> x = [[im, -im], [1-im 1+im]]
2-element Array{Array{Complex{Int64},N} where N,1}:
[0+1im, 0-1im]
[1-1im 1+1im]
julia> permutedims(x)
1×2 Array{Array{Complex{Int64},N} where N,2}:
[0+1im, 0-1im] [1-1im 1+1im]
julia> Matrix(x')
1×2 Array{AbstractArray{Complex{Int64},N} where N,2}:
[0-1im 0+1im] [1+1im; 1-1im]
However, unless you really need to you do not have to do it if you really need to get a conjugate transpose of your data. It is enough to change type assertion to
return fx::Array{Float64,2}, fy::AbstractArray{Float64,2}
or
return fx::Matrix{Float64}, fy::AbstractMatrix{Float64}
Conjugate transpose was designed to avoid unnecessary allocation of data and most of the time this will be more efficient for you (especially with large matrices).
Finally the line:
return fx::Array{Float64,2}, fy::Array{Float64,2}
throws an error also in the Julia command line (not only when run from a script).

How to use comprehensions on linspace to create matrix

I would like to produce an n x 3 matrix where n is the number of pixels (width * height).
x = linspace(-1, 1, width)
y = linspace(-1, 1, height)
r = 1.0
viewDirections = [[i j 1.0] for i in x for j in y]
However, when I run this I get a:
16-element Array{Array{Float64,2},1}
and not my desired a 16x3 Array{Float64,2}. I am obviously not using comprehensions properly to construct matrices. I tried using comprehensions to create an array of tuples, but I can't then convert those tuples into a matrix.
The problem here is array comprehension will give us a nested array instead of a Matrix. This is the right behavior of comprehension, it won't do extra guesswork for us, so we need to convert the nested array to matrix manually, which can be done using vcat with splating operator(...):
julia> vcat(viewDirections...)
6×3 Array{Float64,2}:
-1.0 -1.0 1.0
-1.0 1.0 1.0
0.0 -1.0 1.0
0.0 1.0 1.0
1.0 -1.0 1.0
1.0 1.0 1.0
It seems like you're constructing homogeneous coordinates from 2D Euclidean space. Using Base.Iterators.product is a more concise and robust way to create the iterator:
julia> w = linspace(-1,1,3)
-1.0:1.0:1.0
julia> h = linspace(-1,1,2)
-1.0:2.0:1.0
julia> r = 1.0
1.0
julia> viewDirections = [collect(i) for i in Iterators.product(w, h, r)]
3×2 Array{Array{Float64,1},2}:
[-1.0, -1.0, 1.0] [-1.0, 1.0, 1.0]
[0.0, -1.0, 1.0] [0.0, 1.0, 1.0]
[1.0, -1.0, 1.0] [1.0, 1.0, 1.0]
julia> hcat(viewDirections...).'
6×3 Array{Float64,2}:
-1.0 -1.0 1.0
0.0 -1.0 1.0
1.0 -1.0 1.0
-1.0 1.0 1.0
0.0 1.0 1.0
1.0 1.0 1.0
Note that, the order of coordinates is different from your original version, that's because Julia is column-major, Iterators.product will iterate the rightest dimension "outestly" i.e. [[i j r] for j in y for i in x ]. If the order is important in your use case, just pay attention to it.
Here are some benchmark results when width/height goes large:
julia> w = linspace(-1,1,300)
-1.0:0.006688963210702341:1.0
julia> h = linspace(-1,1,200)
-1.0:0.010050251256281407:1.0
julia> foo(w,h,r) = hcat([collect(i) for i in Iterators.product(w, h, r)]...).'
julia> bar(w,h,r) = vcat([[i j r] for i in w for j in h]...)
julia> #btime foo($w,$h,$r);
6.172 ms (60018 allocations: 10.99 MiB)
julia> #btime bar($w,$h,$r);
11.294 ms (360028 allocations: 17.02 MiB)

error with vectorized function in Julia: "arrays could not be broadcast to a common size"

I get an error when trying to evaluate the following function in Julia (Version 0.3.11, 2015-07-27 06:18 UTC, LinuxMint Rebecca):
# this_script.jl
# global parameters
c = [ 1.0 , 2.0]
u = [-1.0 , 3.5]
# A simplified version of a more complicated function
function f(x,y)
xi = c .* (x/y - u)
1.0 + sum( erfi(xi) )
end
#vectorize_2arg Number f
I can evaluate things like f(2,1), f(2+im,1), or
x=linspace(-2,2,4);
f(x,x)
y=rand(4,4)
f(y,y)
However, the following lines throw an error:
u=repmat(x,1,4)
f(u,u)
ERROR: arrays could not be broadcast to a common size
in broadcast_shape at broadcast.jl:40
in .* at broadcast.jl:278
in f at operators.jl:377
in include at ./boot.jl:245
in include_from_node1 at ./loading.jl:128
while loading this_script.jl, in expression starting on line 103
After that, I cannot evaluate f anymore even with f(2,1) nor f(x,x). Notice that u and y have the same dimensions and type.
How can I handle this?
The problem is that you've updated u to be 4x4, but c is still a two element vector.
julia> c,u
([1.0,2.0],
4x4 Array{Float64,2}:
-2.0 -2.0 -2.0 -2.0
-0.666667 -0.666667 -0.666667 -0.666667
0.666667 0.666667 0.666667 0.666667
2.0 2.0 2.0 2.0 )
julia> c.*(1/2-u)
ERROR: DimensionMismatch("arrays could not be broadcast to a common size")
(As an aside, note that globals like c and u can be a performance trap unless they're marked as const.)

Resources