We will need two primitive sets in our model. The first set will have eight members to represent the quarters that we have historical data for. The second set will have four members corresponding to the four quarters of the year. This second set is used for defining the four seasonal factors. Here is our sets section that incorporates these two sets:

SETS:

  PERIODS: OBSERVED, PREDICT, ERROR;

  QUARTERS: SEASFAC;

ENDSETS

The three attributes on the PERIODS set—OBSERVED, PREDICT, and ERROR—correspond to the observed sales values, predicted sales values, and the prediction error. The prediction error is simply predicted sales minus observed sales. The SEASFAC attribute on the SEASONS set corresponds to the seasonal sales factors and will be computed by LINGO.

We will also need to add a data section to initialize the set members and the OBSERVED attribute with the historical sales data. We can do this with the following:

DATA:

  PERIODS = P1..P8;

  QUARTERS = Q1..Q4;

  OBSERVED = 10 14 12 19 14 21 19 26;

ENDDATA

Next, we must add a formula to compute the error terms. As mentioned, the error term in a period is the difference between the observed and predicted sales. We can express this in LINGO as:

@FOR( PERIODS: ERROR =

PREDICT - OBSERVED);

Our objective is to minimize the sum of the squared error terms, which may be written as:

MIN = @SUM( PERIODS: ERROR ^ 2);

We choose to use squared error terms as a measure to minimize because we want to weight large errors relatively more heavily. Another option might be to minimize the sum of the absolute values of the errors, which would weight large and small errors proportionally the same.

In order to compute the error terms, we will also need to compute predicted sales. Using our theoretical formula, we compute predicted sales as follows:

@FOR( PERIODS( P): PREDICT( P) =

SEASFAC( @WRAP( P, 4))

 * ( BASE + P * TREND));

The @WRAP function is used here to allow us to apply the four seasonal factors over a time horizon exceeding four periods. Had we simply used the index P, instead of @WRAP( P, 4), we would have generated a subscript out of range error. For a more in depth explanation of the use of the @WRAP function, please see the staff scheduling example.

For esthetic reasons, we would like the seasonal factors to average out to a value of one. We can do this by adding the constraint:

@SUM( QUARTERS: SEASFAC) = 4;

Finally, it is possible for the error terms to be negative as well as positive. Given that variables in LINGO default to a lower bound of zero, we will need to use the @FREE function to allow the error terms to go negative. By embedding the @FREE function in an @FOR loop, we can apply @FREE to all the ERROR variables in the statement:

@FOR( PERIODS: @FREE( ERROR));