Change the array of struct field value in Julia - julia

Let's say I want to define the following object
mutable struct Coord
x::Float
y::Float
end
and create a vector of the coordinate
coordVec = Vector{Coord}(undef, 3)
by using for loop we can define the value of coordinate in the coordVec, but how to assign a new value of the coordinate? I have try following way but not working
coordVec[1].x = 3.1
(p->p.x).(coordVec)[1] = 3.1

The problem is that your array coordVec is uninitialized because you used the undef to construct the array, meaning its values are undefined:
julia> coordVec = Vector{Coord}(undef, 3)
3-element Array{Coord,1}:
#undef
#undef
#undef
And therefore you can't update the fields. If you put Coord objects in your array you can update them as expected:
julia> coordVec[2] = Coord(1, 2)
Coord(1.0, 2.0)
julia> coordVec[2].x = 3.0
3.0
julia> coordVec
3-element Array{Coord,1}:
#undef
Coord(3.0, 2.0)
#undef

When initializing the whole Vector at once it is also always to consider broadcasting (this assume that Coord has Float64 fields:
julia> Coord.([1.,2.,3.], 4:6)
3-element Array{Coord,1}:
Coord(1.0, 4.0)
Coord(2.0, 5.0)
Coord(3.0, 6.0)

Related

Can two structs reference each other? - Julia

I have a struct that includes a field of the same type, which I cannot assign at creation.
Julia does not seem to like the following. (It coughs up a circular reference complaint.) I intend this to boil the problem down to its essentials
mutable struct Test
test:: Union{Test,Nothing}
end
t1 = Test(nothing)
t2 = Test(nothing)
t1.test = t2
t2.test = t1
What is the right way to achieve this? (E.g., how can I point to my partner, who can point to me as his partner?)
Separately, is the above currently the right way to have an initially "null" field?
What you propose is a correct way to have initially nothing field.
Alternatively you can do something like:
julia> mutable struct Test
test::Test
Test(t::Test) = new(t)
Test() = new()
end
julia> t1 = Test()
Test(#undef)
julia> t2 = Test()
Test(#undef)
julia> t1.test = t2
Test(#undef)
julia> t2.test = t1
Test(Test(Test(#= circular reference #-2 =#)))
where you have temporarily #undef field.
See also Incomplete Initialization section of the Julia Manual.
Edit
An example of circular reference with a standard Vector{Any}:
julia> x = Any[]
Any[]
julia> push!(x, x)
1-element Vector{Any}:
1-element Vector{Any}:#= circular reference #-1 =#

Julia 1.1.1 - absolutely global variables

I am coming from Fortran and I use global vectors of data over the full program. Usually I declare a module:
module xyz
real, allocatable :: vector(:,:,:) ! a 3 dim vector, undefined
end module
Now, in some place, let say Subroutine (Function) A, I am allocating memory for it and initialize to some values:
allocate(vector(10,20,30))
vector = ran()
Now, in any other unit of the program (Subroutine or function B, C, D...), if I am using the module, i.e:
using xyz
The above declared vector is available.
I was not able to obtain this behavior in the new technological wonder Julia 1.1. The scope rules are just giving a headache.
In Julia the rules for accessing variables from other modules are explained in detail here.
The key issues in your situation are the following things:
a variable is visible after using only if it is exported in the module
you are allowed to access the variable in other modules
you are not allowed to rebind a variable from other modules
This means that global variable binding creation operation is private to the module.
Here is a simple example module definition:
module M
export x
x = Int[]
function rebindx()
global x = Int[]
end
end
now assume you define and later use it in REPL (it could be any other module)
julia> module M
export x
x = Int[]
function rebindx()
global x = Int[]
end
end
Main.M
julia> using .M
Now you can access x:
julia> x
0-element Array{Int64,1}
julia> push!(x, 1)
1-element Array{Int64,1}:
1
julia> x
1-element Array{Int64,1}:
1
julia> x[1] = 10
10
julia> x
1-element Array{Int64,1}:
10
But not rebind x:
julia> x = 0
ERROR: cannot assign variable M.x from module Main
However, you can call a function defined inside M module to change the binding of x like this:
julia> x
1-element Array{Int64,1}:
10
julia> M.rebindx()
0-element Array{Int64,1}
julia> x
0-element Array{Int64,1}
This was possible because rebindx was defined inside module M so it has the right to change the binding of variable x defined in this module.

Push SVector into vector of SVector in Julia

I want to push a SVector (provided by JuliaArrays/StaticArrays.jl) into a vector of SVector. The following code is my trial:
using StaticArrays
lst = Vector{SVector{2, Float64}}[]
a = SVector(1, 2)
push!(lst, a)
But it causes the following error:
ERROR: LoadError: MethodError: Cannot `convert` an object of type Int64 to an object of type SArray{Tuple{2},Float64,1,2}
How can I fix it?
The mistake you are making is that you create an Array of Array of an SVector. T[] creates an empty array of type T.
# This creates an empty array of type Float64
julia> lst = Float64[]
0-element Array{Float64,1}
# This creates an empty array of a Float64 array
julia> lst = Vector{Float64}[]
0-element Array{Array{Float64,1},1}
So you need to redefine your array as an array of SVector.
julia> lst = SVector{2, Float64}[] # an empty 1D array(i.e. Vector) of `SVector`
0-element Array{SArray{Tuple{2},Float64,1,2},1}
julia> a = SVector(1, 2)
2-element SArray{Tuple{2},Int64,1,2}:
1
2
julia> push!(lst, a)
1-element Array{SArray{Tuple{2},Float64,1,2},1}:
[1.0, 2.0]
You can also use this instead of your way of empty array definition:
lst = Vector{SVector{2, Float64}}(undef, 0) # this creates a `Vector` of `SVector` of size 0 (empty)

How to port C++ union to Julia

I am trying to port some code and now I've hit a sticky bit. The original code is in C++. I need to port a union that has two 32 bit ints (in an array) and a double.
So far I have:
I1 = UInt32(56) # arbitrary integer values for example
I2 = UInt32(1045195987)
# do transforms on I1 and I2 as per the code I'm porting
A = bits(I1)
B = bits(I2)
return parse(Float64, string(A,B))
Is this the way to do it? The string operation seems expensive. Any advice appreciated.
I also come from mostly C/C++ programming, and this is what I do to handle the problem:
First, create an immutable type with two UInt32 elements:
immutable MyType
a::UInt32
b::UInt32
end
Then you can convert a vector of Float64 to that type with reinterpret.
For example:
julia> x = [1.5, 2.3]
2-element Array{Float64,1}:
1.5
2.3
julia> immutable MyType ; a::UInt32 ; b::UInt32 ; end
julia> y = reinterpret(MyType, x)
2-element Array{MyType,1}:
MyType(0x00000000,0x3ff80000)
MyType(0x66666666,0x40026666)
julia> x[1]
1.5
julia> y[1]
MyType(0x00000000,0x3ff80000)
julia> y[1].a
0x00000000
julia> y[1].b
0x3ff80000
Note: the two vectors still point to the same memory, so you can even update elements, using either type.
julia> x[1] = 10e91
1.0e92
julia> y[1].a
0xbf284e24
julia> y[1].b
0x53088ba3
julia> y[1] = MyType(1,2)
MyType(0x00000001,0x00000002)
julia> x[1]
4.2439915824e-314

Julia: check whether array entry is undef

What is the best way in Julia to check whether an array entry is #undef?
Example:
julia> a = Array(Vector,2)
julia> isdefined(a[1]) # fails
julia> isempty(a[1]) # fails
You can push the access into isdefined by using isdefined(a, 1) instead of isdefined(a[1]):
julia> a = Array(Vector,2);
julia> a[2] = {10}
1-element Array{Any,1}:
10
julia> a
2-element Array{Array{T,1},1}:
#undef
{10}
julia> isdefined(a[1])
ERROR: access to undefined reference
in getindex at array.jl:246
julia> isdefined(a, 1)
false
julia> isdefined(a, 2)
true

Resources