piecewise.m#

function piecewise()
% Copyright 2024, Gurobi Optimization, LLC
%
% This example considers the following separable, convex problem:
%
%   minimize    f(x) - y + g(z)
%   subject to  x + 2 y + 3 z <= 4
%               x +   y       >= 1
%               x,    y,    z <= 1
%
% where f(u) = exp(-u) and g(u) = 2 u^2 - 4 u, for all real u. It
% formulates and solves a simpler LP model by approximating f and
% g with piecewise-linear functions. Then it transforms the model
% into a MIP by negating the approximation for f, which corresponds
% to a non-convex piecewise-linear function, and solves it again.

names = {'x'; 'y'; 'z'};

model.A = sparse([1 2 3; 1 1 0]);
model.obj = [0; -1; 0];
model.rhs = [4; 1];
model.sense = '<>';
model.vtype = 'C';
model.lb = [0; 0; 0];
model.ub = [1; 1; 1];
model.varnames = names;

% Compute f and g on 101 points in [0,1]
u = linspace(0.0, 1.0, 101);
f = exp(-u);
g = 2*u.^2 - 4*u;

% Set piecewise-linear objective f(x)
model.pwlobj(1).var = 1;
model.pwlobj(1).x   = u;
model.pwlobj(1).y   = f;

% Set piecewise-linear objective g(z)
model.pwlobj(2).var   = 3;
model.pwlobj(2).x     = u;
model.pwlobj(2).y     = g;

% Optimize model as LP
result = gurobi(model);

disp(result);

for v=1:length(names)
    fprintf('%s %d\n', names{v}, result.x(v));
end

fprintf('Obj: %e\n', result.objval);

% Negate piecewise-linear objective function for x
f = -f;
model.pwlobj(1).y = f;

gurobi_write(model, 'pwl.lp')

% Optimize model as a MIP
result = gurobi(model);

disp(result);

for v=1:length(names)
    fprintf('%s %d\n', names{v}, result.x(v));
end

fprintf('Obj: %e\n', result.objval);
end