@@ -848,29 +848,119 @@ sub twiddle {
848
848
return $self -> make(@coords );
849
849
}
850
850
851
+ =head3 C<slice >
852
+
853
+ Produce the degree (n-1) Matrix defined by a given index and value for that index. If n is 1,
854
+ this produces a Real/Complex/Fraction.
855
+
856
+ Usage:
857
+
858
+ $A = Matrix([ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]);
859
+ $A->slice(1, 2) # will be same as Matrix([5, 6, 7, 8])
860
+ $A->slice(2, 3) # will be same as Matrix([3, 7, 11])
861
+
862
+ $B = Matrix([ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ]);
863
+ $B->slice(1, 2) # will be same as Matrix([ [ 5, 6 ], [ 7, 8 ] ])
864
+ $B->slice(2, 1) # will be same as Matrix([ [ 1, 2 ], [ 5, 6 ] ])
865
+ $B->slice(3, 1) # will be same as Matrix([ [ 1, 3 ], [ 5, 7 ] ])
866
+
867
+ =cut
868
+
869
+ sub slice {
870
+ my $self = shift ;
871
+ my ($index , $value ) = @_ ;
872
+ my @d = $self -> dimensions;
873
+ my $d = scalar (@d );
874
+ my $w = $d [0];
875
+ Value::Error(" index must be an integer from 1 to $d " ) unless ($index == int ($index ) && $index >= 1 && $index <= $d );
876
+ my $M = $self -> data;
877
+ if ($index == 1) {
878
+ Value::Error(" value must be an integer from 1 to $w " )
879
+ unless ($value == int ($value ) && $value >= 1 && $value <= $w );
880
+ return $M -> [ $value - 1 ];
881
+ return $self -> make($M -> [ $value - 1 ]);
882
+ } else {
883
+ my @rows ;
884
+ for (1 .. $w ) {
885
+ push @rows , $M -> [ $_ - 1 ]-> slice($index - 1, $value );
886
+ }
887
+ return $self -> make(@rows );
888
+ }
889
+ }
890
+
851
891
=head3 C<transpose >
852
892
853
- Take the transpose of a matrix.
893
+ Take the transpose of a matrix. For a degree 1 Matrix, first promote to a degree 2 Matrix.
894
+ For a degree n Matrix, apply a permutation of the indices. The default permutation transposes the
895
+ last two indices. To specify a permutation, provide an array reference representing a cycle
896
+ or an array of array references that represents a product of cycles. If a permutation is not
897
+ specified, the default is the usual transposition of the last two indices.
854
898
855
899
Usage:
856
900
857
901
$A = Matrix([ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]);
858
- $A->transpose;
902
+ $A->transpose # will be [ [ 1, 5, 9 ], [ 2, 6, 10 ], [ 3, 7, 11 ], [ 4, 8, 12 ] ]
859
903
904
+ $B = Matrix([ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ]);
905
+ $B->transpose([1, 2, 3]) # will be [ [ [ 1, 3 ], [ 5, 7 ] ], [ [2 , 4 ], [ 6, 8 ] ] ]
906
+
907
+ $C = Matrix([ [ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ], [ [ [ 9, A ], [ B, C ] ], [ [ D, E ], [ F, 0 ] ] ] ]);
908
+ $C->transpose([ [ 1, 2], [3, 4] ]) # will be [ [ [ [ 1, 3 ], [ 2, 4 ] ], [ [ 9, B ], [ A, C ] ] ], [ [ [ 5, 7 ], [ 6, 8 ] ], [ [ D, F ], [ E, 0 ] ] ]
860
909
=cut
861
910
862
911
sub transpose {
863
- my $self = promote(@_ );
912
+ my $self = shift ;
913
+ my $p = shift ;
864
914
my @d = $self -> dimensions;
865
- if (scalar (@d ) == 1) { @d = (1, @d ); $self = $self -> make($self ) }
866
- Value::Error(" Can't transpose %d -dimensional matrices" , scalar (@d )) unless scalar (@d ) == 2;
915
+ my $N = scalar (@d );
916
+
917
+ # elevate a degree 1 Matrix to degree 2
918
+ if ($N == 1) { @d = (1, @d ); $N = 2; $self = $self -> make($self ) }
919
+
920
+ # default to transpose last two indices
921
+ $p = [ [ $N - 1, $N ] ] unless $p ;
922
+
923
+ # build the permutation hash from cycles
924
+ my %p ;
925
+ if (ref $p eq ' HASH' ) {
926
+ %p = %{$p };
927
+ } else {
928
+ $p = [$p ] unless ref ($p -> [0]);
929
+ my @p = (1 .. $N );
930
+ for my $cycle (@{$p }) {
931
+ next unless defined $cycle -> [0];
932
+ my $tmp = $p [ $cycle -> [0] - 1 ];
933
+ for my $i (0 .. $# {$cycle } - 1) {
934
+ $p [ $cycle -> [$i ] - 1 ] = $p [ $cycle -> [ $i + 1 ] - 1 ];
935
+ }
936
+ $p [ $cycle -> [ $# {$cycle } ] - 1 ] = $tmp ;
937
+ }
938
+ %p = map { $_ => $p [ $_ - 1 ] } (1 .. $N );
939
+ }
940
+ %p = reverse %p ;
867
941
868
942
my @M = ();
869
- my $M = $self -> data;
870
- for my $j (0 .. $d [1] - 1) {
871
- my @row = ();
872
- for my $i (0 .. $d [0] - 1) { push (@row , $M -> [$i ]-> data-> [$j ]) }
873
- push (@M , $self -> make(@row ));
943
+ if ($N == 2) {
944
+ return $self if ($p {1 } == 1);
945
+ my $M = $self -> data;
946
+ for my $j (0 .. $d [1] - 1) {
947
+ my @row = ();
948
+ for my $i (0 .. $d [0] - 1) { push (@row , $M -> [$i ]-> data-> [$j ]) }
949
+ push (@M , $self -> make(@row ));
950
+ }
951
+ } else {
952
+ # reduce the permutation hash
953
+ my @q = map { $p {$_ } } (1 .. $N );
954
+ my $p1 = shift @q ;
955
+ for (@q ) {
956
+ $_ -- if ($_ >= $p1 );
957
+ }
958
+ my %q = map { $_ => $q [ $_ - 1 ] } (1 .. $N - 1);
959
+
960
+ for my $j (1 .. $d [ $p1 - 1 ]) {
961
+ my $slice = $self -> slice($p1 , $j );
962
+ push (@M , $slice -> class eq ' Matrix' ? $slice -> transpose(\%q ) : $slice );
963
+ }
874
964
}
875
965
return $self -> make(@M );
876
966
}
0 commit comments