Parent Directory
|
Revision Log
Revision 6899 - (view) (download) (as text)
| 1 : | sh002i | 2558 | ########################################################################### |
| 2 : | # | ||
| 3 : | # Implements the Matrix class. | ||
| 4 : | dpvc | 5089 | # |
| 5 : | sh002i | 2558 | # @@@ Still needs lots of work @@@ |
| 6 : | # | ||
| 7 : | package Value::Matrix; | ||
| 8 : | my $pkg = 'Value::Matrix'; | ||
| 9 : | |||
| 10 : | dpvc | 5696 | use strict; no strict "refs"; |
| 11 : | dpvc | 6899 | use Matrix; use Complex1; |
| 12 : | dpvc | 4975 | our @ISA = qw(Value); |
| 13 : | sh002i | 2558 | |
| 14 : | # | ||
| 15 : | # Convert a value to a matrix. The value can be: | ||
| 16 : | dpvc | 5108 | # a list of numbers or list of (nested) references to arrays of numbers, |
| 17 : | dpvc | 3165 | # a point, vector or matrix object, a matrix-valued formula, or a string |
| 18 : | dpvc | 3166 | # that evaluates to a matrix |
| 19 : | sh002i | 2558 | # |
| 20 : | sub new { | ||
| 21 : | my $self = shift; my $class = ref($self) || $self; | ||
| 22 : | dpvc | 4991 | my $context = (Value::isContext($_[0]) ? shift : $self->context); |
| 23 : | dpvc | 5108 | my $M = shift; $M = [] unless defined $M; $M = [$M,@_] if scalar(@_) > 0; |
| 24 : | dpvc | 6899 | $M = @{$M}[0] if ref($M) =~ m/^Matrix(Real1)?/; |
| 25 : | dpvc | 5108 | $M = Value::makeValue($M,context=>$context) if ref($M) ne 'ARRAY'; |
| 26 : | dpvc | 4991 | return bless {data => $M->data, context=>$context}, $class |
| 27 : | dpvc | 4993 | if (Value::classMatch($M,'Point','Vector','Matrix') && scalar(@_) == 0); |
| 28 : | dpvc | 5108 | return $M if Value::isFormula($M) && Value::classMatch($self,$M->type); |
| 29 : | my @M = (ref($M) eq 'ARRAY' ? @{$M} : $M); | ||
| 30 : | Value::Error("Matrices must have at least one entry") unless scalar(@M) > 0; | ||
| 31 : | return $self->matrixMatrix($context,@M) if ref($M[0]) eq 'ARRAY' || | ||
| 32 : | Value::classMatch($M[0],'Matrix','Vector','Point') || | ||
| 33 : | (Value::isFormula($M[0]) && $M[0]->type =~ m/Matrix|Vector|Point/); | ||
| 34 : | return $self->numberMatrix($context,@M); | ||
| 35 : | sh002i | 2558 | } |
| 36 : | |||
| 37 : | # | ||
| 38 : | dpvc | 3165 | # (Recursively) make a matrix from a list of array refs |
| 39 : | sh002i | 2558 | # and report errors about the entry types |
| 40 : | # | ||
| 41 : | sub matrixMatrix { | ||
| 42 : | my $self = shift; my $class = ref($self) || $self; | ||
| 43 : | dpvc | 5108 | my $context = shift; |
| 44 : | dpvc | 2592 | my ($x,$m); my @M = (); my $isFormula = 0; |
| 45 : | sh002i | 2558 | foreach $x (@_) { |
| 46 : | if (Value::isFormula($x)) {push(@M,$x); $isFormula = 1} else { | ||
| 47 : | dpvc | 5108 | $m = $self->new($context,$x); push(@M,$m); |
| 48 : | sh002i | 2558 | $isFormula = 1 if Value::isFormula($m); |
| 49 : | } | ||
| 50 : | } | ||
| 51 : | my ($type,$len) = ($M[0]->entryType->{name},$M[0]->length); | ||
| 52 : | foreach $x (@M) { | ||
| 53 : | Value::Error("Matrix rows must all be the same type") | ||
| 54 : | unless (defined($x->entryType) && $type eq $x->entryType->{name}); | ||
| 55 : | Value::Error("Matrix rows must all be the same length") unless ($len eq $x->length); | ||
| 56 : | } | ||
| 57 : | return $self->formula([@M]) if $isFormula; | ||
| 58 : | dpvc | 5108 | bless {data => [@M], context=>$context}, $class; |
| 59 : | sh002i | 2558 | } |
| 60 : | |||
| 61 : | # | ||
| 62 : | # Form a 1 x n matrix from a list of numbers | ||
| 63 : | # (could become a row of an m x n matrix) | ||
| 64 : | # | ||
| 65 : | sub numberMatrix { | ||
| 66 : | my $self = shift; my $class = ref($self) || $self; | ||
| 67 : | dpvc | 5108 | my $context = shift; |
| 68 : | sh002i | 2558 | my @M = (); my $isFormula = 0; |
| 69 : | foreach my $x (@_) { | ||
| 70 : | dpvc | 5108 | $x = Value::makeValue($x,context=>$context); |
| 71 : | dpvc | 3171 | Value::Error("Matrix row entries must be numbers") unless Value::isNumber($x); |
| 72 : | sh002i | 2558 | push(@M,$x); $isFormula = 1 if Value::isFormula($x); |
| 73 : | } | ||
| 74 : | return $self->formula([@M]) if $isFormula; | ||
| 75 : | dpvc | 5108 | bless {data => [@M], context=>$context}, $class; |
| 76 : | sh002i | 2558 | } |
| 77 : | |||
| 78 : | # | ||
| 79 : | # Recursively get the entries in the matrix and return | ||
| 80 : | # an array of (references to arrays of ... ) numbers | ||
| 81 : | # | ||
| 82 : | sub value { | ||
| 83 : | my $self = shift; | ||
| 84 : | my $M = $self->data; | ||
| 85 : | dpvc | 4993 | return @{$M} unless Value::classMatch($M->[0],'Matrix'); |
| 86 : | sh002i | 2558 | my @M = (); |
| 87 : | foreach my $x (@{$M}) {push(@M,[$x->value])} | ||
| 88 : | return @M; | ||
| 89 : | } | ||
| 90 : | dpvc | 5108 | |
| 91 : | sh002i | 2558 | # |
| 92 : | # Recursively get the dimensions of the matrix. | ||
| 93 : | # Returns (n) for a 1 x n, or (n,m) for an n x m, etc. | ||
| 94 : | # | ||
| 95 : | sub dimensions { | ||
| 96 : | my $self = shift; | ||
| 97 : | my $r = $self->length; | ||
| 98 : | my $v = $self->data; | ||
| 99 : | dpvc | 4993 | return ($r,) unless Value::classMatch($v->[0],'Matrix'); |
| 100 : | sh002i | 2558 | return ($r,$v->[0]->dimensions); |
| 101 : | } | ||
| 102 : | dpvc | 5108 | |
| 103 : | sh002i | 2558 | # |
| 104 : | # Return the proper type for the matrix | ||
| 105 : | # | ||
| 106 : | sub typeRef { | ||
| 107 : | my $self = shift; | ||
| 108 : | return Value::Type($self->class, $self->length, $Value::Type{number}) | ||
| 109 : | dpvc | 4993 | unless Value::classMatch($self->data->[0],'Matrix'); |
| 110 : | sh002i | 2558 | return Value::Type($self->class, $self->length, $self->data->[0]->typeRef); |
| 111 : | } | ||
| 112 : | |||
| 113 : | # | ||
| 114 : | # True if the matrix is a square matrix | ||
| 115 : | # | ||
| 116 : | sub isSquare { | ||
| 117 : | my $self = shift; | ||
| 118 : | my @d = $self->dimensions; | ||
| 119 : | return 0 if scalar(@d) > 2; | ||
| 120 : | return 1 if scalar(@d) == 1 && $d[0] == 1; | ||
| 121 : | return $d[0] == $d[1]; | ||
| 122 : | } | ||
| 123 : | |||
| 124 : | # | ||
| 125 : | # True if the matrix is 1-dimensional (i.e., is a matrix row) | ||
| 126 : | # | ||
| 127 : | sub isRow { | ||
| 128 : | my $self = shift; | ||
| 129 : | my @d = $self->dimensions; | ||
| 130 : | return scalar(@d) == 1; | ||
| 131 : | } | ||
| 132 : | |||
| 133 : | # | ||
| 134 : | dpvc | 2800 | # See if the matrix is an Indenity matrix |
| 135 : | # | ||
| 136 : | sub isOne { | ||
| 137 : | my $self = shift; | ||
| 138 : | return 0 unless $self->isSquare; | ||
| 139 : | my $i = 0; | ||
| 140 : | foreach my $row (@{$self->{data}}) { | ||
| 141 : | my $j = 0; | ||
| 142 : | foreach my $k (@{$row->{data}}) { | ||
| 143 : | return 0 unless $k eq (($i == $j)? "1": "0"); | ||
| 144 : | $j++; | ||
| 145 : | } | ||
| 146 : | $i++; | ||
| 147 : | } | ||
| 148 : | return 1; | ||
| 149 : | } | ||
| 150 : | |||
| 151 : | # | ||
| 152 : | # See if the matrix is all zeros | ||
| 153 : | # | ||
| 154 : | sub isZero { | ||
| 155 : | my $self = shift; | ||
| 156 : | foreach my $x (@{$self->{data}}) {return 0 unless $x->isZero} | ||
| 157 : | return 1; | ||
| 158 : | } | ||
| 159 : | |||
| 160 : | # | ||
| 161 : | sh002i | 2558 | # Make arbitrary data into a matrix, if possible |
| 162 : | # | ||
| 163 : | sub promote { | ||
| 164 : | dpvc | 4975 | my $self = shift; my $class = ref($self) || $self; |
| 165 : | dpvc | 4996 | my $context = (Value::isContext($_[0]) ? shift : $self->context); |
| 166 : | dpvc | 4975 | my $x = (scalar(@_) ? shift : $self); |
| 167 : | dpvc | 4996 | return $self->new($context,$x,@_) if scalar(@_) > 0 || ref($x) eq 'ARRAY'; |
| 168 : | dpvc | 5108 | $x = Value::makeValue($x,context=>$context); |
| 169 : | dpvc | 4996 | return $x->inContext($context) if ref($x) eq $class; |
| 170 : | return $self->make($context,@{$x->data}) if Value::classMatch($x,'Point','Vector'); | ||
| 171 : | Value::Error("Can't convert %s to %s",Value::showClass($x),Value::showClass($self)); | ||
| 172 : | sh002i | 2558 | } |
| 173 : | |||
| 174 : | dpvc | 5888 | # |
| 175 : | # Don't inherit ColumnVector flag | ||
| 176 : | # | ||
| 177 : | sub noinherit { | ||
| 178 : | my $self = shift; | ||
| 179 : | return ("ColumnVector",$self->SUPER::noinherit); | ||
| 180 : | } | ||
| 181 : | |||
| 182 : | sh002i | 2558 | ############################################ |
| 183 : | # | ||
| 184 : | # Operations on matrices | ||
| 185 : | # | ||
| 186 : | |||
| 187 : | sub add { | ||
| 188 : | dpvc | 5468 | my ($self,$l,$r,$other) = Value::checkOpOrderWithPromote(@_); |
| 189 : | dpvc | 4975 | my @l = @{$l->data}; my @r = @{$r->data}; |
| 190 : | Value::Error("Can't add Matrices with different dimensions") | ||
| 191 : | unless scalar(@l) == scalar(@r); | ||
| 192 : | sh002i | 2558 | my @s = (); |
| 193 : | dpvc | 4975 | foreach my $i (0..scalar(@l)-1) {push(@s,$l[$i] + $r[$i])} |
| 194 : | dpvc | 5468 | return $self->inherit($other)->make(@s); |
| 195 : | sh002i | 2558 | } |
| 196 : | |||
| 197 : | sub sub { | ||
| 198 : | dpvc | 5468 | my ($self,$l,$r,$other) = Value::checkOpOrderWithPromote(@_); |
| 199 : | dpvc | 4975 | my @l = @{$l->data}; my @r = @{$r->data}; |
| 200 : | Value::Error("Can't subtract Matrices with different dimensions") | ||
| 201 : | unless scalar(@l) == scalar(@r); | ||
| 202 : | sh002i | 2558 | my @s = (); |
| 203 : | dpvc | 4975 | foreach my $i (0..scalar(@l)-1) {push(@s,$l[$i] - $r[$i])} |
| 204 : | dpvc | 5468 | return $self->inherit($other)->make(@s); |
| 205 : | sh002i | 2558 | } |
| 206 : | |||
| 207 : | sub mult { | ||
| 208 : | dpvc | 5468 | my ($l,$r,$flag) = @_; my $self = $l; my $other = $r; |
| 209 : | sh002i | 2558 | # |
| 210 : | # Constant multiplication | ||
| 211 : | # | ||
| 212 : | if (Value::matchNumber($r) || Value::isComplex($r)) { | ||
| 213 : | my @coords = (); | ||
| 214 : | foreach my $x (@{$l->data}) {push(@coords,$x*$r)} | ||
| 215 : | dpvc | 4975 | return $self->make(@coords); |
| 216 : | sh002i | 2558 | } |
| 217 : | # | ||
| 218 : | # Make points and vectors into columns if they are on the right | ||
| 219 : | # | ||
| 220 : | dpvc | 4993 | if (!$flag && Value::classMatch($r,'Point','Vector')) |
| 221 : | dpvc | 4975 | {$r = ($self->promote($r))->transpose} else {$r = $self->promote($r)} |
| 222 : | sh002i | 2558 | # |
| 223 : | if ($flag) {my $tmp = $l; $l = $r; $r = $tmp} | ||
| 224 : | my @dl = $l->dimensions; my @dr = $r->dimensions; | ||
| 225 : | dpvc | 4975 | if (scalar(@dl) == 1) {@dl = (1,@dl); $l = $self->make($l)} |
| 226 : | if (scalar(@dr) == 1) {@dr = (@dr,1); $r = $self->make($r)->transpose} | ||
| 227 : | sh002i | 2558 | Value::Error("Can only multiply 2-dimensional matrices") if scalar(@dl) > 2 || scalar(@dr) > 2; |
| 228 : | dpvc | 3370 | Value::Error("Matices of dimensions %dx%d and %dx%d can't be multiplied",@dl,@dr) |
| 229 : | sh002i | 2558 | unless ($dl[1] == $dr[0]); |
| 230 : | # | ||
| 231 : | # Do matrix multiplication | ||
| 232 : | # | ||
| 233 : | dpvc | 4975 | my @l = $l->value; my @r = $r->value; my @M = (); |
| 234 : | dpvc | 3074 | foreach my $i (0..$dl[0]-1) { |
| 235 : | sh002i | 2558 | my @row = (); |
| 236 : | dpvc | 3074 | foreach my $j (0..$dr[1]-1) { |
| 237 : | sh002i | 2558 | my $s = 0; |
| 238 : | foreach my $k (0..$dl[1]-1) {$s += $l[$i]->[$k] * $r[$k]->[$j]} | ||
| 239 : | push(@row,$s); | ||
| 240 : | } | ||
| 241 : | dpvc | 4975 | push(@M,$self->make(@row)); |
| 242 : | sh002i | 2558 | } |
| 243 : | dpvc | 5468 | $self = $self->inherit($other) if Value::isValue($other); |
| 244 : | dpvc | 4975 | return $self->make(@M); |
| 245 : | sh002i | 2558 | } |
| 246 : | |||
| 247 : | sub div { | ||
| 248 : | dpvc | 4975 | my ($l,$r,$flag) = @_; my $self = $l; |
| 249 : | sh002i | 2558 | Value::Error("Can't divide by a Matrix") if $flag; |
| 250 : | dpvc | 5108 | Value::Error("Matrices can only be divided by Numbers") |
| 251 : | sh002i | 2558 | unless (Value::matchNumber($r) || Value::isComplex($r)); |
| 252 : | Value::Error("Division by zero") if $r == 0; | ||
| 253 : | my @coords = (); | ||
| 254 : | foreach my $x (@{$l->data}) {push(@coords,$x/$r)} | ||
| 255 : | dpvc | 4975 | return $self->make(@coords); |
| 256 : | sh002i | 2558 | } |
| 257 : | |||
| 258 : | sub power { | ||
| 259 : | dpvc | 5012 | my ($l,$r,$flag) = @_; my $self = shift; my $context = $self->context; |
| 260 : | sh002i | 2558 | Value::Error("Can't use Matrices in exponents") if $flag; |
| 261 : | Value::Error("Only square matrices can be raised to a power") unless $l->isSquare; | ||
| 262 : | dpvc | 5108 | $r = Value::makeValue($r,context=>$context); |
| 263 : | Value::Error("Matrix powers must be non-negative integers") unless $r->isNumber && $r =~ m/^\d+$/; | ||
| 264 : | dpvc | 5012 | return $context->Package("Matrix")->I($l->length,$context) if $r == 0; |
| 265 : | sh002i | 2558 | my $M = $l; foreach my $i (2..$r) {$M = $M*$l} |
| 266 : | return $M; | ||
| 267 : | } | ||
| 268 : | |||
| 269 : | # | ||
| 270 : | dpvc | 5108 | # Do lexicographic comparison (row by row) |
| 271 : | sh002i | 2558 | # |
| 272 : | sub compare { | ||
| 273 : | dpvc | 5042 | my ($self,$l,$r) = Value::checkOpOrderWithPromote(@_); |
| 274 : | dpvc | 4975 | Value::Error("Can't compare Matrices with different dimensions") |
| 275 : | dpvc | 5108 | unless join(',',$l->dimensions) eq join(',',$r->dimensions); |
| 276 : | my @l = @{$l->data}; my @r = @{$r->data}; | ||
| 277 : | dpvc | 4975 | foreach my $i (0..scalar(@l)-1) { |
| 278 : | dpvc | 5108 | my $cmp = $l[$i] <=> $r[$i]; |
| 279 : | return $cmp if $cmp; | ||
| 280 : | sh002i | 2558 | } |
| 281 : | dpvc | 5108 | return 0; |
| 282 : | sh002i | 2558 | } |
| 283 : | |||
| 284 : | sub neg { | ||
| 285 : | dpvc | 4975 | my $self = promote(@_); my @coords = (); |
| 286 : | foreach my $x (@{$self->data}) {push(@coords,-$x)} | ||
| 287 : | return $self->make(@coords); | ||
| 288 : | sh002i | 2558 | } |
| 289 : | |||
| 290 : | # | ||
| 291 : | # Transpose an n x m matrix | ||
| 292 : | # | ||
| 293 : | sub transpose { | ||
| 294 : | dpvc | 4975 | my $self = promote(@_); |
| 295 : | sh002i | 2558 | my @d = $self->dimensions; |
| 296 : | dpvc | 5108 | if (scalar(@d) == 1) {@d = (1,@d); $self = $self->make($self)} |
| 297 : | dpvc | 3370 | Value::Error("Can't transpose %d-dimensional matrices",scalar(@d)) unless scalar(@d) == 2; |
| 298 : | sh002i | 2558 | my @M = (); my $M = $self->data; |
| 299 : | foreach my $j (0..$d[1]-1) { | ||
| 300 : | my @row = (); | ||
| 301 : | foreach my $i (0..$d[0]-1) {push(@row,$M->[$i]->data->[$j])} | ||
| 302 : | dpvc | 4975 | push(@M,$self->make(@row)); |
| 303 : | sh002i | 2558 | } |
| 304 : | dpvc | 4975 | return $self->make(@M); |
| 305 : | sh002i | 2558 | } |
| 306 : | |||
| 307 : | # | ||
| 308 : | # Get an identity matrix of the requested size | ||
| 309 : | # | ||
| 310 : | sub I { | ||
| 311 : | dpvc | 4975 | my $self = shift; my $d = shift; my $context = shift || $self->context; |
| 312 : | dpvc | 5108 | $d = ($self->dimensions)[0] if !defined $d && ref($self) && $self->isSquare; |
| 313 : | Value::Error("You must provide a dimension for the Identity matrix") unless defined $d; | ||
| 314 : | Value::Error("Dimension must be a positive integer") unless $d =~ m/^[1-9]\d*$/; | ||
| 315 : | sh002i | 2558 | my @M = (); my @Z = split('',0 x $d); |
| 316 : | foreach my $i (0..$d-1) { | ||
| 317 : | my @row = @Z; $row[$i] = 1; | ||
| 318 : | dpvc | 4991 | push(@M,$self->make($context,@row)); |
| 319 : | sh002i | 2558 | } |
| 320 : | dpvc | 4991 | return $self->make($context,@M); |
| 321 : | sh002i | 2558 | } |
| 322 : | |||
| 323 : | # | ||
| 324 : | # Extract a given row from the matrix | ||
| 325 : | # | ||
| 326 : | sub row { | ||
| 327 : | dpvc | 4975 | my $self = (ref($_[0]) ? $_[0] : shift); |
| 328 : | my $M = $self->promote(shift); my $i = shift; | ||
| 329 : | sh002i | 2558 | return if $i == 0; $i-- if $i > 0; |
| 330 : | dpvc | 5108 | if ($M->isRow) {return if $i != 0 && $i != -1; return $M} |
| 331 : | sh002i | 2558 | return $M->data->[$i]; |
| 332 : | } | ||
| 333 : | |||
| 334 : | # | ||
| 335 : | # Extract a given column from the matrix | ||
| 336 : | # | ||
| 337 : | sub column { | ||
| 338 : | dpvc | 4975 | my $self = (ref($_[0]) ? $_[0] : shift); |
| 339 : | my $M = $self->promote(shift); my $j = shift; | ||
| 340 : | sh002i | 2558 | return if $j == 0; $j-- if $j > 0; |
| 341 : | dpvc | 5108 | my @d = $M->dimensions; |
| 342 : | if (scalar(@d) == 1) { | ||
| 343 : | return if $j+1 > $d[0] || $j < -$d[0]; | ||
| 344 : | return $M->data->[$j]; | ||
| 345 : | } | ||
| 346 : | return if $j+1 > $d[1] || $j < -$d[1]; | ||
| 347 : | my @col = (); | ||
| 348 : | dpvc | 4975 | foreach my $row (@{$M->data}) {push(@col,$self->make($row->data->[$j]))} |
| 349 : | return $self->make(@col); | ||
| 350 : | sh002i | 2558 | } |
| 351 : | |||
| 352 : | dpvc | 6899 | # |
| 353 : | # Extract a given element from the matrix | ||
| 354 : | # | ||
| 355 : | sub element { | ||
| 356 : | my $self = (ref($_[0]) ? $_[0] : shift); | ||
| 357 : | my $M = $self->promote(shift); | ||
| 358 : | return $M->extract(@_); | ||
| 359 : | } | ||
| 360 : | |||
| 361 : | # @@@ assign @@@ | ||
| 362 : | sh002i | 2558 | # @@@ removeRow, removeColumn @@@ |
| 363 : | dpvc | 4975 | # @@@ Minor @@@ |
| 364 : | sh002i | 2558 | |
| 365 : | dpvc | 6899 | |
| 366 : | ################################################## | ||
| 367 : | # | ||
| 368 : | # Convert MathObject Matrix to old-style Matrix | ||
| 369 : | # | ||
| 370 : | sub wwMatrix { | ||
| 371 : | my $self = (ref($_[0]) ? $_[0] : shift); | ||
| 372 : | my $M = $self->promote(shift); my $j = shift; my $wwM; | ||
| 373 : | return $self->{wwM} if defined($self->{wwM}); | ||
| 374 : | my @d = $M->dimensions; | ||
| 375 : | Value->Error("Matrix must be two-dimensional to convert to MatrixReal1") if scalar(@d) > 2; | ||
| 376 : | if (scalar(@d) == 1) { | ||
| 377 : | $wwM = new Matrix(1,$d[0]); | ||
| 378 : | foreach my $j (0..$d[0]-1) { | ||
| 379 : | $wwM->[0][0][$j] = $self->wwMatrixEntry($M->data->[$j]); | ||
| 380 : | } | ||
| 381 : | } else { | ||
| 382 : | $wwM = new Matrix(@d); | ||
| 383 : | foreach my $i (0..$d[0]-1) { | ||
| 384 : | my $row = $M->data->[$i]; | ||
| 385 : | foreach my $j (0..$d[1]-1) { | ||
| 386 : | $wwM->[0][$i][$j] = $self->wwMatrixEntry($row->data->[$j]); | ||
| 387 : | } | ||
| 388 : | } | ||
| 389 : | } | ||
| 390 : | $self->{wwM} = $wwM; | ||
| 391 : | return $wwM; | ||
| 392 : | } | ||
| 393 : | sub wwMatrixEntry { | ||
| 394 : | my $self = shift; my $x = shift; | ||
| 395 : | return $x->value if $x->isReal; | ||
| 396 : | return Complex1::cplx($x->Re->value,$x->Im->value) if $x->isComplex; | ||
| 397 : | return $x; | ||
| 398 : | } | ||
| 399 : | sub wwMatrixLR { | ||
| 400 : | my $self = shift; | ||
| 401 : | return $self->{lrM} if defined($self->{lrM}); | ||
| 402 : | $self->wwMatrix; | ||
| 403 : | $self->{lrM} = $self->{wwM}->decompose_LR; | ||
| 404 : | return $self->{lrM}; | ||
| 405 : | } | ||
| 406 : | |||
| 407 : | |||
| 408 : | ################################### | ||
| 409 : | # | ||
| 410 : | # From MatrixReal1.pm | ||
| 411 : | # | ||
| 412 : | |||
| 413 : | sub det { | ||
| 414 : | my $self = shift; $self->wwMatrixLR; | ||
| 415 : | return $self->{lrM}->det_LR; | ||
| 416 : | } | ||
| 417 : | |||
| 418 : | sub inverse { | ||
| 419 : | my $self = shift; $self->wwMatrixLR; | ||
| 420 : | return $self->new($self->{lrM}->invert_LR); | ||
| 421 : | } | ||
| 422 : | |||
| 423 : | sub decompose_LR { | ||
| 424 : | my $self = shift; | ||
| 425 : | return $self->wwMatrixLR; | ||
| 426 : | } | ||
| 427 : | |||
| 428 : | sub dim { | ||
| 429 : | my $self = shift; | ||
| 430 : | return $self->wwMatrix->dim(); | ||
| 431 : | } | ||
| 432 : | |||
| 433 : | sub norm_one { | ||
| 434 : | my $self = shift; | ||
| 435 : | return $self->wwMatrix->norm_one(); | ||
| 436 : | } | ||
| 437 : | |||
| 438 : | sub norm_max { | ||
| 439 : | my $self = shift; | ||
| 440 : | return $self->wwMatrix->norm_max(); | ||
| 441 : | } | ||
| 442 : | |||
| 443 : | sub kleene { | ||
| 444 : | my $self = shift; | ||
| 445 : | return $self->new($self->wwMatrix->kleene()); | ||
| 446 : | } | ||
| 447 : | |||
| 448 : | sub normalize { | ||
| 449 : | my $self = shift; | ||
| 450 : | my $v = $self->new(shift)->wwMatrix; | ||
| 451 : | my ($M,$b) = $self->wwMatrix->normalize($v); | ||
| 452 : | return ($self->new($M),$self->new($b)); | ||
| 453 : | } | ||
| 454 : | |||
| 455 : | sub solve_LR { | ||
| 456 : | my $self = shift; | ||
| 457 : | my $v = $self->new(shift)->wwMatrix; | ||
| 458 : | my ($d,$b,$M) = $self->lrMatrix->solve_LR($v); | ||
| 459 : | return ($d,$self->new($b),$self->new($M)); | ||
| 460 : | } | ||
| 461 : | |||
| 462 : | sub condition { | ||
| 463 : | my $self = shift; | ||
| 464 : | my $I = $self->new(shift)->wwMatrix; | ||
| 465 : | return $self->new($self->wwMatrix->condition($I)); | ||
| 466 : | } | ||
| 467 : | |||
| 468 : | sub order_LR { | ||
| 469 : | my $self = shift; | ||
| 470 : | return $self->wwMatrixLR->order_LR; | ||
| 471 : | } | ||
| 472 : | |||
| 473 : | sub solve_GSM { | ||
| 474 : | my $self = shift; | ||
| 475 : | my $x0 = $self->new(shift)->wwMatrix; | ||
| 476 : | my $b = $self->new(shift)->wwMatrix; | ||
| 477 : | my $e = shift; | ||
| 478 : | my $v = $self->wwMatrix->solve_GSM($x0,$b,$e); | ||
| 479 : | $v = $self->new($v) if defined($v); | ||
| 480 : | return $v; | ||
| 481 : | } | ||
| 482 : | |||
| 483 : | sub solve_SSM { | ||
| 484 : | my $self = shift; | ||
| 485 : | my $x0 = $self->new(shift)->wwMatrix; | ||
| 486 : | my $b = $self->new(shift)->wwMatrix; | ||
| 487 : | my $e = shift; | ||
| 488 : | my $v = $self->wwMatrix->solve_SSM($x0,$b,$e); | ||
| 489 : | $v = $self->new($v) if defined($v); | ||
| 490 : | return $v; | ||
| 491 : | } | ||
| 492 : | |||
| 493 : | sub solve_RM { | ||
| 494 : | my $self = shift; | ||
| 495 : | my $x0 = $self->new(shift)->wwMatrix; | ||
| 496 : | my $b = $self->new(shift)->wwMatrix; | ||
| 497 : | my $w = shift; my $e = shift; | ||
| 498 : | my $v = $self->wwMatrix->solve_RM($x0,$b,$w,$e); | ||
| 499 : | $v = $self->new($v) if defined($v); | ||
| 500 : | return $v; | ||
| 501 : | } | ||
| 502 : | |||
| 503 : | sub is_symmetric { | ||
| 504 : | my $self = shift; | ||
| 505 : | return $self->wwMatrix->is_symmetric; | ||
| 506 : | } | ||
| 507 : | |||
| 508 : | ################################### | ||
| 509 : | # | ||
| 510 : | # From Matrix.pm | ||
| 511 : | # | ||
| 512 : | |||
| 513 : | sub trace { | ||
| 514 : | my $self = shift; | ||
| 515 : | return $self->wwMatrix->trace; | ||
| 516 : | } | ||
| 517 : | |||
| 518 : | sub proj { | ||
| 519 : | my $self = shift; | ||
| 520 : | my $v = $self->new(shift)->wwMatrix; | ||
| 521 : | return $self->new($self->wwMatrix->proj($v)); | ||
| 522 : | } | ||
| 523 : | |||
| 524 : | sub proj_coeff { | ||
| 525 : | my $self = shift; | ||
| 526 : | my $v = $self->new(shift)->wwMatrix; | ||
| 527 : | return $self->new($self->wwMatrix->proj_coeff($v)); | ||
| 528 : | } | ||
| 529 : | |||
| 530 : | sub L { | ||
| 531 : | my $self = shift; | ||
| 532 : | return $self->new($self->wwMatrixLR->L); | ||
| 533 : | } | ||
| 534 : | |||
| 535 : | sub R { | ||
| 536 : | my $self = shift; | ||
| 537 : | return $self->new($self->wwMatrixLR->R); | ||
| 538 : | } | ||
| 539 : | |||
| 540 : | sub PL { | ||
| 541 : | my $self = shift; | ||
| 542 : | return $self->new($self->wwMatrixLR->PL); | ||
| 543 : | } | ||
| 544 : | |||
| 545 : | sub PR { | ||
| 546 : | my $self = shift; | ||
| 547 : | return $self->new($self->wwMatrixLR->PR); | ||
| 548 : | } | ||
| 549 : | |||
| 550 : | |||
| 551 : | sh002i | 2558 | ############################################ |
| 552 : | # | ||
| 553 : | # Generate the various output formats | ||
| 554 : | # | ||
| 555 : | |||
| 556 : | # | ||
| 557 : | dpvc | 3265 | # Use array environment to lay out matrices |
| 558 : | sh002i | 2558 | # |
| 559 : | sub TeX { | ||
| 560 : | my $self = shift; my $equation = shift; | ||
| 561 : | dpvc | 4979 | my $def = ($equation->{context} || $self->context)->lists->get('Matrix'); |
| 562 : | dpvc | 3265 | my $open = shift || $self->{open} || $def->{open}; |
| 563 : | my $close = shift || $self->{close} || $def->{close}; | ||
| 564 : | dpvc | 5089 | $open =~ s/([{}])/\\$1/g; $close =~ s/([{}])/\\$1/g; |
| 565 : | dpvc | 2592 | my $TeX = ''; my @entries = (); my $d; |
| 566 : | dpvc | 2579 | if ($self->isRow) { |
| 567 : | foreach my $x (@{$self->data}) { | ||
| 568 : | dpvc | 5089 | if (Value::isValue($x)) { |
| 569 : | $x->{format} = $self->{format} if defined $self->{format}; | ||
| 570 : | push(@entries,$x->TeX($equation)); | ||
| 571 : | } else {push(@entries,$x)} | ||
| 572 : | sh002i | 2558 | } |
| 573 : | dpvc | 2579 | $TeX .= join(' &',@entries) . "\n"; |
| 574 : | dpvc | 2592 | $d = scalar(@entries); |
| 575 : | dpvc | 2579 | } else { |
| 576 : | foreach my $row (@{$self->data}) { | ||
| 577 : | foreach my $x (@{$row->data}) { | ||
| 578 : | dpvc | 5089 | if (Value::isValue($x)) { |
| 579 : | $x->{format} = $self->{format} if defined $self->{format}; | ||
| 580 : | push(@entries,$x->TeX($equation)); | ||
| 581 : | } else {push(@entries,$x)} | ||
| 582 : | dpvc | 2579 | } |
| 583 : | dpvc | 2592 | $TeX .= join(' &',@entries) . '\cr'."\n"; |
| 584 : | $d = scalar(@entries); @entries = (); | ||
| 585 : | dpvc | 2579 | } |
| 586 : | sh002i | 2558 | } |
| 587 : | dpvc | 5943 | $TeX =~ s/\\cr\n$/\n/; |
| 588 : | dpvc | 2592 | return '\left'.$open.'\begin{array}{'.('c'x$d).'}'."\n".$TeX.'\end{array}\right'.$close; |
| 589 : | sh002i | 2558 | } |
| 590 : | dpvc | 4975 | |
| 591 : | sh002i | 2558 | ########################################################################### |
| 592 : | |||
| 593 : | 1; | ||
| 594 : |
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |