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 =#
Related
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.
I am trying to use ForwardDiff in a library where almost all functions are restricted to only take in Floats. I want to generalise these function signatures so that ForwardDiff can be used while still being restrictive enough so functions only take numeric values and not things like Dates. I have alot of functions with the same name but different types (ie functions that take in "time" as either a float or a Date with the same function name) and do not want to remove the type qualifiers throughout.
Minimal Working Example
using ForwardDiff
x = [1.0, 2.0, 3.0, 4.0 ,5.0]
typeof(x) # Array{Float64,1}
function G(x::Array{Real,1})
return sum(exp.(x))
end
function grad_F(x::Array)
return ForwardDiff.gradient(G, x)
end
G(x) # Method Error
grad_F(x) # Method error
function G(x::Array{Float64,1})
return sum(exp.(x))
end
G(x) # This works
grad_F(x) # This has a method error
function G(x)
return sum(exp.(x))
end
G(x) # This works
grad_F(x) # This works
# But now I cannot restrict the function G to only take numeric arrays and not for instance arrays of Dates.
Is there are a way to restict functions to only take numeric values (Ints and Floats) and whatever dual number structs that ForwardDiff uses but not allow Symbols, Dates, etc.
ForwardDiff.Dual is a subtype of the abstract type Real. The issue you have, however, is that Julia's type parameters are invariant, not covariant. The following, then, returns false.
# check if `Array{Float64, 1}` is a subtype of `Array{Real, 1}`
julia> Array{Float64, 1} <: Array{Real, 1}
false
That makes your function definition
function G(x::Array{Real,1})
return sum(exp.(x))
end
incorrect (not suitable for your use). That's why you get the following error.
julia> G(x)
ERROR: MethodError: no method matching G(::Array{Float64,1})
The correct definition should rather be
function G(x::Array{<:Real,1})
return sum(exp.(x))
end
or if you somehow need an easy access to the concrete element type of the array
function G(x::Array{T,1}) where {T<:Real}
return sum(exp.(x))
end
The same goes for your grad_F function.
You might find it useful to read the relevant section of the Julia documentation for types.
You might also want to type annotate your functions for AbstractArray{<:Real,1} type rather than Array{<:Real, 1} so that your functions can work other types of arrays, like StaticArrays, OffsetArrays etc., without a need for redefinitions.
This would accept any kind of array parameterized by any kind of number:
function foo(xs::AbstractArray{<:Number})
#show typeof(xs)
end
or:
function foo(xs::AbstractArray{T}) where T<:Number
#show typeof(xs)
end
In case you need to refer to the type parameter T inside the body function.
x1 = [1.0, 2.0, 3.0, 4.0 ,5.0]
x2 = [1, 2, 3,4, 5]
x3 = 1:5
x4 = 1.0:5.0
x5 = [1//2, 1//4, 1//8]
xss = [x1, x2, x3, x4, x5]
function foo(xs::AbstractArray{T}) where T<:Number
#show xs typeof(xs) T
println()
end
for xs in xss
foo(xs)
end
Outputs:
xs = [1.0, 2.0, 3.0, 4.0, 5.0]
typeof(xs) = Array{Float64,1}
T = Float64
xs = [1, 2, 3, 4, 5]
typeof(xs) = Array{Int64,1}
T = Int64
xs = 1:5
typeof(xs) = UnitRange{Int64}
T = Int64
xs = 1.0:1.0:5.0
typeof(xs) = StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}
T = Float64
xs = Rational{Int64}[1//2, 1//4, 1//8]
typeof(xs) = Array{Rational{Int64},1}
T = Rational{Int64}
You can run the example code here: https://repl.it/#SalchiPapa/Restricting-function-signatures-in-Julia
Say I have a tuple of Cchar like
str = ('f', 'o', 'o', '\0', '\0')
and I want to convert it to a more traditional string. If str were a Vector, I could create Ptr and do all sorts of things with that. I've tried various ways of passing str to methods of pointer, Ptr, Ref, and unsafe_string without success since those normally work on arrays rather than tuples. Any suggestions?
Note: what I really have is a C struct that looks like
typedef struct foo {
char str[FOO_STR_MAX_SZ];
...
} foo_t;
which Clang.jl wrapped as
struct foo_t
str :: NTuple{FOO_STR_MAX_SZ, UInt8}
...
end
I also played around with NTuple of Cchar (ie, Int8) instead of UInt8, and I tried to use SVector instead of NTuple as well. But I still couldn't find a way to generate a Ptr from the str field. Am I missing something?
Since you asked the question, I think collecting it to an array a = collect(x.str) is not the answer you are expecting...
You could use ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a) to get the pointer of a even if a is immutable. However, blindly using it will produce some confusing results:
julia> struct foo_t
str::NTuple{2, UInt8}
end
julia> a = foo_t((2, 3))
foo_t((0x02, 0x03))
julia> ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a.str)
Ptr{Nothing} #0x00007f4302c4f670
julia> ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a.str)
Ptr{Nothing} #0x00007f4302cc47e0
We got two different pointers from the same object! The reason is that since NTuple is immutable, the compiler will do many "optimizations" for it, for example, coping it every time you use it. This is why getting pointers from immutable objects is explicitly forbidden in the source code:
function pointer_from_objref(#nospecialize(x))
#_inline_meta
typeof(x).mutable || error("pointer_from_objref cannot be used on immutable objects")
ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
end
However, there are several workarounds for it. First, since the expression a.str copies the tuple, you can avoid this expressoin and calculate the address of it directly using the address of a and fieldoffset(typeof(a), 1). (1 means str is the first field of foo_t)
julia> p = Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1)
Ptr{UInt8} #0x00007f4304901df0
julia> p2 = Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1)
Ptr{UInt8} #0x00007f4304901df0
julia> p === p2
true
julia> unsafe_store!(p, 5)
Ptr{UInt8} #0x00007f4304901df0
julia> a
foo_t((0x05, 0x03))
It now works. However, there are still caveats: when you try to wrap the code in a function, it became wrong again:
julia> mut!(a) = unsafe_store!(Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1), 8)
mut! (generic function with 1 method)
julia> mut!(a)
Ptr{UInt8} #0x00007f42ec560294
julia> a
foo_t((0x05, 0x03))
a is not changed because, well, foo_t itself is also immutable and will be copied to mut!, so the change made within the function will not be visible outside. To solve this, we need to wrap a in a mutable object to give it a stable address in the heap. Base.RefValue can be used for this purpose:
julia> b = Base.RefValue(a)
Base.RefValue{foo_t}(foo_t((0x05, 0x03)))
julia> mut!(b) = unsafe_store!(Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), b)) + fieldoffset(typeof(b), 1) + fieldoffset(typeof(a), 1), 8)
mut! (generic function with 1 method)
julia> mut!(b)
Ptr{UInt8} #0x00007f43057b3820
julia> b
Base.RefValue{foo_t}(foo_t((0x08, 0x03)))
julia> b[]
foo_t((0x08, 0x03))
As explained by #张实唯, str is a constant array which is stack-allocated, so you need to use pointer arithmetics to access the field. There is a package called Blobs.jl for this kinda purpose. As for the mutability, you could also use Setfield.jl for convenience.
BTW, Clang.jl do support generating mutable structs via ctx.options["is_struct_mutable"] = true.
How could I check the element type of a nested array assumming I don't know the level of nesting?:
julia> a = [[[[1]]]]
1-element Array{Array{Array{Array{Int64,1},1},1},1}:
Array{Array{Int64,1},1}[Array{Int64,1}[[1]]]
julia> etype(a)
Int64?
As it is often the case for type computations, a recursive approach works very well:
nested_eltype(x) = nested_eltype(typeof(x))
nested_eltype{T<:AbstractArray}(::Type{T}) = nested_eltype(eltype(T))
nested_eltype{T}(::Type{T}) = T
This has no runtime overhead:
julia> #code_llvm nested_eltype([[[[[[[[[[1]]]]]]]]]])
define %jl_value_t* #julia_nested_eltype_71712(%jl_value_t*) #0 {
top:
ret %jl_value_t* inttoptr (i64 140658266768816 to %jl_value_t*)
}
There is probably a clever way to do this with one line, but in the meantime, you can use recursive calls to eltype to do this inside a while loop:
function nested_eltype(x::AbstractArray)
y = eltype(x)
while y <: AbstractArray
y = eltype(y)
end
return(y)
end
Note that this works for nested arrays of any dimension, ie it doesn't just have to be Vector like the example in your question...
This is a generated version using .depth attribute:
#generated function etype{T}(x::T)
ex = :(x)
for i = 1:T.depth
ex = :($ex |> eltype)
end
ex
end
julia> a = [[[[1]]]]
1-element Array{Array{Array{Array{Int64,1},1},1},1}:
Array{Array{Int64,1},1}[Array{Int64,1}[[1]]]
julia> etype(a)
Int64
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