File Coverage

blib/lib/Math/MatrixReal/Ext1.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Math::MatrixReal::Ext1;
2              
3 1     1   688 use strict;
  1         3  
  1         32  
4 1     1   1387 use Math::MatrixReal;
  0            
  0            
5             use Carp;
6              
7             use base qw/Math::MatrixReal/;
8              
9             our $VERSION = '0.07';
10              
11             sub new_from_cols {
12             my $this = shift;
13             my $extra_args = ( @_ > 1 && ref($_[-1]) eq 'HASH' ) ? pop : {};
14             $extra_args->{_type} = 'column';
15              
16             return $this->_new_from_rows_or_cols(@_, $extra_args );
17             }
18             sub new_from_columns {
19             my $this = shift;
20             $this->new_from_cols(@_);
21             }
22             sub new_from_rows {
23             my $this = shift;
24             my $extra_args = ( @_ > 1 && ref($_[-1]) eq 'HASH' ) ? pop : {};
25             $extra_args->{_type} = 'row';
26              
27             return $this->_new_from_rows_or_cols(@_, $extra_args );
28             }
29              
30             sub _new_from_rows_or_cols {
31             my $proto = shift;
32             my $class = ref($proto) || $proto;
33             my $ref_to_vectors = shift;
34              
35             # these additional args are internal at the moment,
36             # but in the future the user could pass e.g. {pad=>1} to
37             # request padding
38             my $args = pop;
39             my $vector_type = $args->{_type};
40             die "Internal ".__PACKAGE__." error" unless $vector_type =~ /^(row|column)$/;
41              
42             # step back one frame because this private method is
43             # not how the user called it
44             my $caller_subname = (caller(1))[3];
45              
46             # note--this die() could be inconvenient if someone had something
47             # really fancy that knew how to be dereffed as an array
48             # (can you do that with a tied scalar?), but I'm not putting
49             # the rest of the world through an eval--they can just
50             # deref and pass a reference themselves. If that ever happens
51             # we can add an arg to skip this check
52             croak "$caller_subname: need a reference to an array of ${vector_type}s" unless ref($ref_to_vectors) eq 'ARRAY';
53             my @vectors = @{$ref_to_vectors};
54              
55             my $matrix;
56              
57             my $other_type = {row=>'column', column=>'row'}->{$vector_type};
58              
59             my %matrix_dim = (
60             $vector_type => scalar( @vectors ),
61             $other_type => 0, # we will correct this in a bit
62             );
63              
64             # row and column indices are one based
65             my $current_vector_count = 1;
66             foreach my $current_vector (@vectors) {
67             # dimension is one-based, so we're
68             # starting with one here and incrementing
69             # as we go. The other dimension is fixed (for now, until
70             # we add the 'pad' option), and gets set later
71             my $ref = ref( $current_vector ) ;
72              
73             if ( $ref eq '' ) {
74             # we hope this is a properly formatted Math::MatrixReal string,
75             # but if not we just let the Math::MatrixReal die() do it's
76             # thing
77             $current_vector = $class->new_from_string( $current_vector );
78             }
79             elsif ( $ref eq 'ARRAY' ) {
80             my @array = @$current_vector;
81             croak "$caller_subname: one $vector_type you gave me was a ref to an array with no elements" unless @array ;
82             # we need to create the right kind of string based on whether
83             # they said they were sending us rows or columns:
84             if ($vector_type eq 'row') {
85             $current_vector = $class->new_from_string( '[ '. join( " ", @array) ." ]\n" );
86             }
87             else {
88             $current_vector = $class->new_from_string( '[ '. join( " ]\n[ ", @array) ." ]\n" );
89             }
90             }
91             elsif ( $ref ne 'HASH' and $current_vector->isa('Math::MatrixReal') ) {
92             # it's already a Math::MatrixReal something.
93             # we don't need to do anything, it will all
94             # work out
95             }
96             else {
97             # we have no idea, error time!
98             croak "$caller_subname: I only know how to deal with array refs, strings, and things that inherit from Math::MatrixReal\n";
99             }
100              
101             # starting now we know $current_vector isa Math::MatrixReal thingy
102             my @vector_dims = $current_vector->dim;
103              
104             #die unless the appropriate dimension is 1
105             croak "$caller_subname: I don't accept $other_type vectors"
106             unless ($vector_dims[ $vector_type eq 'row' ? 0 : 1 ] == 1) ;
107              
108             # the other dimension is the length of our vector
109             my $length = $vector_dims[ $vector_type eq 'row' ? 1 : 0 ];
110              
111             # set the "other" dimension to the length of this
112             # vector the first time through
113             $matrix_dim{$other_type} ||= $length;
114              
115             # die unless length of this vector matches the first length
116             croak "$caller_subname: one $vector_type has [$length] elements and another one had [$matrix_dim{$other_type}]--all of the ${vector_type}s passed in must have the same dimension"
117             unless ($length == $matrix_dim{$other_type}) ;
118              
119             # create the matrix the first time through
120             $matrix ||= $class->new($matrix_dim{row}, $matrix_dim{column});
121              
122             # step along the vector assigning the value of each element
123             # to the correct place in the matrix we're building
124             foreach my $element_index ( 1..$length ){
125             # args for vector assignment:
126             # initialize both to one and reset the correct
127             # one below
128             my ($v_r, $v_c) = (1,1);
129              
130             # args for matrix assignment
131             my ($row_index, $column_index, $value);
132              
133             if ($vector_type eq 'row') {
134             $row_index = $current_vector_count;
135             $v_c = $column_index = $element_index;
136             }
137             else {
138             $v_r = $row_index = $element_index;
139             $column_index = $current_vector_count;
140             }
141             $value = $current_vector->element($v_r, $v_c);
142             $matrix->assign($row_index, $column_index, $value);
143             }
144             $current_vector_count ++ ;
145             }
146             return $matrix;
147             }
148              
149              
150             1;
151             __END__