This example illustrates the ability of PROC OPTLSO to optimize a discontinuous function. The example generates a data set of discrete values that approximate a given smooth nonlinear function. The function being optimized is simply using that data set as a lookup table to find the appropriate discretized value.
%let N = 100; %let L = 0; %let U = 10; options cmplib = sasuser.myfuncs; proc fcmp outlib=sasuser.myfuncs.mypkg; function SmoothFunc(x); y = x*sin(x) + x*x*cos(x); return (y); endsub; function DiscretizedFunc(x); array lookup[&N, 2] / nosymbols; rc = read_array('f_discrete', lookup); do i = 1 to %eval(&N-1); if x >= lookup[i,1] and x < lookup[i+1,1] then do; /* lookup value at nearest smaller discretized point */ y = lookup[i,2]; i = %eval(&N-1); end; end; return (y); endsub; run;
The previous statements define PROC FCMP functions for both the smooth and discretized versions of the objective function.
The smooth version is used as follows to generate the discrete points in the lookup table data set f_discrete
for x values at 100 () points between 0 () and 10 (). The values in the following data set created are used in the discretized version of the function that will be used in PROC
OPTLSO for optimization. That discretized version of the function performs a simple lookup of the point data that are contained
in the f_discrete
data set. For a specified x value, the function finds the two discrete values in the data set that are closest to x. Then the smaller of the two nearest points is returned as the function value.
data f_discrete; a=&L; b=&U; n=&N; drop i a b n; do i = 1 to n; x = a + (i/n)*(b-a); y = SmoothFunc(x); output; end; run; data vardata; input _id_ $ _lb_ _ub_; datalines; x 0 10 ; /* Use the discretized function as the objective */ data objdata; length _function_ $16; input _id_ $ _function_ $ _sense_ $; datalines; f DiscretizedFunc min ; options cmplib = sasuser.myfuncs; proc optlso primaluut = finalsol variables = vardata objective = objdata; readarray f_discrete; run; proc print data=finalsol; run;
Output 3.9.1 shows the ODS tables that are produced.
The following code optimizes the smooth version of the same function to demonstrate that virtually the same result is achieved in both cases:
%let N = 100; %let L = 0; %let U = 10; options cmplib = sasuser.myfuncs; proc fcmp outlib=sasuser.myfuncs.mypkg; function SmoothFunc(x); y = x*sin(x) + x*x*cos(x); return (y); endsub; run; data vardata; input _id_ $ _lb_ _ub_; datalines; x 0 10 ; /* Use the smooth function as the objective */ data objdata; length _function_ $16; input _id_ $ _function_ $ _sense_ $; datalines; f SmoothFunc min ; options cmplib = sasuser.myfuncs; proc optlso primaluut = finalsol variables = vardata objective = objdata; run; proc print data=finalsol; run;
Output 3.9.2 shows the ODS tables that are produced.