nlconstr_vb.vb#

' Copyright 2026, Gurobi Optimization, LLC
'
' This example formulates and solves the following simple nonlinear model
' using the nonlinear 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 example is split into two functions that show two ways to build the
' nonlinear constraints with the new NL API:
'
'   - nlconstrNLAPI(): uses the nonlinear expression API. The left-hand sides
'     of the constraints are built as GRBNLExpr objects with the overloaded
'     operators, the nonlinear functions hosted on GRBNLExpr, and the Pow()
'     helper, and passed directly to AddNLConstr().
'
'   - nlconstrNLAPIAdv(): uses the advanced expression-tree variant of
'     AddNLConstr(), where the left-hand side of each constraint is described
'     with arrays of opcodes, data, and parent pointers.
'
' In both cases we retrieve a nonlinear constraint with GetNLConstrLHS(),
' delete it with Remove(), replace it with a simple linear constraint, and
' re-optimize.


Imports System
Imports Gurobi

Class nlconstr_vb
    ' Run both ways of building nonlinear constraints: the nonlinear
    ' expression API and the advanced expression-tree API.
    Shared Sub Main()
        Try
            ' First, the nonlinear expression API
            nlconstrNLAPI()

            ' Then, the advanced expression-tree API
            nlconstrNLAPIAdv()

        Catch e As GRBException
            Console.WriteLine("Error code: " & e.ErrorCode & ". " & e.Message)
        End Try
    End Sub

    ' nlconstrNLAPI(): formulates the model with the nonlinear expression API,
    ' passing GRBNLExpr left-hand sides to AddNLConstr().
    Shared Sub nlconstrNLAPI()
        ' Create environment
        Dim env As GRBEnv = New GRBEnv("nlconstr.log")

        ' Create empty model
        Dim model As GRBModel = New GRBModel(env)

        ' Create variables
        Dim x As GRBVar = model.AddVar(-1.0, 2.0, 1.0, GRB.CONTINUOUS, "x")
        Dim y As GRBVar = model.AddVar(0.0, 2.0, -1.0, GRB.CONTINUOUS, "y")

        ' Add nonlinear constraint: sin(x)*x + x^2*y <= 1.
        ' The left-hand side is built as a GRBNLExpr:
        '   GRBNLExpr.Sin(x)      -> sin(x)
        '   GRBNLExpr.Pow(x, 2.0) -> x^2 (a SQUARE node)
        Dim nlc1 As GRBNLConstr = model.AddNLConstr( _
            GRBNLExpr.Sin(x) * x + GRBNLExpr.Pow(x, 2.0) * y <= 1.0, _
            "NonlinearConstraint1")

        ' Add nonlinear constraint: cos(x) - y = 0
        Dim nlc2 As GRBNLConstr = model.AddNLConstr(GRBNLExpr.Cos(x) - y = 0.0, _
                                                    "NonlinearConstraint2")

        ' Optimize model
        model.Optimize()

        Console.WriteLine("")
        Console.WriteLine("First solve (nonlinear constraints)")
        If model.Status = GRB.Status.OPTIMAL Then
            Console.WriteLine("Optimal objective: " & model.ObjVal.ToString("E4"))
            Console.WriteLine("  x=" & x.X.ToString("F6") & _
                              ", y=" & y.X.ToString("F6"))
        ElseIf model.Status = GRB.Status.INF_OR_UNBD Then
            Console.WriteLine("Model is infeasible or unbounded")
        Else
            Console.WriteLine("Optimization was stopped early")
        End If

        ' Retrieve the first nonlinear constraint as a GRBNLExpr and print it
        Dim lhs As GRBNLExpr = model.GetNLConstrLHS(nlc1)
        Console.WriteLine("")
        Console.WriteLine("Retrieved NL constraint: """ & lhs.ToString() & """")

        ' Delete the nonlinear constraints
        model.Remove(nlc1)
        model.Remove(nlc2)
        model.Update()
        Console.WriteLine("Deleted nonlinear constraints")

        ' Add a simple linear constraint instead: x + y >= 1
        model.AddConstr(x + y, GRB.GREATER_EQUAL, 1.0, "LinearConstraint")

        ' Re-optimize
        model.Optimize()

        Console.WriteLine("")
        Console.WriteLine("Second solve (linear constraint)")
        If model.Status = GRB.Status.OPTIMAL Then
            Console.WriteLine("Optimal objective: " & model.ObjVal.ToString("E4"))
            Console.WriteLine("  x=" & x.X.ToString("F6") & _
                              ", y=" & y.X.ToString("F6"))
        ElseIf model.Status = GRB.Status.INF_OR_UNBD Then
            Console.WriteLine("Model is infeasible or unbounded")
        Else
            Console.WriteLine("Optimization was stopped early")
        End If

        ' Dispose of model and env
        model.Dispose()
        env.Dispose()
    End Sub

    ' nlconstrNLAPIAdv(): formulates the model with the advanced
    ' expression-tree variant of AddNLConstr(), where the left-hand side of
    ' each constraint is described with arrays of opcodes, data, and parents.
    Shared Sub nlconstrNLAPIAdv()
        ' Create environment
        Dim env As GRBEnv = New GRBEnv("nlconstr.log")

        ' Create empty model
        Dim model As GRBModel = New GRBModel(env)

        ' Create variables
        Dim x As GRBVar = model.AddVar(-1.0, 2.0, 1.0, GRB.CONTINUOUS, "x")
        Dim y As GRBVar = model.AddVar(0.0, 2.0, -1.0, GRB.CONTINUOUS, "y")

        ' 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)

        Dim opcode1 As Integer() = New Integer() { _
            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 _
        }
        Dim data1 As Double() = New Double() { _
            -1.0, -1.0, -1.0, _
            x.Index, _
            x.Index, _
            -1.0, -1.0, _
            x.Index, _
            2.0, _
            y.Index _
        }
        Dim parent1 As Integer() = New Integer() {-1, 0, 1, 2, 1, 0, 5, 6, 6, 5}

        ' Expression tree for cos(x) - y = 0 (4 nodes)
        '
        '   node 0: MINUS      (root)
        '   node 1: COS        (child of 0)
        '   node 2: VARIABLE x (child of 1)
        '   node 3: VARIABLE y (child of 0)

        Dim opcode2 As Integer() = New Integer() { _
            GRB.OPCODE_MINUS, _
            GRB.OPCODE_COS, _
            GRB.OPCODE_VARIABLE, _
            GRB.OPCODE_VARIABLE _
        }
        Dim data2 As Double() = New Double() { _
            -1.0, -1.0, _
            x.Index, _
            y.Index _
        }
        Dim parent2 As Integer() = New Integer() {-1, 0, 1, 0}

        ' Add nonlinear constraint: sin(x)*x + x^2*y <= 1
        Dim nlc1 As GRBNLConstr = model.AddNLConstr(opcode1, data1, parent1, _
                                                    GRB.LESS_EQUAL, 1.0, _
                                                    "NonlinearConstraint1")

        ' Add nonlinear constraint: cos(x) - y = 0
        Dim nlc2 As GRBNLConstr = model.AddNLConstr(opcode2, data2, parent2, _
                                                    GRB.EQUAL, 0.0, _
                                                    "NonlinearConstraint2")

        ' Optimize model
        model.Optimize()

        Console.WriteLine("")
        Console.WriteLine("First solve (nonlinear constraints)")
        If model.Status = GRB.Status.OPTIMAL Then
            Console.WriteLine("Optimal objective: " & model.ObjVal.ToString("E4"))
            Console.WriteLine("  x=" & x.X.ToString("F6") & _
                              ", y=" & y.X.ToString("F6"))
        ElseIf model.Status = GRB.Status.INF_OR_UNBD Then
            Console.WriteLine("Model is infeasible or unbounded")
        Else
            Console.WriteLine("Optimization was stopped early")
        End If

        ' Retrieve the first nonlinear constraint and print the number of nodes
        Dim nnodes As Integer
        model.GetNLConstrLHS(nlc1, nnodes, Nothing, Nothing, Nothing)
        Console.WriteLine("")
        Console.WriteLine("Retrieved NL constraint with " & nnodes & " nodes")

        ' Delete the nonlinear constraints
        model.Remove(nlc1)
        model.Remove(nlc2)
        model.Update()
        Console.WriteLine("Deleted nonlinear constraints")

        ' Add a simple linear constraint instead: x + y >= 1
        model.AddConstr(x + y, GRB.GREATER_EQUAL, 1.0, "LinearConstraint")

        ' Re-optimize
        model.Optimize()

        Console.WriteLine("")
        Console.WriteLine("Second solve (linear constraint)")
        If model.Status = GRB.Status.OPTIMAL Then
            Console.WriteLine("Optimal objective: " & model.ObjVal.ToString("E4"))
            Console.WriteLine("  x=" & x.X.ToString("F6") & _
                              ", y=" & y.X.ToString("F6"))
        ElseIf model.Status = GRB.Status.INF_OR_UNBD Then
            Console.WriteLine("Model is infeasible or unbounded")
        Else
            Console.WriteLine("Optimization was stopped early")
        End If

        ' Dispose of model and env
        model.Dispose()
        env.Dispose()
    End Sub
End Class