I was working on a structure with theirs fields are vectors and matrices and I have a vector of it. I need to change elements of this vector to be of a structure which its fields are static vectors and matrices. How can I do that?
I’m not sure what is your doubt, but be careful in that:
julia> isconcretetype(MVector{Float64})
false
julia> isconcretetype(MVector{3,Float64})
true
julia> isconcretetype(MMatrix{Float64})
false
julia> isconcretetype(MMatrix{3,3,Float64,9})
true
(meaning that your RRs
structure has abstract fields as it is)
Concerning the rest, I don’t think I get what you want, but maybe something like this:
julia> struct A
x::Vector{Float64}
end
julia> struct B
x::SVector{3,Float64}
end
julia> B(a::A) = B(SVector{3,Float64}(a.x...))
B
julia> a = A(rand(3))
A([0.8719748854921427, 0.48118038068468383, 0.9809479464441135])
julia> B(a)
B([0.8719748854921427, 0.48118038068468383, 0.9809479464441135])
julia> v = [ A(rand(3)), A(rand(3)) ]
2-element Vector{A}:
A([0.3015634495239551, 0.6358999576371009, 0.09630161737144594])
A([0.5218204629518881, 0.289523727629152, 0.16346835337852283])
julia> B.(v)
2-element Vector{B}:
B([0.3015634495239551, 0.6358999576371009, 0.09630161737144594])
B([0.5218204629518881, 0.289523727629152, 0.16346835337852283])
You don’t need the MVector(....)
call at all when constructing B
. You can write this as simply as:
B(a::A) = B(a.x, a.d)
You can also automatically generate a function like this with @eval
:
@eval B(a::A) = B($([:(a.$x) for x in fieldnames(A)]...))
In which sense? What do you mean by identical?
From where VVector
comes? I am not aware of this data structure. About the differences:
- You can only do something like
Bx[i].d = rand(3,3)*rand(3)
, i.e., replacing the whole array in a swoop, if thestruct
you define is mutable. - If your
struct
is not mutable, then you can yet change the values inside the matrix if the matrix type is mutable.MVector
is mutable and, while you cannot replace the wholeMVector
with a new one, you can replace the values inside it withBx[i].d .= rand(3,3)*rand(3)
(notice the dot before the equal sign). - If your struct is not mutable neither the type of the matrix inside it then you cannot modify its value after creation and must create a new object to pass around each time you need the value to be changed.
About (1), I mean that you cannot replace the array inside the struct by an entirely new array, the array used in the construction of the struct will always be the same, the only thing that can be changed is its contents.
julia> struct A; a :: Vector{Int}; end
julia> x = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> a_var = A(x)
A([1, 2, 3])
julia> a_var.a = [4, 5, 6]
ERROR: setfield! immutable struct of type A cannot be changed
Stacktrace:
[1] setproperty!(::A, ::Symbol, ::Array{Int64,1}) at ./Base.jl:34
[2] top-level scope at REPL[4]:1
julia> x
3-element Array{Int64,1}:
1
2
3
julia> a_var.a .= [4, 5, 6]
3-element Array{Int64,1}:
4
5
6
julia> x
3-element Array{Int64,1}:
4
5
6
julia> mutable struct B; b :: Vector{Int}; end
julia> y = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> b_var = B(y)
B([1, 2, 3])
julia> b_var.b = [4, 5, 6]
3-element Array{Int64,1}:
4
5
6
julia> y
3-element Array{Int64,1}:
1
2
3
julia> b_var.b
3-element Array{Int64,1}:
4
5
6
julia> b_var.b
3-element Array{Int64,1}:
4
5
6
- Yes, you can.
I fell like the answers to some of your questions could be obtained by just running your code through the REPL.
- Yes. You cannot replace values inside
d
because theSArray
object is immutable. However, theB3
object is mutable, and therefore a new object may be assigned to fieldd
. - What do you mean by unique usage? I do not undertsand the question.
- You cannot “solve” the error. It is a consequence of you using a
SArray
(i.e., an immutable object), you cannot mutate anSArray
. The best you can do is to create a new array with the changed values and assign it.a_var.d = [4, 5, a_var.d[3]]
mutate
does not exist, not as a function, at least. Mutation happens when you use =
but the left-hand side is not just a variable name but a field inside an object (or a position inside an array). For example, a = 10
is a binding that binds the name a
to the value 10 (i.e., not mutation) but a.my_field = 10
is an assignment of the value 10 to the field my_field
of object a
(i.e., a mutation). a = 10
is a language primitive, a.my_field = 10
calls Base.setproperty!(a, :my_field, 10)
and its meaning can be changed by adding methods to this function. Finally, .=
is another completely distinct thing, it can never be used for binding (i.e., to create a new variable) it only works on already existing objects/variables that are containers and it mutates each element of the container in the left-hand side to the value of the elements on the container of the right-hand side. You can use ?.=
in the REPL to check its documentation, it is replaced by Julia to a call to broadcast!(identity, left_hand_variable, right_hand_variable)
.
In other words, things that look similar are completely different things, in fact.
See: Assignment and mutation · JuliaNotes.jl
It compiles other previous answers to that.
Thank you very much for explanation. I know that in Julia a scalar is immutable. However, if I have an immutable structure B3
, is there any way (a trick) to change its scalar property s
to be mutable, i.e. B3
remains immutable?
struct B3
d::MVector{3,Float64}
s::Int64
end
a_var = B3([1,2,3],0)
a_var.d[1:3] = [6,6,6]
a_var.s = Int(4)
ERROR: setfield!: immutable struct of type B3 cannot be changed
Not really.
You can change field s
to be of type Base.RefValue{Int64}
but this needs the struct
definition to be different and you will need to use []
every time you want to access the value, as in:
julia> struct B3
s::Base.RefValue{Int64}
end
julia> b3 = B3(Ref(1))
B3(Base.RefValue{Int64}(1))
julia> b3.s[]
1
julia> b3.s[] = 2
2
julia> b3
B3(Base.RefValue{Int64}(2))
What you will probably want is to rebuild the object with everything the same except the changed value.
julia> struct B3
d::Vector{Float64}
s::Int64
end
julia> b3 = B3([1, 2, 3], 10)
B3([1.0, 2.0, 3.0], 10)
julia> b3 = B3(b3.d, 11)
B3([1.0, 2.0, 3.0], 11)
There is a library called Setfield.jl
that make it easier to re-create an object changing just a single field, but note this is not the same as changing the original.
Thank you very much for your very help feedbacks!