Skip to content

Commit c9a6152

Browse files
committed
transpose degree n matrices
1 parent 9093018 commit c9a6152

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
@@ -836,29 +836,119 @@ sub twiddle {
836836
return $self->make(@coords);
837837
}
838838

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

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

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

0 commit comments

Comments
 (0)