SAS Proc Optmodel约束语法

时间:2015-01-15 16:09:42

标签: optimization sas

我正在努力完成一项优化练习,并再次陷入语法困境。以下是我的尝试,除了解决方案代码之外,我还非常喜欢对语法的详尽解释。我认为这是我遇到麻烦的具体索引。

问题: 我想要在十周内卖掉一件商品。我有一个历史趋势,并希望通过降低价格来改变这种趋势。我想要最高保证金。以下工作,但我希望添加两个约束,不能理顺语法。我在代码中有这两个约束的空格,我简要解释了我认为它们的样子。以下是我需要做每个约束的更详细的解释。

inv_cap =每个地点只有这么多库存。我希望把它全部卖掉。对于位置1,它是800,位置2是1200.列FRC_UNITS的总和应该等于这个数量,但不能超过它。

price_down_or_same =价格无法反弹,因此需要始终小于或大于前一周。因此,价格(i)< =价格(i-1),其中i =周。

这是我的尝试。提前感谢您的帮助。

*read in data;
data opt_test_mkdown_raw;
    input 
        ITM_NBR
        ITM_DES_TXT $
        LCT_NBR
        WEEK
        LY_UNITS
        ELAST 
        COST
        PRICE
        TOTAL_INV;
cards;
1 stuff 1 1 300 1.2 6 10 800
1 stuff 1 2 150 1.2 6 10 800
1 stuff 1 3 100 1.2 6 10 800
1 stuff 1 4 60 1.2 6 10 800
1 stuff 1 5 40 1.2 6 10 800
1 stuff 1 6 20 1.2 6 10 800
1 stuff 1 7 10 1.2 6 10 800
1 stuff 1 8 10 1.2 6 10 800
1 stuff 1 9 5 1.2 6 10 800
1 stuff 1 10 1 1.2 6 10 800
1 stuff 2 1 400 1.1 6 9 1200
1 stuff 2 2 200 1.1 6 9 1200
1 stuff 2 3 100 1.1 6 9 1200
1 stuff 2 4 100 1.1 6 9 1200
1 stuff 2 5 100 1.1 6 9 1200
1 stuff 2 6 50 1.1 6 9 1200
1 stuff 2 7 20 1.1 6 9 1200
1 stuff 2 8 20 1.1 6 9 1200
1 stuff 2 9 5 1.1 6 9 1200
1 stuff 2 10 3 1.1 6 9 1200
;
run;

data opt_test_mkdown_raw;
    set opt_test_mkdown_raw;
    ITM_LCT_WK=cats(ITM_NBR, LCT_NBR, WEEK);
    ITM_LCT=cats(ITM_NBR, LCT_NBR);
run;

proc optmodel;

*set variables and inputs;

set<string> ITM_LCT_WK;
number ITM_NBR{ITM_LCT_WK};
string ITM_DES_TXT{ITM_LCT_WK};
string ITM_LCT{ITM_LCT_WK};
number LCT_NBR{ITM_LCT_WK};
number WEEK{ITM_LCT_WK}; 
number LY_UNITS{ITM_LCT_WK}; 
number ELAST{ITM_LCT_WK}; 
number COST{ITM_LCT_WK}; 
number PRICE{ITM_LCT_WK};
number TOTAL_INV{ITM_LCT_WK}; 

*read data into procedure;
read data opt_test_mkdown_raw into
    ITM_LCT_WK=[ITM_LCT_WK]
    ITM_NBR
    ITM_DES_TXT
    ITM_LCT
    LCT_NBR
    WEEK
    LY_UNITS
    ELAST
    COST
    PRICE
    TOTAL_INV; 

var NEW_PRICE{i in ITM_LCT_WK};
impvar FRC_UNITS{i in ITM_LCT_WK}=(1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i])*LY_UNITS[i];

con ceiling_price {i in ITM_LCT_WK}: NEW_PRICE[i]<=PRICE[i];
/*con inv_cap {j in ITM_LCT}: sum{i in ITM_LCT_WK}=I want this to be 800 for location 1 and 1200 for location 2;*/
con supply_last {i in ITM_LCT_WK}: FRC_UNITS[i]>=LY_UNITS[i];
/*con price_down_or_same {j in ITM_LCT} : NEW_PRICE[week]<=NEW_PRICE[week-1];*/

*state function to optimize;
max  margin=sum{i in ITM_LCT_WK}
    (NEW_PRICE[i]-COST[i])*(1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i])*LY_UNITS[i];

/*expand;*/
solve;

*write output dataset;
create data results_MKD_maxmargin
    from 
    [ITM_LCT_WK]={ITM_LCT_WK} 
    ITM_NBR
    ITM_DES_TXT
    LCT_NBR
    WEEK
    LY_UNITS
    FRC_UNITS
    ELAST
    COST
    PRICE
    NEW_PRICE
    TOTAL_INV; 

*write results to window;
print 
/*NEW_PRICE */
margin;
quit;

1 个答案:

答案 0 :(得分:1)

主要困难在于,在您的应用程序中,决策由(项目,位置)对和周进行索引,但在您的代码中,您已合并(项目,位置,周)三元组。我更喜欢使用数据步骤,但此示例中的结果是您的代码无法引用特定周和特定对。

更改代码的修复程序是通过使用OPTMODEL可以为您计算的已定义集和输入来添加这些关系。然后,您将知道哪些三元组引用(项目,位置)对和周的每个组合:

/* This code creates a set version of the Item x Location pairs 
   that you already have as strings */ 
set ITM_LCTS = setof{ilw in ITM_LCT_WK} itm_lct[ilw];
/* For each Item x Location pair, define a set of which 
   Item x Location x Week entries refer to that Item x Location */
set ILWperIL{il in ITM_LCTS} = {ilw in ITM_LCT_WK: itm_lct[ilw] = il};

通过这种关系,您可以添加其他两个约束。

我按原样保留了代码,但是在新代码中应用了一个我认为有用的约定,特别是当有类似的名称如itm_lct和ITM_LCTS时:

  • 设为全部上限;
  • 输入参数以小写字母开头;
  • 输出(vars,impvars和constraints)以大写* /
  • 开头

以下是新的OPTMODEL代码:

proc optmodel;

*set variables and inputs;

set<string> ITM_LCT_WK;
number ITM_NBR{ITM_LCT_WK};
string ITM_DES_TXT{ITM_LCT_WK};
string ITM_LCT{ITM_LCT_WK};
number LCT_NBR{ITM_LCT_WK};
number WEEK{ITM_LCT_WK}; 
number LY_UNITS{ITM_LCT_WK}; 
number ELAST{ITM_LCT_WK}; 
number COST{ITM_LCT_WK}; 
number PRICE{ITM_LCT_WK};
number TOTAL_INV{ITM_LCT_WK}; 

*read data into procedure;
read data opt_test_mkdown_raw into
    ITM_LCT_WK=[ITM_LCT_WK]
    ITM_NBR
    ITM_DES_TXT
    ITM_LCT
    LCT_NBR
    WEEK
    LY_UNITS
    ELAST
    COST
    PRICE
    TOTAL_INV; 

var    NEW_PRICE{i in ITM_LCT_WK} <= price[i];
impvar FRC_UNITS{i in ITM_LCT_WK} = 
       (1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i]) * LY_UNITS[i];

* Moved to bound
con ceiling_price {i in ITM_LCT_WK}: NEW_PRICE[i] <= PRICE[i];

con supply_last{i in ITM_LCT_WK}: FRC_UNITS[i] >= LY_UNITS[i];

/* This code creates a set version of the Item x Location pairs 
   that you already have as strings */ 
set ITM_LCTS = setof{ilw in ITM_LCT_WK} itm_lct[ilw];
/* For each Item x Location pair, define a set of which 
   Item x Location x Week entries refer to that Item x Location */
set ILWperIL{il in ITM_LCTS} = {ilw in ITM_LCT_WK: itm_lct[ilw] = il};
/* I assume that for each item and location 
   the inventory is the same for all weeks for convenience,
   i.e., that is not a coincidence */
num inventory{il in ITM_LCTS} = max{ilw in ILWperIL[il]} total_inv[ilw];
con inv_cap {il in ITM_LCTS}: 
    sum{ilw in ILWperIL[il]} Frc_Units[ilw] = inventory[il]; 

num lastWeek = max{ilw in ITM_LCT_WK} week[ilw];
/* Concatenating indexes is not the prettiest, but gets the job done here*/
con Price_down_or_same {il in ITM_LCTS, w in 2 .. lastWeek}: 
    New_Price[il || w] <= New_Price[il || w - 1];*/

*state function to optimize;
max  margin=sum{i in ITM_LCT_WK}
    (NEW_PRICE[i]-COST[i])*(1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i])*LY_UNITS[i];

expand;
solve;

*write output dataset;
create data results_MKD_maxmargin
    from 
    [ITM_LCT_WK]={ITM_LCT_WK} 
    ITM_NBR
    ITM_DES_TXT
    LCT_NBR
    WEEK
    LY_UNITS
    FRC_UNITS
    ELAST
    COST
    PRICE
    NEW_PRICE
    TOTAL_INV; 

*write results to window;
print 
    NEW_PRICE FRC_UNITS
    margin
;

quit;