File Coverage

blib/lib/Math/Zap/Matrix2.pm
Criterion Covered Total %
statement 95 105 90.4
branch 21 34 61.7
condition 3 9 33.3
subroutine 30 34 88.2
pod 22 29 75.8
total 171 211 81.0


line stmt bran cond sub pod time code
1            
2             =head1 Matrix2
3            
4             2*2 matrix manipulation
5            
6             PhilipRBrenan@yahoo.com, 2004, Perl License
7            
8            
9             =head2 Synopsis
10            
11             Example t/matrix2.t
12            
13             #_ Matrix _____________________________________________________________
14             # Test 2*2 matrices
15             # philiprbrenan@yahoo.com, 2004, Perl License
16             #______________________________________________________________________
17            
18             use Math::Zap::Matrix2 identity=>i;
19             use Math::Zap::Vector2;
20             use Test::Simple tests=>8;
21            
22             my ($a, $b, $c, $v);
23            
24             $a = matrix2
25             (8, 0,
26             0, 8,
27             );
28            
29             $b = matrix2
30             (4, 2,
31             2, 4,
32             );
33            
34             $c = matrix2
35             (2, 2,
36             1, 2,
37             );
38            
39             $v = vector2(1,2);
40            
41             ok($a/$a == i());
42             ok($b/$b == i());
43             ok($c/$c == i());
44             ok(2/$a*$a/2 == i());
45             ok(($a+$b)/($a+$b) == i());
46             ok(($a-$c)/($a-$c) == i());
47             ok(-$a/-$a == i());
48             ok(1/$a*($a*$v) == $v);
49            
50            
51            
52            
53             =head2 Description
54            
55             2*2 matrix manipulation
56            
57             =cut
58            
59            
60             package Math::Zap::Matrix2;
61             $VERSION=1.07;
62 6     6   1098 use Math::Zap::Vector2 check=>'vector2Check', is=>'vector2Is';
  6         12  
  6         181  
63 6     6   30 use Carp;
  6         12  
  6         396  
64 6     6   30 use constant debug => 0; # Debugging level
  6         12  
  6         11227  
65            
66            
67             =head2 Constructors
68            
69            
70             =head3 new
71            
72             Create a matrix
73            
74             =cut
75            
76            
77 3     3 1 6 sub new($$$$)
78             {my
79             ($a11, $a12,
80             $a21, $a22,
81             ) = @_;
82            
83 3         16 my $m = round(bless(
84             {11=>$a11, 12=>$a12,
85             21=>$a21, 22=>$a22,
86             }));
87 3         9 singular($m, 1);
88 3         9 $m;
89             }
90            
91            
92             =head3 matrix2
93            
94             Create a matrix. Synonym for L.
95            
96             =cut
97            
98            
99 3     3 1 11 sub matrix2($$$$)
100             {new($_[0],$_[1],$_[2],$_[3]);
101             }
102            
103            
104             =head3 identity
105            
106             Identity matrix
107            
108             =cut
109            
110            
111 7     7 1 30 sub identity()
112             {bless
113             {11=>1, 21=>0,
114             12=>0, 22=>1,
115             };
116             }
117            
118            
119             =head3 new2v
120            
121             Create a matrix from two vectors
122            
123             =cut
124            
125            
126 57     57 1 71 sub new2v($$)
127             {vector2Check(@_) if debug;
128 57         93 my ($a, $b, $c) = @_;
129 57         268 my $m = round(bless(
130             {11=>$a->{x}, 12=>$b->{x},
131             21=>$a->{y}, 22=>$b->{y},
132             }));
133 57         115 singular($m, 1);
134 57         203 $m;
135             }
136            
137            
138             =head2 Methods
139            
140            
141             =head3 check
142            
143             Check its a matrix
144            
145             =cut
146            
147            
148             sub check(@)
149 157     157 1 159 {if (debug)
150             {for my $m(@_)
151             {confess "$m is not a matrix2" unless ref($m) eq __PACKAGE__;
152             }
153             }
154 157         257 return (@_)
155             }
156            
157            
158             =head3 is
159            
160             Test its a matrix
161            
162             =cut
163            
164            
165 7 50       29 sub is(@)
166 7     7 1 15 {for my $m(@_)
167             {return 0 unless ref($m) eq __PACKAGE__;
168             }
169 7         41 'matrix2';
170             }
171            
172            
173             =head3 accuracy
174            
175             Get/Set accuracy
176            
177             =cut
178            
179            
180             my $accuracy = 1e-10;
181            
182             sub accuracy
183 0 0   0 1 0 {return $accuracy unless scalar(@_);
184 0         0 $accuracy = shift();
185             }
186            
187            
188             =head3 round
189            
190             Round: round to nearest integer if within accuracy of that integer
191            
192             =cut
193            
194            
195 141         591 sub round($)
196 141     141 1 157 {unless (debug)
197             {return $_[0];
198             }
199             else
200             {my ($a) = @_;
201             for my $k(keys(%$a))
202             {my $n = $a->{$k};
203             my $N = int($n);
204             $a->{$k} = $N if abs($n-$N) < $accuracy;
205             }
206             return $a;
207             }
208             }
209            
210            
211             =head3 singular
212            
213             Singular matrix?
214            
215             =cut
216            
217            
218 66     66 1 89 sub singular($$)
219             {my $m = shift; # Matrix
220 66         85 my $a = 1e-2; # Accuracy
221 66         77 my $A = shift; # Action 0: return indicator, 1: confess
222 66         386 my $n = abs
223             ($m->{11} * $m->{22} -
224             $m->{12} * $m->{21})
225             < $a;
226 66 50 33     177 confess "Singular matrix2" if $n and $A;
227 66         97 $n;
228             }
229            
230            
231             =head3 clone
232            
233             Create a matrix from another matrix
234            
235             =cut
236            
237            
238 0     0 1 0 sub clone($)
239             {my ($m) = check(@_); # Matrix
240 0         0 round bless
241             {11=>$m->{11}, 12=>$m->{12},
242             21=>$m->{21}, 22=>$m->{22},
243             };
244             }
245            
246            
247             =head3 print
248            
249             Print matrix
250            
251             =cut
252            
253            
254 4     4 1 10 sub print($)
255             {my ($m) = check(@_); # Matrix
256 4         27 'matrix2('.$m->{11}.', '.$m->{12}.
257             ', '.$m->{21}.', '.$m->{22}.
258             ')';
259             }
260            
261            
262             =head3 add
263            
264             Add matrices
265            
266             =cut
267            
268            
269 2     2 1 6 sub add($$)
270             {my ($a, $b) = check(@_); # Matrices
271 2         16 my $m = round bless
272             {11=>$a->{11}+$b->{11}, 12=>$a->{12}+$b->{12},
273             21=>$a->{21}+$b->{21}, 22=>$a->{22}+$b->{22},
274             };
275 2         7 singular($m, 1);
276 2         7 $m;
277             }
278            
279            
280             =head3 negate
281            
282             Negate matrix
283            
284             =cut
285            
286            
287 2     2 1 6 sub negate($)
288             {my ($a) = check(@_); # Matrices
289 2         14 my $m = round bless
290             {11=>-$a->{11}, 12=>-$a->{12},
291             21=>-$a->{21}, 22=>-$a->{22},
292             };
293 2         4 singular($m, 1);
294 2         7 $m;
295             }
296            
297            
298             =head3 subtract
299            
300             Subtract matrices
301            
302             =cut
303            
304            
305 2     2 1 5 sub subtract($$)
306             {my ($a, $b) = check(@_); # Matrices
307 2         17 my $m = round bless
308             {11=>$a->{11}-$b->{11}, 12=>$a->{12}-$b->{12},
309             21=>$a->{21}-$b->{21}, 22=>$a->{22}-$b->{22},
310             };
311 2         14 singular($m, 1);
312 2         8 $m;
313             }
314            
315            
316             =head3 matrixVectorMultiply
317            
318             Vector = Matrix * Vector
319            
320             =cut
321            
322            
323             sub matrixVectorMultiply($$)
324 59     59 1 61 { check(@_[0..0]) if debug; # Matrix
325 59         116 vector2Check(@_[1..1]) if debug; # Vector
326 59         72 my ($a, $b) = @_;
327 59         1901 vector2
328             ($a->{11}*$b->{x}+$a->{12}*$b->{y},
329             $a->{21}*$b->{x}+$a->{22}*$b->{y},
330             );
331             }
332            
333            
334             =head3 matrixScalarMultiply
335            
336             Matrix = Matrix * scalar
337            
338             =cut
339            
340            
341 2     2 1 7 sub matrixScalarMultiply($$)
342             {my ($a) = check(@_[0..0]); # Matrix
343 2         6 my ($b) = @_[1..1]; # Scalar
344 2 50       9 confess "$b is not a scalar" if ref($b);
345 2         26 round bless
346             {11=>$a->{11}*$b, 12=>$a->{12}*$b,
347             21=>$a->{21}*$b, 22=>$a->{22}*$b,
348             };
349             }
350            
351            
352             =head3 matrixMatrixMultiply
353            
354             Matrix = Matrix * Matrix
355            
356             =cut
357            
358            
359 7     7 1 14 sub matrixMatrixMultiply($$)
360             {my ($a, $b) = check(@_); # Matrices
361 7         67 round bless
362             {11=>$a->{11}*$b->{11}+$a->{12}*$b->{21}, 12=>$a->{11}*$b->{12}+$a->{12}*$b->{22},
363             21=>$a->{21}*$b->{11}+$a->{22}*$b->{21}, 22=>$a->{21}*$b->{12}+$a->{22}*$b->{22},
364             };
365             }
366            
367            
368             =head3 matrixScalarDivide
369            
370             Matrix=Matrix / non zero scalar
371            
372             =cut
373            
374            
375 1     1 1 4 sub matrixScalarDivide($$)
376             {my ($a) = check(@_[0..0]); # Matrices
377 1         3 my ($b) = @_[1..1]; # Scalar
378 1 50       15 confess "$b is not a scalar" if ref($b);
379 1 50       5 confess "$b is zero" if $b == 0;
380 1         16 round bless
381             {11=>$a->{11}/$b, 12=>$a->{12}/$b,
382             21=>$a->{21}/$b, 22=>$a->{22}/$b,
383             };
384             }
385            
386            
387             =head3 det
388            
389             Determinant of matrix.
390            
391             =cut
392            
393            
394 65     65 1 106 sub det($)
395             {my ($a) = check(@_); # Matrices
396            
397 65         201 +$a->{11}*$a->{22}
398             -$a->{12}*$a->{21}
399             }
400            
401            
402             =head3 inverse
403            
404             Inverse of matrix
405            
406             =cut
407            
408            
409 65     65 1 128 sub inverse($)
410             {my ($a) = check(@_); # Matrices
411            
412 65         122 my $d = det($a);
413 65 50       157 return undef if $d == 0;
414            
415 65         358 round bless
416             {11=> $a->{22}/$d, 21=>-$a->{21}/$d,
417             12=>-$a->{12}/$d, 22=> $a->{11}/$d,
418             };
419             }
420            
421            
422             =head3 rotate
423            
424             Rotation matrix: rotate anti-clockwise by t radians
425            
426             =cut
427            
428            
429 0     0 1 0 sub rotate($)
430             {my ($a) = @_;
431 0         0 bless
432             {11=>cos($t), 21=>-sin($t),
433             12=>sin($t), 22=> cos($t),
434             };
435             }
436            
437            
438             =head3 equals
439            
440             Equals to within accuracy
441            
442             =cut
443            
444            
445 7     7 1 15 sub equals($$)
446             {my ($a, $b) = check(@_); # Matrices
447 7 50 33     123 abs($a->{11}-$b->{11}) < $accuracy and
      33        
448             abs($a->{12}-$b->{12}) < $accuracy and
449            
450             abs($a->{21}-$b->{21}) < $accuracy and
451             abs($a->{22}-$b->{22}) < $accuracy;
452             }
453            
454            
455             =head2 Operators
456            
457             Operator overloads
458            
459             =cut
460            
461            
462             use overload
463 6         101 '+' => \&add3, # Add two vectors
464             '-' => \&subtract3, # Subtract one vector from another
465             '*' => \&multiply3, # Times by a scalar, or vector dot product
466             '/' => \÷3, # Divide by a scalar
467             '!' => \&det3, # Determinant
468             '==' => \&equals3, # Equals (to accuracy)
469             '""' => \&print3, # Print
470 6     6   43 'fallback' => FALSE;
  6         20  
471            
472            
473             =head3 add operator
474            
475             Add operator.
476            
477             =cut
478            
479            
480             sub add3
481 2     2 0 4 {my ($a, $b) = @_;
482 2         8 $a->add($b);
483             }
484            
485            
486             =head3 subtract operator
487            
488             Subtract operator.
489            
490             =cut
491            
492            
493             sub subtract3
494 4     4 0 9 {my ($a, $b, $c) = @_;
495            
496 4 100       21 return $a->subtract($b) if $b;
497 2         5 negate($a);
498             }
499            
500            
501             =head3 multiply operator
502            
503             Multiply operator.
504            
505             =cut
506            
507            
508             sub multiply3
509 3     3 0 6 {my ($a, $b) = @_;
510 3 50       11 return $a->matrixScalarMultiply($b) unless ref($b);
511 3 100       108 return $a->matrixVectorMultiply($b) if vector2Is($b);
512 1 50       3 return $a->matrixMatrixMultiply($b) if is($b);
513 0         0 confess "Cannot multiply $a by $b\n";
514             }
515            
516            
517             =head3 divide operator
518            
519             Divide operator.
520            
521             =cut
522            
523            
524             sub divide3
525 66     66 0 118 {my ($a, $b, $c) = @_;
526 66 100       138 if (!ref($b))
  3 100       18  
527 63 100       1709 {return $a->matrixScalarDivide($b) unless $c;
528 2 50       11 return $a->inverse->matrixScalarMultiply($b) if $c;
529             }
530             else
531             {return $a->inverse->matrixVectorMultiply($b) if vector2Is($b);
532 6 50       17 return $a->matrixMatrixMultiply($b->inverse) if is($b);
533 0         0 confess "Cannot multiply $a by $b\n";
534             }
535             }
536            
537            
538             =head3 equals operator
539            
540             Equals operator.
541            
542             =cut
543            
544            
545             sub equals3
546 7     7 0 15 {my ($a, $b, $c) = @_;
547 7         20 return $a->equals($b);
548             }
549            
550            
551             =head3 determinant operator
552            
553             Determinant of a matrix
554            
555             =cut
556            
557            
558             sub det3
559 0     0 0 0 {my ($a, $b, $c) = @_;
560 0         0 $a->det;
561             }
562            
563            
564             =head3 print operator
565            
566             Print a vector.
567            
568             =cut
569            
570            
571             sub print3
572 4     4 0 7 {my ($a) = @_;
573 4         11 return $a->print;
574             }
575            
576            
577             =head2 Exports
578            
579             Export L, L
580            
581             =cut
582            
583            
584 6         44 use Math::Zap::Exports qw(
585             matrix2 ($$$$)
586             new2v ($$)
587             identity ()
588 6     6   3040 );
  6         13  
589            
590             #_ Matrix2 ____________________________________________________________
591             # Package loaded successfully
592             #______________________________________________________________________
593            
594             1;
595            
596            
597             =head2 Credits
598            
599             =head3 Author
600            
601             philiprbrenan@yahoo.com
602            
603             =head3 Copyright
604            
605             philiprbrenan@yahoo.com, 2004
606            
607             =head3 License
608            
609             Perl License.
610            
611            
612             =cut