#noinline f1(x::Int) = x + 1
#noinline f2(x::Int) = x + 2
#Base.pure function f(x::Int, p::Int)
if p == 1
return f1(x)
else
return f2(x)
end
end
I would like a call such as f(1, 2) to be compiled as f2(1) directly without branching due to 2 being a constant.
#code_warntype f(1, 2)
Body::Int64
│╻ ==5 1 ─ %1 = (p === 1)::Bool
│ └── goto #3 if not %1
│ 6 2 ─ %3 = invoke Main.f1(_2::Int64)::Int64
│ └── return %3
│ 8 3 ─ %5 = invoke Main.f2(_2::Int64)::Int64
│ └── return %5
#code_native f(1, 2)
.text
; Function f {
; Location: In[1]:5
; Function ==; {
; Location: In[1]:5
pushq %rax
cmpq $1, %rsi
;}
jne L21
; Location: In[1]:6
movabsq $julia_f1_35810, %rax
callq *%rax
popq %rcx
retq
; Location: In[1]:8
L21:
movabsq $julia_f2_35811, %rax
callq *%rax
popq %rcx
retq
nopw %cs:(%rax,%rax)
;}
However by the look of the code it generates, constant propagation doesn't happen. Is it possible the constant propagation happens in real life but the monitoring tool such as #code_native or #code_warntype are unable to tell because they don't treat 2 as a constant.
Constant propagation will happen if you call f in a compiled part of code with a constant argument (e.g. called from a function).
So in your case you have:
julia> #noinline f1(x::Int) = x + 1
f1 (generic function with 1 method)
julia> #noinline f2(x::Int) = x + 2
f2 (generic function with 1 method)
julia> function f(x::Int, p::Int)
if p == 1
return f1(x)
else
return f2(x)
end
end
f (generic function with 1 method)
julia> #code_warntype f(1,2)
Body::Int64
2 1 ─ %1 = (p === 1)::Bool │╻ ==
└── goto #3 if not %1 │
3 2 ─ %3 = invoke Main.f1(_2::Int64)::Int64 │
└── return %3 │
5 3 ─ %5 = invoke Main.f2(_2::Int64)::Int64 │
└── return %5 │
julia> g() = f(1,2)
g (generic function with 1 method)
julia> #code_warntype g()
Body::Int64
1 1 ─ return 3
julia> h(x) = f(x,2)
h (generic function with 1 method)
julia> #code_warntype h(10)
Body::Int64
1 1 ─ %1 = invoke Main.f2(_2::Int64)::Int64 │╻ f
└── return %1
As a side note, AFAIK #pure macro should not be used with functions that call generic functions, as is the case of f.
EDIT: I have found an interesting corner case here:
julia> f(x,p) = (p==1 ? sin : cos)(x)
f (generic function with 1 method)
julia> #code_warntype f(10, 2)
Body::Any
1 1 ─ %1 = (p === 1)::Bool │╻ ==
└── goto #3 if not %1 │
2 ─ %3 = Main.sin::Core.Compiler.Const(sin, false) │
└── goto #4 │
3 ─ %5 = Main.cos::Core.Compiler.Const(cos, false) │
4 ┄ %6 = φ (#2 => %3, #3 => %5)::Union{typeof(cos), typeof(sin)} │
│ %7 = (%6)(x)::Any │
└── return %7 │
julia> g() = f(10, 2)
g (generic function with 1 method)
julia> #code_warntype g()
Body::Float64
1 1 ─ %1 = invoke Base.Math.cos(10.0::Float64)::Float64 │╻╷ f
└── return %1 │
julia> h(x) = f(x, 2)
h (generic function with 1 method)
julia> #code_warntype h(10)
Body::Any
1 1 ─ %1 = invoke Main.f(_2::Int64, 2::Int64)::Any │
└── return %1
julia> z() = h(10)
z (generic function with 1 method)
julia> #code_warntype z()
Body::Float64
1 1 ─ %1 = invoke Base.Math.cos(10.0::Float64)::Float64 │╻╷╷ h
└── return %1
The thing that is interesting is that for g constant propagation happens as above, but not for h, but then if you wrap h in a function it happens again.
So in general the conclusion probably is that in standard cases in compiled code you can expect constant propagation to happen, but in complex cases the compiler may not be smart enough (of course this can improve in the future).
Related
Is there a way to access current_row_index in the following snippet ?
#with df begin
fn.(:col, current_row_index)
end
In this context, since you are broacasting just pass first axes of df:
julia> using DataFramesMeta
julia> fn(x, y) = (x, y)
fn (generic function with 1 method)
julia> df = DataFrame(col=["a", "b", "c"])
3×1 DataFrame
Row │ col
│ String
─────┼────────
1 │ a
2 │ b
3 │ c
julia> #with df begin
fn.(:col, axes(df, 1))
end
3-element Vector{Tuple{String, Int64}}:
("a", 1)
("b", 2)
("c", 3)
Does Julia provide something similar to std::bind in C++? I wish to do something along the lines of:
function add(x, y)
return x + y
end
add45 = bind(add, 4, 5)
add2 = bind(add, _1, 2)
add3 = bind(add, 3, _2)
And if this is possible does it incur any performance overhead?
As answered here you can obtain this behavior using higher order functions in Julia.
Regarding the performance. There should be no overhead. Actually the compiler should inline everything in such a situation and even perform constant propagation (so that the code could actually be faster). The use of const in the other answer here is needed only because we are working in global scope. If all this would be used within a function then const is not required (as the function that takes this argument will be properly compiled), so in the example below I do not use const.
Let me give an example with Base.Fix1 and your add function:
julia> using BenchmarkTools
julia> function add(x, y)
return x + y
end
add (generic function with 1 method)
julia> add2 = Base.Fix1(add, 10)
(::Base.Fix1{typeof(add), Int64}) (generic function with 1 method)
julia> y = 1:10^6;
julia> #btime add.(10, $y);
1.187 ms (2 allocations: 7.63 MiB)
julia> #btime $add2.($y);
1.189 ms (2 allocations: 7.63 MiB)
Note that I did not define add2 as const and since we are in global scope I need to prefix it with $ to interpolate its value into the benchmarking suite.
If I did not do it you would get:
julia> #btime add2.($y);
1.187 ms (6 allocations: 7.63 MiB)
Which is essentially the same timing and memory use, but does 6 not 2 allocations since in this case add2 is a type-unstable global variable.
I work on DataFrames.jl, and there using the patterns which we discuss here is very useful. Let me give just one example:
julia> using DataFrames
julia> df = DataFrame(x = 1:5)
5×1 DataFrame
Row │ x
│ Int64
─────┼───────
1 │ 1
2 │ 2
3 │ 3
4 │ 4
5 │ 5
julia> filter(:x => <(2.5), df)
2×1 DataFrame
Row │ x
│ Int64
─────┼───────
1 │ 1
2 │ 2
What the operation does is picking rows where values from column :x that are less than 2.5. The key thing to understand here is what <(2.5) does. It is:
julia> <(2.5)
(::Base.Fix2{typeof(<), Float64}) (generic function with 1 method)
so as you can see it is similar to what we would have obtained if we defined the x -> x < 2.5 function (essentially fixing the second argument of < function, as in Julia < is just a two argument function). Such shortcuts like <(2.5) above are defined in Julia by default for several common comparison operators.
I have implemented the next code for going down and right in a grid, and I am trying to implement some sort of counting like return +1 but I can't, if I'm forced to use global it makes the runtime considerably longer (like times 8 though it varies with the number of iterations).
Please advise on how to code correctly in this language.
I also thought about using pointers like in C but had hard time implementing it
function numOfPaths(NominalSize,x,y)
(x < NominalSize) && numOfPaths(NominalSize,x+1,y)
(y < NominalSize) && numOfPaths(NominalSize,x,y+1)
(x >= NominalSize && y>=NominalSize) && global count+=1;
end
count = 0;
t1 = #elapsed numOfPaths(16,0,0)
2nd version with Ref instead of using global, pretty much same horrible performance.
function numOfPaths(NominalSize,x,y)
(x < NominalSize) && numOfPaths(NominalSize,x+1,y)
(y < NominalSize) && numOfPaths(NominalSize,x,y+1)
((y >= NominalSize) && (x >= NominalSize)) && (ref[] += 1 ;)
end
count = 0;
ref = Ref(count)
t1 = #elapsed anse = numOfPaths(15,0,0)
With the current state of the Julia compiler I think you have two options (assuming you do not change the logic of your code).
The first one is leave things as they are in your code, but change count to be a global const. However, as you want to mutate it you have to introduce some wrapper, a natural one is Ref. So you can go with something like:
const count = Ref(0)
function numOfPaths(NominalSize,x,y)
(x < NominalSize) && numOfPaths(NominalSize,x+1,y)
(y < NominalSize) && numOfPaths(NominalSize,x,y+1)
(x >= NominalSize && y>=NominalSize) && global (count[] +=1)
end
count[] = 0
#time numOfPaths(16,0,0)
count[]
Now you could pass around count like this:
function numOfPaths(NominalSize,x,y, count=Ref(0))
(x < NominalSize) && numOfPaths(NominalSize,x+1,y, count)
(y < NominalSize) && numOfPaths(NominalSize,x,y+1, count)
(x >= NominalSize && y>=NominalSize) && (count[] +=1)
return count[]
end
as a parameter, but it will be a bit slower.
Finally (and this is an option that is a bit faster than the first one and is recommended) you can perform the accumulation of count without passing it as an argument (this time it will be just an integer):
function numOfPaths(NominalSize,x,y)
count = 0
x < NominalSize && (count += numOfPaths(NominalSize,x+1,y))
y < NominalSize && (count += numOfPaths(NominalSize,x,y+1))
x >= NominalSize && y>=NominalSize && (count+=1)
return count
end
EDIT:
Additionally let me comment on what does not work. Naturally you would want to rewrite your function like this:
function numOfPaths(NominalSize,x,y)
function f(x, y)
x < NominalSize && f(x+1,y)
y < NominalSize && f(x,y+1)
x >= NominalSize && y>=NominalSize && (count+=1)
end
count = 0
f(x, y)
return count
end
Unfortunately, currently such code is slow, as Julia is boxing count:
julia> #code_warntype numOfPaths(16, 0, 0)
Variables
#self#::Core.Compiler.Const(numOfPaths, false)
NominalSize::Int64
x::Int64
y::Int64
f#_5::Core.Box
count#_6::Core.Box
f#_7::Union{}
f#_8::Union{}
count#_9::Union{}
Body::Any
1 ─ (f#_5 = Core.Box())
│ (count#_6 = Core.Box())
│ %3 = Main.:(var"#f#3")::Core.Compiler.Const(var"#f#3", false)
│ %4 = Core.typeof(NominalSize)::Core.Compiler.Const(Int64, false)
│ %5 = Core.apply_type(%3, %4)::Core.Compiler.Const(var"#f#3"{Int64}, false)
│ %6 = f#_5::Core.Box
│ %7 = %new(%5, NominalSize, %6, count#_6)::var"#f#3"{Int64}
│ Core.setfield!(f#_5, :contents, %7)
│ Core.setfield!(count#_6, :contents, 0)
│ %10 = Core.isdefined(f#_5, :contents)::Bool
└── goto #3 if not %10
2 ─ goto #4
3 ─ Core.NewvarNode(:(f#_8))
└── f#_8
4 ┄ %15 = Core.getfield(f#_5, :contents)::Any
│ (%15)(x, y)
│ %17 = Core.isdefined(count#_6, :contents)::Bool
└── goto #6 if not %17
5 ─ goto #7
6 ─ Core.NewvarNode(:(count#_9))
└── count#_9
7 ┄ %22 = Core.getfield(count#_6, :contents)::Any
└── return %22
Hopefully in the future this will get resolved (it is a known issue).
EDIT 2
First let me comment what to do if you wanted to make this code run faster. In this case instead of recursion one can use dynamic programming, e.g.:
function numOfPaths(NominalSize, x, y)
y, x = minmax(x, y)
a = ones(BigInt, NominalSize + 1 - y)
for i in 2:NominalSize - x + 1
i > length(a) || (a[i] = 2 * a[i])
for j in i+1:length(a)
a[j] += a[j-1]
end
end
return a[end]
end
(note that I am using BigInt here, as with this code you can test values that are much larger than the range of Int64 type; if you would want to be even faster just switch BigInt to Int in the code, but then for NominalSize greater than 33 you will get an overflow)
Now, going to the question of #Alex Zh why the second code runs slowly. You can run #code_warntype on it to learn the following:
julia> function numOfPaths(NominalSize,x,y)
(x < NominalSize) && numOfPaths(NominalSize,x+1,y)
(y < NominalSize) && numOfPaths(NominalSize,x,y+1)
((y >= NominalSize) && (x >= NominalSize)) && (ref[] += 1 ;)
end
numOfPaths (generic function with 1 method)
julia> count = 0;
julia> ref = Ref(count)
Base.RefValue{Int64}(0)
julia> #code_warntype numOfPaths(15,0,0)
Variables
#self#::Core.Compiler.Const(numOfPaths, false)
NominalSize::Int64
x::Int64
y::Int64
Body::Any
1 ─ %1 = (x < NominalSize)::Bool
└── goto #3 if not %1
2 ─ %3 = (x + 1)::Int64
│ Main.numOfPaths(NominalSize, %3, y)
└── goto #3
3 ┄ %6 = (y < NominalSize)::Bool
└── goto #5 if not %6
4 ─ %8 = (y + 1)::Int64
│ Main.numOfPaths(NominalSize, x, %8)
└── goto #5
5 ┄ %11 = (y >= NominalSize)::Bool
└── goto #9 if not %11
6 ─ %13 = (x >= NominalSize)::Bool
└── goto #8 if not %13
7 ─ %15 = Base.getindex(Main.ref)::Any
│ %16 = (%15 + 1)::Any
│ Base.setindex!(Main.ref, %16)
└── return %16
8 ─ return false
9 ─ return false
Now in the line:
%15 = Base.getindex(Main.ref)::Any
you see that when Julia fetches ref from Main it does not know what is its type, as it is a global variable that is not a constant. Therefore the compiler is not able to generate an efficient machine code, as the type of ref has to be resolved at run time (not at compile time).
Now consider the following change (you need to restart Julia to test it):
ulia> function numOfPaths(NominalSize,x,y)
(x < NominalSize) && numOfPaths(NominalSize,x+1,y)
(y < NominalSize) && numOfPaths(NominalSize,x,y+1)
((y >= NominalSize) && (x >= NominalSize)) && (ref[] += 1 ;)
end
numOfPaths (generic function with 1 method)
julia> count = 0;
julia> const ref = Ref(count)
Base.RefValue{Int64}(0)
julia> #code_warntype numOfPaths(15,0,0)
Variables
#self#::Core.Compiler.Const(numOfPaths, false)
NominalSize::Int64
x::Int64
y::Int64
Body::Union{Bool, Int64}
1 ─ %1 = (x < NominalSize)::Bool
└── goto #3 if not %1
2 ─ %3 = (x + 1)::Int64
│ Main.numOfPaths(NominalSize, %3, y)
└── goto #3
3 ┄ %6 = (y < NominalSize)::Bool
└── goto #5 if not %6
4 ─ %8 = (y + 1)::Int64
│ Main.numOfPaths(NominalSize, x, %8)
└── goto #5
5 ┄ %11 = (y >= NominalSize)::Bool
└── goto #9 if not %11
6 ─ %13 = (x >= NominalSize)::Bool
└── goto #8 if not %13
7 ─ %15 = Base.getindex(Main.ref)::Int64
│ %16 = (%15 + 1)::Int64
│ Base.setindex!(Main.ref, %16)
└── return %16
8 ─ return false
9 ─ return false
Now I have made ref a global const. This tells the compiler that ref is guaranteed not to change its type. Therefore you have:
7 ─ %15 = Base.getindex(Main.ref)::Int64
as this time the compiler has all type information it needs, so a much more efficient machine code can be generated.
I found a Pkg that uses cache, runtime for 20 NominalSize is 0.0002673 [sec]
doing it without cache takes about 20 [min] for same size
so its Bogumił Kamiński answer + memoization
using Memoization
#memoize function numOfPaths(NominalSize,x,y)
count = 0
x < NominalSize && (count += numOfPaths(NominalSize,x+1,y))
y < NominalSize && (count += numOfPaths(NominalSize,x,y+1))
x >= NominalSize && y>=NominalSize && (count+=1)
return count
end
t = #elapsed paths = numOfPaths(20,0,0)
I would like to do some residual analysis for a GLM.
My model is in the form
using GLM
model = glm(#formula(y ~ x), data, Binomial(), LogitLink())
My text book suggests that residual analysis in the GLM be performed using deviance residuals. I was glad to see that Julia's GLM has a devresid() function, and that it suggests how to use it for plotting (sign(y - μ) * sqrt(devresid(D, y, μ))). However, I'm at a total loss as to what the input arguments are supposed to be. Looking at the doc-string:
?devresid
devresid(D, y, μ::Real)
Return the squared deviance residual of μ from y for distribution D
The deviance of a GLM can be evaluated as the sum of the squared deviance residuals. This is the principal use for these values. The actual deviance residual, say for plotting, is the signed square root of this value
sign(y - μ) * sqrt(devresid(D, y, μ))
Examples
julia> devresid(Normal(), 0, 0.25) ≈ abs2(0.25)
true
julia> devresid(Bernoulli(), 1, 0.75) ≈ -2*log(0.75)
true
julia> devresid(Bernoulli(), 0, 0.25) ≈ -2*log1p(-0.25)
true
D: I'm guessing that in my case it is Binomial()
y: I'm guessing this is the indicator variable for a single case, i.e. 1 or 0
μ: What is this?
How can I use this function to produce things like plots of the deviance residual on a normal probability scale and versus fitted values?
Here's the data I'm using in CSV form
x,y
400,0
220,1
490,0
210,1
500,0
270,0
200,1
470,0
480,0
310,1
240,1
490,0
420,0
330,1
280,1
210,1
300,1
470,1
230,0
430,0
460,0
220,1
250,1
200,1
390,0
I understand this is what you want:
julia> data = DataFrame(X=[1,1,1,2,2], Y=[1,1,0,0,1])
5×2 DataFrame
│ Row │ X │ Y │
│ │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1 │ 1 │ 1 │
│ 2 │ 1 │ 1 │
│ 3 │ 1 │ 0 │
│ 4 │ 2 │ 0 │
│ 5 │ 2 │ 1 │
julia> model = glm(#formula(Y ~ X), data, Binomial(), LogitLink())
StatsModels.TableRegressionModel{GeneralizedLinearModel{GLM.GlmResp{Array{Float64,1},Binomial{Float64},LogitLink},GLM.DensePredChol{Float64,LinearAlgebra.Cholesky{Float64,Array{Float64,2}}}},Array{Float64,2}}
Y ~ 1 + X
Coefficients:
─────────────────────────────────────────────────────────────────────────────
Estimate Std. Error z value Pr(>|z|) Lower 95% Upper 95%
─────────────────────────────────────────────────────────────────────────────
(Intercept) 1.38629 2.82752 0.490286 0.6239 -4.15554 6.92813
X -0.693146 1.87049 -0.37057 0.7110 -4.35923 2.97294
─────────────────────────────────────────────────────────────────────────────
julia> p = predict(model)
5-element Array{Float64,1}:
0.6666664218508201
0.6666664218508201
0.6666664218508201
0.5
0.5
julia> y = data.Y
5-element Array{Int64,1}:
1
1
0
0
1
julia> #. sign(y - p) * sqrt(devresid(Bernoulli(), y, p))
5-element Array{Float64,1}:
0.9005170462928523
0.9005170462928523
-1.4823033118905455
-1.1774100225154747
1.1774100225154747
(this is what you would get from calling residuals(model, type="deviance") in R)
Note that in the last line I use #. to vectorize the whole line. Alternatively you could have written it as:
julia> sign.(y .- p) .* sqrt.(devresid.(Bernoulli(), y, p))
5-element Array{Float64,1}:
0.9005170462928523
0.9005170462928523
-1.4823033118905455
-1.1774100225154747
1.1774100225154747
I am new to Julia and was working on some example problems from here as a way of getting a handle on the language. To describe the specific issue I'm facing. I am trying to write some code for question 11 in the programming problems which requires me to compute a summation. I am reproducing my code below. I set a variable k to 1 and the formula needs to find the value of -1 to the power of k + 1. When k = 1, it should compute the result as -1 squared which should be 1 but it returns -1. Not sure what is going wrong here. Help me understand my error?
function computeequation()
result = 0
for k = 1:1000000
result = result + ((-1^(k+1))/((2 * k) - 1))
end
return 4 * result
end
This is common to several programming languages, not just Julia: exponentiation has a higher precedence than subtraction or negation. For Julia, you can see the list table of operator precedence here: https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity-1.
For this reason, -1^2 doesn't produce what you may naively expect:
julia> -1^2
-1
In order to override the default precedence, just use parentheses as appropriate:
julia> (-1)^2
1
As suggested by Lyndon White in a comment, a nice way to visualise the precedence of operations in an expression is to quote it
julia> :(-1 ^ 2)
:(-(1 ^ 2))
julia> :((-1) ^ 2)
:((-1) ^ 2)
and dump it to see the full AST:
julia> dump(:(-1 ^ 2))
Expr
head: Symbol call
args: Array{Any}((2,))
1: Symbol -
2: Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol ^
2: Int64 1
3: Int64 2
julia> dump(:((-1) ^ 2))
Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol ^
2: Int64 -1
3: Int64 2
Here you can note that in the first case the exponentiation is done before the negation, in the second case where parentheses are used, negation comes before exponentiation.
Another neat way to see how an expression is lowered in Julia is to use the Meta.lower function:
julia> Meta.lower(Main, :(-1 ^ 2) )
:($(Expr(:thunk, CodeInfo(
# none within `top-level scope'
1 ─ %1 = Core.apply_type(Base.Val, 2)
│ %2 = (%1)()
│ %3 = Base.literal_pow(^, 1, %2)
│ %4 = -%3
└── return %4
))))
julia> Meta.lower(Main, :((-1) ^ 2) )
:($(Expr(:thunk, CodeInfo(
# none within `top-level scope'
1 ─ %1 = Core.apply_type(Base.Val, 2)
│ %2 = (%1)()
│ %3 = Base.literal_pow(^, -1, %2)
└── return %3
))))
For your particular problem you can do
function computeequation()
result = 0
for k = 1:1000_000
result = result + ((-1) ^ (k + 1))/((2 * k) - 1)
end
return 4 * result
end
Answering my own question. Looks like adding braces around the -1 solves the problem.
function computeequation()
result = 0
for k = 1:1000000
result = result + (((-1)^(k+1))/((2 * k) - 1))
end
return 4 * result
end