James Ma
James Ma

Reputation: 23

Max function for complex matrix in Mathematica

I want to compare matrices with element by element and find the maximum values of the matrices, like I have three 3x3 matrices

tdata = {{{1, 5, 1}, {7, 4, 2}, {2, 4, 3}}, {{2, 0, 8}, {9, 8, 2}, {2,
 3, 0}}, {{2, 2, 9}, {10, 9, 5}, {9, 3, 3}}}

Then by using

MapThread[Max, tdata, 2] // MatrixForm

I can get the correct result.

{{2, 5, 9}, {10, 9, 5}, {9, 4, 3}}

However, when the matrices are complex matrices, Max function doesn't work. For example,

tdata = {{{0.323031 + 5.23687 I, 8.92856 + 1.31365 I},
{9.94387 + 3.04104 I, 8.72483 + 2.5648 I}},
{{5.96575 + 9.2521 I,  8.58461 + 2.56753 I},
{0.902715 + 3.75791 I, 4.06809 + 8.61552 I}},
{{9.36592 + 1.17263 I, 9.74628 + 2.22183 I},
{4.61866 + 4.61158 I, 9.0791 + 2.50036 I}}}

I have tried to implement a new Max function for complex matrices, but it doesn't work. Here is a demo,

complexMax[lis_] := Module[{abs = Abs[lis]}, Take[lis, Position[abs, Max[abs]][[1]]]]

Then

MapThread[complexMax, tdata, 2]

The result is like

{{complexMax[0.323031 + 5.23687 I, 5.96575 + 9.2521 I, 9.36592 + 1.17263 I], 
 complexMax[8.92856 + 1.31365 I, 8.58461 + 2.56753 I, 9.74628 + 2.22183 I]}, 
{complexMax[9.94387 + 3.04104 I, 0.902715 + 3.75791 I, 4.61866 + 4.61158 I], 
 complexMax[8.72483 + 2.5648 I, 4.06809 + 8.61552 I, 9.0791 + 2.50036 I]}}

Is there any idea how to solve the problem?

Upvotes: 2

Views: 572

Answers (3)

Mr.Wizard
Mr.Wizard

Reputation: 24336

There is a dedicated StackExchange site for Mathematica now: https://mathematica.stackexchange.com/ -- please ask your future questions there.


As already explained by latkin your max function needs to accept multiple arguments if it is to be used as shown in MapThread. You can write the function to handle both forms by using a second pattern, e.g. cMax[ns__] := cMax[{ns}].

Faster than Position is Ordering.

cMax[ns__] := cMax[{ns}]

cMax[lis_List] := lis ~Extract~ Ordering[Abs[lis], -1]

Now:

MapThread[cMax, tdata, 2]
{{5.96575 + 9.2521 I, 9.74628 + 2.22183 I},
 {9.94387 + 3.04104 I, 4.06809 + 8.61552 I}}

However, when working with packed data it will be faster not to use MapThread, which results in unpacking but rather to keep the numbers in lists by using Transpose:

Map[cMax, Transpose[tdata, {3, 1, 2}], {2}]
{{5.96575 + 9.2521 I, 9.74628 + 2.22183 I},
 {9.94387 + 3.04104 I, 4.06809 + 8.61552 I}}

Timings:

cd = RandomComplex[9 + 9 I, {15000, 7, 7}];

MapThread[Last@SortBy[{##}, Abs] &, cd, 2] // Timing // First

MapThread[cMax, cd, 2]                     // Timing // First

Map[cMax, Transpose[cd, {3, 1, 2}], {2}]   // Timing // First

0.562

0.483

0.0156

Upvotes: 1

latkin
latkin

Reputation: 16792

The problem with your current code is that using MapThread results in complexMax being called not with a single argument that is a list (i.e. complexMax[{elem1, elem2, elem3...}]), but with multiple arguments (i.e. complexMax[elem1, elem2, elem3]).

You can correct for this by declaring the argument not as a single expression (lis_ w/ single underscore) but as a sequence of expressions: lis__ with double underscore.

Making this correction leads to another issue, though - Abs expects a list as input, as does Take. So you need to wrap lis in brackets in a couple places.

Lastly, looks like you need one additional [[1]] at the end.

complexMax[lis__] := Module[{abs = Abs[{lis}]},
  Take[{lis}, Position[abs, Max[abs]][[1]]][[1]]] 

MapThread[complexMax, tdata, 2]

Result

{{5.96575 + 9.2521 I, 9.74628 + 2.22183 I}, {9.94387 + 3.04104 I, 
  4.06809 + 8.61552 I}}

Upvotes: 2

agentp
agentp

Reputation: 6989

I think this is what you want:

MapThread[Last@SortBy[{##}, Abs] &, tdata, 2] // MatrixForm

(* {{5.96575 + 9.2521 I, 9.74628 + 2.22183 I}, {9.94387 + 3.04104 I, 4.06809 + 8.61552 I}} *)

FWIW this sorts complex numbers by cannonical order, ( real part first )

MapThread[Last@Sort[{##}] &, tdata, 2] // MatrixForm

(* {{9.36592 + 1.17263 I, 9.74628 + 2.22183 I}, {9.94387 + 3.04104 I, 9.0791 + 2.50036 I}} *)

Note your approach works as well if you do this:

 MapThread[complexMax[{##}] &, tdata, 2]

The trick is the argument passed by Mapthread to your function is a sequence, not a list.

Upvotes: 2

Related Questions