@@ -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
844888Usage:
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
851900sub 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