Reputation: 23
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
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
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
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