Get branch and bound node count in JuMP/Gurobi - julia

I am trying to get the branch and bound node count using the JuMP interface and the Gurobi solver in Julia.
I tried getnodecount(m) as suggested on the JuMP website, but this came back as undefined. After doing more research, I read to try:
MathProgBase.getnodecount(m)
A simple example:
using Gurobi
using JuMP
using MathProgBase
m = Model(with_optimizer(Gurobi.Optimizer))
#variable(m, x, Bin)
#variable(m, y >=0)
#objective(m, Min, x*y)
optimize!(m)
println(value(x))
# getnodecount(m)
MathProgBase.getnodecount(m)
I expected to get a node count of 0, but got this error:
LoadError: MethodError: no method matching getnodecount(::Model)
Closest candidates are:
getnodecount(!Matched::Gurobi.GurobiMathProgModel) at /uliapro/JuliaPro_v1.1.1.1/packages/Gurobi/dlJep/src/MPB_wrapper.jl:759

You seem to be using the new MathOptInterface rather than MathProgBase. That is why you do not get a GurobiMathProgModel and hence the error. In MathOptInterface, you can do the following to get the node count.
MOI.get(model, MOI.NodeCount())
which will call the Gurobi.get_node_count(model::Model) method implemented here. For other attributes, please refer to the MOI API Reference.

Related

Dialyzer does not catch errors on returned functions

Background
While playing around with dialyzer, typespecs and currying, I was able to create an example of a false positive in dialyzer.
For the purposes of this MWE, I am using diallyxir (versions included) because it makes my life easier. The author of dialyxir confirmed this was not a problem on their side, so that possibility is excluded for now.
Environment
$ elixir -v
Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]
Elixir 1.13.2 (compiled with Erlang/OTP 24)
Which version of Dialyxir are you using? (cat mix.lock | grep dialyxir):
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
Current behavior
Given the following code sample:
defmodule PracticingCurrying do
#spec greater_than(integer()) :: (integer() -> String.t())
def greater_than(min) do
fn number -> number > min end
end
end
Which clearly has a wrong typing, I get a success message:
$ mix dialyzer
Compiling 1 file (.ex)
Generated grokking_fp app
Finding suitable PLTs
Checking PLT...
[:compiler, :currying, :elixir, :gradient, :gradualizer, :kernel, :logger, :stdlib, :syntax_tools]
Looking up modules in dialyxir_erlang-24.2.1_elixir-1.13.2_deps-dev.plt
Finding applications for dialyxir_erlang-24.2.1_elixir-1.13.2_deps-dev.plt
Finding modules for dialyxir_erlang-24.2.1_elixir-1.13.2_deps-dev.plt
Checking 518 modules in dialyxir_erlang-24.2.1_elixir-1.13.2_deps-dev.plt
Adding 44 modules to dialyxir_erlang-24.2.1_elixir-1.13.2_deps-dev.plt
done in 0m24.18s
No :ignore_warnings opt specified in mix.exs and default does not exist.
Starting Dialyzer
[
check_plt: false,
init_plt: '/home/user/Workplace/fl4m3/grokking_fp/_build/dev/dialyxir_erlang-24.2.1_elixir-1.13.2_deps-dev.plt',
files: ['/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.ImmutableValues.beam',
'/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.PracticingCurrying.beam',
'/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.TipCalculator.beam'],
warnings: [:unknown]
]
Total errors: 0, Skipped: 0, Unnecessary Skips: 0
done in 0m1.02s
done (passed successfully)
Expected behavior
I expected dialyzer to tell me the correct spec is #spec greater_than(integer()) :: (integer() -> bool()).
As a side note (and comparison, if you will) gradient does pick up the error.
I know that comparing these tools is like comparing oranges and apples, but I think it is still worth mentioning.
Questions
Is dialyzer not intended to catch this type of error?
If it should catch the error, what can possibly be failing? (is it my example that is incorrect, or something inside dialyzer?)
I personally find it hard to believe this could be a bug in Dialyzer, the tool has been used rather extensively by a lot of people for me to be the first to discover this error. However, I cannot explain what is happening.
Help is appreciated.
Dialyzer is pretty optimistic in its analysis and ignores some categories of errors.
This article provides some advanced explanations about its approach and limitations.
In the particular case of anonymous functions, dialyzer seems to perform a very minimal check
when they are being declared: it will ignore both the types of its arguments and return type, e.g.
the following doesn't lead any error even if is clearly wrong:
# no error
#spec add(integer()) :: (String.t() -> String.t())
def add(x) do
fn y -> x + y end
end
It will however point out a mismatch in arity, e.g.
# invalid_contract
# The #spec for the function does not match the success typing of the function.
#spec add2(integer()) :: (integer(), integer() -> integer())
def add2(x) do
fn y -> x + y end
end
Dialyzer might be able to detect a type conflict when trying to use the anonymous function,
but this isn't guaranteed (see article above), and the error message might not be helpful:
# Function main/0 has no local return.
def main do
positive? = greater_than(0)
positive?.(2)
end
We don't know what is the problem exactly, not even the line causing the error. But at least we know there is one and can debug it.
In the following example, the error is a bit more informative (using :lists.map/2 instead of Enum.map/2 because
dialyzer doesn't understand the enumerable protocol):
# Function main2/0 has no local return.
def main2 do
positive? = greater_than(0)
# The function call will not succeed.
# :lists.map(_positive? :: (integer() -> none()), [-2 | 0 | 1, ...])
# will never return since the success typing arguments are
# ((_ -> any()), [any()])
:lists.map(positive?, [1, 0, -2])
end
This tells us that dialyzer inferred the return type of greater_than/1 to be (integer() -> none()).
none is described in the article above as:
This is a special type that means that no term or type is valid.
Usually, when Dialyzer boils down the possible return values of a function to none(), it means the function should crash.
It is synonymous with "this stuff won't work."
So dialyzer knows that this function cannot be called successfully, but doesn't consider it to be a type clash until actually called, so it will allow the declaration (in the same way you can perfectly create a function that just raises).
Disclaimer: I couldn't find an official explanation regarding how dialyzer handles anonymous
functions in detail, so the explanations above are based on my observations and interpretation

Julia CUDA: UndefVarError: parameters not defined

I have a program for doing Fourier series and I wanted to switch to CuArrays to make it faster. The code is as follows (extract):
#Arrays I want to use
coord = CuArray{ComplexF64,1}(complex.(a[:,1],a[:,2]))
t=CuArray{Float64,1}(-L:(2L/(N-1)):L)
#Array of indexes in the form [0,1,-1,2,-2,...]
n=[((-1)^i)div(i,2) for i in 1:grado]
#Array of functions I need for calculations
base= [x -> exp(π * im * i * x / L) / L for i in n]
base[i](1.) #This line is OK
base[i](-1:.1:1) #This line is OK
base[i].(t) #This line gives error!
base[i].(CuArray{Float64,1}(t)) #This line gives error!
And the error is:
GPU broadcast resulted in non-concrete element type Any.
This probably means that the function you are broadcasting contains an error or type instability.
If I change it like this
base= [(x::Float64) -> (exp(π * im * i * x / L) / L)::ComplexF64 for i in n]
the same lines still give error, but the error now is:
UndefVarError: parameters not defined
Any idea how I could fix this?
Thank you in advance!
Package information:
(#v1.6) pkg> st CUDA
Status `C:\Users\marce\.julia\environments\v1.6\Project.toml`
[052768ef] CUDA v2.6.2
P.S.: This other function has the same problem:
function integra(inizio, fine, arr)
N=size(arr,1)
h=(fine-inizio)/N
integrale=sum(arr)
integrale -= (first(arr)+last(arr))/2
integrale *= h
end
L=2
integra(-L,L,coord)
The first and easier problem is that you should take care to declare global variables to be constant so that the compiler can assume a constant type: const L = 2. A mere L = 2 allows you to do something like L = SomeOtherType(), and if that type can be Anything, so must the return type of your functions. On the CPU that's only a performance hit, but it's a no-no for the GPU. If you actually want L to vary in value, pass it in as an argument so the compiler can still infer types within a function.
Your ::ComplexF64 assertion did actually force a concrete return type, though the middle of the function is still type unstable (check with #code_warntype). The second problem you ran into after that patch was probably caused by this recently patched conflict between ExprTools.jl and LLVM.jl. Seems like you just need to update the packages or maybe reinstall them.

LoadError: UndefVarError in julia for loop

I am defining a variable phi_old at the start of my function, and assigning it a value of phi_start.
I then have an iterative loop that:
uses phi_old
solves a PDE to get a solution T
uses the solution T to calculate phi_new
checks the difference between phi_new and phi_old, if it is larger than error the iterative loop begins again, with phi_old using the values of phi_new.
if the difference is less than the error, the iteration stops.
But I am getting this error:
Warning: Assignment to `T` in soft scope is ambiguous because a global variable by the same name exists:
ERROR: LoadError: UndefVarError: phi_old not defined
Here is an example of my code's structure:
phi_old = createCellVariable(m,phi_start)
for i=1:i_end
phi_new = myfunction(T)
error = sum(phi_new.value[2,1:end]-phi_old.value[2,1:end])
if error > 1E-03
phi_old = phi_new
else
i=i+1
break
end
end
Are there any techniques I could use to better initialize/assign my arrays and fix this error? The arrays are quite large, so I would like to preallocate if possible, and only copy arrays if necessary.

Julia: Even-number datatype for functions

I have about 50 functions which should consume only even positive numbers. Right now I am checking each time with an "if" whether the number put in is zero or not:
function grof(x::Int)
if (x % 2) == 0
println("good")
else
throw("x is not an even number!!!!!!!!!!!!! Stupid programmer!")
end
end
Ideally, I would like to have a datatype which produces this automatically, i.e.
function grof(x::EvenInt)
println("good")
end
However, I am not able to produce this datatype by my own since I am unable to understand the documentary. Thanks for your help!
Best, v.
I don't think creating a type is warranted in such a situation: I would simply #assert that the condition is verified at the beginning of the function(s). (Funnily enough, checking the whether a number is even is the example that was chosen in the documentation to illustrate the effect of #assert)
For example:
julia> function grof(x::Int)
#assert iseven(x) "Stupid programmer!"
println("good")
end
grof (generic function with 1 method)
julia> grof(2)
good
julia> grof(3)
ERROR: AssertionError: Stupid programmer!
Stacktrace:
[1] grof(::Int64) at ./REPL[5]:2
[2] top-level scope at REPL[7]:1
EDIT: If you really want to create a type enforcing such a constraint, it is possible. The way to do this would be to
create a type (possibly subtyping one of the Number abstract types; maybe Signed)
define an inner constructor ensuring that such a type cannot hold an odd value
A very simple example to build upon would be along the lines of:
# A wrapper around an even integer value
struct EvenInt
val :: Int
# inner constructor
function EvenInt(val)
#assert iseven(val)
new(val)
end
end
# Accessor to the value of an EvenInt
val(x::EvenInt) = x.val
# A method working only on even numbers
grof(x::EvenInt) = println("good: $(val(x)) is even")
You'd use this like so:
julia> x = EvenInt(42)
EvenInt(42)
julia> grof(x)
good: 42 is even
julia> y = EvenInt(1)
ERROR: AssertionError: iseven(val)
Stacktrace:
[1] EvenInt(::Int64) at ./REPL[1]:5
[2] top-level scope at REPL[6]:1
but note that you can't do anything on EvenInts yet: you need to either unwrap them (using val() in this case), or define operations on them (a task which can be vastly simplified if you make EvenInt a subtype of one of the abstract number types and follow the relevant interface).
All integers multiplied by two are even, so redefine your function to take half the number it currently takes.
function grof2(halfx::Int)
x=2*halfx
println("good")
end

What does the "Base" keyword mean in Julia?

I saw this example in the Julia language documentation. It uses something called Base. What is this Base?
immutable Squares
count::Int
end
Base.start(::Squares) = 1
Base.next(S::Squares, state) = (state*state, state+1)
Base.done(S::Squares, s) = s > S.count;
Base.eltype(::Type{Squares}) = Int # Note that this is defined for the type
Base.length(S::Squares) = S.count;
Base is a module which defines many of the functions, types and macros used in the Julia language. You can view the files for everything it contains here or call whos(Base) to print a list.
In fact, these functions and types (which include things like sum and Int) are so fundamental to the language that they are included in Julia's top-level scope by default.
This means that we can just use sum instead of Base.sum every time we want to use that particular function. Both names refer to the same thing:
Julia> sum === Base.sum
true
Julia> #which sum # show where the name is defined
Base
So why, you might ask, is it necessary is write things like Base.start instead of simply start?
The point is that start is just a name. We are free to rebind names in the top-level scope to anything we like. For instance start = 0 will rebind the name 'start' to the integer 0 (so that it no longer refers to Base.start).
Concentrating now on the specific example in docs, if we simply wrote start(::Squares) = 1, then we find that we have created a new function with 1 method:
Julia> start
start (generic function with 1 method)
But Julia's iterator interface (invoked using the for loop) requires us to add the new method to Base.start! We haven't done this and so we get an error if we try to iterate:
julia> for i in Squares(7)
println(i)
end
ERROR: MethodError: no method matching start(::Squares)
By updating the Base.start function instead by writing Base.start(::Squares) = 1, the iterator interface can use the method for the Squares type and iteration will work as we expect (as long as Base.done and Base.next are also extended for this type).
I'll grant that for something so fundamental, the explanation is buried a bit far down in the documentation, but http://docs.julialang.org/en/release-0.4/manual/modules/#standard-modules describes this:
There are three important standard modules: Main, Core, and Base.
Base is the standard library (the contents of base/). All modules
implicitly contain using Base, since this is needed in the vast
majority of cases.

Resources