Julia JUMP Gurobi MIP - query and store best objective and bound at runtime - callback

I am using Gurobi through the JuMP package in Julia to solve a mixed-integer program.
I would like to obtain a graph
like this one, where also a solution based on Python is provided (which was also addressed on
Gurobi community form).
However, I have not found working solutions for Julia calling Gurobi through JuMP.
I understand that callback functions have to be used (such as this suggestion or even the main documentation here), but I do not fully understand how they work and what is essential to achieve my goal.
Any help is much appreciated, as well as a possible description of what the callback function is doing at each step.
If it helps, I am using Gurobi (v.9.0.0), JuMP (v0.20.1), MathOptInterface (v0.9.22) and Julia (v.1.3.0).

You need to use the C API. Here is a translation of Eli's answer on the Gurobi forum:
using JuMP, Gurobi
model = direct_model(Gurobi.Optimizer())
N = 30
#variable(model, x[1:N], Bin)
#constraint(model, rand(N)' * x <= 10)
#objective(model, Max, rand(N)' * x)
data = Any[]
start_time = 0.0
function my_callback_function(cb_data, cb_where::Cint)
#show cb_where
if cb_where == GRB_CB_MIP
objbst = Ref{Cdouble}()
GRBcbget(cb_data, cb_where, GRB_CB_MIP_OBJBST, objbst)
objbnd = Ref{Cdouble}()
GRBcbget(cb_data, cb_where, GRB_CB_MIP_OBJBND, objbnd)
push!(data, (time() - start_time, objbst[], objbnd[]))
end
return
end
MOI.set(model, Gurobi.CallbackFunction(), my_callback_function)
start_time = time()
optimize!(model)
open("data.csv", "w") do io
for x in data
println(io, join(x, ", "))
end
end
p.s. please update to Julia 1.6 and JuMP 0.22. I have not tested whether this works on the older version.

Related

Inplace parameter updation without torch.no_grad()

I have just started learning this awesome tool called PyTorch but sadly I am stuck in an equivocal situation.
Below is a code snippet from one of the tutorials
with torch.no_grad():
weights -= weights.grad * lr
bias -= bias.grad * lr
weights.grad.zero_()
bias.grad.zero_()
I am kind of confused that even if I will do parameter update without using torch.no_grad() ( i.e. only in-place ) like this:-
# with torch.no_grad()
weights -= weights.grad * lr
bias -= bias.grad * lr
weights.grad.zero_()
bias.grad.zero_()
and since the backward call has already been made in the code above this snippet( not included in the snippet ) which basically means all the “grad” attributes are already computed and don’t require the “original” values again. Then, why is it illegal to do those operations without torch.no_grad()?
I know it will flag off the error in PyTorch but I just wanted to know where my line of thought is at fault?
The questions have been solved by one of the PyTorch Moderator on the PyTorch Discussion forum.
Here's the link to it :- Inplace parameter updation without torch.no_grad()

How do I create arbitrary parameterized layers in DiffEqFlux.lj neuralODE? Julia Julialang Flux.jl

I am able to create and optimize neuralODEs in julia(1.3 and 1.2) using Flux.jl and DiffEqFlux.jl but it fails under a crucial important general case.
what works:
I can train the Neural net parameters if it is built out of the
provided Flux.jl layers like Dense().
I can include an arbitrary function as a layer in the network chain, e.g. x -> x.*x
What fails:
However if the arbitrary function has parameters I want to train then Flux. Train will not adjust these parameters causing it to fail.
I have tried making these added parameters Tracked and included in the list of parameters given to the training system but it ignores them and they remain unvaried.
The documentation says very cryptically that one can use Flux.#functor on a layer to make sure it's parameters get tracked. However functor was not included in Flux till version 0.10.0 and the only version of Flux compatible with NeuralODEs in DiffEqFlux is 0.9.0
So here's an toy example of a 2 layer neural net I want to use
p = param([1.0])
dudt = chain( x -> p[1]*x.*x, Dense(2,2) )
ps = Flux.params(dudt)
then I use the flux train on this. when I do this the parameter p is not varied, but the parameters in the Dense layer are.
I have tried explicitly including like this
ps = Flux.Params([p,dudt])
but that has the same result and the same problem
I think what I need to do is build a struct with an associted function that implements the
x->p[1]*x*x
then call #functor on this. That struct can then be used in the chain.
But as I noted the version of Flux with #functor is not compatible with DiffEqFlux of any version.
So I need a way to make flux pay attention to my custom parameters, not just the ones in Dense()
How???
I think I get what your question is, but please clarify if I am answering the wrong question here. The issue is that the p is only grabbing from a global reference and thus not differentiated during adjoints. A much better way to handle this in 2020 is to use FastChain. The FastChan interface lets you define layer functions and their parameter dependencies, so this is a nice way to make your neural network incorporate arbitrary functions with parameters. Here's what that looks like:
using DifferentialEquations
using Flux, Zygote
using DiffEqFlux
x = Float32[2.; 0.]
p = Float32[2.0]
tspan = (0.0f0,1.0f0)
mylayer(x,p) = p[1]*x
DiffEqFlux.paramlength(::typeof(mylayer)) = 1
DiffEqFlux.initial_params(::typeof(mylayer)) = rand(Float32,1)
dudt = FastChain(FastDense(2,50,tanh),FastDense(50,2),mylayer)
p = DiffEqFlux.initial_params(dudt)
function f(u,p,t)
dudt(u,p)
end
ex_neural_ode(x,p) = solve(ODEProblem(f,x,tspan,p),Tsit5())
solve(ODEProblem(f,x,tspan,p),Tsit5())
du0,dp = Zygote.gradient((x,p)->sum(ex_neural_ode(x,p)),x,p)
where the last value of p is the one parameter for p in mylayer. Or you can directly use Flux:
using DifferentialEquations
using Flux, Zygote
using DiffEqFlux
x = Float32[2.; 0.]
p2 = Float32[2.0]
tspan = (0.0f0,1.0f0)
dudt = Chain(Dense(2,50,tanh),Dense(50,2))
p,re = Flux.destructure(dudt)
function f(u,p,t)
re(p[1:end-1])(u) |> x-> p[end]*x
end
ex_neural_ode() = solve(ODEProblem(f,x,tspan,[p;p2]),Tsit5())
grads = Zygote.gradient(()->sum(ex_neural_ode()),Flux.params(x,p,p2))
grads[x]
grads[p]
grads[p2]

How to write a script for Wolfram SystemModeler to run several simulations?

I want to run around 100 simulations with my model changing two parameters f and TLoadand track the changes on the phase currents currentSensor.i[1] etc.
Now I'm stuck with the documentation on the Wolfram website because there is no definite explanation on how to use scripting with the SystemModeler. I found for example this link on the Wolfram site with some code but no explanation in which commandline I should use it.
I downloaded the WolframScript program and tried to open my model with wolframscript -file SMPM_VoltageSource_Inverter.mo but it says ToExpression::sntx: Invalid syntax in or before ... eventhouh my model simulates totally fine and without any errors in the SimulationCenter.
Can someone explain to me:
Is it possible to write scripts ?
If Yes:
How can I simulate my model?
How can I do a parameter sweep of f and TLoad? Is it as described in the link?
Is it possible to export data of currentSensor.i[1] as a csv-file? And how to?
Thank you for any help!
I don't know about wolfram sorry, but for OpenModelica the following works:
// to load Model from file use
// loadFile("fileName.mo");
loadString("
model M
parameter Real a = 1;
Real x;
equation
x = a * sin(time);
end M;
"); getErrorString();
buildModel(M); getErrorString();
for a in {1,2,3,4} loop
str_a := String(a); getErrorString();
system("./M -override a=" + str_a); getErrorString();
// for windows use
//system("M.exe -override a=" + str_a); getErrorString();
system("mv M_res.mat " + "M_" + str_a + ".mat");
end for;
Put this in a file named for example model.mos and call it from terminal or command line, depending on your os, with omc model.mos if you have OpenModelica installed. this should generate a csv.
EDIT: I realized the original just saves the last value of x, you might want the full output. Therefore i changed the .mos-file. Each different result will be saved in a different file, if you want to change it to csv you just have to change the generated xml.

Editing the Code of a "MATLAB Function" Block in Simulink Programmatically

I'd like to create a simple Simulink model containing a "MATLAB Function" block programmatically -- i.e. using Matlab code.
Thanks to this guide, I've managed to create a new model containing the block:
open_system(new_system('my_system'))
add_block('simulink/User-Defined Functions/MATLAB Function', 'my_system/my_func')
Usually, in order to edit the "MATLAB Function" block's code, one has to "open" the block by double-clicking on it then entering the new code.
However, I would like to set that code programmatically using e.g. set_param() or any relevant function.
For instance, to set the following as the block's code:
function y = fcn(v)
%#codegen
y = 2 * u;
I would like to use something like:
set_param('my_system/my_func', 'Script',...
'function y = fcn(u)\n%#codegen\n\ny = 2 * u;'...
);
I've looked at the output of get_param('my_system/my_func', 'ObjectParameters') and tried to guess which parameter might be used to set the block's function code: So far, I couldn't find any. Therefore, my question is:
Q: Is it possible, using only Matlab commands, to set the code of a "MATLAB Function" block in Simulink?
(As requested by #Ander Biguri, I've moved a solution that worked for me to a separete answer post. If anyone has an alternative/better approach, please feel free to post it as well)
Well, it seems that this question was asked here before. (perhaps formulated differently though?) I've managed to solve my issue using the following code:
sf = sfroot()
block = sf.find('Path','my_system/my_func','-isa','Stateflow.EMChart');
block.Script = sprintf('function y = fcn(u)\n%%#codegen\n\ny = 2 * u;')

Equivalent of InputParser on an Older Version of Matlab?

I am currently running an older version of Matlab - 7.0.4 to be exact, and I'm trying to convert code that involves the newer InputParser into code that would work with this older version. I was wondering if there are any similar commands like inputParser that could be used.
This is the section of code that I'm struggling to convert.
p=inputParser;
p.addParamValue('clusters', repmat(2,k,1), #(x)isvector(x) && length(x)==k);
p.addParamValue('numit', 1000, #(x)x>0 && mod(x,1)==0);
p.addParamValue('abort', 1e-10, #(x)x>=0);
p.addParamValue('verbose', true, #islogical);
p.addParamValue('verbosecompact', true, #islogical);
p.parse(varargin{:});
res=p.Results;
r=res.clusters;
if res.verbose
fprintf('starting graphclustering of %i-partite graph with partition sizes: ',k);
disp(n');
end
Prior to InputParser I used to use 50 to 100 lines of code at the beginning of some complex functions. (Or you can try to roll your own equivalent of the InputParser class.)
Manual input handling is not hard, just a little tedious. The code woudl look something like:
%Check for Clusters
ix = find(cellfun(#(x)strcmpi(x,'clusters'),varargin));
if ~isempty(ix) && (ix+1)<length(varargin)
rec.clusters = varargin{ix+1};
else
rec.clusters = repmat(2,k,1);
end
%Check for 'numit'
% ... following the template above
That will work. For extra credit,. and improved maintainability, you can define the a cell array or structure of with parameter names and default values, and write a loop over that structure, rather than copying the same template code and risking copy/paste errors.
Edit:
This purports to be an example of an input parsing function. I have not tested it, but it may be somewhere to start.
http://www.mathworks.com/matlabcentral/fileexchange/10670-parseargs-simplifies-input-processing-for-functions-with-multiple-options