# 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 '15 at 7:58
• @ciao. General and lapidary manipulation of that result would suffice. – garej Aug 9 '15 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 '15 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? – garej Aug 9 '15 at 8:19
• In example, one needs to transform @ciao result into something like {q -> 1/2, q -> 2/5} – garej Aug 9 '15 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. – garej Aug 9 '15 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[]… :) – J. M.'s torpor Aug 14 '15 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? – Michael E2 Aug 14 '15 at 16:01
• None offhand; a function that converts inequalities to a standard form (e.g. entirely in terms of </<=) would be very handy. – J. M.'s torpor Aug 14 '15 at 16:07
• Now, that, I haven't tried using. Nice find! – J. M.'s torpor Aug 14 '15 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. – garej Aug 9 '15 at 14:18
• Sorry, I have to break the rule and say very impressive! – Jack LaVigne Aug 16 '15 at 0:31