fixanddive_vb.vb#

' Copyright 2025, Gurobi Optimization, LLC
'
' Implement a simple MIP heuristic.  Relax the model,
' sort variables based on fractionality, and fix the 25% of
' the fractional variables that are closest to integer variables.
' Repeat until either the relaxation is integer feasible or
' linearly infeasible.

Imports System
Imports System.Collections.Generic
Imports Gurobi

Class fixanddive_vb
    ' Comparison class used to sort variable list based on relaxation
    ' fractionality

    Private Class FractionalCompare : Implements IComparer(Of GRBVar)
        Public Function Compare(ByVal v1 As GRBVar, ByVal v2 As GRBVar) As Integer _
                             Implements IComparer(Of Gurobi.GRBVar).Compare
            Try
                Dim sol1 As Double = Math.Abs(v1.X)
                Dim sol2 As Double = Math.Abs(v2.X)
                Dim frac1 As Double = Math.Abs(sol1 - Math.Floor(sol1 + 0.5))
                Dim frac2 As Double = Math.Abs(sol2 - Math.Floor(sol2 + 0.5))
                If frac1 < frac2 Then
                    Return -1
                ElseIf frac1 > frac2 Then
                    Return 1
                Else
                    Return 0
                End If
            Catch e As GRBException
                Console.WriteLine("Error code: " & e.ErrorCode & ". " & e.Message)
            End Try
            Return 0
        End Function
    End Class

    Shared Sub Main(ByVal args As String())

        If args.Length < 1 Then
            Console.WriteLine("Usage: fixanddive_vb filename")
            Return
        End If

        Try
            ' Read model
            Dim env As New GRBEnv()
            Dim model As New GRBModel(env, args(0))

            ' Collect integer variables and relax them
            Dim intvars As New List(Of GRBVar)()
            For Each v As GRBVar In model.GetVars()
                If v.VType <> GRB.CONTINUOUS Then
                    intvars.Add(v)
                    v.VType = GRB.CONTINUOUS
                End If
            Next

            model.Parameters.OutputFlag = 0
            model.Optimize()

            ' Perform multiple iterations. In each iteration, identify the first
            ' quartile of integer variables that are closest to an integer value
            ' in the relaxation, fix them to the nearest integer, and repeat.

            For iter As Integer = 0 To 999

                ' create a list of fractional variables, sorted in order of
                ' increasing distance from the relaxation solution to the nearest
                ' integer value

                Dim fractional As New List(Of GRBVar)()
                For Each v As GRBVar In intvars
                    Dim sol As Double = Math.Abs(v.X)
                    If Math.Abs(sol - Math.Floor(sol + 0.5)) > 0.00001 Then
                        fractional.Add(v)
                    End If
                Next

                Console.WriteLine("Iteration " & iter & ", obj " & _
                                  model.ObjVal & ", fractional " & fractional.Count)

                If fractional.Count = 0 Then
                    Console.WriteLine("Found feasible solution - objective " & _
                                      model.ObjVal)
                    Exit For
                End If

                ' Fix the first quartile to the nearest integer value

                fractional.Sort(New FractionalCompare())
                Dim nfix As Integer = Math.Max(fractional.Count / 4, 1)
                For i As Integer = 0 To nfix - 1
                    Dim v As GRBVar = fractional(i)
                    Dim fixval As Double = Math.Floor(v.X + 0.5)
                    v.LB = fixval
                    v.UB = fixval
                    Console.WriteLine("  Fix " & v.VarName & " to " & fixval & _
                                      " ( rel " & v.X & " )")
                Next

                model.Optimize()

                ' Check optimization result

                If model.Status <> GRB.Status.OPTIMAL Then
                    Console.WriteLine("Relaxation is infeasible")
                    Exit For
                End If
            Next

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

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