I have 4 var arrays that have <sku plant tp> as indexed values. Not every <sku plant tp> is in each array. I have a set that has all known <sku plant tp> values that may exist in 1 or more arrays. The sum of these values must be >= to a value in another table for all <sku plant tp> I am running a linear model. I want to sum for all possible values within the 4 arrays together and just assume zero wherever a value does not exist. When I tried to set up a constraint looking across all possible values it failed saying the indexed vars must have all the entries. When I added all the entries to each table but did not compute a value for those I wanted to be zero, optmodel plugged values into those cells to reduce costs, as I had no equation to set those specific values. I then added a constraint so that those missing values I wanted to be zero had to be zero. That fixed my "problem" but my solution time jumped from under 10 minutes to over an hour. That amount of time to solve is not acceptable. Any ideas, thoughts, or suggestions out there that could simplify this process or speed up the solve time would greatly be appreciated. fyi... I am running on SAS Office Analytics 9.4 TS1M8. Thanks. Roger
Are you able to share code and preferably also data?
I can't share the data as it has confidential production information. Below is the code. My issue was that I could not do a constraint by p,k,t unless every array and all the p,k,t entries in. When I added all the entries to each table, SAS would put values in the undefined vars to reduce cost. So, then I added the constraint to make those be zero. When I have arrays with many more index values and sum on a lesser number of indexes, no problem. but when the indexes have the same index, it will not let me have arrays that don't have all the indexed items. Not sure why. This is a huge model, but I know this is my issue as without these constraints it will solve in less than 10 minutes vs over 60 minutes with these constraints. Thanks for any help you can provide. Roger
This looks like the "after" code, where you defined variables over a common index set and then explicitly forced some of them to 0. Can you please share the "before" code, too? If possible, please share at least the first error message.
Also, it looks like you have omitted the declarations of TS, PK, S1, and S2. Are these variables or parameters, and what do their index sets look like?
in ixFFTP} :
1204 FFS1C[p,k,t] + FFS2C[p,k,t] + FFTSC[p,k,t] + FFPKC[p,k,t]
1205 = FFTPC[p,k,t];
This was the code changed to ignore the zeros ;
* Set up FIFO logic;
* Load Beg Inv and the time period it must ship out by;
set ixFFTP;
num FFBIO{ixFFTP};
read data scomdata.FFBImins into ixFFTP=[plt sku tp] FFBIO=cwt;
* Define the vars for FIFO - Note the indexes must be in sync or the constraints will fail;
var FFTSO{ixFFTP} >= 0 init 0;
var FFPKO{ixFFTP} >= 0 init 0;
var FFTPO{ixFFTP} >= 0 init 0;
var FFTDO{ixFFTP} >= 0 init 0;
var FFTPC{ixFFTP} >= 0 init 0;
var FFTDC{ixFFTP} >= 0 init 0;
var FFDX{ixFFTP} >= 0 init 0;
* When inventory arrives at a warehouse, when must it ship out by;
set ixFFTSO;
read data scomdata.inFFTSO into ixFFTSO=[plt sku tp tpo];
con CTSO {
in ixFFTSO} :
sum{<(k),f,fic,m,po,(p),(tp)> in ixTS} TS[k,f,fic,m,po,p,tp]
- FFTSO[p,k,tpo]
= 0;
* If a product is packaged into a new product, when must the new product leave by;
set ixFFPKO;
read data scomdata.inFFPKO into ixFFPKO=[plt sku tp tpo];
con CPKO {
in ixFFPKO} :
sum{ in ixPK} PK[ki,k,w,pl,p,tp]
- FFPKO[p,k,tpo]
= 0;
* Load the time period minimum values that must be moved out in one bucket;
con CTPO {
in ixFFTP} :
FFBIO[p,k,t] + FFTSO[p,k,t] + FFPKO[p,k,t]
= FFTPO[p,k,t];
* Compute a todate value for each of the periods on what must move by said tp;
* In FFTD1 time period t always = 1;
set FFTD1;
read data scomdata.FFTD1 into FFTD1=[plt sku tp];
con CTDO1 {
in FFTD1} :
FFTPO[p,k,t] = FFTDO[p,k,t];
* In FFTDx t = 2 to number of time periods;
set FFTDx;
read data scomdata.FFTDx into FFTDx=[plt sku tp];
con CTDO2 {
in FFTDX} :
FFTPO[p,k,t]
+ FFTDO[p,k,t-1]
- FFTDO[p,k,t] = 0;
* Load FIFO Consumption criteria;
* How much product was delivered to customers from this plant;
set FFS1Cx;
var FFS1C{FFS1Cx} >= 0 init 0;
* For p,k,t where there are no delivered shipments set the values to zero;
read data scomdata.FFS1Cx into FFS1Cx=[plt sku tp];
*set FFS1Cz;
* For p,k,t where there are no pickup shipments set the values to zero;
*read data scomdata.FFS1Cz into FFS1Cz=[plt sku tp];
* How much product was picked up by customers at this plant;
set FFS2Cx;
var FFS2C{FFS2Cx} >= 0 init 0;
read data scomdata.FFS2Cx into FFS2Cx=[plt sku tp];
* For p,k,t where there are no pickup shipments set the values to zero;
*set FFS2Cz;
*read data scomdata.FFS2Cz into FFS2Cz=[plt sku tp];
* How much product left this plant to go to another plant;
set FFTSCx;
var FFTSC{FFTSCx} >= 0 init 0;
read data scomdata.FFTSCx into FFTSCx=[plt sku tp];
* For p,k,t where there are no trans ships set the values to zero;
*set FFTSCz;
* How much of of this product was consumed by time period to make another product;
*read data scomdata.FFTSCz into FFTSCz=[plt sku tp];
set FFPKCx;
var FFPKC{FFPKCx} >= 0 init 0;
read data scomdata.FFPKCx into FFPKCx=[plt sku tp];
* For p,k,t where not packaging consumption set the values to zero;
set FFPKCz;
read data scomdata.FFPKCz into FFPKCz=[plt sku tp];
* Load Customer Delivered Shipments into Consumption;
con CS1C {
in FFS1Cx} :
sum{<(k),f,fic,c,(p),m,(t)> in ixS1} S1[k,f,fic,c,p,m,t]
= FFS1C[p,k,t];
* Constain zero nodes to zero;
*con CS1Z {
in FFS1Cz} :
* FFS1C[p,k,t] = 0;
* Load Customer Pickup Shipments into Consumption;
con CS2C {
in FFS2Cx} :
sum{<(k),f,fic,c,(p),m,(t)> in ixS2} S2[k,f,fic,c,p,m,t]
= FFS2C[p,k,t];
* Constain zero nodes to zero;
*con CS2Z {
in FFS2Cz} :
* FFS2C[p,k,t] = 0;
* Load Outbound Transport Orders into Consumption;
con CTSC {
in FFTSCx} :
sum{<(k),f,fic,m,(p),p2,(t)> in ixTS} TS[k,f,fic,m,p,p2,t]
= FFTSC[p,k,t];
* Constain zero nodes to zero;
*con CTSZ {
in FFTSCz} :
* FFTSC[p,k,t] = 0;
* Load Packaging Consumption;
con CPKC {
in FFPKCx} :
sum{<(k),k2,w,pl,(p),(t)> in ixPK} PK[k,k2,w,pl,p,t]
= FFPKC[p,k,t];
* Constain zero nodes to zero;
*con CPKZ {
in FFPKCz} :
* FFPKC[p,k,t] = 0;
* Load all the consumption into each of the period values;
con CTPC {
in ixFFTP} :
FFS1C[p,k,t] + FFS2C[p,k,t] + FFTSC[p,k,t] + FFPKC[p,k,t]
= FFTPC[p,k,t];
* Add the periods together to get a ytd amount that must be shipped;
* Compute a todate value for each of the periods on what must move by said date;
* In FFTD1 time period t always = 1;
con CTDC1 {
in FFTD1} :
= FFTDC[p,k,t];
* Monthly FIFO constraint, FFDX will be a high cost valve to avoid infeasibility;
con FFTPC[p,k,t] = FFTDC[p,k,t] ;
* In FFTDx t = 2 to ntp;
con CTDC2{
in FFTDX} :
FFTPC[p,k,t] + FFTDC[p,k,t-1]
CFFD{
in ixFFTP} :
FFTDC[p,k,t]
+ FFDX[p,k,t]
>= FFTDO[p,k,t];
If I make all the arrays so that they contain all the possible observations and I don't add the constraint to force those added ones to zero, then the solver will fill the missing values with values to shrink the overall cost.
Hope this makes sense. The real issue is that the constraint assumes each array has identical index values.
Regards,
Roger
The error message somehow did not get pasted, but I think I understand what you want to do.
Suppose the original variable declarations were as follows, with bounds and INIT omitted for simplicity:
var FFS1C {MYSET1};
var FFS2C {MYSET2};
var FFSSC {MYSET3};
var FFPKC {MYSET4};
var FFTPC {MYSET5};
If your constraint is as follows, you will get an error if <p,k,t> is not in each variable's index set:
con CTPC {<p,k,t> in ixFFTP} :
FFS1C[p,k,t] + FFS2C[p,k,t] + FFTSC[p,k,t] + FFPKC[p,k,t]
= FFTPC[p,k,t];
One way to avoid the error is to enlarge each variable's index set to be ixFFTP and then force the unwanted variables to 0 (either with an explicit constraint or via the FIX statement), as you did.
A simpler and more efficient approach is to use IF-THEN expressions like this:
con CTPC {<p,k,t> in ixFFTP} :
(if <p,k,t> in MYSET1 then FFS1C[p,k,t])
+ (if <p,k,t> in MYSET2 then FFS2C[p,k,t])
+ (if <p,k,t> in MYSET3 then FFTSC[p,k,t])
+ (if <p,k,t> in MYSET4 then FFPKC[p,k,t])
= (if <p,k,t> in MYSET5 then FFTPC[p,k,t]);
That way, you can keep the original variable declarations, and each variable appears in the constraint only if the tuple is in that variable's index set.
Glad to help. Please mark my answer as accepted.
Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!