The OPTMODEL Procedure |
Programming Statements |
PROC OPTMODEL supports several programming statements. You can perform various actions with these statements, such as reading or writing data sets, setting parameter values, generating text output, or invoking a solver.
Statements are read from the input and are executed immediately when complete. Note that certain statements can contain one or more substatements. The execution of substatements is held until the statements that contain them are submitted. Parameter values that are used by expressions in programming statements are resolved when the statement is executed. Note that this resolution might cause errors to be detected. For example, the use of undefined parameters is detected during resolution of the symbolic expressions from declarations.
A statement is terminated by a semicolon. The positions at which semicolons are placed are shown explicitly in the following statement syntax descriptions.
The programming statements can be grouped into these categories:
Control |
Looping |
General |
Input/Output |
Model |
The assignment statement assigns a variable or parameter value. The type of the target identifier-expression must match the type of the right-hand-side expression.
For example, the following code sets the current value for variable x to 3:
proc optmodel; var x; x = 3;
Note:Parameters that were declared with the equal sign (=) initialization forms must not be reassigned a value with an assignment statement. If this occurs, PROC OPTMODEL reports an error.
The CALL statement invokes the named library subroutine. The values that are determined for each argument expression are passed to the subroutine when the subroutine is invoked. The subroutine can update the values of PROC OPTMODEL parameters and variables when an argument is an identifier-expression (see the section Identifier Expressions). For example, the following code sets the parameter array a to a random permutation of 1 to 4:
proc optmodel; number a{i in 1..4} init i; number seed init -1; call ranperm(seed, a[1], a[2], a[3], a[4]);
See Chapter 4, "Functions and CALL Routines," in SAS Language Reference: Dictionary for a list of CALL routines.
The CLOSEFILE statement closes files that were opened by the FILE statement. Each file is specified by a logical name, a physical filename in quotation marks, or an expression enclosed in parentheses that evaluates to a physical filename. See the section FILE Statement for more information about file specifications.
The following example shows how the CLOSEFILE statement is used with a logical filename:
filename greet 'hello.txt'; proc optmodel; file greet; put 'Hi!'; closefile greet;
Generally you must close a file with a CLOSEFILE statement before external programs can access the file. However, any open files are automatically closed when PROC OPTMODEL terminates.
The CONTINUE statement terminates the current iteration of the loop statement (iterative DO, DO UNTIL, DO WHILE, or FOR) that immediately contains the CONTINUE statement. Execution resumes at the start of the loop after checking WHILE or UNTIL tests. The FOR or iterative DO loops apply new iteration values.
The CREATE DATA statement creates a new SAS data set and copies data into it from PROC OPTMODEL parameters and variables. The CREATE DATA statement can create a data set with a single observation or a data set with observations for every location in one or more arrays. The data set is closed after the execution of the CREATE DATA statement.
The arguments to the CREATE DATA statement are as follows:
specifies the output data set name and options.
declares index values and their corresponding data set variables. The values are used to index array locations in column(s).
specifies a set of index values for the key-column(s).
specifies data set variables as well as the PROC OPTMODEL source data for the variables.
Each column or key-column defines output data set variables and a data source for a column. For example, the following code generates the output SAS data set resdata from the PROC OPTMODEL array opt, which is indexed by the set indset:
create data resdata from [solns]=indset opt;
The output data set variable solns contains the index elements in indset.
Column(s) can have the following forms:
transfers data from the PROC OPTMODEL parameter or variable specified by the identifier-expression. The output data set variable has the same name as the name part of the identifier-expression (see the section Identifier Expressions). If the identifier-expression refers to an array, then the index can be omitted when it matches the key-column(s). The following example creates a data set with the variables m and n:
proc optmodel; number m = 7, n = 5; create data example from m n;
transfers the value of a PROC OPTMODEL expression to the output data set variable name. The expression is reevaluated for each observation. If the expression contains any operators or function calls, then it must be enclosed in parentheses. If the expression is an identifier-expression that refers to an array, then the index can be omitted if it matches the key-column(s). The following example creates a data set with the variable ratio:
proc optmodel; number m = 7, n = 5; create data example from ratio=(m/n);
transfers the value of a PROC OPTMODEL expression to the output data set variable named by the string expression name-expression. The PROC OPTMODEL expression is reevaluated for each observation. If this expression contains any operators or function calls, then it must be enclosed in parentheses. If the PROC OPTMODEL expression is an identifier-expression that refers to an array, then the index can be omitted if it matches the key-column(s). The following example uses the COL expression to form the variable s5:
proc optmodel; number m = 7, n = 5; create data example from col("s"||n)=(m+n);
performs the transfers by iterating each column specified by <column(s)> for each member of the index set. If there are columns and index set members, then columns are generated. The dummy parameters from the index set can be used in the columns to generate distinct output data set variable names in the iterated columns, using COL expressions. The columns are expanded when the CREATE DATA statement is executed, before any output is performed. This form of column(s) cannot be nested. In other words, the following form of column(s) is NOT allowed:
{ index-set } < { index-set } < column(s) > >
The following example demonstrates the use of the iterated column(s) form:
proc optmodel; set<string> alph = {'a', 'b', 'c'}; var x{1..3, alph} init 2; create data example from [i]=(1..3) {j in alph}<col("x"||j)=x[i,j]>;
The data set created by this code is shown in Figure 8.10.
Note:When no key-column(s) are specified, the output data set has a single observation.
The following code incorporates several of the preceding examples to create and print a data set by using PROC OPTMODEL parameters:
proc optmodel; number m = 7, n = 5; create data example from m n ratio=(m/n) col("s"||n)=(m+n); proc print; run;
The output from the PRINT procedure is shown in Figure 8.11.
Key-column(s) declare index values that enable multiple observations to be written from array column(s). An observation is created for each unique index value combination. The index values supply the index for array column(s) that do not have an explicit index.
Key-column(s) define the data set variables where the index value elements are written. They can also declare local dummy parameters for use in expressions in the column(s). Key-column(s) are syntactically similar to column(s), but are more restricted in form. The following forms of key-column(s) are allowed:
transfers an index element value to the data set variable name. A local dummy parameter, name, is declared to hold the index element value.
transfers an index element value to the data set variable named by the string-valued name-expression. Index-name optionally declares a local dummy parameter to hold the index element value.
A key-set in the CREATE DATA statement explicitly specifies the set of index values. Key-set can be specified as a set expression, although it must be enclosed in parentheses if it contains any function calls or operators. Key-set can also be specified as an index set expression, in which case the index-set dummy parameters override any dummy parameters that are declared in the key-column(s) items. The following code creates a data set from the PROC OPTMODEL parameter m, a matrix whose only nonzero entries are located at (1, 1) and (4, 1):
proc optmodel; number m{1..5, 1..3} = [[1 1] 1 [4 1] 1]; create data example from [i j] = {setof{i in 1..2}<i**2>, {1, 2}} m; proc print data=example noobs; run;
The dummy parameter i in the SETOF expression takes precedence over the dummy parameter i declared in the key-column(s) item. The output from this code is shown in Figure 8.12.
If no key-set is specified, then the set of index values is formed from the union of the index sets of the implicitly indexed column(s). The number of index elements for each implicitly indexed array must match the number of key-column(s). The type of each index element (string versus numeric) must match the element of the same position in other implicit indices.
The arrays for implicitly indexed columns in a CREATE DATA statement do not need to have identical index sets. A missing value is supplied for the value of an implicitly indexed array location when the implied index value is not in the array’s index set.
In the following code, the key-set is unspecified. The set of index values is , which is the union of the index sets of x and y. These index sets are not identical, so missing values are supplied when necessary. The results of this code are shown in Figure 8.13.
proc optmodel; number x{1..2} init 2; var y{2..3} init 3; create data exdata from [keycol] x y; proc print; run;
The types of the output data set variables match the types of the source values. The output variable type for a key-column(s) matches the corresponding element type in the index value tuple. A numeric element matches a NUMERIC data set variable, while a string element matches a CHAR variable. For regular column(s) the source expression type determines the output data set variable type. A numeric expression produces a NUMERIC variable, while a string expression produces a CHAR variable.
Lengths of character variables in the output data set are determined automatically. The length is set to accommodate the longest string value output in that column.
You can use the iterated column(s) form to output selected rows of multiple arrays, assigning a different data set variable to each column. For example, the following code outputs the last two rows of the two-dimensional array, a, along with corresponding elements of the one-dimensional array, b:
proc optmodel; num m = 3; /* number of rows/observations */ num n = 4; /* number of columns in a */ num a{i in 1..m, j in 1..n} = i*j; /* compute a */ num b{i in 1..m} = i**2; /* compute b */ set<num> subset = 2..m; /* used to omit first row */ create data out from [i]=subset {j in 1..n}<col("a"||j)=a[i,j]> b;
To specify the data set to be created, the CREATE DATA statement uses the form key-column(s) {index set}<column(s)> column(s). The preceding code creates a data set out, which has observations and variables. The variables are named i, a1 through a, and b, as shown in Figure 8.14.
See the section Data Set Input/Output for more examples of using the CREATE DATA statement.
The DO statement groups a sequence of statements together as a single statement. Each statement within the list is executed sequentially. The DO statement can be used for grouping with the IF and FOR statements.
The iterative DO statement assigns the values from the sequence of specification items to a previously declared parameter or variable, name. The specified statement sequence is executed after each assignment. This statement corresponds to the iterative DO statement of the DATA step.
Each specification provides either a single number or a single string value, or a sequence of such values. Each specification takes the following form:
The expression in the specification provides a single value or set of values to assign to the target name. Multiple values can be provided for the loop by giving multiple specification items that are separated by commas. For example, the following code outputs the values 1, 3, and 5:
proc optmodel; number i; do i=1,3,5; put i; end;
The same effect can be achieved with a single range expression in place of the explicit list of values, as in the following code:
proc optmodel; number i; do i=1 to 5 by 2; put 'value of i assigned by the DO loop = ' i; i=i**2; put 'value of i assigned in the body of the loop = ' i; end;
The output of this code is shown in Figure 8.15.
Note that unlike the DATA step, a range expression requires the limit to be specified. Additionally the BY part, if any, must follow the limit expression. Moreover, while the name parameter can be reassigned in the body of the loop, the sequence of values that is assigned by the DO loop is unaffected.
Expression can also be an expression that returns a set of numbers or strings. For example, the following code produces the same output as the previous code but uses a set parameter value:
proc optmodel; set s = {1,3,5}; number i; do i = s; put i; end;
Each specification can include a WHILE or UNTIL clause. A WHILE or UNTIL clause applies to the expression that immediately precedes the clause. The sequence that is specified by an expression can be terminated early by a WHILE or UNTIL clause. A WHILE logic-expression is evaluated for each sequence value before the nested statements. If the logic-expression returns a false (zero or missing) value, then the current sequence is terminated immediately. An UNTIL logic-expression is evaluated for each sequence value after the nested statements. The sequence from the current specification is terminated if the logic-expression returns a true value (nonzero and nonmissing). After early termination of a sequence due to a WHILE or UNTIL expression, the DO loop execution continues with the next specification, if any.
To demonstrate use of the WHILE clause, the following code outputs the values 1, 2, and 3. In this case the sequence of values from the set s is stopped when the value of i reaches 4.
proc optmodel; set s = {1,2,3,4,5}; number i; do i = s while(i NE 4); put i; end;
The DO UNTIL loop executes the specified sequence of statements repeatedly until the logic-expression, evaluated after the statements, returns true (a nonmissing nonzero value).
For example, the following code outputs the values 1 and 2:
proc optmodel; number i; i = 1; do until (i=3); put i; i=i+1; end;
Note that multiple criteria can be introduced using expression operators, as in the following example:
do until (i=3 and j=7);
For a list of expression operators, see Table 8.3.
The DO WHILE loop executes the specified sequence of statements repeatedly as long as the logic-expression, evaluated before the statements, returns true (a nonmissing nonzero value).
For example, the following code outputs the values 1 and 2:
proc optmodel; number i; i = 1; do while (i<3); put i; i=i+1; end;
Note that multiple criteria can be introduced using expression operators, as in the following example:
do while (i<3 and j<7);
For a list of expression operators, see Table 8.3.
The DROP statement causes the solver to ignore the specified constraint, constraint array, or constraint array location. The identifier-expression specifies the dropped constraint. An entire constraint array is dropped if the identifier-expression omits the index for an array name.
The following example code uses the DROP statement:
proc optmodel; var x{1..10}; con c1: x[1] + x[2] <= 3; con disp{i in 1..9}: x[i+1] >= x[i] + 0.1; drop c1; /* drops the c1 constraint */ drop disp[5]; /* drops just disp[5] */ drop disp; /* drops all disp constraints */
The constraint can be added back to the model with the RESTORE statement.
Multiple names can be specified in a single DROP statement. For example, the following line drops both the c1 and disp[5] constraints:
drop c1 disp[5];
The EXPAND statement prints the specified constraint, variable, implicit variable, or objective declaration expressions in the current problem after expanding aggregation operators, substituting the current value for parameters and indices, and resolving constant subexpressions. Identifier-expression is the name of a variable, objective, or constraint. If the name is omitted and no options are specified, then all variables, objectives, implicit variables, and undropped constraints in the current problem are printed. The following code shows an example EXPAND statement:
proc optmodel; number n=2; var x{1..n}; min z1=sum{i in 1..n}(x[i]-i)**2; max z2=sum{i in 1..n}(i-x[i])**3; con c{i in 1..n}: x[i]>=0; fix x[2]=3; expand;
This code produces the output in Figure 8.16.
Specifying an identifier-expression restricts output to the specified declaration. A nonarray name prints only the specified item. If an array name is used with a specific index, then information for the specified array location is output. Using an array name without an index restricts output to all locations in the array.
Use options to further control the EXPAND statement output. The supported options follow:
causes the EXPAND statement to print the variables, objectives, and constraints in the same form that would be seen by the solver if a SOLVE statement were executed. This includes any transformations by the OPTMODEL presolver (see the section Presolver). In this form any fixed variables are replaced by their values. Unless an identifier-expression specifies a particular nonarray item or array location, the EXPAND output is restricted to only the variables, the constraints, and the most recent objective seen in a MAX or MIN declaration or specified in a SOLVE statement.
The following options restrict the types of declarations output when no specific nonarray item or array location is requested. By default all types of declarations are output. Only the requested declaration types are output when one or more of the following options are used.
requests the output of unfixed variables. The VAR option can also be used in combination with the name of a variable array to display just the unfixed elements of the array.
requests the output of fixed variables. These variables might have been fixed by the FIX statement (or by the presolver if the SOLVE option is specified). The FIX option can also be used in combination with the name of a variable array to display just the fixed elements of the array.
requests the output of implicit variables referenced in the current problem.
requests the output of objectives used in the current problem. This includes the current problem objective and any objectives referenced as implicit variables.
restricts the display to items found in the irreducible infeasible set (IIS) after the most recent SOLVE performed by the LP solver with the IIS=ON option. The IIS option for the EXPAND statement can also be used in combination with the name of a variable or constraint array to display only the elements of the array in the IIS. For more information about IIS, see the section Irreducible Infeasible Set.
For example, you can see the effect of a FIX statement on the problem that is presented to the solver by using the SOLVE option. You can modify the previous example as follows:
proc optmodel; number n=2; var x{1..n}; min z1=sum{i in 1..n}(x[i]-i)**2; max z2=sum{i in 1..n}(i-x[i])**3; con c{i in 1..n}: x[i]>=0; fix x[2]=3; expand / solve;
This code produces the output in Figure 8.17.
Compare the results in Figure 8.17 to those in Figure 8.16. The constraint c[1] has been converted to a variable bound. The subexpression that uses the fixed variable has been resolved to a constant.
The FILE statement selects the current output file for the PUT statement. By default PUT output is sent to the SAS log. Use the FILE statement to manage a group of output files. The specified file is opened for output if it is not already open. The output file remains open until it is closed with the CLOSEFILE statement.
File-specification names the output file. It can use any of the following forms:
specifies the physical name of an external file in quotation marks. The interpretation of the filename depends on the operating environment.
specifies the logical name associated with a file by the FILENAME statement or by the operating environment. The names PRINT and LOG are reserved to refer to the SAS listing and log files, respectively.
Note:Details about the FILENAME statement can be found in SAS Language Reference: Dictionary.
specifies an expression that evaluates to a string that contains the physical name of an external file.
The LRECL option sets the line length of the output file. If the option is omitted, then the line length defaults to 256 characters. The LRECL option is ignored if the file is already open or if the PRINT or LOG file is specified.
In SAS/OR release 9.2, if the LRECL= option is omitted, then the default line length is defined by the value of the SAS LRECL system option. The default value for the SAS LRECL system option is 256. In SAS/OR releases before 9.2, the default line length is 256.
The LRECL value can be specified in these forms:
specifies the desired line length.
specifies the name of a numeric parameter that contains the length.
specifies a numeric expression in parentheses that returns the line length.
The LRECL value cannot exceed the largest four-byte signed integer, which is .
The following example shows how to use the FILE statement to handle multiple files:
proc optmodel; file 'file.txt' lrecl=80; /* opens file.txt */ put 'This is line 1 of file.txt.'; file print; /* selects the listing */ put 'This goes to the listing.'; file 'file.txt'; /* reselects file.txt */ put 'This is line 2 of file.txt.'; closefile 'file.txt'; /* closes file.txt */ file log; /* selects the SAS log */ put 'This goes to the log.'; /* using expression to open and write a collection of files */ str ofile; num i; num l = 40; do i = 1 to 3; ofile = ('file' || i || '.txt'); file (ofile) lrecl=(l*i); put ('This goes to ' || ofile); closefile (ofile); end;
The following code illustrates the usefulness of using a logical name associated with a file by FILENAME statement:
proc optmodel; /* assigns a logical name to file.txt */ /* see FILENAME statement in */ /* SAS Language Reference: Dictionary */ filename myfile 'file.txt' mod; file myfile; put 'This is line 3 of file.txt.'; closefile myfile; file myfile; put 'This is line 4 of file.txt.'; closefile myfile;
Notice that the FILENAME statement opens the file referenced for append. Therefore, new data are appended to the end every time the logical name, myfile, is used in the FILE statement.
The FIX statement causes the solver to treat a list of variables, variable arrays, or variable array locations as fixed in value. The identifier-list consists of one or more variable names separated by spaces. Each member of the identifier-list is fixed to the same expression. For example, the following code fixes the variables x and y to 3:
proc optmodel; var x, y; num a = 2; fix x y=(a+1);
A variable is specified with an identifier-expression (see the section Identifier Expressions). An entire variable array is fixed if the identifier-expression names an array without providing an index. A new value can be specified with the expression. If the expression is a constant, then the parentheses can be omitted. For example, the following code fixes all locations in array x to 0 except x[10], which is fixed to 1:
proc optmodel; var x{1..10}; fix x = 0; fix x[10] = 1;
If expression is omitted, the variable is fixed at its current value. For example, you can fix some variables to be their optimal values after the SOLVE statement is invoked.
The effect of FIX can be reversed using the UNFIX statement.
The FOR statement executes its substatement for each member of the specified index-set. The index set can declare local dummy parameters. You can reference the value of these parameters in the substatement. For example, consider the following code:
proc optmodel; for {i in 1..2, j in {'a', 'b'}} put i= j=;
This code produces the output in Figure 8.18.
As another example, the following code sets the current values for variable x to random values between 0 and 1:
proc optmodel; var x{1..10}; for {i in 1..10} x[i] = ranuni(-1);
Multiple statements can be controlled by specifying a DO statement group for the substatement.
Caution:Avoid modifying the parameters that are used by the FOR statement index set from within the substatement. The set value that is used for the left-most index set item is not affected by such changes. However, the effect of parameter changes on later index set items cannot be predicted.
The IF statement evaluates the logical expression and then conditionally executes the THEN or ELSE substatements. The substatement that follows the THEN keyword is executed when the logical expression result is nonmissing and nonzero. The ELSE substatement, if any, is executed when the logical expression result is a missing value or zero. The ELSE part is optional and must immediately follow the THEN substatement. When IF statements are nested, an ELSE is always matched to the nearest incomplete unmatched IF-THEN. Multiple statements can be controlled by using DO statements with the THEN or ELSE substatements.
Note:When an IF-THEN statement is used without an ELSE substatement, substatements of the IF statement are executed when possible as they are entered. Under certain circumstances, such as when an IF statement is nested in a FOR loop, the statement is not executed during interactive input until the next statement is seen. By following the IF-THEN statement with an extra semicolon, you can cause it to be executed upon submission, since the extra semicolon is handled as a null statement.
The LEAVE statement terminates the execution of the entire loop body (iterative DO, DO UNTIL, DO WHILE, or FOR) that immediately contains the LEAVE statement. Execution resumes at the statement that follows the loop. The following example demonstrates a simple use of the LEAVE statement:
proc optmodel; number i, j; do i = 1..5; do j = 1..4; if i >= 3 and j = 2 then leave; end; print i j; end;
The results from this code are displayed in Figure 8.19.
For values of i equal to 1 or 2, the inner loop continues uninterrupted, leaving j with a value of 5. For values of i equal to 3, 4, or 5, the inner loop terminates early, leaving j with a value of 2.
The null statement is treated as a statement in the PROC OPTMODEL syntax, but its execution has no effect. It can be used as a placeholder statement.
The PRINT statement outputs string and numeric data in tabular form. The statement specifies a list of arrays or other data items to print. Multiple items can be output together as data columns in the same table.
If no format is specified, the PRINT statement handles the details of formatting automatically (see the section Formatted Output for details). The default format for a numerical column is the fixed-point format (w.d format), which is chosen based on the values of the PDIGITS= and PWIDTH= options (see the section PROC OPTMODEL Statement) as well as the values in the column. The PRINT statement uses scientific notation (the Ew. format) when a value is too large or too small to display in fixed format. The default format for a character column is the $w. format, where the width is set to be the length of the longest string (ignoring trailing blanks) in the column.
Print-item can be specified in the following forms:
specifies a data item to output. Identifier-expression can name an array. In that case all defined array locations are output. Format specifies a SAS format that overrides the default format.
specifies a data value to output. Format specifies a SAS format that overrides the default format.
specifies a data item to output under the control of an index set. The item is printed as if it were an array with the specified set of indices. This form can be used to print a subset of the locations in an array, such as a single column. If the identifier-expression names an array, then the indices of the array must match the indices of the index-set. Format specifies a SAS format that overrides the default format.
specifies a data item to output under the control of an index set. The item is printed as if it were an array with the specified set of indices. In this form the expression is evaluated for each member of the index-set to create the array values for output. Format specifies a SAS format that overrides the default format.
specifies a string value to print.
specifies a page break.
The following example demonstrates the use of several print-item forms:
proc optmodel; num x = 4.3; var y{j in 1..4} init j*3.68; print y; /* identifier-expression */ print (x * .265) dollar6.2; /* (expression) [format] */ print {i in 2..4} y; /* {index-set} identifier-expression */ print {i in 1..3}(i + i*.2345692) best7.; /* {index-set} (expression) [format] */ print "Line 1"; /* string */
The output is displayed in Figure 8.20.
Adjacent print items that have similar indexing are grouped together and output in the same table. Items have similar indexing if they specify arrays that have the same number of indices and have matching index types (numeric versus string). Nonarray items are considered to have the same indexing as other nonarray items. The resulting table has a column for each array index followed by a column for each print item value. This format is called list form. For example, the following code produces a list form table:
proc optmodel; num a{i in 1..3} = i*i; num b{i in 3..5} = 4*i; print a b;
This code produces the listing output in Figure 8.21.
The array index columns show the set of valid index values for the print items in the table. The array index column for the th index is labeled [i]. There is a row for each combination of index values that was used. The index values are displayed in sorted ascending order.
The data columns show the array values that correspond to the index values in each row. If a particular array index is invalid or the array location is undefined, then the corresponding table entry is displayed as blank for numeric arrays and as an empty string for string arrays. If the print items are scalar, then the table has a single row and no array index columns.
If a table contains a single array print item, the array is two-dimensional (has two indices), and the array is dense enough, then the array is shown in matrix form. In this format there is a single index column that contains the row index values. The label of this column is blank. This column is followed by a column for every unique column index value for the array. The latter columns are labeled by the column value. These columns contain the array values for that particular array column. Table entries that correspond to array locations that have invalid or undefined combinations of row and column indices are blank or (for strings) printed as an empty string.
The following code generates a simple example of matrix output:
proc optmodel; print {i in 1..6, j in i..6} (i*10+j);
The PRINT statement produces the output in Figure 8.22.
The PRINT statement prints single two-dimensional arrays in the form that uses fewer table cells (headings are ignored). Sparse arrays are normally printed in list form, and dense arrays are normally printed in matrix form. In a PROC OPTMODEL statement, the PMATRIX= option enables you to tune how the PRINT statement displays a two-dimensional array. The value of this option scales the total number of nonempty array elements, which is used to compute the tables cells needed for list form display. Specifying values for the PMATRIX= option less than 1 causes the list form to be used in more cases, while specifying values greater than 1 causes the matrix form to be used in more cases. If the value is 0, then list form is always used. The default value of the PMATRIX= option is 1. Changing the default can be done with the RESET OPTIONS statement.
The following code illustrates how the PMATRIX= option affects the display of the PRINT statement:
proc optmodel; num a{i in 1..6, i..i} = i; num b{i in 1..3, j in 1..3} = i*j; print a; print b; reset options pmatrix=3; print a; reset options pmatrix=0.5; print b;
The output is shown in Figure 8.23.
From Figure 8.23, it can be seen that by default, the PRINT statement tries to make the display compact. However, the default can be changed by using the PMATRIX= option.
The PUT statement writes text data to the current output file. The syntax of the PUT statement in PROC OPTMODEL is similar to the syntax of the PROC IML and DATA step PUT statements. The PUT statement contains a list of items that specify data for output and provide instructions for formatting the data.
The current output file is initially the SAS log. This can be overridden with the FILE statement. An output file can be closed with the CLOSEFILE statement.
Normally the PUT statement outputs the current line after processing all items. Final @ or @@ operators suppress this automatic line output and cause the current column position to be retained for use in the next PUT statement.
Put-item can take any of the following forms.
outputs the value of the parameter or variable that is specified by the identifier-expression. The equal sign (=) causes a name for the location to be printed before each location value.
Normally each item value is printed in a default format. Any leading and trailing blanks in the formatted value are removed and the value is followed by a blank space. When an explicit format is specified, the value is printed within the width determined by the format.
outputs each defined location value for an array parameter. The array name is specified as in the identifier-expression form except that the index list is replaced by an asterisk (*). The equal sign (=) causes a name for the location to be printed before each location value along with the actual index values to be substituted for the asterisk.
Each item value normally prints in a default format. Any leading and trailing blanks in the formatted value are removed and the value is followed by a blank space. When an explicit format is specified, the value is printed within the width determined by the format.
outputs the value of the expression enclosed in parentheses. This produces similar results to the identifier-expression form except that the equal sign (=) uses the expression to form the name.
copies the string to the output file.
sets the absolute column position within the current line. The literal or expression value determines the new column position.
sets the relative column position within the current line. The literal or expression value determines the amount to update the column position.
outputs the current line and moves to the first column of the next line.
outputs any pending line data and moves to the top of the next page.
The QUIT statement terminates the OPTMODEL execution. The statement is executed immediately, so it cannot be a nested statement. A QUIT statement is implied when a DATA or PROC statement is read.
The READ DATA statement reads data from a SAS data set into PROC OPTMODEL parameter and variable locations. The arguments to the READ DATA statement are as follows:
specifies the input data set name and options.
specifies a set parameter in which to save the set of observation key values read from the input data set.
provide the index values for array destinations.
specify the data values to read and the destination locations.
The following example uses the READ DATA statement to copy data set variables j and k from the SAS data set indata into parameters of the same name. The READ= data set option is used to specify a password.
proc optmodel; number j, k; read data indata(read=secret) into j k;
If any read-key-column(s) are specified, then the READ DATA statement reads all observations from the input data set. If no read-key-column(s) are specified, then only the first observation of the data set is read. The data set is closed after reading the requested information.
Each read-key-column declares a local dummy parameter and specifies a data set variable that supplies the column value. The values of the specified data set variables from each observation are combined into a key tuple. This combination is known as the observation key. The observation key is used to index array locations specified by the read-column(s) items. The observation key is expected to be unique for each observation read from the data set.
The syntax for a read-key-column(s) is as follows:
A read-key-column creates a local dummy parameter named name that holds an element of the observation key tuple. The dummy parameter can be used in subsequent read-column(s) items to reference the element value. If a source-name is given, then it specifies the data set variable that supplies the value. Otherwise the source data set variable has the same name as the dummy parameter, name. Use the special data set variable name _N_ to refer to the number identification of the observations.
You can specify a set-name to save the set of observation keys into a set parameter. If the observation key consists of a single scalar value, then the set member type must match the scalar type. Otherwise the set member type must be a tuple with element types that match the corresponding observation key element types.
The READ DATA statement initially assigns an empty set to the target set-name parameter. As observations are read, a tuple for each observation key is added to the set. A set used to index an array destination in the read-column(s) can be read at the same time as the array values. Consider a data set, invdata, created by the following code:
data invdata; input item $ invcount; datalines; table 100 sofa 250 chair 80 ;
The following code reads the data set invdata, which has two variables, item and invcount. The READ DATA statement constructs a set of inventory items, Items. At the same time, the parameter location invcount[item] is assigned the value of the data set variable invcount in the corresponding observation.
proc optmodel; set<string> Items; number invcount{Items}; read data invdata into Items=[item] invcount; print invcount;
The output of this code is shown in Figure 8.24.
When observations are read, the values of data set variables are copied to parameter locations. Numeric values are copied unchanged. For character values, trim-option controls how leading and trailing blanks are processed. Trim-option is ignored when the value type is numeric. Specify any of the following keywords for trim-option:
Read-column(s) specify data set variables to read and PROC OPTMODEL parameter locations to which to assign the values. The types of the input data set variables must match the types of the parameters. Array parameters can be implicitly or explicitly indexed by the observation key values.
Normally, missing values from the data set are assigned to the parameters that are specified in the read-column(s). The NOMISS keyword suppresses the assignment of missing values, leaving the corresponding parameter locations unchanged. Note that the parameter location does not need to have a valid index in this case. This permits a single statement to read data into multiple arrays that have different index sets.
Read-column(s) has the following forms:
transfers an input data set variable to a target parameter or variable. Identifier-expression specifies the target. If the identifier-expression specifies an array without an explicit index, then the observation key provides an implicit index. The name of the input data set variable can be specified with a name or a COL expression. Otherwise the data set variable name is given by the name part of the identifier-expression. For COL expressions, the string-valued name-expression is evaluated to determine the data set variable name. Trim-option controls removal of leading and trailing blanks in the incoming data. For example, the following code reads the data set variables column1 and column2 from the data set exdata into the PROC OPTMODEL parameters p and q, respectively. The observation numbers in exdata are read into the set indx, which indexes p and q.
data exdata; input column1 column2; datalines; 1 2 3 4 ;
proc optmodel; number n init 2; set<num> indx; number p{indx}, q{indx}; read data exdata into indx=[_N_] p=column1 q=col("column"||n); print p q;
The output is shown in Figure 8.25.
performs the transfers by iterating each column specified by <read-column(s)> for each member of the index-set. If there are columns and index set members, then columns are generated. The dummy parameters from the index set can be used in the columns to generate distinct input data set variable names in the iterated columns, using COL expressions. The columns are expanded when the READ DATA statement is executed, before any observations are read. This form of read-column(s) cannot be nested. In other words, the following form of read-column(s) is NOT allowed:
{ index-set } < { index-set } < read-column(s) > >
An example demonstrating the use of the iterated column read-option follows.
You can use an iterated column read-option to read multiple data set variables into the same array. For example, a data set might store an entire row of array data in a group of data set variables. The following code demonstrates how to read a data set containing demand data divided by day:
data dmnd; input loc $ day1 day2 day3 day4 day5; datalines; East 1.1 2.3 1.3 3.6 4.7 West 7.0 2.1 6.1 5.8 3.2 ; proc optmodel; set DOW = 1..5; /* days of week, 1=Monday, 5=Friday */ set<string> LOC; /* locations */ number demand{LOC, DOW}; read data dmnd into LOC=[loc] {d in DOW} < demand[loc, d]=col("day"||d) >; print demand;
This reads a set of demand variables named DAY1–DAY5 from each observation, filling in the two-dimensional array demand. The output is shown in Figure 8.26.
The RESET OPTIONS statement sets PROC OPTMODEL option values or restores them to their defaults. Options can be specified by using the same syntax as in the PROC OPTMODEL statement. The RESET OPTIONS statement provides two extensions to the option syntax. If an option normally requires a value (specified with an equal sign (=) operator), then specifying the option name alone resets it to its default value. You can also specify an expression enclosed in parentheses in place of a literal value. See the section OPTMODEL Options for an example.
The RESET OPTIONS statement can be placed inside loops or conditional code. The statement is applied each time it is executed.
The RESTORE statement adds a constraint, constraint array, or constraint array location that was dropped by the DROP statement back into the solver model. Identifier-expression specifies the constraint. An entire constraint array is restored if the identifier-expression omits the index from an array name. For example, the following code declares a constraint array and then drops it:
con c{i in 1..4}: x[i] + y[i] <=1; drop c;
The following statement restores the first constraint:
restore c[1];
Multiple names can be specified in a single RESTORE statement. The following statement restores the second and third constraints:
restore c[2] c[3];
If you want to restore all of them, you can submit the following statement:
restore c;
The SAVE MPS statement saves the structure and coefficients for a linear programming model into a SAS data set. This data set can be used as input data for the OPTLP or OPTMILP procedure.
Note:The OPTMODEL presolver (see the section Presolver) is automatically bypassed so that the statement saves the original model without eliminating fixed variables, tightening bounds, etc.
The SAS-data-set argument specifies the output data set name and options. The output data set uses the MPS format described in Chapter 16. The generated data set contains observations that define different parts of the linear program.
Variables, constraints, and objectives are referenced in the data set by using label text from the corresponding .label suffix value. The default text is based on the name in the model. See the section Suffixes for more details. Labels are limited by default to 32 characters and are abbreviated to fit. You can change the maximum length for labels by using the MAXLABLEN= option. When needed, a programmatically generated number is added to labels to avoid duplication. Only the most recent objective, which was specified in a MIN or MAX declaration or specified in a SOLVE statement, is included in the data set.
When an integer variable has been assigned a nondefault branching priority or direction, the MPS data set includes a BRANCH section. See Chapter 16, The MPS-Format SAS Data Set for more details.
The following code shows an example of the SAVE MPS statement. The model is specified using the OPTMODEL procedure. Then it is saved as the MPS data set MPSData, as shown in Figure 8.27. Next, PROC OPTLP is used to solve the resulting linear program.
proc optmodel; var x >= 0, y >= 0; con c: x >= y; con bx: x <= 2; con by: y <= 1; min obj=0.5*x-y; save mps MPSData; quit; proc optlp data=MPSData pout=PrimalOut dout=DualOut; run;
The SAVE QPS statement saves the structure and coefficients for a quadratic programming model into a SAS data set. This data set can be used as input data for the OPTQP procedure.
Note:The OPTMODEL presolver (see the section Presolver) is automatically bypassed so that the statement saves the original model without eliminating fixed variables, tightening bounds, etc.
The SAS-data-set argument specifies the output data set name and options. The output data set uses the QPS format described in Chapter 16. The generated data set contains observations that define different parts of the quadratic program.
Variables, constraints, and objectives are referenced in the data set by using label text from the corresponding .label suffix value. The default text is based on the name in the model. See the section Suffixes for more details. Labels are limited by default to 32 characters and are abbreviated to fit. You can change the maximum length for labels by using the MAXLABLEN= option. When needed, a programmatically generated number is added to labels to avoid duplication. Only the most recent objective, which was specified in a MIN or MAX declaration or specified in a SOLVE statement, is included in the output data set. The coefficients of the objective function appear in the QSECTION section.
The following code shows an example of the SAVE QPS statement. The model is specified using the OPTMODEL procedure. Then it is saved as the QPS data set QPSData, as shown in Figure 8.28. Next, PROC OPTQP is used to solve the resulting quadratic program.
proc optmodel; var x{1..2} >= 0; min z = 2*x[1] + 3 * x[2] + x[1]**2 + 10*x[2]**2 + 2.5*x[1]*x[2]; con c1: x[1] - x[2] <= 1; con c2: x[1] + 2*x[2] >= 100; save qps QPSData; quit; proc optqp data=QPSData pout=PrimalOut dout=DualOut; run;
Obs | FIELD1 | FIELD2 | FIELD3 | FIELD4 | FIELD5 | FIELD6 |
---|---|---|---|---|---|---|
1 | NAME | QPSData | . | . | ||
2 | ROWS | . | . | |||
3 | N | z | . | . | ||
4 | L | c1 | . | . | ||
5 | G | c2 | . | . | ||
6 | COLUMNS | . | . | |||
7 | x[1] | z | 2.0 | c1 | 1 | |
8 | x[1] | c2 | 1.0 | . | ||
9 | x[2] | z | 3.0 | c1 | -1 | |
10 | x[2] | c2 | 2.0 | . | ||
11 | RHS | . | . | |||
12 | .RHS. | c1 | 1.0 | . | ||
13 | .RHS. | c2 | 100.0 | . | ||
14 | QSECTION | . | . | |||
15 | x[1] | x[1] | 2.0 | . | ||
16 | x[1] | x[2] | 2.5 | . | ||
17 | x[2] | x[2] | 20.0 | . | ||
18 | ENDATA | . | . |
The SOLVE statement invokes a PROC OPTMODEL solver. The current model is first resolved to the numeric form that is required by the solver. The resolved model and possibly the current values of any optimization variables are passed to the solver. After the solver finishes executing, the SOLVE statement prints a short table that shows a summary of results from the solver (see the section ODS Table and Variable Names) and updates the _OROPTMODEL_ macro variable.
Here are the arguments to the SOLVE statement:
selects the named solver: LP, MILP, QP, NLPC, NLPU, SQP, or IPNLP (see corresponding chapters in this book for details). If no WITH clause is specified, then a solver is chosen automatically, depending on the problem type.
specifies the objective to use. You can abbreviate the OBJECTIVE keyword as OBJ. If no name is specified, then the solver uses the most recent objective seen in a MAX or MIN declaration or specified in a SOLVE statement.
requests that any integral variables be relaxed to be continuous. RELAXINT can be used with linear and nonlinear problems in addition to any solver.
specifies solver options. Solver options can be specified only when the WITH clause is used. A list of the options available with the solver is provided in the individual chapters that describe each solver.
Optimization techniques that use initial values obtain them from the current values of the optimization variables unless the NOINITVAR option is specified. When the solver finishes executing, the current value of each optimization variable is replaced by the optimal value found by the solver. These values can then be used as the initial values for subsequent solver invocations. The .init suffix location for each variable saves the initial value used for the most recent SOLVE statement.
Note:If a solver fails, any currently pending statement is stopped and processing continues with the next complete statement read from the input. For example, if a SOLVE statement enclosed in a DO group (see the section DO Statement) fails, then the subsequent statements in the group are not executed and processing resumes at the point immediately following the DO group. Note that neither an infeasible result, an unbounded result, nor reaching an iteration limit is considered to be a solver failure.
Note:The information that appears in the macro variable _OROPTMODEL_ (see the section Macro Variable _OROPTMODEL_) varies by solver.
Note:The RELAXINT keyword is applied immediately before the problem is passed to the solver, after any processing by the OPTMODEL presolver. So the problem presented to the solver might not be equivalent to the one produced by setting the .RELAX suffix of all variables to a nonzero value. In particular, the bounds of integer variables are still adjusted to be integral, and OPTMODEL’s presolver might use integrality to tighten bounds further.
The STOP statement halts the execution of all statements that contain it, including DO statements and other control or looping statements. Execution continues with the next top-level source statement. The following statements demonstrate a simple use of the STOP statement:
proc optmodel; number i, j; do i = 1..5; do j = 1..4; if i = 3 and j = 2 then stop; end; end; print i j;
The output is shown in Figure 8.29.
When the counters i and j reach 3 and 2, respectively, the STOP statement terminates both loops. Execution continues with the PRINT statement.
The UNFIX statement reverses the effect of FIX statements. The solver can vary the specified variables, variable arrays, or variable array locations specified by identifier-list. The identifier-list consists of one or more variable names separated by spaces.
Variable is an identifier expression (see the section Identifier Expressions). The UNFIX statement affects an entire variable array if the identifier expression omits the index from an array name. The expression specifies a new initial value that will be stored in each element of the identifier-list.
The following example demonstrates the UNFIX command:
proc optmodel; var x{1..3}; fix x; /* fixes entire array to 0 */ unfix x[1]; /* x[1] can now be varied again */ unfix x[2] = 2; /* x[2] is given an initial value 2 */ /* and can be varied now */ unfix x; /* all x indices can now be varied */
After the following code is executed, the variables x[1] and x[2] are not fixed. They each hold the value 4. The variable x[3] is fixed at a value of 2.
proc optmodel; var x{1..3} init 2; num a = 1; fix x; unfix x[1] x[2]=(a+3);
The USE PROBLEM programming statement makes the problem specified by the identifier-expression be the current problem. If the problem has not been previously used, the problem is created using the PROBLEM declaration corresponding to the name. The problem must have been previously declared.
Copyright © SAS Institute, Inc. All Rights Reserved.