How to efficiently get breakpoints of piecewise functions

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]


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?

• Is Min[try] // PiecewiseExpand (and manipulation of that result) what you're after?
– ciao
Aug 9, 2015 at 7:58
• @ciao. General and lapidary manipulation of that result would suffice. Aug 9, 2015 at 8:09
• 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 9, 2015 at 8: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? Aug 9, 2015 at 8:19
• In example, one needs to transform @ciao result into something like {q -> 1/2, q -> 2/5} Aug 9, 2015 at 8:37

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}}.

• Smart solution. Thank you. Aug 9, 2015 at 14:19

The undocumented function InternalFromPiecewise 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};
InternalFromPiecewise@ 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@ InternalFromPiecewise@ 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@ InternalFromPiecewise@ 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:

NIntegratePiecewiseNIntegrateMultipleRanges[
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 @@
NIntegratePiecewiseNIntegrateMultipleRanges[
f, {{x, -Infinity, Infinity}}, {}, {}][[All, 2, 2 ;; 3]]

pwBreaks[Min[try], q]
(*  {2/5, 1/2}  *)

• I was waiting for somebody to bring up FromPiecewise[]… :) Aug 14, 2015 at 15:37
• @J.M. Thanks. You'd think there would a common internal way to turn an inequality into an iterator {x, a, b} or return the end points -- I can't find one. Dealing with the multiplicity of forms of inequalities is irritating. Know of something? Aug 14, 2015 at 16:01
• None offhand; a function that converts inequalities to a standard form (e.g. entirely in terms of </<=) would be very handy. Aug 14, 2015 at 16:07
• Now, that, I haven't tried using. Nice find! Aug 14, 2015 at 16:56
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}

• Rule[q, #] & /@ breaks. Very nice, thank you. Aug 9, 2015 at 14:18
• Sorry, I have to break the rule and say very impressive! Aug 16, 2015 at 0:31