! Optimize a model with a ratio objective.
 Sometimes called fractional or hyperbolic programing.
 This example illustrates Dinkelbach's method, which allows integer variables.
 This may be a useful approach if the model is linear except for the ratio objective;
! Ref: Dinkelbach, W. (1967) "On nonlinear fractional programming,"
    Management Science, 13(7), 492–498;
! Keywords: Dinkelbach, Fractional programming, Hyperbolic programming, Ratio objective;
SUBMODEL dinkel:
! We really want to :
  MAX = objn/ objd;
! We instead optimize a weighted sum of objn and objd;
  MAX = objlin;
  objlin = objn - theta* objd;

  objn = y1 + 3*y2 + x1 - x2 + 1;
  objd = 2*y1 + y2 + 3*x1 + 5*x2 + 1;
  -y1 + 2* y2 <= 9;
  4*y1 + y2 <= 21;
  y1 - 3*y2 <= 0;
  4*y1 + 5*y2 >= 12;
  -2*x1 + 6*x2 <= 21;
  7*x1 + 4*x2 <= 39;
  @GIN( y1);
  @GIN( y2);
ENDSUBMODEL
CALC: ! Set some solve parameters; @SET( 'OROUTE',1); ! 1: Route output immediately to the window line by line; @SET( 'TERSEO',2); ! Output level (0:verb, 1:terse, 2:only errors, 3:none); @SET( 'IPTOLR', .005); ! Set ending relative optimality tolerance for individual solves; @SET( 'TIM2RL', 30); ! Time in seconds to apply optimality tolerance; ! We want to maximize objn/ objd. Suppose we have a feasible solution with THETA = objn/ objd, or objn - THETA * objd = 0. If there is a better solution, objn1/ objd1 > THETA, then objn1 - THETA * objd1 > 0, and we will find it if we Maximize objn - THETA* objd. Applying this idea repeatedly is Dinkelbach's method; tolopt = 0.000001; ! Final relative optimality tolerance; theta = -9999; thet0 = 0.5; ! Guess initial value for the ratio; iter = 0; @WHILE( @ABS( theta - thet0)/@SMAX(@ABS( theta),@ABS( thet0)) #GT# tolopt: iter = iter + 1; theta = thet0; ! Can we find a solution with a linearized objective > 0; @SOLVE( dinkel); thetafeas = objn/ objd; @WRITE( iter,') Found new feasible solution. Linear obj= ', objlin,', True obj= ', thetafeas, @NEWLINE(1)); ! Write a little solution report; @WRITE(' Soln has objn= ', objn, ', objd= ', objd,'. Ratio= ', objn/objd, @NEWLINE(1)); @WRITE( ' y1, y2, x1, x2= ', y1,' ', y2,' ', x1,' ', x2, @NEWLINE(1)); @IFC( objlin #LE# 0: @WRITE(' An upper bound on theta= ', theta, @NEWLINE(1)); ); thet0 = theta + objlin/ objd; ); ENDCALC