<?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 do an optimization with a piecewise linear constraint? in Mathematical Optimization, Discrete-Event Simulation, and OR</title>
    <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-do-an-optimization-with-a-piecewise-linear-constraint/m-p/721203#M3326</link>
    <description>Thanks, for the fast reply.&lt;BR /&gt;</description>
    <pubDate>Tue, 23 Feb 2021 07:33:49 GMT</pubDate>
    <dc:creator>Bernd_S</dc:creator>
    <dc:date>2021-02-23T07:33:49Z</dc:date>
    <item>
      <title>How to do an optimization with a piecewise linear constraint?</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-do-an-optimization-with-a-piecewise-linear-constraint/m-p/720898#M3323</link>
      <description>&lt;P&gt;Hello,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I'm trying to solve the following optimization problem:&lt;/P&gt;&lt;P&gt;min f(x) under h(x) &amp;gt; L, where x is n-dimensional and h is a piecewise linear function.&lt;/P&gt;&lt;P&gt;h(x) can also be written as h(x) = h_1(x_1)+...+h_n(x_n), where each h_i is a piecewise linear function. E.g.: h_i = 0 if x_i &amp;lt; 5 and 10 if x_i &amp;gt;=5.&lt;/P&gt;&lt;P&gt;Note that each h_i is monotonically increasing.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;For the problem i'm trying to solve, n is &amp;gt; 100 and each piecewise function h_i consists of around 25 "cutpoints".&lt;/P&gt;&lt;P&gt;I have a dataset which describes h (columns: i, "start cutpoint", "end cutpoint", value).&lt;/P&gt;&lt;P&gt;Is there an easy way to solve this problem?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I tried to solve a really simple version of the problem:&lt;/P&gt;&lt;P&gt;n = 2, f(x) = x_1+x_2 and h(x) = 0, unless x_1 &amp;gt;=4, then h(x) = 3. Furthermore I set 1&amp;lt;= x_i&amp;lt;=10 and L = 2. Therefore the optimal solution is (4,1).&lt;/P&gt;&lt;P&gt;However the following SAS code fails to deliver the optimal solution:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="sas"&gt;proc optmodel;
number n = 2;
var x{1..n} &amp;gt;=1 &amp;lt;=10;
minimize f = x[1]+x[2];
con loss: (x[1] &amp;gt;= 4)*3 &amp;gt;= 2;
solve with NLP /multistart=(Maxstarts=20);
print x[1] x[2];
run;&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Without the multistart option, the solution is not feasible (1.15, 1.15). With the multistart option the solution is better, but not good (4.8,1.6).&lt;/P&gt;&lt;P&gt;It seems to me, that the solver is not able to work with the constraint. I tried to write the constraint in other ways, but so far I was not able to achieve a satisfying solution.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Obviously the feasible region of the problem I'm trying to solve is complicated, however since each h_i is monotonically increasing the region is connected and therefore it should be possible to solve this problem, or am I missing something?&lt;/P&gt;&lt;P&gt;So my question is: How to do an optimization with a piecewise linear constraint?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Greetings&lt;/P&gt;&lt;P&gt;Bernd&lt;/P&gt;</description>
      <pubDate>Mon, 22 Feb 2021 12:55:06 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-do-an-optimization-with-a-piecewise-linear-constraint/m-p/720898#M3323</guid>
      <dc:creator>Bernd_S</dc:creator>
      <dc:date>2021-02-22T12:55:06Z</dc:date>
    </item>
    <item>
      <title>Re: How to do an optimization with a piecewise linear constraint?</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-do-an-optimization-with-a-piecewise-linear-constraint/m-p/720936#M3324</link>
      <description>&lt;P&gt;Derivative-based NLP solvers have difficulty with discontinuities like this.&amp;nbsp; One alternative approach is to use the black-box solver:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc optmodel;
   number n = 2;
   var x{1..n} &amp;gt;=1 &amp;lt;=10;
   minimize f = x[1]+x[2];
   con loss: (x[1] &amp;gt;= 4)*3 &amp;gt;= 2;
   solve with blackbox;
   print x;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;DIV class="branch lia-align-center"&gt;
&lt;DIV class="lia-align-left"&gt;
&lt;DIV align="center"&gt;
&lt;TABLE class="table" summary="Procedure Optmodel: Solution Summary" frame="box" rules="all" cellspacing="0" cellpadding="5"&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH class="c b header" colspan="2" scope="colgroup"&gt;Solution Summary&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Solver&lt;/TH&gt;
&lt;TD class="r data"&gt;Black-Box&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Objective Function&lt;/TH&gt;
&lt;TD class="r data"&gt;f&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Solution Status&lt;/TH&gt;
&lt;TD class="r data"&gt;Function Convergence&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Objective Value&lt;/TH&gt;
&lt;TD class="r data"&gt;5.0000000097&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;&amp;nbsp;&lt;/TH&gt;
&lt;TD class="r data"&gt;&amp;nbsp;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Infeasibility&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Random Seed Used&lt;/TH&gt;
&lt;TD class="r data"&gt;1&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;&amp;nbsp;&lt;/TH&gt;
&lt;TD class="r data"&gt;&amp;nbsp;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Evaluations&lt;/TH&gt;
&lt;TD class="r data"&gt;1578&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Cached Evaluations&lt;/TH&gt;
&lt;TD class="r data"&gt;105&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Iterations&lt;/TH&gt;
&lt;TD class="r data"&gt;30&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Presolve Time&lt;/TH&gt;
&lt;TD class="r data"&gt;0.19&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Solution Time&lt;/TH&gt;
&lt;TD class="r data"&gt;0.24&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;DIV&gt;
&lt;DIV class="lia-align-left" align="center"&gt;
&lt;DIV class="branch"&gt;
&lt;DIV&gt;
&lt;DIV align="center"&gt;
&lt;TABLE class="table" summary="Procedure Optmodel: PrintTable" frame="box" rules="all" cellspacing="0" cellpadding="5"&gt;&lt;COLGROUP&gt; &lt;COL /&gt;&lt;/COLGROUP&gt; &lt;COLGROUP&gt; &lt;COL /&gt;&lt;/COLGROUP&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH class="l b header" scope="col"&gt;[1]&lt;/TH&gt;
&lt;TH class="r b header" scope="col"&gt;x&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;1&lt;/TH&gt;
&lt;TD class="r data"&gt;1&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;2&lt;/TH&gt;
&lt;TD class="r data"&gt;4&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;BR /&gt;
&lt;P class="lia-align-left"&gt;The black-box solver does find an optimal solution here, but that is not guaranteed.&amp;nbsp; To guarantee an optimal solution, you can linearize the problem and use the MILP solver:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc optmodel;
   number n = 2;
   var x{1..n} &amp;gt;=1 &amp;lt;=10;
   minimize f = x[1]+x[2];
   set INTERVALS = 1..2;
   var y {INTERVALS} binary;
   num start {INTERVALS} = [1,4];
   num end   {INTERVALS} = [4,10];
   num value {INTERVALS} = [0,3];
   con OneInterval:
      sum {i in INTERVALS} y[i] = 1;
   con loss:
      sum {i in INTERVALS} value[i] * y[i] &amp;gt;= 2;
   num epsilon = 1e-4;
   /* y[i] = 1 implies start[i] &amp;lt;= x[i] &amp;lt;= end[i] - epsilon */
   con Indicator1 {i in INTERVALS}:
      start[i] - x[i] &amp;lt;= (start[i] - x[i].lb) * (1 - y[i]);
   con Indicator2 {i in INTERVALS}:
      x[i] - end[i] + epsilon &amp;lt;= (x[i].ub - end[i] + epsilon) * (1 - y[i]);
   solve;
   print x;
   print y;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;DIV class="branch"&gt;
&lt;DIV&gt;
&lt;DIV align="center"&gt;
&lt;TABLE class="table" summary="Procedure Optmodel: Solution Summary" frame="box" rules="all" cellspacing="0" cellpadding="5"&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH class="c b header" colspan="2" scope="colgroup"&gt;Solution Summary&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Solver&lt;/TH&gt;
&lt;TD class="r data"&gt;MILP&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Algorithm&lt;/TH&gt;
&lt;TD class="r data"&gt;Branch and Cut&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Objective Function&lt;/TH&gt;
&lt;TD class="r data"&gt;f&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Solution Status&lt;/TH&gt;
&lt;TD class="r data"&gt;Optimal&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Objective Value&lt;/TH&gt;
&lt;TD class="r data"&gt;5&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;&amp;nbsp;&lt;/TH&gt;
&lt;TD class="r data"&gt;&amp;nbsp;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Relative Gap&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Absolute Gap&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Primal Infeasibility&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Bound Infeasibility&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Integer Infeasibility&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;&amp;nbsp;&lt;/TH&gt;
&lt;TD class="r data"&gt;&amp;nbsp;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Best Bound&lt;/TH&gt;
&lt;TD class="r data"&gt;5&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Nodes&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Solutions Found&lt;/TH&gt;
&lt;TD class="r data"&gt;2&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Iterations&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Presolve Time&lt;/TH&gt;
&lt;TD class="r data"&gt;0.25&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;Solution Time&lt;/TH&gt;
&lt;TD class="r data"&gt;0.33&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;BR /&gt;&lt;A name="IDX279" target="_blank"&gt;&lt;/A&gt;
&lt;DIV&gt;
&lt;DIV align="center"&gt;
&lt;TABLE class="table" summary="Procedure Optmodel: PrintTable" frame="box" rules="all" cellspacing="0" cellpadding="5"&gt;&lt;COLGROUP&gt; &lt;COL /&gt;&lt;/COLGROUP&gt; &lt;COLGROUP&gt; &lt;COL /&gt;&lt;/COLGROUP&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH class="l b header" scope="col"&gt;[1]&lt;/TH&gt;
&lt;TH class="r b header" scope="col"&gt;x&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;1&lt;/TH&gt;
&lt;TD class="r data"&gt;1&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;2&lt;/TH&gt;
&lt;TD class="r data"&gt;4&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;BR /&gt;&lt;A name="IDX280" target="_blank"&gt;&lt;/A&gt;
&lt;DIV&gt;
&lt;DIV align="center"&gt;
&lt;TABLE class="table" summary="Procedure Optmodel: PrintTable" frame="box" rules="all" cellspacing="0" cellpadding="5"&gt;&lt;COLGROUP&gt; &lt;COL /&gt;&lt;/COLGROUP&gt; &lt;COLGROUP&gt; &lt;COL /&gt;&lt;/COLGROUP&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH class="l b header" scope="col"&gt;[1]&lt;/TH&gt;
&lt;TH class="r b header" scope="col"&gt;y&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;1&lt;/TH&gt;
&lt;TD class="r data"&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;2&lt;/TH&gt;
&lt;TD class="r data"&gt;1&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;P class="lia-align-left"&gt;By the way, we are working on automating the indicator constraints.&amp;nbsp; Stay tuned.&lt;/P&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;</description>
      <pubDate>Mon, 22 Feb 2021 15:40:40 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-do-an-optimization-with-a-piecewise-linear-constraint/m-p/720936#M3324</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2021-02-22T15:40:40Z</dc:date>
    </item>
    <item>
      <title>Re: How to do an optimization with a piecewise linear constraint?</title>
      <link>https://communities.sas.com/t5/Mathematical-Optimization/How-to-do-an-optimization-with-a-piecewise-linear-constraint/m-p/721203#M3326</link>
      <description>Thanks, for the fast reply.&lt;BR /&gt;</description>
      <pubDate>Tue, 23 Feb 2021 07:33:49 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Mathematical-Optimization/How-to-do-an-optimization-with-a-piecewise-linear-constraint/m-p/721203#M3326</guid>
      <dc:creator>Bernd_S</dc:creator>
      <dc:date>2021-02-23T07:33:49Z</dc:date>
    </item>
  </channel>
</rss>

