17
$\begingroup$

I have the impression that these functions have different evaluation rules. I cannot produce a minimal example right now, but in general, what are the differences between these functions? That is, besides the obvious difference in the calling interface. I am interested in knowing when and how these functions will exhibit different behavior.

For example, it is recommended to use Piecewise if the expression will be used inside Integrate. Why? Naively I'd expect that Piecewise[{{val1,cond1},{val2,cond2}...}], Which[cond1,val1,cond2,val2,...] and If[cond1,val1, If[cond2,val2,...]] be all equivalent, but there are subtle differences that I wish to understand.

$\endgroup$
1

2 Answers 2

25
$\begingroup$

The main difference is their intended use.

Which is a "programming function". It is meant for flow control. It is an equivalent of if ... elseif ... elseif ... end in procedural languages.

Piecewise is a "mathematical function". It is meant for a symbolic representation of piecewise functions.

This distinction is not perfect—in Mathematica it never is—but any differences you might find are along these lines.

Think of Which as "do something when a condition holds". If no condition holds, do nothing. Piecewise doesn't do something, it evaluates to a value. This is the only thing that makes sense in a math (not programming) context. Therefore Piecewise has a numerical default value.

Similarly, Which holds its arguments unevaluated. You can safely write Which[x > 0, Print@Sqrt[x]], and trust that Print won't be evaluated until the condition is true. This is what one would expect from a control flow statement.

Piecewise immediately evaluates all of its arguments (regardless of whether their condition is true). It is expected to contain only mathematical expressions, not things like Print that have side effects when evaluated. Its conditions are also expected to be disjoint (though this is not enforced). Symbolic processing functions will always return Piecewise, never Which.


But you are right that in many cases they are interchangeable. For example, this works, even though it is clearly a mathematical use:

D[
 Which[x < 0, Sqrt[-x], True, Sqrt[x]],
 x
 ]
(* Which[x < 0, -(1/(2 Sqrt[-x])), True, 1/(2 Sqrt[x])] *)

Piecewise is compilable (which I'd expect this from a programming function, not a symbolic math one).

$\endgroup$
7
  • $\begingroup$ Can we understand all the differences between Piecewise and Which, just from the fact that one evaluates its arguments and the other doesn't? $\endgroup$
    – a06e
    Commented Nov 27, 2017 at 10:00
  • 1
    $\begingroup$ @becko I didn't attempt to meticulously discover all specific differences. But the intended use is clear. So if you were instead asking: "which should I use?", I would suggest deciding based on what I described above. $\endgroup$
    – Szabolcs
    Commented Nov 27, 2017 at 10:08
  • 3
    $\begingroup$ @becko Note that it isn't even sufficient to look at how each evaluates. You'd also need to look at how other functions (like D above) handle them. That makes listing all differences an impossibly difficult task. Does Simplify, Refine, etc. handle Which? I'm sure there will be some functions which only handle Piecewise and not Which. You'd have to go through all symbolic functions ... $\endgroup$
    – Szabolcs
    Commented Nov 27, 2017 at 10:10
  • 2
    $\begingroup$ I see the difficulty. This is the thing I dislike the most about Mathematica. You cannot summarize its syntax in a few simple rules. Other languages prioritize simplicity, so that understanding the rules and predicting execution behavior is relatively easy. But Mathematica instead prioritizes having these all powerful functions, which are very handy most of the time, but when you try to understand how they work, or when something does not execute like you thought it would, it's a pain. $\endgroup$
    – a06e
    Commented Nov 27, 2017 at 11:16
  • 3
    $\begingroup$ @becko: Mathematica is not a programming language in the usual sense. It is an expression rewriting system. Some rewrite rules behave like programming constructs, so using If is like programming. However, in symbolic analysis, If is too undisciplined to be deconstructed abstractly. Piecewise has the necessary discipline for symbolic analysis, so the rewrite rules behind things like Integrate can manage to rewrite it without evaluating it. If needs to be evaluated before symbolic rules can safely rewrite it. $\endgroup$
    – John Doty
    Commented May 20, 2018 at 16:25
5
$\begingroup$

As @Szabolcs perfectly explained, Which and If are "programming functions", but Piecewise is a "mathematical function". I would just like to add another example that I believe clarifies this:

Let us say that we want to code the function that outputs 0 for any negative input, and the input itself (i.e. the identity function) for any non-negative input. See below:

enter image description here

We are interested in computing the derivative of this function.

The derivative of this function is not defined at zero, since the limits are different depending on whether you come from above or below. Now see the following:

BePositiveIf[x_] := If[x < 0, 0, x]
D[BePositiveIf[x], x]
% /. {x -> 0}

This outputs If[x < 0, 0, 1] and then 1.

The same occurs with Which:

BePositiveWhich[x_] := Which[x < 0, 0, True, x]
D[BePositiveWhich[x], x]
% /. {x -> 0}

However, if you code it with Piecewise...

BePositivePW[x_] := Piecewise[{{0, x < 0}, {x, x >= 0}}]
D[BePositivePW[x], x]
% /. {x -> 0} 

The result is another piecewise function which evaluates to Indeterminate at x = 0:

Piecewise[{{0, x < 0}, {1, x > 0}}, Indeterminate]

Hope this helps to clarify the issue.

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.