nlobj_cs.cs#

// 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();
  }
}