<?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>RobPratt Tracker</title>
    <link>https://communities.sas.com/kntur85557/tracker</link>
    <description>RobPratt Tracker</description>
    <pubDate>Tue, 19 May 2026 12:34:47 GMT</pubDate>
    <dc:date>2026-05-19T12:34:47Z</dc:date>
    <item>
      <title>Re: Proc Optmodel:  How to find the top two or three solutions?</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-How-to-find-the-top-two-or-three-solutions/m-p/981846#M4414</link>
      <description>&lt;P&gt;You can use the MILP solver options MAXPOOLSOLS=3 and SOLTYPE=best to find the best 3 solutions:&lt;/P&gt;
&lt;P&gt;&lt;A href="https://go.documentation.sas.com/doc/en/pgmsascdc/v_070/casmopt/casmopt_milpsolver_syntax02.htm#casmopt.milpsolver.milpcops" target="_blank"&gt;SAS Help Center: MILP Solver Options&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;A less efficient but more flexible approach is to introduce dynamically generated no-good constraints to cut off each solution as it is found:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   num numSolutions init 0;
   set SOLUTIONS = 1..numSolutions;
   set &amp;lt;str,num,num&amp;gt; SUPPORT_sol {SOLUTIONS};
   con NoGood {sol in SOLUTIONS}:
      sum {&amp;lt;c,a,e&amp;gt; in SUPPORT_sol[sol]} (1 - CHI[c,a,e]) &amp;gt;= 1;

   for {1..3} do;
      solve;
      numSolutions = numSolutions + 1;
      SUPPORT_sol[numSolutions] = {&amp;lt;c,a,e&amp;gt; in stations cross orientations: CHI[c,a,e] &amp;gt; 0.5};
   end;

   create data work.OptimalSolution_RoO from [sol station a e]={sol in SOLUTIONS, &amp;lt;c,a,e&amp;gt; in SUPPORT_sol[sol]} CHI=1;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;In the FOR loop, you could alternatively replace the SOLVE statement with your more intricate solution process that loops over pairs to find a good solution.&lt;/P&gt;</description>
      <pubDate>Mon, 12 Jan 2026 19:07:45 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-How-to-find-the-top-two-or-three-solutions/m-p/981846#M4414</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2026-01-12T19:07:45Z</dc:date>
    </item>
    <item>
      <title>Re: Proc Optmodel - output</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-output/m-p/979707#M4410</link>
      <description>&lt;P&gt;The closest you can get to returning a BestBound solution is to solve the LP relaxation:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;solve relaxint;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The resulting objective value will often be close to the first or second BestBound value that appears in the iteration log.&amp;nbsp; The first BestBound value sometimes arises from a trivial bound that considers only the objective function and the variable bounds.&lt;/P&gt;</description>
      <pubDate>Fri, 28 Nov 2025 16:57:01 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-output/m-p/979707#M4410</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-11-28T16:57:01Z</dc:date>
    </item>
    <item>
      <title>Re: Proc Optmodel - output</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-output/m-p/979705#M4408</link>
      <description>&lt;P&gt;What you have is correct, except that the RUN should instead be QUIT.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The values of H and X in the resulting solution data set will correspond to the objective value reported in the BestInteger column.&amp;nbsp; You will see the same values if you execute this statement:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;print H X;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You should also see the value in BestInteger if you execute this statement:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;print obj;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;What makes you suspect that the values of H and X instead correspond to the BestBound column?&lt;/P&gt;</description>
      <pubDate>Fri, 28 Nov 2025 16:31:03 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-output/m-p/979705#M4408</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-11-28T16:31:03Z</dc:date>
    </item>
    <item>
      <title>Re: Proc Optmodel Result: Why is Objective = 0?</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-Result-Why-is-Objective-0/m-p/976973#M4400</link>
      <description>&lt;P&gt;When there are two stations and each one can use at most one orientation, it is not possible for a target to be triply covered, so IsTriplyCovered[t] = 0 for all t, and the maximum objective value is 0.&amp;nbsp; There are multiple optimal solutions, and the one returned by the solver has only one CHI variable &amp;gt; 0.5.&lt;/P&gt;</description>
      <pubDate>Tue, 14 Oct 2025 15:55:24 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/Proc-Optmodel-Result-Why-is-Objective-0/m-p/976973#M4400</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-10-14T15:55:24Z</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/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 2 Find the BEST Improvement on DIF between _tmin_orig and _tmin_x[treatment/method] for BLOC</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976696#M4390</link>
      <description>&lt;P&gt;Please open a new question for that.&lt;/P&gt;</description>
      <pubDate>Thu, 09 Oct 2025 16:55:36 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976696#M4390</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-10-09T16:55:36Z</dc:date>
    </item>
    <item>
      <title>Re: How 2 Find the BEST Improvement on DIF between _tmin_orig and _tmin_x[treatment/method] for BLOC</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976394#M4387</link>
      <description>&lt;P&gt;TotalScore.sol is the value of TotalScore from the most recent solver call.&amp;nbsp; You can alternatively use a manually specified threshold.&amp;nbsp; The following code changes yield the same objective values as in your Excel file:&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;
&lt;P&gt;The PUT statement shows the resulting objective values:&lt;/P&gt;
&lt;P&gt;TotalScore=-3 TotalDif=13365&lt;/P&gt;</description>
      <pubDate>Fri, 03 Oct 2025 21:08:55 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976394#M4387</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-10-03T21:08:55Z</dc:date>
    </item>
    <item>
      <title>Re: How 2 Find the BEST Improvement on DIF between _tmin_orig and _tmin_x[treatment/method] for BLOC</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976283#M4384</link>
      <description>&lt;P&gt;I see a few issues here:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;You cannot have = expression in a VAR statement.&amp;nbsp; You should keep the original impvar Score and max TotalScore declarations.&lt;/LI&gt;
&lt;LI&gt;The outcome parameter requires four arguments, not two: outcome[d,b,t,m], not outcome[d,b].&lt;/LI&gt;
&lt;LI&gt;You have not defined _time_orig[b].&amp;nbsp; Is this maybe supposed to be _tmin_orig[d,b,t]?&lt;/LI&gt;
&lt;LI&gt;Your MinScore declaration is missing a colon, and the right-hand side should depend on the previous objective function value.&amp;nbsp; Correct syntax is: &lt;CODE class=" language-sas" style="font-size: 13px; white-space: normal;"&gt;con MinScore: TotalScore &amp;gt;= TotalScore.sol;&lt;/CODE&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&lt;CODE class=" language-sas" style="font-size: 13px; white-space: normal;"&gt;&lt;/CODE&gt;I'm not quite sure what you want the secondary objective to be, but here's an outline of the two stages:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   /* primary objective */
   solve;

   con MinScore: TotalScore &amp;gt;= TotalScore.sol;

   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} (_tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m];
   max TotalDif = sum {&amp;lt;d,b&amp;gt; in DATE_BLOCK} difx[d,b];

   /* secondary objective */
   solve with milp / primalin;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 02 Oct 2025 22:45:02 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-2-Find-the-BEST-Improvement-on-DIF-between-tmin-orig-and/m-p/976283#M4384</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-10-02T22:45:02Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/976140#M4380</link>
      <description>&lt;P&gt;I would be glad to help, but first please create a new question for this part.&lt;/P&gt;</description>
      <pubDate>Wed, 01 Oct 2025 14:43:45 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/976140#M4380</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-10-01T14:43:45Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975943#M4376</link>
      <description>&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   con CardinalityTreatment234:
      sum {t in 2..4} SelectTreatment[t] = 1;
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Mon, 29 Sep 2025 13:46:30 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975943#M4376</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-29T13:46:30Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975537#M4374</link>
      <description>&lt;P&gt;Correct syntax is:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   create data want_x_dtbloc from [d b]=DATE_BLOCK;
   create data want_trtmt from [t]=TREATMENTS;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Tue, 23 Sep 2025 04:52:53 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975537#M4374</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-23T04:52:53Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975486#M4372</link>
      <description>&lt;P&gt;To match the Excel logic, you can change the optimization model as follows:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   /* define optimization model */
   var SelectTreatment {TREATMENTS} binary;
   var SelectMethod {METHODS} binary;
   var SelectTreatmentMethod {TREATMENTS, METHODS} binary;
   var IsGood {DATE_BLOCK} binary;
   /* if IsGood[d,b] = 1 then Score[d,b] = 1 else Score[d,b] = -5 */
   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 CardinalityTreatment:
      sum {t in TREATMENTS} SelectTreatment[t] = 2;
   con CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 1;
   /* SelectTreatmentMethod[t,m] &amp;lt;= SelectTreatment[t] * SelectMethod[m] */
   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];&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The idea is that if IsGood[d,b] = 1, the AtLeastOneGood constraint will force SelectTreatmentMethod[t,m] = 1 for at least one t and m such that outcome[d,b,t,m] &amp;lt; _tmin_orig[d,b,t].&amp;nbsp; And the Linearize1 and Linearize2 constraints together force SelectTreatment[t] = 1 and SelectMethod[m] = 1 for that t and m.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;With these changes, the optimal objective value is 3, and there are 13 such optimal solutions for SelectTreatment.&lt;/P&gt;</description>
      <pubDate>Tue, 23 Sep 2025 15:40:15 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975486#M4372</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-23T15:40:15Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975417#M4369</link>
      <description>Because the two cardinality constraints are equalities, increasing the right-hand side values does not make the problem looser.  If the = were instead &amp;lt;=, then increasing the right-hand side would indeed yield a relaxation.  Do you want to select exactly the specified numbers or at most the specified numbers?&lt;BR /&gt;</description>
      <pubDate>Sat, 20 Sep 2025 20:42:14 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975417#M4369</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-20T20:42:14Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975324#M4366</link>
      <description>&lt;P&gt;It looks like you are using an old version of SAS.&amp;nbsp; That dynamic data set name functionality was introduced in SAS/OR 14.1 in SAS 9.4M3 in 2015:&lt;/P&gt;
&lt;P&gt;&lt;A href="https://support.sas.com/documentation/cdl/en/ormpug/68156/HTML/default/viewer.htm#ormpug_optmodel_details40.htm" target="_blank" rel="noopener"&gt;Data Set Input/Output :: SAS/OR(R) 14.1 User's Guide: Mathematical Programming&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here's a workaround that uses PROC APPEND inside a SUBMIT block:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   /* call MILP solver to find top few solutions for SelectTreatment */
   num numSolsWanted = 5;
   num numSolsFound init 0;
   set SOLS = 1..numSolsFound;
   set TREATMENTS_s {SOLS};
   con ExcludeSolution {s in SOLS}:
      sum {t in TREATMENTS_s[s]} SelectTreatment[t] &amp;lt;= card(TREATMENTS_s[s]) - 1;
   for {1..numSolsWanted} do;
      put numSolsFound=;
      solve;
      numSolsFound = numSolsFound + 1;
      TREATMENTS_s[numSolsFound] = {t in TREATMENTS: SelectTreatment[t].sol &amp;gt; 0.5};
      create data want_method from [method] sol=numSolsFound SelectMethod;
      create data want_treatment from [treatment] sol=numSolsFound SelectTreatment;
      create data want_dt_bloc from [dt bloc] sol=numSolsFound IsGood Score;
      submit;
         proc append base=want_method_all data=want_method;
         run;
         proc append base=want_treatment_all data=want_treatment;
         run;
         proc append base=want_dt_bloc_all data=want_dt_bloc;
         run;
      endsubmit;
   end;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Thu, 18 Sep 2025 14:53:37 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975324#M4366</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-18T14:53:37Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975297#M4363</link>
      <description>&lt;P&gt;To get the 5 best pairs of treatments, you can replace the SOLVE and CREATE DATA statements as follows:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   /* call MILP solver to find top few solutions for SelectTreatment */
   num numSolsWanted = 5;
   num numSolsFound init 0;
   set SOLS = 1..numSolsFound;
   set TREATMENTS_s {SOLS};
   con ExcludeSolution {s in SOLS}:
      sum {t in TREATMENTS_s[s]} SelectTreatment[t] &amp;lt;= card(TREATMENTS_s[s]) - 1;
   for {1..numSolsWanted} do;
      put numSolsFound=;
      solve;
      numSolsFound = numSolsFound + 1;
      TREATMENTS_s[numSolsFound] = {t in TREATMENTS: SelectTreatment[t].sol &amp;gt; 0.5};
      create data ('want_method'||numSolsFound) from [method] SelectMethod;
      create data ('want_treatment'||numSolsFound) from [treatment] SelectTreatment;
      create data ('want_dt_bloc'||numSolsFound) from [dt bloc] IsGood Score;
   end;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Thu, 18 Sep 2025 00:36:34 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975297#M4363</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-18T00:36:34Z</dc:date>
    </item>
    <item>
      <title>Re: HOW TO Find the Best Combination Of Treatments for Date/BLOC[dt/bloc] ?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975283#M4361</link>
      <description>&lt;P&gt;If I understand correctly, the following code does what you want:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
   set mm_out_x6_x;
   rename _tmin=method1 _tmin_ew=method2 _tmin_wt_r=method3 _tmin_wt_r2=method4;
run;

proc optmodel;
   /* read input data */
   set METHODS = 1..4;
   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 SelectMethod {METHODS} binary;
   var SelectTreatment {TREATMENTS} binary;
   var IsGood {DATE_BLOCK} binary;
   /* if IsGood[d,b] = 1 then Score[d,b] = 1 else Score[d,b] = -5 */
   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 CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 1;
   con CardinalityTreatment:
      sum {t in TREATMENTS} SelectTreatment[t] = 2;
   /* if IsGood[d,b] = SelectMethod[m] = SelectTreatment[t] = 1 then outcome[d,b,t,m] &amp;lt; _tmin_orig[d,b,t] */
   con NoGood {&amp;lt;d,b,t&amp;gt; in DATE_BLOCK_TREATMENT, m in METHODS: outcome[d,b,t,m] &amp;gt;= _tmin_orig[d,b,t]}:
      IsGood[d,b] + SelectMethod[m] + SelectTreatment[t] &amp;lt;= 2; 

   /* call MILP solver */
   solve;

   /* create output data */
   create data want_method from [method] SelectMethod;
   create data want_treatment from [treatment] SelectTreatment;
   create data want_dt_bloc from [dt bloc] IsGood Score;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;An optimal solution selects method 3 and treatments 12 and 15, yielding a maximum total score of -21.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If this does not match your expectation, please provide a sample solution, together with the calculation of its total score.&lt;/P&gt;</description>
      <pubDate>Wed, 17 Sep 2025 19:52:42 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/HOW-TO-Find-the-Best-Combination-Of-Treatments-for-Date-BLOC-dt/m-p/975283#M4361</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-17T19:52:42Z</dc:date>
    </item>
    <item>
      <title>Re: How to find the BEST combination of two CID to Score this?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-find-the-BEST-combination-of-two-CID-to-Score-this/m-p/975188#M4354</link>
      <description>&lt;P&gt;Here's a way to use the runOptmodel action with groupBy to solve a separate problem for each dt and bloc:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
   set lib.mmind_temp_x;
   if _tmin_orig &amp;gt; _tmin OR _tmin_orig &amp;gt; _tmin_ew OR _tmin_orig &amp;gt; _tmin_wt_r OR _tmin_orig &amp;gt; _tmin_wt_r2
   then score = 1;
   else score = -5;
run;

data mycas.have;
   set have;
run;

proc cas;
   source pgm;
      /* read input data */
      set IDS;
      num score {IDS};
      read data have into IDS=[condi_id] score;

      /* define optimization model */
      var Select {IDS} binary;
      max TotalScore = sum {i in IDS} score[i] * Select[i];
      con Cardinality:
         sum {i in IDS} Select[i] = 2;

      /* call MILP solver */
      solve;

      /* create output data */
      create data want from [condi_id] score Select;
   endsource;

   action optimization.runOptmodel / code=pgm groupBy={'dt','bloc'};
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;But you can get the same results by sorting in descending order of score and keeping the top two:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sort data=have out=want;
   by dt bloc descending score;
run;&lt;BR /&gt;
data want;
   set want;
   by dt bloc;
   retain rank;
   if first.bloc then rank = 1;
   else rank + 1;
   Select = (rank &amp;lt;= 2);
run;
&lt;BR /&gt;proc sort data=want;
   by dt bloc condi_id;
run;
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Tue, 16 Sep 2025 19:40:38 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-find-the-BEST-combination-of-two-CID-to-Score-this/m-p/975188#M4354</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-16T19:40:38Z</dc:date>
    </item>
    <item>
      <title>Re: How to find the BEST combination of two CID to Score this?!</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-find-the-BEST-combination-of-two-CID-to-Score-this/m-p/975171#M4352</link>
      <description>&lt;P&gt;To help clarify the problem, can you please share a feasible (not necessarily optimal) solution and the corresponding objective values?&lt;/P&gt;</description>
      <pubDate>Tue, 16 Sep 2025 15:55:18 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-find-the-BEST-combination-of-two-CID-to-Score-this/m-p/975171#M4352</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-16T15:55:18Z</dc:date>
    </item>
    <item>
      <title>Re: find all possible sum of variables that amount to a value</title>
      <link>https://communities.sas.com/t5/SAS-Programming/find-all-possible-sum-of-variables-that-amount-to-a-value/m-p/974747#M377974</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/18408"&gt;@Ksharp&lt;/a&gt;&amp;nbsp;Sorry, I had oversimplfiied the code, which I have now corrected.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The corrected line is:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;set VARS {IDS} init VARS_ALL;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Wed, 10 Sep 2025 14:49:57 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/find-all-possible-sum-of-variables-that-amount-to-a-value/m-p/974747#M377974</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2025-09-10T14:49:57Z</dc:date>
    </item>
  </channel>
</rss>

