The following introductory examples illustrate how to get started using the OPTLSO procedure.
Consider the simple example of minimizing the Branin function,
subject to and (Jones, Perttunen, and Stuckman, 1993). The minimum function value is at You can use the following statements to solve this problem:
data vardata; input _id_ $ _lb_ _ub_; datalines; x1 -5 10 x2 0 15 ; proc fcmp outlib=sasuser.myfuncs.mypkg; function branin(x1, x2); pi = constant('PI'); y1 = (x2-(5.1/(4*pi**2))*x1*x1+5*x1/pi-6)**2; y2 = 10*(1-1/(8*pi))*cos(x1); return (y1+y2+10); endsub; run; data objdata; input _id_ $ _function_ $ _sense_ $; datalines; f branin min ; options cmplib = sasuser.myfuncs; proc optlso primalout = solution variables = vardata objective = objdata; performance nthreads=4; run; proc print data=solution; run;
The OBJECTIVE= option in the PROC OPTLSO statement refers to the OBJDATA data set, which identifies BRANIN as the name of the objective
function that is defined in the FCMP library sasuser.myfuncs
and specifies that BRANIN should be minimized. The VARIABLES= option in the PROC OPTLSO statement names the decision variables x1
and x2
and specifies lower and upper bounds. The PERFORMANCE statement specifies the number of threads that PROC OPTLSO can use.
Figure 3.1 shows the ODS tables that the OPTLSO procedure produces by default.
Figure 3.1: Bound-Constrained Problem: Output
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 4 |
Problem Summary | |
---|---|
Problem Type | NLP |
Objective Definition Set | OBJDATA |
Variables | VARDATA |
Number of Variables | 2 |
Integer Variables | 0 |
Continuous Variables | 2 |
Number of Constraints | 0 |
Linear Constraints | 0 |
Nonlinear Constraints | 0 |
Objective Definition Source | OBJDATA |
Objective Sense | Minimize |
Solution Summary | |
---|---|
Solution Status | Function convergence |
Objective | 0.3978873689 |
Infeasibility | 0 |
Iterations | 32 |
Evaluations | 1760 |
Cached Evaluations | 81 |
Global Searches | 1 |
Population Size | 80 |
Seed | 1 |
Obs | _sol_ | _id_ | _value_ |
---|---|---|---|
1 | 0 | _obj_ | 0.39789 |
2 | 0 | _inf_ | 0.00000 |
3 | 0 | x1 | 9.42482 |
4 | 0 | x2 | 2.47508 |
5 | 0 | f | 0.39789 |
You can use a LINCON= option to specify general linear equality or inequality constraints of the following form:
For example, suppose that in addition to the bound constraints on the decision variables, you need to guarantee that the sum is less than or equal to . To guarantee this, you can add a LINCON= option to the previous data set definitions, as in the following statements:
data lindata; input _id_ $ _lb_ x1 x2 _ub_; datalines; a1 . 1 1 0.6 ; proc optlso variables = vardata objective = objdata lincon = lindata; run;
Here the symbol A1 denotes the name of the given linear constraints that are specified in the _ID_ column. The corresponding lower and upper bounds are specified in the _LB_ and _UB_ columns, respectively.
You can specify general nonlinear equality or inequality constraints by using the NLINCON= option and adding its definition to the existing PROC FCMP library. Consider the previous problem with the following additional constraint:
You can specify this constraint by adding a new FCMP function library and providing it a corresponding name and bounds in the NLINCON= option, as in the following statements:
data condata; input _id_ $ _lb_ _ub_; datalines; c1 14 . ; proc fcmp outlib=sasuser.myfuncs.mypkg; function c1(x1, x2); return (x1**2 - 2*x2); endsub; run; proc optlso variables = vardata objective = objdata lincon = lindata nlincon = condata; run;
By calling PROC FCMP a second time, you can append the definition of C1 to your existing user library. That is, you do not need to redefine BRANIN after it has been added.
The following is a very simple example of a maximum likelihood estimation problem that uses the log-likelihood function:
The maximum likelihood estimates of the parameters and form the solution to
where and
The following sets of statements demonstrate two ways to formulate this example problem:
data lkhvar; input _id_ $ _lb_; datalines; mu . sigma 0 ; data lkhobj1; input _id_ $ _function_ $ _sense_ $; datalines; f loglkh1 max ;
In the following statements, the FCMP function is “stand-alone” because all the necessary data are defined within the function itself:
proc fcmp outlib=sasuser.myfuncs.mypkg; function loglkh1(mu, sigma); array x[5] / nosym (1 3 4 5 7); s=0; do j=1 to 5; s = s - log(sigma) - 0.5*((x[j]-mu)/sigma)**2; end; return (s); endsub; run; proc optlso variables = lkhvar objective = lkhobj1; run;
Alternatively, you can use an external data set to store the necessary observations and run PROC OPTLSO to feed each observation to an FCMP function that processes a single line of data. In this case, PROC OPTLSO sums the results for you. This mode is particularly useful when the data set is large and possibly distributed over a set of nodes, as shown in Using External Data Sets.
The following statements demonstrate how to store the necessary observations in an external data set for use with PROC FCMP:
data logdata; input x @@; datalines; 1 3 4 5 7 ; data lkhobj2; input _id_ $ _function_ $ _sense_ $ _dataset_ $; datalines; f loglkh2 max logdata ; proc fcmp outlib=sasuser.myfuncs.mypkg; function loglkh2(mu, sigma, x); return (-log(sigma) -0.5*((x-mu)/sigma)**2); endsub; run; proc optlso variables = lkhvar objective = lkhobj2; run;
In this case, for each line of data in the data set logdata
, the FCMP function LOGLKH2 is called. It is important that the non-variable arguments of LOGLKH2 coincide with a subset of
the column names in logdata
, in this case X. However, the order in which the variables and data column names appear is not important. The following definition
would work as well:
data lkhobj3; input _id_ $ _function_ $ _sense_ $ _dataset_ $; datalines; f loglkh3 max logdata ; proc fcmp outlib=sasuser.myfuncs.mypkg; function loglkh3(x, sigma, mu); return (- log(sigma) - 0.5*((x-mu)/sigma)**2); endsub; run; proc optlso variables = lkhvar objective = lkhobj3; run;