// Copyright 2026, Gurobi Optimization, LLC
// This example formulates and solves the following simple nonlinear model
// using the nonlinear objective API:
//
// minimize sin(x) * x + x^2 * y
// subject to x + y >= 1
// -1 <= x <= 2
// 0 <= y <= 2
//
// The example is split into two functions that show two ways to build a
// nonlinear objective with the new NL API:
//
// - nlobjNLAPI(): uses the nonlinear expression API. The nonlinear
// objective is built as a GRBNLExpr object with the overloaded
// operators, the nonlinear functions hosted on GRBNLExpr, and the Pow()
// helper, and passed directly to SetNLObj().
//
// - nlobjNLAPIAdv(): uses the advanced expression-tree variant of
// SetNLObj(), where the nonlinear expression is described
// with arrays of opcodes, data, and parent pointers.
//
// In both cases we retrieve the nonlinear objective with GetNLObj(),
// delete it with DelNLObj(), replace it with a simple linear objective, and
// re-optimize.
using System;
using Gurobi;
using static Gurobi.GRBNLExpr;
class nlobj_cs
{
/// <summary>
/// Run both ways of building nonlinear objectives: the nonlinear
/// expression API and the advanced expression-tree API.
/// </summary>
static void Main()
{
try {
// First, the nonlinear expression API
nlobjNLAPI();
// Then, the advanced expression-tree API
nlobjNLAPIAdv();
} catch (GRBException e) {
Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
}
}
/// <summary>
/// Formulate the nonlinear objective with the nonlinear expression API,
/// passing a GRBNLExpr object to SetNLObj().
/// </summary>
static void nlobjNLAPI()
{
// Create environment
GRBEnv env = new GRBEnv("nlobj.log");
// Create empty model
GRBModel model = new GRBModel(env);
// Create variables
GRBVar x = model.AddVar(-1.0, 2.0, 0.0, GRB.CONTINUOUS, "x");
GRBVar y = model.AddVar( 0.0, 2.0, 0.0, GRB.CONTINUOUS, "y");
// Add constraint: x + y >= 1
model.AddConstr(x + y, GRB.GREATER_EQUAL, 1.0, "c0");
// Add nonlinear objective: sin(x)*x + x^2*y <= 1.
// The nonlinear expression is built as a GRBNLExpr:
// GRBNLExpr.Sin(x) -> sin(x)
// GRBNLExpr.Pow(x, 2.0) -> x^2 (a SQUARE node)
model.SetNLObj(Sin(x) * x + Pow(x, 2.0) * y);
// Optimize model
model.Optimize();
Console.WriteLine("\nFirst solve (nonlinear objective)");
if (model.Status == GRB.Status.OPTIMAL) {
Console.WriteLine("Optimal objective: {0:E4}", model.ObjVal);
Console.WriteLine(" x={0:F6}, y={1:F6}", x.X, y.X);
} else {
Console.WriteLine("Optimization did not produce an optimal solution");
}
// Retrieve the nonlinear objective and print the number of nodes
GRBNLExpr nlobj = model.GetNLObj();
Console.WriteLine("\nRetrieved NL objective: \"" + nlobj + "\"");
// Delete the nonlinear objective
model.DelNLObj();
Console.WriteLine("Deleted nonlinear objective");
// Set a simple linear objective instead: minimize x + y
model.SetObjective(x + y, GRB.MINIMIZE);
// Re-optimize
model.Optimize();
Console.WriteLine("\nSecond solve (linear objective)");
if (model.Status == GRB.Status.OPTIMAL) {
Console.WriteLine("Optimal objective: {0:E4}", model.ObjVal);
Console.WriteLine(" x={0:F6}, y={1:F6}", x.X, y.X);
} else {
Console.WriteLine("Optimization did not produce an optimal solution");
}
// Dispose of model and env
model.Dispose();
env.Dispose();
}
/// <summary>
/// Formulate the nonlinear objective with the advanced expression-tree
/// variant of SetNLObj(), where the nonlinear expression is
/// described with arrays of opcodes, data, and parent pointers.
/// </summary>
static void nlobjNLAPIAdv()
{
// Create environment
GRBEnv env = new GRBEnv("nlobj.log");
// Create empty model
GRBModel model = new GRBModel(env);
// Create variables
GRBVar x = model.AddVar(-1.0, 2.0, 0.0, GRB.CONTINUOUS, "x");
GRBVar y = model.AddVar( 0.0, 2.0, 0.0, GRB.CONTINUOUS, "y");
// Add constraint: x + y >= 1
model.AddConstr(x + y, GRB.GREATER_EQUAL, 1.0, "c0");
// Expression tree for sin(x) * x + x^2 * y (10 nodes)
//
// node 0: PLUS (root)
// node 1: MULTIPLY (child of 0) -> sin(x) * x
// node 2: SIN (child of 1)
// node 3: VARIABLE x (child of 2)
// node 4: VARIABLE x (child of 1)
// node 5: MULTIPLY (child of 0) -> x^2 * y
// node 6: POW (child of 5)
// node 7: VARIABLE x (child of 6)
// node 8: CONSTANT 2 (child of 6)
// node 9: VARIABLE y (child of 5)
int[] opcode = new int[] {
GRB.OPCODE_PLUS,
GRB.OPCODE_MULTIPLY,
GRB.OPCODE_SIN,
GRB.OPCODE_VARIABLE,
GRB.OPCODE_VARIABLE,
GRB.OPCODE_MULTIPLY,
GRB.OPCODE_POW,
GRB.OPCODE_VARIABLE,
GRB.OPCODE_CONSTANT,
GRB.OPCODE_VARIABLE
};
double[] data = new double[] {
-1.0, -1.0, -1.0,
x.Index,
x.Index,
-1.0, -1.0,
x.Index,
2.0,
y.Index
};
int[] parent = new int[] {-1, 0, 1, 2, 1, 0, 5, 6, 6, 5};
// Set nonlinear objective
model.SetNLObj(opcode, data, parent);
// Optimize model
model.Optimize();
Console.WriteLine("\nFirst solve (nonlinear objective)");
if (model.Status == GRB.Status.OPTIMAL) {
Console.WriteLine("Optimal objective: {0:E4}", model.ObjVal);
Console.WriteLine(" x={0:F6}, y={1:F6}", x.X, y.X);
} else {
Console.WriteLine("Optimization did not produce an optimal solution");
}
// Retrieve the nonlinear objective and print the number of nodes
int nnodes;
model.GetNLObj(out nnodes, null, null, null);
Console.WriteLine("\nRetrieved NL objective with " + nnodes + " nodes");
// Delete the nonlinear objective
model.DelNLObj();
Console.WriteLine("Deleted nonlinear objective");
// Set a simple linear objective instead: minimize x + y
model.SetObjective(x + y, GRB.MINIMIZE);
// Re-optimize
model.Optimize();
Console.WriteLine("\nSecond solve (linear objective)");
if (model.Status == GRB.Status.OPTIMAL) {
Console.WriteLine("Optimal objective: {0:E4}", model.ObjVal);
Console.WriteLine(" x={0:F6}, y={1:F6}", x.X, y.X);
} else {
Console.WriteLine("Optimization did not produce an optimal solution");
}
// Dispose of model and env
model.Dispose();
env.Dispose();
}
}