<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: How to build/code up a penalty function?! in Mathematical Optimization, Discrete-Event Simulation, and OR</title>
    <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976767#M4393</link>
    <description>&lt;P&gt;Assuming you want to minimize the total penalty, here is one way:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
         if      _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;lt;= 0 then -10
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 60 then   2
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 36 then   4
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 24 then   8
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 12 then   6
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt;  6 then   2
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt;  0 then   1
         ) * SelectTreatmentMethod[t,m];
   min TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;An alternative approach is to use an &lt;A href="https://go.documentation.sas.com/doc/en/pgmsascdc/v_067/casmopt/casmopt_optmodel_details81.htm" target="_self"&gt;FCMP function&lt;/A&gt;:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc fcmp outlib=work.funcs.test;
   function penaltyCoefficient(dif);
      if      dif &amp;lt;= 0 then return(-10);
      else if dif &amp;gt; 60 then return(2);
      else if dif &amp;gt; 36 then return(4);
      else if dif &amp;gt; 24 then return(8);
      else if dif &amp;gt; 12 then return(6);
      else if dif &amp;gt;  6 then return(2);
      else if dif &amp;gt;  0 then return(1);
   endsub;
run;

option cmplib=work.funcs;

data try;
   do x = -5 to 70 by 5;
      p = penaltyCoefficient(x);
      output;
   end;
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Then the Penalty declaration can be written more compactly:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} penaltyCoefficient(_tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m];
&lt;/CODE&gt;&lt;/PRE&gt;</description>
    <pubDate>Fri, 10 Oct 2025 14:19:51 GMT</pubDate>
    <dc:creator>RobPratt</dc:creator>
    <dc:date>2025-10-10T14:19:51Z</dc:date>
    <item>
      <title>How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976743#M4391</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/1636"&gt;@RobPratt&lt;/a&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;How to code-up a penalty function on the difference between _tmin_orig and _tmin_x?!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If _tmin_orig&amp;lt;=_tmin_x, score=-10&lt;/P&gt;
&lt;P&gt;else if _tmin_orig&amp;gt;_tmin_x+60, score=2&lt;/P&gt;
&lt;P&gt;else if _tmin_orig&amp;gt;_tmin_x+36, score=4&lt;/P&gt;
&lt;P&gt;else if _tmin_orig&amp;gt;_tmin_x+24, score=8&lt;/P&gt;
&lt;P&gt;else if _tmin_orig&amp;gt;_tmin_x+12, score=6&lt;/P&gt;
&lt;P&gt;else if _tmin_orig&amp;gt;_tmin_x+6, score=2&lt;/P&gt;
&lt;P&gt;else if _tmin_orig&amp;gt;_tmin_x+0, score=1&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;con CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 1;

   /* primary objective */
   solve;

/*   con MinScore: TotalScore &amp;gt;= TotalScore.sol;*/
   con MinScore: TotalScore &amp;gt;= -5;

   impvar difx {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m];
   max TotalDif = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} difx[d,b];

   /* secondary objective */
   solve with milp / primalin;
   put TotalScore= TotalDif=;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Fri, 10 Oct 2025 02:01:19 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976743#M4391</guid>
      <dc:creator>hellohere</dc:creator>
      <dc:date>2025-10-10T02:01:19Z</dc:date>
    </item>
    <item>
      <title>Re: How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976744#M4392</link>
      <description>Initial Thread and dataset:

&lt;A href="https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976238#M4381" target="_blank"&gt;https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976238#M4381&lt;/A&gt;</description>
      <pubDate>Fri, 10 Oct 2025 02:02:18 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976744#M4392</guid>
      <dc:creator>hellohere</dc:creator>
      <dc:date>2025-10-10T02:02:18Z</dc:date>
    </item>
    <item>
      <title>Re: How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976767#M4393</link>
      <description>&lt;P&gt;Assuming you want to minimize the total penalty, here is one way:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
         if      _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;lt;= 0 then -10
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 60 then   2
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 36 then   4
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 24 then   8
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt; 12 then   6
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt;  6 then   2
         else if _tmin_orig[d,b,t] - outcome[d,b,t,m] &amp;gt;  0 then   1
         ) * SelectTreatmentMethod[t,m];
   min TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;An alternative approach is to use an &lt;A href="https://go.documentation.sas.com/doc/en/pgmsascdc/v_067/casmopt/casmopt_optmodel_details81.htm" target="_self"&gt;FCMP function&lt;/A&gt;:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc fcmp outlib=work.funcs.test;
   function penaltyCoefficient(dif);
      if      dif &amp;lt;= 0 then return(-10);
      else if dif &amp;gt; 60 then return(2);
      else if dif &amp;gt; 36 then return(4);
      else if dif &amp;gt; 24 then return(8);
      else if dif &amp;gt; 12 then return(6);
      else if dif &amp;gt;  6 then return(2);
      else if dif &amp;gt;  0 then return(1);
   endsub;
run;

option cmplib=work.funcs;

data try;
   do x = -5 to 70 by 5;
      p = penaltyCoefficient(x);
      output;
   end;
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Then the Penalty declaration can be written more compactly:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} penaltyCoefficient(_tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m];
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Fri, 10 Oct 2025 14:19:51 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976767#M4393</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-10-10T14:19:51Z</dc:date>
    </item>
    <item>
      <title>Re: How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976804#M4394</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/1636"&gt;@RobPratt&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks for helps.&lt;/P&gt;
&lt;P&gt;I tried the codes below, two variations.&amp;nbsp; Both complains "ERROR: The specified optimization technique does not allow nonlinear objectives." .&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Note, TotalPenalty is like TotalScore. It is to MAX'it.&amp;nbsp; Also -10 is swtiched to -20.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;With Treatment/Method, if _tmin_x is less than _tmin_orig, improvement[Score&amp;gt;0].&lt;/P&gt;
&lt;P&gt;&lt;U&gt;&lt;STRONG&gt;The Score is consider by each BLOC/DT.&amp;nbsp;&lt;/STRONG&gt;&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;  impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
         if      sum((_tmin_orig[d,b,t] - outcome[d,b,t,m])* SelectTreatmentMethod[t,m]) &amp;lt;= 0 then -20
         else if sum((_tmin_orig[d,b,t] - outcome[d,b,t,m])* SelectTreatmentMethod[t,m]) &amp;gt; 60 then   2
         else if sum((_tmin_orig[d,b,t] - outcome[d,b,t,m])* SelectTreatmentMethod[t,m]) &amp;gt; 36 then   4
         else if sum((_tmin_orig[d,b,t] - outcome[d,b,t,m])* SelectTreatmentMethod[t,m]) &amp;gt; 24 then   8
         else if sum((_tmin_orig[d,b,t] - outcome[d,b,t,m])* SelectTreatmentMethod[t,m]) &amp;gt; 12 then   6
         else if sum((_tmin_orig[d,b,t] - outcome[d,b,t,m])* SelectTreatmentMethod[t,m]) &amp;gt;  6 then   2
         else if sum((_tmin_orig[d,b,t] - outcome[d,b,t,m])* SelectTreatmentMethod[t,m]) &amp;gt;  0 then   1
         ) * SelectTreatmentMethod[t,m];
   max TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
         if  	 max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;lt;= 0 then -20
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 60 then   2
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 36 then   4
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 24 then   8
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 12 then   6
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt;  6 then   2
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt;  0 then   1
         ) * SelectTreatmentMethod[t,m];
   max TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Complete codes are below. Also attached is the dataset.&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let optds=Mm_out_x6_x;  %let methct=4;  
data have;
   set &amp;amp;optds.;
   rename _tmin=method1 _tmin_ew=method2 _tmin_wt_r=method3 _tmin_wt_r2=method4;
run;

title "OPT on &amp;amp;optds.";
proc optmodel;
   /* read input data */
   set METHODS = 1..&amp;amp;methct.;
   set &amp;lt;str,num,num&amp;gt; DATE_BLOCK_TREATMENT;
   num _tmin_orig {DATE_BLOCK_TREATMENT};
   num outcome {DATE_BLOCK_TREATMENT, METHODS};
   read data have into DATE_BLOCK_TREATMENT=[dt bloc condi_id] _tmin_orig
      {m in METHODS} &amp;lt;outcome[dt,bloc,condi_id,m]=col('method'||m)&amp;gt;;
   set TREATMENTS = setof {&amp;lt;d,b,t&amp;gt; in DATE_BLOCK_TREATMENT} t;
   set DATE_BLOCK = setof {&amp;lt;d,b,t&amp;gt; in DATE_BLOCK_TREATMENT} &amp;lt;d,b&amp;gt;;

  /* define optimization model */
   var SelectTreatment {TREATMENTS} binary;
   var SelectMethod {METHODS} binary;
   var SelectTreatmentMethod {TREATMENTS, METHODS} binary;
   var IsGood {DATE_BLOCK} binary;
   /* IT WAS*/
   impvar Score {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 1 * IsGood[d,b] - 5 * (1 - IsGood[d,b]);
   max TotalScore = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Score[d,b];
 
   /*con CardinalityTrtmtBloc:
      sum {t in 5..6} SelectTreatment[t] = 1;  /*enforce to select ONE AND ONLY ONE among 2-4[or alike]*/
   con CardinalityTreatment:
      sum {t in TREATMENTS} SelectTreatment[t] = 2;
   con CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 2; 
   con Linearize1 {t in TREATMENTS, m in METHODS}:
      SelectTreatmentMethod[t,m] &amp;lt;= SelectTreatment[t];
   con Linearize2 {t in TREATMENTS, m in METHODS}:
      SelectTreatmentMethod[t,m] &amp;lt;= SelectMethod[m];
   con AtLeastOneGood {&amp;lt;d,b&amp;gt; in DATE_BLOCK}:
      IsGood[d,b] &amp;lt;= sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, 
			m in METHODS: outcome[d,b,t,m] &amp;lt; _tmin_orig[d,b,t]} SelectTreatmentMethod[t,m];
   

   /* call MILP solver , TOP one only
   solve;
   create data want_method from [method] SelectMethod;
   create data want_treatment from [treatment] SelectTreatment;
   create data want_dt_bloc from [dt bloc] IsGood Score;
   create data want_x_dtbloc from [d b]=DATE_BLOCK;
   create data want_trtmt from [t]=TREATMENTS;*/

	/* source: https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976283/highlight/false#M4384
	*/
   /* primary objective */
   solve;
   create data want_method from [method] SelectMethod;
   create data want_treatment from [treatment] SelectTreatment;
   create data want_dt_bloc from [dt bloc] IsGood Score;
   create data want_x_dtbloc from [d b]=DATE_BLOCK;
   create data want_trtmt from [t]=TREATMENTS;

	/*   con MinScore: TotalScore &amp;gt;= TotalScore.sol;*/
   con MinScore: TotalScore &amp;gt;= -5;

   /*impvar difx {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m];
   max TotalDif = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} difx[d,b];
   */

   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
         if  	 max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;lt;= 0 then -20
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 60 then   2
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 36 then   4
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 24 then   8
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt; 12 then   6
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt;  6 then   2
         else if max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m] &amp;gt;  0 then   1
         ) * SelectTreatmentMethod[t,m];
   max TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];

   /* secondary objective */
   solve with milp / primalin;
   put TotalScore= TotalPenalty=;

   create data want_method_f from [method] SelectMethod;
   create data want_treatment_f from [treatment] SelectTreatment;
   create data want_dt_bloc_f from [dt bloc] IsGood Score;
   create data want_x_dtbloc_f from [d b]=DATE_BLOCK;
   create data want_trtmt_f from [t]=TREATMENTS;

quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sat, 11 Oct 2025 02:36:15 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976804#M4394</guid>
      <dc:creator>hellohere</dc:creator>
      <dc:date>2025-10-11T02:36:15Z</dc:date>
    </item>
    <item>
      <title>Re: How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976805#M4395</link>
      <description>&lt;P&gt;I also tried the code below, which I bet is more meaningful.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
	if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
     	_tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;lt; 0 then -20
	else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
        _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 60 then 2
	else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
        _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 36 then 4
	else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
        _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 24 then 8
	else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
        _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 12 then 6
	else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
        _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt;  6 then 2
	else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
        _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt;= 0 then 1;
		
   max TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;It still has the same complain. Might need to set nonlinear approach?!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;21702  impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} =
21703      if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
21704          _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;lt; 0 then -20
21705      else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
21706          _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 60 then 2
21707      else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
21708          _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 36 then 4
21709      else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
21710          _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 24 then 8
21711      else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
21712          _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt; 12 then 6
21713      else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
21714          _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt;  6 then 2
21715      else if sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} (
21716          _tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m] &amp;gt;= 0 then 1;
21717
21718     max TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];
21719
21720     /* secondary objective */
21721     solve with milp / primalin;
NOTE: Problem generation will use 4 threads.
NOTE: The problem has 109 variables (0 free, 0 fixed).
NOTE: The problem uses 31 implicit variables.
NOTE: The problem has 109 binary and 0 integer variables.
NOTE: The problem has 162 linear constraints (159 LE, 2 EQ, 1 GE, 0 range).
NOTE: The problem has 819 linear constraint coefficients.
NOTE: The problem has 0 nonlinear constraints (0 LE, 0 EQ, 0 GE, 0 range).
ERROR: The specified optimization technique does not allow nonlinear objectives.
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sat, 11 Oct 2025 02:54:00 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976805#M4395</guid>
      <dc:creator>hellohere</dc:creator>
      <dc:date>2025-10-11T02:54:00Z</dc:date>
    </item>
    <item>
      <title>Re: How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976806#M4396</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/1636"&gt;@RobPratt&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Attached is the EXCEL/SOLVER version. The Penalty is only the function on difx[from previous].&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Note the columns AE:AJ are completely identical to the columns U:Z, because&amp;nbsp;The Penalty is only the function on difx[from previous].&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sat, 11 Oct 2025 03:26:35 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976806#M4396</guid>
      <dc:creator>hellohere</dc:creator>
      <dc:date>2025-10-11T03:26:35Z</dc:date>
    </item>
    <item>
      <title>Re: How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976894#M4397</link>
      <description>&lt;P&gt;The Excel file makes it clearer what you are trying to do.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here's a way to use the black-box solver:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   impvar Difx {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m];
   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = 
      if      DifX[d,b] &amp;lt;=  0 then -20
      else if DifX[d,b] &amp;gt;  60 then   2
      else if DifX[d,b] &amp;gt;  36 then   4
      else if DifX[d,b] &amp;gt;  24 then   8
      else if DifX[d,b] &amp;gt;  12 then   6
      else if DifX[d,b] &amp;gt;   6 then   2
      else if DifX[d,b] &amp;gt;   0 then   1;
/*   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = penaltyCoefficient(DifX[d,b]);*/
   max TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];

   /* secondary objective */
   solve obj TotalPenalty with blackbox / primalin;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;Note that the commented out line instead uses the FCMP function from my earlier reply (but with -20 instead of -10) and is mathematically equivalent.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But the solution returned by the black-box solver is not necessarily globally optimal.&amp;nbsp; Here's an alternative approach that uses the MILP solver to find a globally optimally solution:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   num upperBoundDifx = 
      max {&amp;lt;d,b&amp;gt; in DATE_BLOCK}
         sum {&amp;lt;(d),(b),t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS} max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0);
   num epsilon = 1e-2;
   num numIntervals = 7;
   set INTERVALS = 1..numIntervals;
   num ub {INTERVALS};
   ub[1] = 0;
   ub[2] = 6;
   ub[3] = 12;
   ub[4] = 24;
   ub[5] = 36;
   ub[6] = 60;
   ub[7] = upperBoundDifx;
   num lb {i in INTERVALS} = (if i = 1 then 0 else ub[i-1] + epsilon);
   num p {INTERVALS} = [-20, 1, 2, 6, 8, 4, 2];
   print lb ub p;
   var IsInterval {DATE_BLOCK, INTERVALS} binary;
   con OneInterval {&amp;lt;d,b&amp;gt; in DATE_BLOCK}:
      sum {i in INTERVALS} IsInterval[d,b,i] = 1;
   con LeftCon {&amp;lt;d,b&amp;gt; in DATE_BLOCK}:
      sum {i in INTERVALS} lb[i] * IsInterval[d,b,i] &amp;lt;= DifX[d,b];
   con RightCon {&amp;lt;d,b&amp;gt; in DATE_BLOCK}:
      sum {i in INTERVALS} ub[i] * IsInterval[d,b,i] &amp;gt;= DifX[d,b];
   impvar Penalty {&amp;lt;d,b&amp;gt; in DATE_BLOCK} = sum {i in INTERVALS} p[i] * IsInterval[d,b,i];
   max TotalPenalty = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} Penalty[d,b];

   /* secondary objective */
   solve with milp / primalin;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;If you know that the values of DifX will always take integer values, you can use 1 instead of 1e-2 for epsilon.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;For your input data, both black-box and MILP return a solution with TotalPenalty = 2.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If you fix the selected treatments and methods to the ones selected in the Excel file and then call either solver, the resulting solutions match the Excel file and yield TotalPenalty = -7:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   /* temporarily fix to match Excel solution */
   for {t in TREATMENTS} fix SelectTreatment[t] = (t in {13,15});
   for {m in METHODS}    fix SelectMethod[m]    = (m = 3);&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 14 Oct 2025 15:03:01 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976894#M4397</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-10-14T15:03:01Z</dc:date>
    </item>
    <item>
      <title>Re: How to build/code up a penalty function?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976916#M4399</link>
      <description>&lt;P&gt;Thanks a lot. I bet you take great efforts to help. I guess I need to pick up own IML.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;No need to be global optimal.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 14 Oct 2025 00:03:19 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-build-code-up-a-penalty-function/m-p/976916#M4399</guid>
      <dc:creator>hellohere</dc:creator>
      <dc:date>2025-10-14T00:03:19Z</dc:date>
    </item>
  </channel>
</rss>

