4
$\begingroup$

For later conversion into a programming language where if is the only conditional construct, I would like to convert a Piecewise into a nested If in Mathematica. For instance, how can I convert:

f = Piecewise[{{x^3, x < -1}, {-x^2, -1 <= x < 0}, {x, 0 <= x < 1}, {Sqrt[x], 1 <= x}}]

into

If[x < -1, x^3, If[-1 <= x < 0, -x^2, If[0 <= x < 1, x, If[1 <= x, Sqrt[x], 0]]]]

?

$\endgroup$
1

5 Answers 5

2
$\begingroup$

Note the structure of Piecewise. The first element is a list of {value, condition} pairs and the second element is the "default" value for when no other condition applies. If you view it as a list, here's how f looks:

f /. Piecewise -> List

{{{x^3, x < -1}, {-x^2, -1 <= x < 0}, {x, 0 <= x < 1}, {Sqrt[x], 1 <= x}}, 0}

First, here is a recursive function to nest each list at the third position of the previous list, stopping at the deepest list.

nestLists[lists_] := If[Length[lists] == 1, lists[[1]], {Sequence @@ lists[[1]], nestLists[Rest[lists]]}]

This lets us do this:

nestLists[Map[Reverse,f[[1]]]

yielding

{x < -1, x^3, {-1 <= x < 0, -x^2, {0 <= x < 1, x, {1 <= x, Sqrt[x]}}}}

We still need to insert the default value into the third position of the deepest list, then convert the Lists to Ifs.

pwti[pw_] := ReplaceAll[Insert[#, pw[[2]], ConstantArray[-1, Length[Flatten[#]]/2]] &[nestLists[Map[Reverse, pw[[1]]]]], List -> If]

Now the Piecewise can be directly converted thus:

pwti[f]

If[x < -1, x^3, If[-1 <= x < 0, -x^2, If[0 <= x < 1, x, If[1 <= x, Sqrt[x], 0]]]]

Note that this will probably be broken if any of the values or conditions contains a list...

$\endgroup$
1
  • $\begingroup$ Does anyone know a better way? $\endgroup$ Mar 6, 2015 at 1:56
1
$\begingroup$
ifs = Reverse /@ (f /. Piecewise -> List /. {{x__, v_}, e_} :> {x, Join[{e}, v]});
Hold @@ Quiet@(ifs //. {x___, {a__, b__}, {c__, d__}, e___} :> {x, {a, b, {c, d}}, e} /. List -> If)

(* Hold[If[x < -1, x^3, If[-1 <= x < 0, -x^2, If[0 <= x < 1, x, If[1 <= x, Sqrt[x], 0]]]]]*)
$\endgroup$
3
  • $\begingroup$ Try on my f3 case... $\endgroup$
    – ciao
    Mar 6, 2015 at 2:50
  • $\begingroup$ @rasher He's migrating the code, so no lists on the new platform either :)} $\endgroup$ Mar 6, 2015 at 2:58
  • $\begingroup$ Just joking. Or not :) $\endgroup$ Mar 6, 2015 at 2:58
1
$\begingroup$

My quick-n-dirty (meaning pretty untested on anything but simple cases):

toif = With[{if = If @@@ (Reverse /@ #[[1]]), l = #[[2]]}, 
    Nest[{Insert[#[[1]], if[[Length@#[[2]] + 1]], #[[2]]], 
        Append[#[[2]], -1]} &, {if[[1]], {-1}}, Length@if - 1] //
        Insert[#[[1]], l, #[[2]]] &] &;

Seems a bit more robust than your solution:

f1 = Piecewise[{{x^3, x < -1}, {-x^2, -1 <= x < 0}, {x, 
     0 <= x < 1}, {Sqrt[x], 1 <= x}}];

f2 = Piecewise[{{x*2, x[1] == 2}, {x*3, x[2] == 3}}];

f3 = Piecewise[{{2, x == {1, 2, 3}}, {{1, 2, 3}, x == {3, 2, 1}}, {x, 
     True}}];

Column[{toif[f1],pwti[f1]," ",
        toif[f2],pwti[f2]," ",
        toif[f3],pwti[f3]}]

(*

If[x<-1,x^3,If[-1<=x<0,-x^2,If[0<=x<1,x,If[1<=x,Sqrt[x],0]]]]
If[x<-1,x^3,If[-1<=x<0,-x^2,If[0<=x<1,x,If[1<=x,Sqrt[x],0]]]]

If[x[1]==2,2 x,If[x[2]==3,3 x,0]]
0

If[x=={1,2,3},2,If[x=={3,2,1},{1,2,3},x]]
x

*)

I'll ponder further when lounging later, gut tells me there's an elegant way to do this.

Much prettier:

toif2 = Fold[Insert[#2, #1, {-1}] &, Prepend[If @@@ Reverse /@ #[[1]], #[[2]]]] &;

toif2[f3]

(* If[x == {3, 2, 1}, {1, 2, 3}, If[x == {1, 2, 3}, 2, x]] *)

N.b.: this reorders terms, end result is the same. Completely untested - gotta go eat!

$\endgroup$
1
$\begingroup$
pwToIf = With[{fpw = Reverse@Transpose@Internal`FromPiecewise@#}, 
              Fold[If[## & @@ #2, #] &, fpw[[1, 2]], fpw[[2 ;;]]]] &;

Examples:

pw = Piecewise[{{x^3, x < -1}, {-x^2, -1 <= x < 0}, {x, 0 <= x < 1}, {Sqrt[x], 1 <= x}}];
pwToIf@pw
(* If[x < -1, x^3, If[-1 <= x < 0, -x^2, If[0 <= x < 1, x, If[1 <= x, Sqrt[x], 0]]]] *)

pw2 = Piecewise[{{x^3, x < -1}, {-x^2, -1 <= x < 0}, {x,  0 <= x < 1}, {Sqrt[x], 1 <= x}}, 100];
pwToIf@pw2
(* If[x < -1, x^3, If[-1 <= x < 0, -x^2, If[0 <= x < 1, x, If[1 <= x, Sqrt[x], 100]]]]*)

pw3 = Piecewise[{{2, x == {1, 2, 3}}, {{1, 2, 3}, x == {3, 2, 1}}, {x, True}}]; (* rasher's f3*)
pwToIf@pw3
(* If[x == {1, 2, 3}, 2, If[x == {3, 2, 1}, {1, 2, 3}, x]] *)
$\endgroup$
0
$\begingroup$
(Fold[{Sequence @@ (Reverse@#2), #1} &, f[[2]], Reverse@f[[1]]]) /.List -> If
(*If[x < -1, x^3,If[-1 <= x < 0, -x^2, If[0 <= x < 1, x, If[1 <= x, Sqrt[x], 0]]]]*)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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