@@ -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
843887Usage:
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
850899sub 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