# Elegantly split a matrix into positive and negative parts?

I have a matrix $M$ of real components, and I want to split it into two matrices $M^+$ and $M^-$ of the same dimensions as $M$, where $M^+$ contains the positive components of $M$ (the remaining entries being filled with zeros), and $M^-$ contains the negative components, such that $M=M^+ + M^-$.

Suppose the matrices are represented in the usual way in Mathematica (as lists of lists, or as sparse arrays)

How can I do this efficiently and elegantly in Mathematica?

Clip is usually quite fast:

m = RandomReal[{-10^6, 10^6}, {3, 3}];

neg = Clip[m, {-Infinity, 0}]
pos = Clip[m, {0, Infinity}]

(*{{0., -181286., -442666.}, {0., -233694., -847828.}, {-128249., 0., -540037.}}

{{947792., 0., 0.}, {755278., 0., 0.}, {0., 63058.1, 0.}}*)

neg + pos == m


True

• You might even save a few characters with things like pos=m-neg... Dec 19, 2013 at 22:33
• This is MUCH faster than mine! Dec 20, 2013 at 0:58
• I bet you didn't think this would be one of your most popular answers ever. +1 :-) Dec 20, 2013 at 17:34
• @Mr.Wizard Innuendo :D Only what that says about my average contribution, I dare not dwell upon. I was also waiting for you to steal my thunder... Dec 20, 2013 at 18:20
• @Yves What it says is that your average contribution is more esoteric than these little nuggets that have popular appeal and that the voting system provides no way to differentiate between "interesting" and "mindbogglingly amazing." Some of the answers I have put the most thought and effort into scored the lowest, while something minor dropped in passing scores highly. Occasionally something that took a lot of thought is apparently concise and general enough to be popular. Dec 21, 2013 at 4:54

You could also use the functions Positive and Negative:

m = RandomInteger[{-10, 10}, {10, 10}];
pos = m Boole[Positive[m]];
neg = m Boole[Negative[m]];


give the positive and negative portions. As becko points out, replacing Boole[Positive[mat]] with UnitStep[m]:

pos = m UnitStep[m];
neg = m UnitStep[-m];


is even more succinct. These can even be combined into one line (as suggested by Mechanical Snail:

{pos, neg} = m*UnitStep[#] & /@ {m, -m}

• +1 Instead of Boole[Positive[mat]], you can also use UnitStep[mat], and instead of Boole[Negative[mat]], you can also use UnitStep[-mat]... No big improvement, just one function instead of two :) Dec 19, 2013 at 22:56
• Or in one line: {pos, neg} = m * UnitStep /@ {m, -m} Dec 20, 2013 at 23:07

This is yet another way:

mat = RandomInteger[{-10, 10}, {10, 10}];
matPair = Map[Sort[{#, 0}] &, mat, {2}] // Transpose[#, {2, 3, 1}] &;

Grid[# /. {
x_?NumericQ :> If[x < 0,
Item["", Background -> Darker[Red, .5]],
If[x > 0,
Item["", Background -> Darker[Green, .4]],
Item["", Background -> GrayLevel[.9]]]]
}, Frame -> True, ItemSize -> {.4, 1}] & /@
Prepend[matPair, mat] It can be seen like this: transpose the 3rd level i.e. the {negative, positive} level to be the 1st level, and leave other levels untouched (thus level-down in order).

• Darn - so blindingly obvious :D Dec 19, 2013 at 22:39
• Hey Silvia! Can you help me? cooking.stackexchange.com/q/40424/2882 Dec 19, 2013 at 22:45
• @belisarius man you should have asked before eating that! Dec 19, 2013 at 22:49
• @ChrisDegnen "the ideal mind boggling" ? :) Dec 20, 2013 at 0:16
• @ChrisDegnen It can be seen like this: transpose the 3rd level i.e. the {-,+} level to be the first level, and leave other levels untouched (thus level-down in order). Dec 20, 2013 at 0:39

Another one for fun.

Positive:

(m + Abs[m])/2


Negative:

(m - Abs[m])/2

• +1 Instead of Sqrt[m^2], you can also use Abs[m]. Dec 19, 2013 at 23:00
• my only quarrel with this solution is that you could run into numerical issues. Dec 19, 2013 at 23:03
• @becko That's better, thanks. Dec 19, 2013 at 23:10
• @YvesKlett The switch to Abs partly fixes this in that Abs will warn when it reaches the precision limit. Addition and division by two shouldn't be a problem, I think. Dec 19, 2013 at 23:11
• Also, Abs[-m] is the same as Abs[m]. Dec 20, 2013 at 16:15

An approach using UnitStep:

{pos, neg} = With[{u = UnitStep}, {# u@#, # u@-#}] &@mat


or with Positive and Negative:

{pos, neg} = {#, #} Boole@Through[{Positive, Negative}@#] &@mat

• Go obfuscious (^_-) Dec 19, 2013 at 22:47
• +1... Are you using With[{u = UnitStep}, ...] just to save characters? You're not helping the OP :( Dec 19, 2013 at 23:05
• @becko I would never use something like that to save characters... that's Mr.Wizard's modus operandi :) In fact, this takes more characters than just writing out UnitStep in both places. It must've been the wine... Also, why are you referring to yourself in the third person? o_O
– rm -rf
Dec 20, 2013 at 2:08

Here's a way...

mat = RandomInteger[{-10, 10}, {10, 10}];

{neg, pos} = {mat /. x_ /; x > 0 -> 0, mat /. x_ /; x < 0 -> 0};

neg+pos==mat


True

And here's another way using Map:

{neg, pos} = {Map[Min[#, 0] &, mat, {2}], Map[Max[#, 0] &, mat, {2}]}

• neg and pos is somehow universal :D Dec 19, 2013 at 22:19
• @YvesKlett, Oh, I like your Clip method...
– kale
Dec 19, 2013 at 22:20