FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browser

Mosel files for the Mosel-Python comparison blog

Description

Mosel files for the blog post comparing Mosel and Python.

Instructions for running these files:
  1. Extract the data files into the same directory as the Mosel files
  2. To run a single file via the command line, call Mosel and pass the filename followed by "DATA_FILE_PREFIX=" and the first 2 digits of the data file. For example: mosel SparseGrouping_std.mos DATA_FILE_PREFIX=00
Further explanation of this example: See the blog 4 Main Takeaways from Comparing Xpress Mosel and Python for Optimization Models


Source Files

Data Files





TSP_adv.mos

(!******************************************************
   Mosel Example Problems
   ======================

   file TSP_adv.mos
   ````````````````
   Improved version of model 'TSP_std.mos'.
   -- Advanced optimization tasks (solution loading, callbacks, cuts) --

   (c) 2019-2025 Fair Isaac Corporation
       author: S.Heipcke
*******************************************************!)
model "TSP test"
  uses "mmxprs", "mmsystem", "mmsheet", "mmetc"

  parameters
    DATA_FILE_PREFIX = "00"
    TOL=10E-10
  end-parameters
  writeln("#E:IMPORT")

  forward procedure printsol

  forward procedure cb_preintsol(isheur: boolean, cutoff: real)
  forward function cb_optnode: boolean

  writeln("#S:READ")
  declarations
    CITIES: range                  ! Set of cities
    X,Y: array(CITIES) of real
    ONETOL = 1-TOL                 ! Constant to replace repeated calculations
  end-declarations

  initializations from "mmetc.diskdata:"
    [X, Y] as "csv,skiph," + DATA_FILE_PREFIX + "_H_TSP_cities.csv"
  end-initializations

  declarations
    NCITIES=getsize(CITIES)

    DIST: array(CITIES,CITIES) of integer  ! Distance between cities
    NEXTC: array(CITIES) of integer        ! Next city after i in the solution
    fly: array(CITIES,CITIES) of mpvar     ! 1 iff flight from i to j

    INITTOURS = 1..10
    InitTours : array(INITTOURS) of mpsol
  end-declarations

  declarations
    CITYORDER = 1..NCITIES + 1
    TOURS: array(INITTOURS, CITYORDER) of integer
  end-declarations

  diskdata(ETC_DENSE, DATA_FILE_PREFIX + "_H_TSP_tours.csv", TOURS)
  writeln("#E:READ")

  writeln("#S:PROC")
  forall(t in INITTOURS,i in CITIES)
    setsol(InitTours(t),fly(TOURS(t, i),TOURS(t, i + 1)),1)

  forall(i,j in CITIES | i<>j)
    DIST(i,j):=ceil(sqrt((X(i)-X(j))^2 + (Y(i)-Y(j))^2))

  ! Objective: total distance
  TotalDist:= sum(i,j in CITIES | i<>j) DIST(i,j)*fly(i,j)

  ! Visit every city once
  forall(i in CITIES) sum(j in CITIES | i<>j) fly(i,j) = 1
  forall(j in CITIES) sum(i in CITIES | i<>j) fly(i,j) = 1

  forall(i,j in CITIES | i<>j) fly(i,j) is_binary

  ! Set a callback to check heuristic solutions
  setcallback(XPRS_CB_PREINTSOL, ->cb_preintsol)

  ! Set a callback to create subtour elimination constraints for integer solutions
  setcallback(XPRS_CB_OPTNODE, ->cb_optnode)

  ! Disable symmetry detection
  setparam("XPRS_SYMMETRY", 0)

  setparam("XPRS_VERBOSE", false)
  setparam("XPRS_TIMELIMIT", 100) ! set a time limit

  loadprob(TotalDist)

  forall(t in INITTOURS)
    addmipsol("InitTour_" + t, InitTours(t))

  minimize(TotalDist)

  assert(getparam("XPRS_MIPSOLS") > 0)
  writeln("#E:PROC")

  writeln("#S:TEST")
  printsol
  writeln("#E:TEST")


  !-----------------------------------------------------------------
  ! Callback function triggered when the Optimizer has a new integer
  ! solution
  !
  ! We use this function to reject any heuristic solutions that
  ! contain subtours.
  procedure cb_preintsol(isheur: boolean, cutoff: real)
    declarations
      iCity: integer
      nCitiesVisited: integer
    end-declarations

    ! Get the tour(s)
    forall(i in CITIES)
      forall(j in CITIES)
        if (getsol(fly(i,j))>=ONETOL) then
          NEXTC(i):=j
          break
        end-if

    ! Verify that we have a complete tour
    nCitiesVisited := 1;
    iCity := 1
    while (NEXTC(iCity) <> 1) do
      iCity := NEXTC(iCity)
      nCitiesVisited += 1
    end-do

    if (nCitiesVisited < NCITIES) then
      if isheur then
        rejectintsol
      else
        writeln("INVALID INTEGER SOLUTION!!!")
      end-if
    end-if

  end-procedure

  !-----------------------------------------------------------------
  ! Callback function triggered when a node relaxation has been
  ! solved to optimality and the Optimizer is about to branch or
  ! declare the node integer feasible.
  !
  ! If the node is about to be declared integer feasible, we need
  ! to check for subtours and add at least one violated subtour
  ! elimination constraint.
  function cb_optnode: boolean
    declarations
      SUBTOUR: set of integer
      VISITEDCITIES: set of integer
      iCity: integer
      MipInfeas: integer
      ncut:integer
      CutRange: range                        ! Counter for cuts
      cut: array(CutRange) of linctr         ! Cuts
      cutid: array(CutRange) of integer      ! Cut type identification
      type: array(CutRange) of integer       ! Cut constraint type
    end-declarations

    returned:=false                     ! Call this function once per node

    MipInfeas := getparam("XPRS_MIPINFEAS");
    if (MipInfeas = 0) then
      ! There are no fractionals left in the current node solution.
      ! Create sub-tour elimination constraints if we do not
      ! have a complete tour.
      ncut:= 0

      forall(i in CITIES)
        forall(j in CITIES)
          if(getsol(fly(i,j))>=ONETOL) then
            NEXTC(i):=j
            break
          end-if

      VISITEDCITIES := {}
      forall (iFirstCity in CITIES)
        if not iFirstCity in VISITEDCITIES then
          SUBTOUR := {}
          iCity := iFirstCity
          while (iCity not in SUBTOUR) do
          SUBTOUR += {iCity}
          iCity := NEXTC(iCity)
          end-do

          if (getsize(SUBTOUR) < NCITIES) then
            ! Create the sub-tour elimination cut(s)
            cutid(ncut):= 0
            type(ncut):= CT_LEQ
            cut(ncut):= sum(i in SUBTOUR) fly(i,NEXTC(i)) - (getsize(SUBTOUR) - 1)
            ncut+=1
            ! Optional: Also exclude the inverse subtour
            cutid(ncut):= 0
            type(ncut):= CT_LEQ
            cut(ncut):= sum(i in SUBTOUR) fly(NEXTC(i),i) - (getsize(SUBTOUR) - 1)
            ncut+=1!)
            ! Optional: Add a stronger subtour elimination cut
            cutid(ncut):= 0
            type(ncut):= CT_GEQ
            cut(ncut) := sum(i in SUBTOUR, j in (CITIES)-SUBTOUR) fly(i,j) - 1
            ncut+=1!)
          end-if
          VISITEDCITIES += SUBTOUR
        end-if

      ! Add cuts to the problem
      if(ncut>0) then
        addcuts(cutid, type, cut);
        num_cuts_added+=ncut
      end-if

    end-if      ! MIPINFEAS

  end-function

  !-----------------------------------------------------------------

  ! Print the current solution
  procedure printsol
    declarations
      ALLCITIES: set of integer
      CalcDistance: real
    end-declarations

    ! Get the final tour
    forall(i in CITIES)
      forall(j in CITIES)
        if (getsol(fly(i,j))>=ONETOL) then
          NEXTC(i):=j
          break
        end-if

    ! Recalculate the length of the tour
    CalcDistance := sum(i in 1..NCITIES) DIST(i, NEXTC(i))

    writeln("Total distance: ", CalcDistance)
    ALLCITIES:={}
    forall(i in CITIES) do
      if (i not in ALLCITIES) then
        write(i)
        first:=i
        repeat
          ALLCITIES+={first}
          write(" - ", NEXTC(first))
          first:=NEXTC(first)
        until first=i
        writeln
      end-if
    end-do
  end-procedure

  !-----------------------------------------------------------------

end-model

Back to examples browser