Julia: Question about variable binding, mutating, and mutable functions - recursion

I am writing code in Julia which collects some output from a function foo (which mutates its input argument), and I'm trying to append the recursive evaluations from this function in an array A.
For instance, foo!(x) changes the value of x by adding 1 to each of its elements.
function foo!(x)
x .= x .+ 1
return(x)
end
julia> x = [1, 1];
julia> foo!(x);
julia> x
2-element Array{Int64,1}:
2
2
I want to create an array A which stores the value of x = f(x) over a fixed range. However, A just ends up containing multiple copies of the final value of f(x), e.g.,
julia> x = [1, 1];
julia> A = [x];
julia> for i=1:3
push!(A, foo!(x))
end
julia> A
4-element Array{Array{Int64,1},1}:
[4, 4]
[4, 4]
[4, 4]
[4, 4]
I'm trying to get it to get it to efficiently output something similar to
julia> B
4-element Array{Array{Int64,1},1}:
[1, 1]
[2, 2]
[3, 3]
[4, 4]
I haven't been able to find a helpful resources for a developing a solid understanding of mutations, or the order in which mutations are executed in Julia. Any help in this regard would be greatly appreciated!

The way you've written it, you repeatedly push! the same object into A, which your foo! function mutates:
julia> x = [1, 1]
2-element Vector{Int64}:
1
1
julia> A = [x]
1-element Vector{Vector{Int64}}:
[1, 1]
julia> foo!(x)
2-element Vector{Int64}:
2
2
julia> A
1-element Vector{Vector{Int64}}:
[2, 2]
One way of fixing this is to copy the elements in A before x gets mutated:
julia> for i ∈ 1:3
A[i] = copy(x)
push!(A, foo!(x))
end
julia> A
4-element Vector{Vector{Int64}}:
[1, 1]
[2, 2]
[3, 3]
[4, 4]
A classic read on values vs. bindings can be found here.

By using only push! you are just creating an array of references to a single array (ie x). This is why you see the same value repeated many times.
If you want to keep copies of the value of x across invocations of foo! you can use copy:
julia> foo!(x) = x .+= 1
foo! (generic function with 1 method)
julia> x = [0,0];
julia> A = [copy(foo!(x)) for i in 1:4]
4-element Vector{Vector{Int64}}:
[1, 1]
[2, 2]
[3, 3]
[4, 4]

Related

How to sum multi dimensional vectors of type "Any" in julia?

julia> A=[]
Any[]
julia> B=[]
Any[]
julia> C=[]
Any[]
julia> push!(A,0.0)
1-element Vector{Any}:
0.0
julia> push!(B,0.0)
1-element Vector{Any}:
0.0
julia> push!(C,0.0)
1-element Vector{Any}:
0.0
julia> push!(C,5.0)
2-element Vector{Any}:
0.0
5.0
julia> A+B+C
ERROR: DimensionMismatch("dimensions must match: a has dims (Base.OneTo(1),), b has dims (Base.OneTo(2),), mismatch at 1")
All you need is sum(A) + sum(B) + sum(C), as #OscarDowson points out. sum will reduce a multidimensional array to a single sum value, so there's no dimension mismatch when you sum the result of that.
If you have many such arrays, say:
julia> A = [0.0]
1-element Vector{Float64}:
0.0
julia> B = [1.0, 2.0]
2-element Vector{Float64}:
1.0
2.0
julia> C = [2.0 0.0]
1×2 Matrix{Float64}:
2.0 0.0
julia> D = [0.0 ;;; 0.0] # 3-dimensional array
1×1×2 Array{Float64, 3}:
[:, :, 1] =
0.0
[:, :, 2] =
0.0
you can also do:
julia> sum(sum(array) for array in (A, B, C, D))
5.0

How can I distinguish arguments and local variables in slot of Julia codeinfo?

I am studying Julia static analysis, and I have the following function:
function f(x,y,z)
d=x+y
d=d*2*z
end
i use code_typed to analyze it.
julia> y=code_typed(f)
1-element Vector{Any}:
CodeInfo(
1 ─ %1 = (x + y)::Any
│ %2 = (%1 * 2)::Any
│ %3 = (%2 * z)::Any
└── return %3
) => Any
i can get slots and slot types of it.
julia> y[1].first.slotnames
5-element Vector{Symbol}:
Symbol("#self#")
:x
:y
:z
:d
julia> y[1].first.slottypes
5-element Vector{Any}:
Core.Const(f)
Any
Any
Any
Any
but do i have any way to know which is argument and which is local variables among the slots?
You can use Base.argnames to find out arguments of your function:
julia> Base.method_argnames.(methods(f))
1-element Vector{Vector{Symbol}}:
[Symbol("#self#"), :x, :y, :z]
You can extract this from the CodeInfo object as well:
julia> Base.method_argnames(y[1].first.parent.def)
4-element Vector{Symbol}:
Symbol("#self#")
:x
:y
:z

How to create a method for an array of arrays in Julia?

I am clearly missing something fundamental here. How can I change the second method of my function to accept c? Additionally, I would really prefer to use AbstractArray instead of AbstractVector as the type so as not to restrict the dimension either, but I wanted to cut down on potential sources of error.
function f(x::AbstractVector{Int})
println(x)
end # f (generic function with 1 method)
function f(x::AbstractVector{AbstractVector{Int}})
for i in x
println(i)
end
end # f (generic function with 2 methods)
a=[1,2,3] # 3-element Array{Int64,1}:
b=[4,5,6] # 3-element Array{Int64,1}:
c=[a,b] # 2-element Array{Array{Int64,1},1}:
typeof(a) <: AbstractVector{Int} # true
typeof(c) <: AbstractVector{AbstractVector{Int}} # false
f(a) # [1, 2, 3]
f(c) # ERROR: MethodError: no method matching f(::Array{Array{Int64,1},1})
Quoting the manual:
Concrete Point types with different values of T are never subtypes of each other:
julia> struct Point{T} end
julia> Point{Float64} <: Point{Int64}
false
julia> Point{Float64} <: Point{Real}
false
This last point is very important: even though Float64 <: Real we DO NOT have Point{Float64} <: Point{Real}.
Translated to your example, as you noted,
julia> Vector{Int} <: AbstractVector{Int}
true
julia> Vector{Vector{Int}} <: AbstractVector{AbstractVector{Int}}
false
What you need here is
julia> Vector{Vector{Int}} <: AbstractVector{T} where T <: AbstractVector{Int}
true
or the convenient shorthand
julia> Vector{Vector{Int}} <: AbstractVector{<:AbstractVector{Int}}
true

Is there an elegant way to do "not in" in Julia?

I am trying to convert a python script to Julia. I am checking to make sure I am doing this code in the most optimal way. Please see the following code:
julia> a = [1,2,3,4,5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> if 1 in a
print("1 is in a")
end
1 is in a
julia> if 6 not in a
print("6 not in a")
end
ERROR: TypeError: non-boolean (Int64) used in boolean context
Stacktrace:
[1] top-level scope at REPL[6]:1
julia> push!(a, 6)
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> if (6 in a) == true
print("6 in a")
end
6 not in a
julia> b = [1]
1-element Array{Int64,1}:
1
julia> if (6 in b) == true
print("6 in b")
end
Am I doing this "not in" check correctly?
julia> a = [1, 2, 3, 4, 5];
julia> 6 ∉ a
true
The ∉ symbol can be typed in the REPL by typing \notin and then hitting TAB. Of course, the ∈ symbol is also available as an alternative to in by typing \in and hitting TAB:
julia> 6 ∈ a
false
Sometimes you need a vectorized version:
julia> x = [2, 7];
julia> x .∉ Ref(a)
2-element BitArray{1}:
0
1
The Ref is needed in this case so that a is treated as a scalar in the broadcasting operation.
If you prefer to avoid Unicode characters, you can write !(6 in a) instead of 6 ∉ a.

Scheme vector-fold and vector-map analog in Clojure?

How can I make in Clojure functions vector-fold and vector-map from scheme?
To map over a vector and get a vector back you can use mapv.
To fold over a vector you can use regular reduce since vectors are seqable.
To get an index in the function you're iterating with, there's map-indexed or you can use (range):
(mapv (fn [i e] [i e]) [1 2 3] (range))
=> [[1 0] [2 1] [3 2]]

Resources