function nlconstr()
% Copyright 2026, Gurobi Optimization, LLC
%
% This example formulates and solves the following simple nonlinear model
% using the nonlinear constraint API:
%
% minimize
% x - y
% subject to
% sin(x) * x + x^2 * y <= 1
% y = cos(x) (<=> cos(x) - y = 0)
% -1 <= x <= 2
% 0 <= y <= 2
%
% The nonlinear constraints are set through the model.nlcon field, a struct
% array holding the expression tree of each constraint together with its
% sense and right-hand side.
model.varnames = {'x', 'y'};
% Set linear objective: x - y
model.obj = [1, -1];
% Bounds: -1 <= x <= 2, 0 <= y <= 2
model.lb = [-1; 0];
model.ub = [ 2; 2];
% There are no linear constraints, but the model still needs a constraint
% matrix with one column per variable
model.A = sparse(0, 2);
% Add nonlinear constraint: sin(x) * x + x^2 * y <= 1
%
% The left-hand side is given as an expression tree with 10 nodes. Every node
% has an opcode, a data value, and the index of its parent node. Nodes are
% 1-based, and the root node is marked by a parent of 0. The data value of a
% VARIABLE node is the 1-based index of that variable, the data value of a
% CONSTANT node is the constant itself, and all other nodes use -1.
%
% node 1: PLUS (root)
% node 2: MULTIPLY (child of 1) -> sin(x) * x
% node 3: SIN (child of 2)
% node 4: VARIABLE x (child of 3)
% node 5: VARIABLE x (child of 2)
% node 6: MULTIPLY (child of 1) -> x^2 * y
% node 7: POW (child of 6)
% node 8: VARIABLE x (child of 7)
% node 9: CONSTANT 2 (child of 7)
% node 10: VARIABLE y (child of 6)
model.nlcon(1).opcode = [ ...
GRB.OPCODE_PLUS, ... % 1: root
GRB.OPCODE_MULTIPLY, ... % 2: sin(x) * x
GRB.OPCODE_SIN, ... % 3: sin(...)
GRB.OPCODE_VARIABLE, ... % 4: x
GRB.OPCODE_VARIABLE, ... % 5: x
GRB.OPCODE_MULTIPLY, ... % 6: x^2 * y
GRB.OPCODE_POW, ... % 7: x^2
GRB.OPCODE_VARIABLE, ... % 8: x
GRB.OPCODE_CONSTANT, ... % 9: 2
GRB.OPCODE_VARIABLE, ... % 10: y
];
model.nlcon(1).data = [-1, -1, -1, 1, 1, -1, -1, 1, 2, 2];
model.nlcon(1).parent = [ 0, 1, 2, 3, 2, 1, 6, 7, 7, 6];
model.nlcon(1).sense = '<';
model.nlcon(1).rhs = 1;
model.nlcon(1).name = 'NonlinearConstraint1';
% Add nonlinear constraint: cos(x) - y = 0
%
% Only a constant right-hand side is allowed, so y = cos(x) is stated by
% moving y to the left-hand side. The expression tree has 4 nodes:
%
% node 1: MINUS (root)
% node 2: COS (child of 1)
% node 3: VARIABLE x (child of 2)
% node 4: VARIABLE y (child of 1)
model.nlcon(2).opcode = [ ...
GRB.OPCODE_MINUS, ... % 1: root
GRB.OPCODE_COS, ... % 2: cos(...)
GRB.OPCODE_VARIABLE, ... % 3: x
GRB.OPCODE_VARIABLE, ... % 4: y
];
model.nlcon(2).data = [-1, -1, 1, 2];
model.nlcon(2).parent = [ 0, 1, 2, 1];
model.nlcon(2).sense = '=';
model.nlcon(2).rhs = 0;
model.nlcon(2).name = 'NonlinearConstraint2';
% Optimize
params.logfile = 'nlconstr.log';
result = gurobi(model, params);
if strcmp(result.status, 'OPTIMAL')
for j = 1:2
fprintf('%s %e\n', model.varnames{j}, result.x(j));
end
fprintf('Obj: %e\n', result.objval);
else
fprintf('Optimization did not produce an optimal solution\n');
end
end