10

Setting. Imagine that we have several arbitrary linear functions in 2D that can be changed manually (say, slopes are parameters). Their Min (or Max) gives a sort of piecewise continuous function.

Example. Let us take three functions.

try = {3 (1 - q), 2 (1 - q) + q, 1 + 1.5 q}

We can get a piecewise function as

Min[try]

It is fine to see it on the plot (for the domain 0<=q<=1):

Plot[{try, Min[try]}, {q, 0, 1}, Frame -> True]

enter image description here

Problem. Is there a simple way (or built-in functionality) to dynamically get coordinates (i.e., q's) of all 'breaking' points of the piecewise function?

garej
  • 4,865
  • 2
  • 19
  • 42
  • Is Min[try] // PiecewiseExpand (and manipulation of that result) what you're after? – ciao Aug 09 '15 at 07:58
  • @ciao. General and lapidary manipulation of that result would suffice. – garej Aug 09 '15 at 08:09
  • 1
    With[{rt = Rationalize[try]}, {#, Reduce[Min[rt] == #]} & /@ rt] might also float your boat - in either case, you'll need to massage the results to pull out the items of interest.... – ciao Aug 09 '15 at 08:12
  • @ciao, that is the 'massage' that puzzles me =) I see, that I have to collect all 'unique' bounds of intervals, but a bit confused how to do that efficiently. any ideas? – garej Aug 09 '15 at 08:19
  • In example, one needs to transform @ciao result into something like {q -> 1/2, q -> 2/5} – garej Aug 09 '15 at 08:37

3 Answers3

12

The undocumented function Internal`FromPiecewise seems to take a Piecewise function in the standard form returned by PiecewiseExpand and return a list consisting of a partition of the real numbers into intervals and a list of corresponding values.

try = {3 (1 - q), 2 (1 - q) + q, 1 + 1.5 q};
Internal`FromPiecewise@ PiecewiseExpand@ Min[try]
(*  {{0.4 <= q < 1/2, q >= 1/2, q < 0.4}, {2 - q, -3 (-1 + q), 1 + 1.5 q}}  *)

Since each break point occurs one at an equality (i.e. <= or >=), we can extract them and solve. The function ineqToEq converts an inequality like those above to an equality or to False (which signifies no end point).

ineqToEq[ie_] := Replace[
  LogicalExpand@ ie /. Less | Greater -> (True &),
   {(GreaterEqual | LessEqual)[a_, b_] :> a == b, True -> False}
  ]

Applied to the OP's example:

Or @@ ineqToEq /@ First@ Internal`FromPiecewise@ PiecewiseExpand@ Min[try] // Solve
(*  {{q -> 0.4}, {q -> 1/2}}  *)

This following passes Patrick Stevens's clever D test, but this method finds the break point:

f = Piecewise[{{q^3, q < 0}}, q^2];
Or @@ ineqToEq /@ First@ Internal`FromPiecewise@ PiecewiseExpand@ f // Solve
(*  {{q -> 0}}  *)

Another internal alternative

There are many functions in Mathematica that process the discontinuities of a piecewise function. You would think there would be an easy way to do it, but there doesn't seem to be one. Well, here's a different function, again internal, undocumented, and subject to change, which is used by NIntegrate. One advantage is that it handles Min with the user first converting it to a Piecewise function.

Here's how it works on the OP's function:

NIntegrate`PiecewiseNIntegrateMultipleRanges[
 Min[try], {{q, -Infinity, Infinity}}, {(* options *)}, {(* piecewise options *)}]
(*  {{2 - q, {q, 2/5, 1/2}}, {-3 (-1 + q), {q, 1/2, ∞}}, {1/2 (2 + 3 q), {q, -∞, 2/5}}} *)

General function and example:

pwBreaks[f_, x_] := 
 DeleteCases[Infinity | -Infinity]@*Union @@ 
  NIntegrate`PiecewiseNIntegrateMultipleRanges[
    f, {{x, -Infinity, Infinity}}, {}, {}][[All, 2, 2 ;; 3]]

pwBreaks[Min[try], q]
(*  {2/5, 1/2}  *)
Michael E2
  • 235,386
  • 17
  • 334
  • 747
8

I have a kind of cheating way, which assumes that the function is differentiable except at the join-points and is not differentiable at the join-points:

Reduce[Not@Reduce[D[Min[try], q] \[Element] Reals, q], q] // ToRules // List

This works for your specified "linear functions" scenario; with your given function, it returns {{q -> 2/5}, {q -> 1/2}}.

Patrick Stevens
  • 6,107
  • 1
  • 16
  • 42
5
try = {3 (1 - q), 2 (1 - q) + q, 1 + 1.5 q} // Rationalize;

breaks = Cases[
   Last /@ (Min[try] // PiecewiseExpand)[[1]], _?NumericQ, {2}] // 
  Union

{2/5, 1/2}

Bob Hanlon
  • 157,611
  • 7
  • 77
  • 198