my $A = [ [ 1, 2 ],
[ 3, 4 ] ]; # matrix A
my $B = [ [ 5, 6 ],
[ 7, 8 ] ]; # matrix B
my $mats = [ $A, $B ]; # array of matrices
####
# [ [ f(1,5), f(2,6) ],
# [ f(3,7), f(4,8) ] ]
##
##
# c=0 c=1
# ________
# Matrix A (m=0) / / /
# r=0 / 1 / 2 /.
# /___/___/ .
# / / / .
# r=1 / 3 / 4 / .
# /___/___/ .
# .
# ________
# Matrix B (m=1) / / /
# r=0 / 5 / 6 /
# /___/___/
# / / /
# r=1 / 7 / 8 /
# /___/___/
#
# c=0 c=1
##
##
my $result;
for my $r (0 .. @{$mats->[0]} - 1) {
for my $c (0 .. @{$mats->[0][0]} - 1) {
$result->[$r][$c] = f( map $_->[$r][$c], @$mats );
}
}
##
##
use Data::Dumper;
sub f {
"f(" . join(", ", map dumpf($_), @_) . ")";
}
sub dumpf {
local $Data::Dumper::Indent = 0;
local $Data::Dumper::Terse = 1;
local $_ = Dumper(@_);
tr/\'//d;
$_;
}
##
##
print dumpf($result), $/;
# [ [f(1,5), f(2,6)],
# [f(3,7), f(4,8)] ]
##
##
sub mapat {
my $depth = shift;
my $f = shift;
$depth
? map [ map mapat($depth-1, $f, $_), @$_ ], @_
: $f->(@_);
}
##
##
for (0..3) {
print "mapat $_ f: ",
dumpf(mapat($_, \&f, $mats)), $/;
}
# mapat 0 f: f([[[1,2],[3,4]],[[5,6],[7,8]]])
# mapat 1 f: [f([[1,2],[3,4]]),f([[5,6],[7,8]])]
# mapat 2 f: [[f([1,2]),f([3,4])],[f([5,6]),f([7,8])]]
# mapat 3 f: [[[f(1),f(2)],[f(3),f(4)]],[[f(5),f(6)],[f(7),f(8)]]]
##
##
# Dimensions
#
# (r,c) <=== transpose ===> (c,r)
#
# Data
#
# [ [ 1, 2 ], [ [ 1, 3, 5 ],
# [ 3, 4 ], <=== transpose ===> [ 2, 4, 6 ] ]
# [ 5, 6 ] ]
#
##
##
sub zip {
my $len = min( map scalar @$_, @_ );
map [ do { my $i=$_; map $_->[$i], @_ } ], 0..$len-1;
}
sub transpose {
map [ zip(@$_) ], @_;
}
##
##
# 0 1 2 0 1 2
# (m,r,c) -> (r,m,c) # via transpose(...)
#
# ([[[1,2],[3,4]],[[5,6],[7,8]]]
# -> [[[1,2],[5,6]],[[3,4],[7,8]]]
##
##
# 0 1 2 0 1 2
# (r,m,c) -> (r,c,m) # via mapat(1, \&transpose, ...)
#
# [[[1,2],[5,6]],[[3,4],[7,8]]]
# -> [[[1,5],[2,6]],[[3,7],[4,8]]]
##
##
mapat(2, \&f, [[[1,5],[2,6]],[[3,7],[4,8]]]);
# [[f([1,5]),f([2,6])],[f([3,7]),f([4,8])]]
##
##
sub matrixwise_map(&@) {
my $f = shift;
# force array context since we're always dealing w/ matricies
( mapat( 2, $f, mapat(1, \&transpose, transpose(@_)) ) )[0];
}
##
##
$result = matrixwise_map(\&f, $mats);
print dumpf($result), $/;
# [[f([1,5]),f([2,6])],[f([3,7]),f([4,8])]]
##
##
use List::Util qw( sum );
sub mean { sum(@_) / @_ }
print dumpf( matrixwise_map {mean(@$_)} $mats ), $/;
# [[3,4],[5,6]]