"Create Data" no longer works in a Proc OPTMODEL statement that has worked w/o issue, over several years.
A Colleague of mine thinks it could be related to change(s) in SAS v9.4:
- I have not seen anything in SAS Community, or, in the Release Notes indicative of such an issue
- Might anyone be familiar with the error code(s) in the attached file, and what edits I need to make?
Thank You.
Bill G (WJG)
w/ attachment
1888
1889 PROC optmodel;
NOTE: Writing HTML Body file: sashtml1.htm
1890 /* Declare Sets and Parameters */
1891 set ACCOUNTS;
1892 set RISK_CLASS;
1893 set <str> LOCATIONS;
1894 num est_write_off {ACCOUNTS}, est_payment {ACCOUNTS};
1895 num risk_segment {ACCOUNTS};
1896 num max_jobs {RISK_CLASS};
1897 num min_restrictions {LOCATIONS};
1898 num max_restrictions {LOCATIONS};
1899 str service_center {ACCOUNTS};
1900
1901 set <str> MCSV;
1902 num min_mcsv {MCSV};
1903 num max_mcsv {MCSV};
1904 str man_proc_q {ACCOUNTS};
1905
1906 set <str> CUST_CLASS;
1907 num min_class_limits {CUST_CLASS};
1908 num max_class_limits {CUST_CLASS};
1909 str customer_class {ACCOUNTS};
1910
1911 /* Read Data from SAS Data Sets */
1912 read data Summary into RISK_CLASS=[New_Rank] max_jobs=Daily_Jobs;
NOTE: There were 7 observations read from the data set WORK.SUMMARY.
1913
1914 read data Location_Restrictions into LOCATIONS=[Service_Center] min_restrictions=min
1914! max_restrictions=max;
NOTE: There were 5 observations read from the data set WORK.LOCATION_RESTRICTIONS.
1915 *print restrictions;
1916
1917 read data Class_Restrictions into CUST_CLASS=[Res_Com] min_class_limits=Min
1917! max_class_limits=Max;
NOTE: There were 2 observations read from the data set WORK.CLASS_RESTRICTIONS.
1918 *print class_limits;
1919
1920 /*DATA Manual_Processes;
1921 infile datalines delimiter=',';
1922 length Manual_Proc $6;
1923 input Manual_Proc Max;
1924 put Manual_Proc Max;
1925 Datalines;
1926 Max_MC,60
1927 Max_SV,35
1928 ;*/
1929
1930 read data Manual_Processes into MCSV=[Manual_Proc] min_mcsv=Min max_mcsv=Max;
NOTE: There were 3 observations read from the data set WORK.MANUAL_PROCESSES.
1931 *print max_mcsv;
1932
1933 read data Selection_File into ACCOUNTS=[Acct_ID] est_write_off=EstWriteOff
1933! est_payment=EstPayment risk_segment=New_Rank service_center=Service_Center
1933! customer_class=Res_Com man_proc_q=Manual_Process;
WARNING: Duplicate key <2023446720> was read at observation 280.
WARNING: Duplicate key <6280665934> was read at observation 650.
WARNING: Duplicate key <8831810000> was read at observation 697.
WARNING: Duplicate key <9821304710> was read at observation 751.
WARNING: Duplicate key <3802555737> was read at observation 763.
WARNING: Duplicate key <5211474099> was read at observation 818.
WARNING: Duplicate key <5176820000> was read at observation 871.
WARNING: Duplicate key <7671540588> was read at observation 966.
WARNING: Duplicate key <8444959622> was read at observation 967.
WARNING: Duplicate key <9938059754> was read at observation 1057.
WARNING: Duplicate key <1154321000> was read at observation 1104.
WARNING: Duplicate key <135411000> was read at observation 1152.
WARNING: Duplicate key <1560331720> was read at observation 1224.
WARNING: Duplicate key <4716410000> was read at observation 1373.
WARNING: Duplicate key <2701757317> was read at observation 1375.
WARNING: Duplicate key <8147351370> was read at observation 1416.
WARNING: Duplicate key <649269833> was read at observation 1426.
WARNING: Duplicate key <9303006735> was read at observation 1434.
WARNING: Duplicate key <2909628081> was read at observation 1455.
WARNING: Duplicate key <97465376> was read at observation 1458.
WARNING: Duplicate key <6219611051> was read at observation 1598.
NOTE: 21 duplicate keys were read.
NOTE: There were 1598 observations read from the data set WORK.SELECTION_FILE.
1934
1935 *print risk_segment est_write_off est_payment service_center customer_class man_proc_q;
1936 *print max_jobs;
1937
1938 /* Declare Variables */
1939 var Target {ACCOUNTS} binary;
1940
1941 impvar NumTarget {r in RISK_CLASS} =
1942 sum {a in ACCOUNTS: risk_segment[a] = r} Target[a];
1943
1944 impvar NumRestrict {s in LOCATIONS} =
1945 sum {a in ACCOUNTS: service_center[a] = s} Target[a];
1946
1947 impvar NumClassRestrict {c in CUST_CLASS} =
1948 sum {a in ACCOUNTS: customer_class[a] = c} Target[a];
1949
1950 impvar NumMCSV {c in MCSV} =
1951 sum {a in ACCOUNTS: man_proc_q[a] = c} Target[a];
1952
1953 impvar Payments =
1954 sum {a in ACCOUNTS} est_payment[a] * Target[a];
1955
1956 impvar WriteOffs =
1957 sum {a in ACCOUNTS} est_write_off[a] * Target[a];
1958
1959 /* Declase Constraints */
1960 *****con Max_Terms {r in RISK_CLASS}: NumTarget[r] = max_jobs[r];
1961
1962 con Restrict {s in LOCATIONS}: min_restrictions[s] <= NumRestrict[s] <= max_restrictions[s];
1963
1964 con ClassRestrict {c in CUST_CLASS}: min_class_limits[c] <= NumClassRestrict[c] <=
1964! max_class_limits[c];
1965
1966 con MCSVRestrict {c in MCSV}: min_mcsv[c]<= NumMCSV[c] <= max_mcsv[c];
1967
1968 *con Max_WO_LB: sum {a in ACCOUNTS} est_write_off[a] * Target[a]
1969 >= &DAILY_WRITE_OFFS. - (&WO_Range. * 1);
1970
1971 *con Max_WO_UB: sum {a in ACCOUNTS} est_write_off[a] * Target[a]
1972 <= &DAILY_WRITE_OFFS. + &WO_Range.;
1973
1974 /* Declare Objective */
1975 *max ReserveImpact = Payments - WriteOffs;
1976 *min ReserveImpact = WriteOffs;
1977
1978 max ReserveImpact = WriteOffs;
1979
1980 solve with milp;
NOTE: Problem generation will use 4 threads.
NOTE: The constraint 'MCSVRestrict[MC]' is empty.
NOTE: The problem has 1577 variables (0 free, 0 fixed).
NOTE: The problem uses 11 implicit variables.
NOTE: The problem has 1577 binary and 0 integer variables.
NOTE: The problem has 10 linear constraints (0 LE, 0 EQ, 0 GE, 10 range).
NOTE: The problem has 4706 linear constraint coefficients.
NOTE: The problem has 0 nonlinear constraints (0 LE, 0 EQ, 0 GE, 0 range).
NOTE: The initial MILP heuristics are applied.
NOTE: The MILP presolver value AUTOMATIC is applied.
NOTE: The MILP presolver removed 646 variables and 8 constraints.
NOTE: The MILP presolver removed 3775 constraint coefficients.
NOTE: The MILP presolver modified 0 constraint coefficients.
NOTE: The presolved problem has 931 variables, 2 constraints, and 931 constraint coefficients.
NOTE: The MILP solver is called.
NOTE: The parallel Branch and Cut algorithm is used.
NOTE: The Branch and Cut algorithm is using up to 4 threads.
NOTE: The problem has a decomposable structure with 2 blocks. The largest block covers 50.00% of the
constraints in the problem. The DECOMP option with METHOD=CONCOMP is recommended for solving
problems with this structure.
Node Active Sols BestInteger BestBound Gap Time
0 1 2 686540 686540 0.00% 0
0 0 2 686540 686540 0.00% 0
NOTE: Optimal.
NOTE: Objective = 686539.96.
1981 *solve with milp / relobjgap=1e-4;
1982
1983 /* Create Dataset */
1984 create data Customers_Offered from [ACCOUNTS]=
--------
708
1985 {a in ACCOUNTS: Target[a]>1e-4} RISK_CLASS=risk_segment;
-
875
515
NOTE 708-782: The name 'ACCOUNTS' hides an outer declaration.
ERROR 875-782: A key set expression may not depend on key column values like 'ACCOUNTS'.
ERROR 515-782: An indexing set subexpression may not be a scalar.
1986 quit;
NOTE: The SAS System stopped processing this step because of errors.
NOTE: PROCEDURE OPTMODEL used (Total process time):
real time 0.51 seconds
user cpu time 0.21 seconds
system cpu time 0.31 seconds
memory 87619.65k
OS Memory 103480.00k
Timestamp 03/29/2022 01:09:01 PM
Step Count 150 Switch Count 10
Indeed, in SAS 9.4M5 (released in 2017) there was a change to the implementation of the CREATE DATA statement because it did not quite match the behavior described in the documentation. Here are three alternative ways to avoid the ERROR just by changing your CREATE DATA statement.
1. Rename the data set variable to ACCOUNT instead of ACCOUNTS:
create data Customers_Offered from [ACCOUNT]=
{a in ACCOUNTS: Target[a]>1e-4} RISK_CLASS=risk_segment;
2. If you really want the data set variable name to be ACCOUNTS, use the RENAME= data set option:
create data Customers_Offered(rename=(ACCOUNT=ACCOUNTS)) from [account]=
{a in ACCOUNTS: Target[a]>1e-4} RISK_CLASS=risk_segment;
3. Or use a COL expression:
create data Customers_Offered from [col("ACCOUNTS")]=
{a in ACCOUNTS: Target[a]>1e-4} RISK_CLASS=risk_segment;
Awesome!
TY for the quick reply, Super Freq.
I will test each of your three solutions, ASAP.
[I love your Moniker].
Bill G.
Glad to help. Besides me, several other SAS employees have also been designated as Super FREQs: https://communities.sas.com/t5/Community-Memo/Meet-the-Super-FREQs/ba-p/291008
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.
Find more tutorials on the SAS Users YouTube channel.