# When are If, Piecewise, Switch, and Which interchangeable and when are they not?

Experimenting with joint dependent distributions via the TransformedDistribution function, I used the following to derive a distribution where the second variate is distributed dependent on the value of the first variate (very simplified & contrived example follows).

distA = TransformedDistribution[{b,
If[b == 1, d1, d2]}, {b \[Distributed]
DiscreteUniformDistribution[{1, 2}],
d1 \[Distributed] UniformDistribution[{1, 2}],
d2 \[Distributed] UniformDistribution[{2, 3}]}]

distB = TransformedDistribution[{b,
Piecewise[{{d1, b == 1}, {d2, b == 2}}]}, {b \[Distributed]
DiscreteUniformDistribution[{1, 2}],
d1 \[Distributed] UniformDistribution[{1, 2}],
d2 \[Distributed] UniformDistribution[{2, 3}]}]

distC = TransformedDistribution[{b,
Switch[b, 1, d1, 2, d2]}, {b \[Distributed]
DiscreteUniformDistribution[{1, 2}],
d1 \[Distributed] UniformDistribution[{1, 2}],
d2 \[Distributed] UniformDistribution[{2, 3}]}]

distD = TransformedDistribution[{b,
Which[b == 1, d1, b == 2, d2]}, {b \[Distributed]
DiscreteUniformDistribution[{1, 2}],
d1 \[Distributed] UniformDistribution[{1, 2}],
d2 \[Distributed] UniformDistribution[{2, 3}]}]


The first two behave as I'd expect: Mean, Var, RandomVariate all do what they're supposed to. The latter two, while behaving as expected for the simple probability functions (e.g. Mean), puke on any attempt to sample with RandomVariate, with the message

TransformedDistribution::nnbprm: The valid numeric parameters of distribution TransformedDistribution[{\FormalX]1,Switch[\FormalX]1,1,\FormalX]2,2,\FormalX]3]},\FormalX]1,\FormalX]2,\FormalX]3}\Distributed]ProductDistribution[DiscreteUniformDistribution[{1,2}],UniformDistribution[{1,2}],UniformDistribution[{2,3}]]] are expected. Use DistributionParameterAssumptions to obtain the parameter assumptions. >>

I'm a bit puzzled by this, seems the forms in this case should result in equivalent behavior. Any insights?

• Your use of If, Switch etc. are not equivalent to begin with. For example, try Switch[b, 1, d1, _, d2] if you want something almost equivalent to your If. (It is equivalent on numeric b). Jan 26, 2014 at 0:38
• @MichaelE2: Not sure I understand you. Since b can only take values 1 or 2, they are logically precisely equivalent.
– ciao
Jan 26, 2014 at 1:42
• I think what @MichaelE2 means is that Switch and Which should (could) be setup to return a result at all times. In addition to the use of Blank[] in Switch you could try Which[test1, ...,test2, ..., True, output if all tests fail] Jan 26, 2014 at 3:34
• @MikeHoneychurch:Yes, I'm aware of the optional use of a fall-through pattern. Nonetheless, such a pattern is unneeded when the test value can only assume "valid" values. In the example with switch, it is always falling through, and that's what I'd like clarification on: it's as if switch and which never see the evaluated form of the test value.
– ciao
Jan 26, 2014 at 3:42
• I guess I mean that it seems Mathematica does not analyze the distributions, so you might have to use code that is equivalent or close enough, if you wish to use different conditional constructs. Perhaps the problem is related to this: Simplify[ Switch[b, 1, d1, 2, d2] == If[b == 1, d1, d2], b == 1 || b == 2 ] does not return True. (It does return True under the assumption b == 1, or b == 2, but not their disjunction.) Jan 26, 2014 at 5:17

I agree, all the forms should result in the same behaviour. That the Switch/Which forms fail for RandomVariate I regard as a bug.

The whole point of If,Which and Switch possessing this dual nature of being both control-flow conditionals and potentially functions is that they can be treated like the latter in cases like this. In other words, the purpose of these constructs remaining unevaluated (when not falling through to a default value) is that they can then assume functional status ready for subsequent symbolic manipulation.

What I suspect is happening here is that RandomVariate/TransformedDistribution's error-handling has been over-aggressive in rejecting a Which/Switch as not being "valid numeric parameters". After all they were happy enough to accept If as a function in this way while Mean and Variance were happy enough to accept Which/Switch as "functions".

One (hacky?) way around situations like this is to hit the conditioned expression with PiecewiseExpand.

distD = TransformedDistribution[{b,
Which[b == 1, d1, b == 2, d2] //
PiecewiseExpand}, {b \[Distributed]
DiscreteUniformDistribution[{1, 2}],
d1 \[Distributed] UniformDistribution[{1, 2}],
d2 \[Distributed] UniformDistribution[{2, 3}]}];

Through[{Mean, Variance, RandomVariate}[distD]]

(* {{3/2, 2}, {1/4, 1/3}, {2, 2.03136}} *)


PiecewiseExpand does two things when applied to these imperative conditionals: 1) it converts it into a Piecewise expression that downstream functions at least recognise as a function 2) It applies a range of simplifications including logical ones on its conditions.

It is tempting therefore to view PiecewiseExpand as an all-purpose tool for instilling robustness as in this example but this is a less than ideal assumption and usage IMO (although the best we have ATM). PiecewiseExpand by name and nature has as its prime function performing simplifications on a Piecewise function most obviously (but not exclusively) on the logic in the conditional expressions.

Its role on the control-flow conditionals however, includes, in addition, converting it into a Piecewise function which may or may not require also hitting it with a rich and extensive set of (logical) transformations. In other words, sometimes we may only want a "ToPiecewise" type of action instead of a following, more expensive PiecewiseExpand action. In fact, this example is one such case. The fact that it succeeds is not due to any logical deduction that the value of b is restricted to either 1 or 2 somehow making Switch and Which's conditions precisely exhaust but rather, it succeeds because of a conversion into a Piecewise function from which such a deduction happens automatically when hit by subsequent functions.

For example restricting b to 1 by specifying DiscreteUniformDistribution[{1, 1}]

TransformedDistribution[{b, Switch[b, 1, d1, 2, d2]} //
PiecewiseExpand, {b \[Distributed]
DiscreteUniformDistribution[{1, 1}],
d1 \[Distributed] UniformDistribution[{1, 2}],
d2 \[Distributed] UniformDistribution[{2, 3}]}]


does not entail the expression immediately collapsing to

Hence in relation to the comments the failure is not due to not having default values in Which/Switch (this absence is necessary for both constructs to not evaluate in order to be construed as functions) nor is it due to the output of

Simplify[Switch[b, 1, d1, 2, d2] == If[b == 1, d1, d2],  b == 1 || b == 2]


not returning True (although perhaps this should given Simplify's mandate, again alluding to the WL unfortunately not automatically recognising these conditionals as functions).

This previous test does however, give us an opportunity to see where PiecewiseExpand's logical simplifications can produce this type of logical deduction.

PiecewiseExpand[Switch[b, 1, d1, 2, d2] == If[b == 1, d1, d2],
b == 1 || b == 2]

(* True *)

• Nice analysis of a question I'd forgotten. +1 and the check.
– ciao
Oct 9, 2021 at 22:08
• Thanks. Always wonder about long-standing questions emerging from a different epoch and whether or inputs/outputs are sufficiently similar to afford a meaningful answer. I found the question helpful in the hunt for some good examples to sharpen-up a recent question. Oct 9, 2021 at 23:38