| 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__ |