Skip to content

Commit 2b3a3df

Browse files
committed
transpose degree n matrices
1 parent a733d6a commit 2b3a3df

File tree

1 file changed

+100
-10
lines changed

1 file changed

+100
-10
lines changed

lib/Value/Matrix.pm

Lines changed: 100 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -837,29 +837,119 @@ sub twiddle {
837837
return $self->make(@coords);
838838
}
839839

840+
=head3 C<slice>
841+
842+
Produce the degree (n-1) Matrix defined by a given index and value for that index. If n is 1,
843+
this produces a Real/Complex/Fraction.
844+
845+
Usage:
846+
847+
$A = Matrix([ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]);
848+
$A->slice(1, 2) # will be same as Matrix([5, 6, 7, 8])
849+
$A->slice(2, 3) # will be same as Matrix([3, 7, 11])
850+
851+
$B = Matrix([ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ]);
852+
$B->slice(1, 2) # will be same as Matrix([ [ 5, 6 ], [ 7, 8 ] ])
853+
$B->slice(2, 1) # will be same as Matrix([ [ 1, 2 ], [ 5, 6 ] ])
854+
$B->slice(3, 1) # will be same as Matrix([ [ 1, 3 ], [ 5, 7 ] ])
855+
856+
=cut
857+
858+
sub slice {
859+
my $self = shift;
860+
my ($index, $value) = @_;
861+
my @d = $self->dimensions;
862+
my $d = scalar(@d);
863+
my $w = $d[0];
864+
Value::Error("index must be an integer from 1 to $d") unless ($index == int($index) && $index >= 1 && $index <= $d);
865+
my $M = $self->data;
866+
if ($index == 1) {
867+
Value::Error("value must be an integer from 1 to $w")
868+
unless ($value == int($value) && $value >= 1 && $value <= $w);
869+
return $M->[ $value - 1 ];
870+
return $self->make($M->[ $value - 1 ]);
871+
} else {
872+
my @rows;
873+
for (1 .. $w) {
874+
push @rows, $M->[ $_ - 1 ]->slice($index - 1, $value);
875+
}
876+
return $self->make(@rows);
877+
}
878+
}
879+
840880
=head3 C<transpose>
841881
842-
Take the transpose of a matrix.
882+
Take the transpose of a matrix. For a degree 1 Matrix, first promote to a degree 2 Matrix.
883+
For a degree n Matrix, apply a permutation of the indices. The default permutation transposes the
884+
last two indices. To specify a permutation, provide an array reference representing a cycle
885+
or an array of array references that represents a product of cycles. If a permutation is not
886+
specified, the default is the usual transposition of the last two indices.
843887
844888
Usage:
845889
846890
$A = Matrix([ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]);
847-
$A->transpose;
891+
$A->transpose # will be [ [ 1, 5, 9 ], [ 2, 6, 10 ], [ 3, 7, 11 ], [ 4, 8, 12 ] ]
848892
893+
$B = Matrix([ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ]);
894+
$B->transpose([1, 2, 3]) # will be [ [ [ 1, 3 ], [ 5, 7 ] ], [ [2 , 4 ], [ 6, 8 ] ] ]
895+
896+
$C = Matrix([ [ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ], [ [ [ 9, A ], [ B, C ] ], [ [ D, E ], [ F, 0 ] ] ] ]);
897+
$C->transpose([ [ 1, 2], [3, 4] ]) # will be [ [ [ [ 1, 3 ], [ 2, 4 ] ], [ [ 9, B ], [ A, C ] ] ], [ [ [ 5, 7 ], [ 6, 8 ] ], [ [ D, F ], [ E, 0 ] ] ]
849898
=cut
850899

851900
sub transpose {
852-
my $self = promote(@_);
901+
my $self = shift;
902+
my $p = shift;
853903
my @d = $self->dimensions;
854-
if (scalar(@d) == 1) { @d = (1, @d); $self = $self->make($self) }
855-
Value::Error("Can't transpose %d-dimensional matrices", scalar(@d)) unless scalar(@d) == 2;
904+
my $N = scalar(@d);
905+
906+
# elevate a degree 1 Matrix to degree 2
907+
if ($N == 1) { @d = (1, @d); $N = 2; $self = $self->make($self) }
908+
909+
# default to transpose last two indices
910+
$p = [ [ $N - 1, $N ] ] unless $p;
911+
912+
# build the permutation hash from cycles
913+
my %p;
914+
if (ref $p eq 'HASH') {
915+
%p = %{$p};
916+
} else {
917+
$p = [$p] unless ref($p->[0]);
918+
my @p = (1 .. $N);
919+
for my $cycle (@{$p}) {
920+
next unless defined $cycle->[0];
921+
my $tmp = $p[ $cycle->[0] - 1 ];
922+
for my $i (0 .. $#{$cycle} - 1) {
923+
$p[ $cycle->[$i] - 1 ] = $p[ $cycle->[ $i + 1 ] - 1 ];
924+
}
925+
$p[ $cycle->[ $#{$cycle} ] - 1 ] = $tmp;
926+
}
927+
%p = map { $_ => $p[ $_ - 1 ] } (1 .. $N);
928+
}
929+
%p = reverse %p;
856930

857931
my @M = ();
858-
my $M = $self->data;
859-
for my $j (0 .. $d[1] - 1) {
860-
my @row = ();
861-
for my $i (0 .. $d[0] - 1) { push(@row, $M->[$i]->data->[$j]) }
862-
push(@M, $self->make(@row));
932+
if ($N == 2) {
933+
return $self if ($p{1} == 1);
934+
my $M = $self->data;
935+
for my $j (0 .. $d[1] - 1) {
936+
my @row = ();
937+
for my $i (0 .. $d[0] - 1) { push(@row, $M->[$i]->data->[$j]) }
938+
push(@M, $self->make(@row));
939+
}
940+
} else {
941+
# reduce the permutation hash
942+
my @q = map { $p{$_} } (1 .. $N);
943+
my $p1 = shift @q;
944+
for (@q) {
945+
$_-- if ($_ >= $p1);
946+
}
947+
my %q = map { $_ => $q[ $_ - 1 ] } (1 .. $N - 1);
948+
949+
for my $j (1 .. $d[ $p1 - 1 ]) {
950+
my $slice = $self->slice($p1, $j);
951+
push(@M, $slice->class eq 'Matrix' ? $slice->transpose(\%q) : $slice);
952+
}
863953
}
864954
return $self->make(@M);
865955
}

0 commit comments

Comments
 (0)