File Coverage

blib/lib/Math/Symbolic/Custom/Matrix.pm
Criterion Covered Total %
statement 178 231 77.0
branch 34 70 48.5
condition 5 15 33.3
subroutine 21 27 77.7
pod 21 21 100.0
total 259 364 71.1


line stmt bran cond sub pod time code
1             package Math::Symbolic::Custom::Matrix;
2              
3 2     2   345016 use 5.006;
  2         15  
4 2     2   16 use strict;
  2         5  
  2         95  
5 2     2   12 use warnings;
  2         5  
  2         400  
6              
7             =pod
8              
9             =encoding utf8
10              
11             =head1 NAME
12              
13             Math::Symbolic::Custom::Matrix - Matrix routines for Math::Symbolic
14              
15             =head1 VERSION
16              
17             Version 0.21
18              
19             =cut
20              
21             require Exporter;
22              
23             our @ISA = qw(Exporter);
24             our @EXPORT = qw(
25             make_matrix
26             make_symbolic_matrix
27             identity_matrix
28             add_matrix
29             sub_matrix
30             multiply_matrix
31             scalar_multiply_matrix
32             scalar_divide_matrix
33             order_of_matrix
34             simplify_matrix
35             transpose_matrix
36             evaluate_matrix
37             implement_matrix
38             set_matrix
39             cofactors_matrix
40             adjugate_matrix
41             invert_matrix
42             is_square_matrix
43             is_equals_matrix
44             is_symmetric_matrix
45             is_skew_symmetric_matrix
46             );
47              
48             our $VERSION = '0.21';
49              
50 2     2   701 use Math::Symbolic qw(:all);
  2         140666  
  2         581  
51 2     2   693 use Math::Symbolic::MiscAlgebra qw/:all/;
  2         1497  
  2         264  
52              
53 2     2   17 use Carp;
  2         3  
  2         8424  
54              
55             =head1 DESCRIPTION
56              
57             Provides some routines for manipulating matrices of Math::Symbolic expressions. A matrix here is just a 2D array of
58             elements. Passing in matrices with elements which are not already Math::Symbolic objects will cause them to be
59             converted to Math::Symbolic objects.
60              
61             =head1 EXAMPLE
62              
63             use strict;
64             use Math::Symbolic 0.613 qw/:all/;
65             use Math::Symbolic::MiscAlgebra qw/:all/;
66             use Math::Symbolic::Custom::Matrix 0.2;
67             use Math::Symbolic::Custom::Polynomial 0.3;
68             use Math::Symbolic::Custom::CollectSimplify 0.2;
69             Math::Symbolic::Custom::CollectSimplify->register();
70              
71             # Say we want the eigenvalues of some matrix with a parameter.
72             # 1. A = | 4, 3-k |
73             # | 2, 3 |
74             my @matrix = ([4,'3-k'],[2,3]);
75             my $A = make_symbolic_matrix(\@matrix);
76              
77             # 2. get an identity matrix
78             my $I = identity_matrix(2);
79              
80             # 3. multiply it with lambda
81             my $lambda_I = scalar_multiply_matrix("lambda", $I);
82              
83             # 4. subtract it from matrix A
84             my $B = sub_matrix($A, $lambda_I);
85              
86             # 5. form the characteristic polynomial, |A-lambda*I|
87             my $c_poly = det(@{$B})->simplify();
88             print "Characteristic polynomial is: $c_poly\n";
89              
90             # 6. analyze the polynomial to get roots
91             my ($var, $coeffs, $disc, $roots) = $c_poly->test_polynomial('lambda');
92             print "Expressions for the roots are:\n\t$roots->[0]\n\t$roots->[1]\n";
93              
94             # 7. Check for some values of parameter k
95             foreach my $k (0..3) {
96             print "For k = $k: lambda_1 = ",
97             $roots->[0]->value('k' => $k), "; lambda_2 = ",
98             $roots->[1]->value('k' => $k), "\n";
99             }
100              
101             =head1 EXPORTS
102              
103             Everything below by default.
104              
105             =head2 make_matrix
106              
107             Creates a matrix of specified dimensions with every element set to the specified expression.
108              
109             use strict;
110             use Math::Symbolic qw/:all/;
111             use Math::Symbolic::Custom::Matrix;
112              
113             my $rows = 1;
114             my $cols = 2;
115             my $M = make_matrix('x', $rows, $cols);
116            
117             =cut
118              
119             sub make_matrix {
120 0     0 1 0 my ($scalar, $r, $c) = @_;
121            
122 0 0       0 $scalar = Math::Symbolic::parse_from_string($scalar) if ref($scalar) !~ /^Math::Symbolic/;
123            
124 0         0 my @m;
125 0         0 foreach my $i (0..$r-1) {
126 0         0 foreach my $j (0..$c-1) {
127 0         0 $m[$i][$j] = $scalar;
128             }
129             }
130            
131 0         0 return \@m;
132             }
133              
134             =head2 make_symbolic_matrix
135              
136             Pass in an array reference to a 2D matrix. This routine will call Math::Symbolic's
137             "parse_from_string()" function to convert any non-Math::Symbolic elements to Math::Symbolic
138             expressions.
139              
140             Returns an array reference to the resulting matrix.
141              
142             =cut
143              
144             sub make_symbolic_matrix {
145 169     169 1 1566183 my ($mat) = @_;
146              
147 169         503 my ($n_r, $n_c) = order_of_matrix($mat);
148              
149 169         306 my @sm;
150 169         554 foreach my $i (0..$n_r-1) {
151 459         1191 foreach my $j (0..$n_c-1) {
152 1264         2541 my $v = $mat->[$i][$j];
153 1264         1862 my $ov = $v;
154 1264 100       3359 if ( ref($ov) !~ /^Math::Symbolic/ ) {
155 659         2156 $ov = Math::Symbolic::parse_from_string($v);
156             }
157 1264         1250685 $sm[$i][$j] = $ov;
158             }
159             }
160              
161 169         751 return simplify_matrix(\@sm);
162             }
163              
164             =head2 identity_matrix
165              
166             Pass in the desired dimension of the (square) identity matrix.
167              
168             Returns an array reference to the resulting matrix (which will be composed of
169             Math::Symbolic constants 1 and 0 where appropriate).
170              
171             =cut
172              
173             sub identity_matrix {
174 17     17 1 70 my ($size) = @_;
175              
176 17         45 my @I;
177 17         59 foreach my $i (0..$size-1) {
178 45         346 foreach my $j (0..$size-1) {
179 125 100       1071 $I[$i][$j] = ($i == $j ? Math::Symbolic::Constant->new(1) : Math::Symbolic::Constant->new(0));
180             }
181             }
182              
183 17         274 return \@I;
184             }
185              
186             =head2 add_matrix
187              
188             Pass in two array references to the matrices to be added.
189              
190             Returns an array reference to the resulting matrix.
191              
192             =cut
193              
194             sub add_matrix {
195 1     1 1 14 my ($m_a, $m_b) = @_;
196              
197 1         4 my @ao = order_of_matrix($m_a);
198 1         2 my @bo = order_of_matrix($m_b);
199            
200 1 50 33     7 return undef unless ($ao[0] == $bo[0]) && ($ao[1] == $bo[1]);
201              
202 1         2 my @m_o;
203              
204 1         4 foreach my $i (0..$ao[0]-1) {
205 3         29 foreach my $j (0..$ao[1]-1) {
206              
207 9         94 my $a_val = $m_a->[$i][$j];
208 9         10 my $b_val = $m_b->[$i][$j];
209              
210             # if one of them (but not the other) is a Math::Symbolic object, then promote the not-Math::Symbolic value
211 9 50       16 $a_val = Math::Symbolic::parse_from_string($a_val) if ref($a_val) !~ /^Math::Symbolic/;
212 9 50       17 $b_val = Math::Symbolic::parse_from_string($b_val) if ref($b_val) !~ /^Math::Symbolic/;
213              
214 9         12 $m_o[$i][$j] = Math::Symbolic::Operator->new('+', $a_val, $b_val);
215             }
216             }
217              
218 1         14 return simplify_matrix(\@m_o);
219             }
220              
221             =head2 sub_matrix
222              
223             Pass in two array references to the matrices. Subtracts the second matrix from the first.
224              
225             Returns an array reference to the resulting matrix.
226              
227             =cut
228              
229             sub sub_matrix {
230 2     2 1 9 my ($m_a, $m_b) = @_;
231              
232 2         7 my @ao = order_of_matrix($m_a);
233 2         7 my @bo = order_of_matrix($m_b);
234            
235 2 50 33     20 return undef unless ($ao[0] == $bo[0]) && ($ao[1] == $bo[1]);
236              
237 2         6 my @m_o;
238              
239 2         30 foreach my $i (0..$ao[0]-1) {
240 6         112 foreach my $j (0..$ao[1]-1) {
241              
242 18         390 my $a_val = $m_a->[$i][$j];
243 18         36 my $b_val = $m_b->[$i][$j];
244              
245 18 50       61 $a_val = Math::Symbolic::parse_from_string($a_val) if ref($a_val) !~ /^Math::Symbolic/;
246 18 50       51 $b_val = Math::Symbolic::parse_from_string($b_val) if ref($b_val) !~ /^Math::Symbolic/;
247              
248 18         59 $m_o[$i][$j] = Math::Symbolic::Operator->new('-', $a_val, $b_val);
249             }
250             }
251              
252 2         57 return simplify_matrix(\@m_o);
253             }
254              
255             =head2 multiply_matrix
256              
257             Pass in array references to two matrices.
258              
259             Returns an array reference to the matrix resulting from multiplying first matrix
260             by the second.
261              
262             =cut
263              
264             sub multiply_matrix {
265 23     23 1 130 my ($m_a, $m_b) = @_;
266              
267 23         121 $m_a = make_symbolic_matrix($m_a);
268 23         98 $m_b = make_symbolic_matrix($m_b);
269              
270 23         125 my ($m_a_rows, $m_a_cols) = order_of_matrix($m_a);
271 23         62 my ($m_b_rows, $m_b_cols) = order_of_matrix($m_b);
272              
273 23 50       110 return undef unless $m_a_cols == $m_b_rows;
274            
275 23         85 my @m_o;
276 23         75 foreach my $i (0..$m_a_rows-1) {
277 62         143 foreach my $j (0..$m_b_cols-1) {
278 163         212 my $m_o_ij;
279 163         284 foreach my $k (0..$m_a_cols-1) {
280 477 100       8050 if ( defined $m_o_ij ) {
281 314         679 $m_o_ij = Math::Symbolic::Operator->new('+', $m_o_ij, Math::Symbolic::Operator->new('*', $m_a->[$i][$k], $m_b->[$k][$j]));
282             }
283             else {
284 163         420 $m_o_ij = Math::Symbolic::Operator->new('*', $m_a->[$i][$k], $m_b->[$k][$j]);
285             }
286             }
287 163         5249 $m_o[$i][$j] = $m_o_ij;
288             }
289             }
290            
291 23         94 return simplify_matrix(\@m_o);
292             }
293              
294             =head2 scalar_multiply_matrix
295              
296             This routine will multiply every element of a matrix by a single expression.
297              
298             Pass in the expression and an array reference to the matrix.
299              
300             Returns an array reference to the resulting matrix.
301              
302             =cut
303              
304             sub scalar_multiply_matrix {
305 35     35 1 119 my ($scalar, $mat) = @_;
306            
307 35 50       152 $scalar = Math::Symbolic::parse_from_string($scalar) if ref($scalar) !~ /^Math::Symbolic/;
308 35         211 $mat = make_symbolic_matrix($mat);
309              
310 35         197 my ($n_r, $n_c) = order_of_matrix($mat);
311              
312 35         67 my @sm;
313 35         172 foreach my $i (0..$n_r-1) {
314 94         1314 foreach my $j (0..$n_c-1) {
315 262         4048 my $m_val = $mat->[$i][$j];
316 262         612 $sm[$i][$j] = Math::Symbolic::Operator->new('*', $scalar, $m_val);
317             }
318             }
319              
320 35         786 return simplify_matrix(\@sm);
321             }
322              
323             =head2 scalar_divide_matrix
324              
325             This routine will produce an output matrix where every element is the input
326             expression divided by every corresponding non-zero element of the input matrix.
327             Elements which are zero are left untouched.
328              
329             Pass in the expression and an array reference to the matrix.
330              
331             Returns an array reference to the resulting matrix.
332              
333             =cut
334              
335             sub scalar_divide_matrix {
336 0     0 1 0 my ($scalar, $mat) = @_;
337            
338 0 0       0 $scalar = Math::Symbolic::parse_from_string($scalar) if ref($scalar) !~ /^Math::Symbolic/;
339 0         0 $mat = make_symbolic_matrix($mat);
340              
341 0         0 my ($n_r, $n_c) = order_of_matrix($mat);
342              
343 0         0 my @sm;
344 0         0 foreach my $i (0..$n_r-1) {
345 0         0 foreach my $j (0..$n_c-1) {
346 0         0 my $m_val = $mat->[$i][$j];
347 0         0 my $m_val_v = $m_val->value();
348 0 0 0     0 if ( defined($m_val_v) && ($m_val_v == 0) ) {
349 0         0 $sm[$i][$j] = Math::Symbolic::Constant->new(0);
350             }
351             else {
352 0         0 $sm[$i][$j] = Math::Symbolic::Operator->new('/', $scalar, $m_val);
353             }
354             }
355             }
356              
357 0         0 return simplify_matrix(\@sm);
358             }
359              
360             =head2 order_of_matrix
361              
362             Pass in an array reference to a matrix.
363              
364             This routine will return the number of rows and columns in the matrix. For example:-
365              
366             use strict;
367             use Math::Symbolic qw/:all/;
368             use Math::Symbolic::Custom::Matrix;
369              
370             my $A = make_symbolic_matrix([[1,2],[3,4],[5,6]]);
371             my ($r, $c) = order_of_matrix($A);
372             print "($r, $c)\n"; # (3, 2)
373              
374             =cut
375              
376             sub order_of_matrix {
377 867     867 1 1490 my ($mat) = @_;
378              
379 867         1250 my $rows = scalar(@{$mat});
  867         1666  
380 867         1259 my $cols;
381 867         1474 foreach my $row (@{$mat}) {
  867         1685  
382 2351         3159 my $c = scalar(@{$row});
  2351         3207  
383 2351 100       3971 if ( defined $cols ) {
384 1484 50       3478 if ( $c != $cols ) {
385 0         0 carp "order_of_matrix: Matrix is malformed!";
386 0         0 return undef;
387             }
388             }
389             else {
390 867         1471 $cols = $c;
391             }
392             }
393              
394 867         2158 return ($rows, $cols);
395             }
396              
397             =head2 simplify_matrix
398              
399             This will call "simplify()" on every element of the matrix,
400             in an effort to tidy it up.
401              
402             Pass in an array reference to the matrix.
403              
404             Returns an array reference to the resulting matrix.
405              
406             =cut
407              
408             sub simplify_matrix {
409 349     349 1 1018 my ($mat) = @_;
410              
411 349         979 my ($n_r, $n_c) = order_of_matrix($mat);
412              
413 349         622 my @sm;
414 349         987 foreach my $i (0..$n_r-1) {
415 948         2165 foreach my $j (0..$n_c-1) {
416              
417 2610         5563 my $m_val = $mat->[$i][$j];
418              
419 2610 50       8196 $m_val = Math::Symbolic::parse_from_string($m_val) if ref($m_val) !~ /^Math::Symbolic/;
420              
421 2610 50       7224 if ( defined(my $m_val_s = $m_val->simplify()) ) {
422              
423 2610         2268005 $sm[$i][$j] = $m_val_s;
424             }
425             else {
426              
427 0         0 carp "simplify_matrix: Could not simplify!: $m_val";
428 0         0 $sm[$i][$j] = $m_val;
429             }
430             }
431             }
432            
433 349         6250 return \@sm;
434             }
435              
436             =head2 transpose_matrix
437              
438             Pass in an array reference to a matrix.
439              
440             Returns an array reference to the resulting transposed matrix.
441              
442             =cut
443              
444             sub transpose_matrix {
445 35     35 1 118 my ($mat) = @_;
446              
447 35 50       108 return undef unless defined $mat;
448              
449 35         140 my ($n_r, $n_c) = order_of_matrix($mat);
450 35         78 my @t;
451              
452 35         113 foreach my $i (0..$n_r-1) {
453 94         172 foreach my $j (0..$n_c-1) {
454 262         422 my $v = $mat->[$i][$j];
455 262 50       464 return undef unless defined $v;
456 262         518 $t[$j][$i] = $v;
457             }
458             }
459              
460 35         98 return \@t;
461             }
462              
463             =head2 evaluate_matrix
464              
465             This will call Math::Symbolic's "value()" method on each element
466             of the passed matrix.
467              
468             Pass in an array reference to a matrix, and a hash ref which will be
469             passed in as the parameters to the "value()" method.
470              
471             Returns an array reference to the resulting matrix.
472              
473             =cut
474              
475             sub evaluate_matrix {
476 3     3 1 9 my ($mat, $vals) = @_;
477 3         9 my %vals = %{$vals};
  3         10  
478              
479 3         13 my ($n_r, $n_c) = order_of_matrix($mat);
480              
481 3         7 my @vm;
482 3         12 foreach my $i (0..$n_r-1) {
483 7         2177 foreach my $j (0..$n_c-1) {
484 17         8021 my $v = $mat->[$i][$j];
485 17 50       53 if ( ref($v) =~ /^Math::Symbolic/ ) {
486 17         44 $vm[$i][$j] = $v->value(%vals);
487             }
488             }
489             }
490              
491 3         2658 return \@vm;
492             }
493              
494             =head2 implement_matrix
495              
496             This will call Math::Symbolic's "implement()" method on each element
497             of the passed matrix.
498              
499             Pass in an array reference to a matrix, and a hash ref which will be
500             passed in as the parameters to the "implement()" method.
501              
502             Returns an array reference to the resulting matrix.
503              
504             =cut
505              
506             sub implement_matrix {
507 0     0 1 0 my ($mat, $vals) = @_;
508 0         0 my %vals = %{$vals};
  0         0  
509              
510 0         0 my ($n_r, $n_c) = order_of_matrix($mat);
511              
512 0         0 my @vm;
513 0         0 foreach my $i (0..$n_r-1) {
514 0         0 foreach my $j (0..$n_c-1) {
515 0         0 my $v = $mat->[$i][$j];
516 0 0       0 if ( ref($v) =~ /^Math::Symbolic/ ) {
517 0         0 $vm[$i][$j] = $v->implement(%vals);
518             }
519             }
520             }
521              
522 0         0 return \@vm;
523             }
524              
525             =head2 set_matrix
526              
527             This will call Math::Symbolic's "set_value()" method on each element
528             of the passed matrix.
529              
530             Pass in an array reference to a matrix, and a hash ref which will be
531             passed in as the parameters to the "set_value()" method.
532              
533             Returns an array reference to the resulting matrix.
534              
535             =cut
536              
537             sub set_matrix {
538 0     0 1 0 my ($mat, $vals) = @_;
539 0         0 my %vals = %{$vals};
  0         0  
540              
541 0         0 my ($n_r, $n_c) = order_of_matrix($mat);
542              
543 0         0 my @vm;
544 0         0 foreach my $i (0..$n_r-1) {
545 0         0 foreach my $j (0..$n_c-1) {
546 0         0 my $v = $mat->[$i][$j];
547 0 0       0 if ( ref($v) =~ /^Math::Symbolic/ ) {
548 0         0 $vm[$i][$j] = $v->set_value(%vals);
549             }
550             }
551             }
552              
553 0         0 return \@vm;
554             }
555              
556             =head2 cofactors_matrix
557              
558             Pass in an array reference to a matrix.
559              
560             Returns an array reference to the resulting cofactors matrix.
561              
562             =cut
563              
564             sub cofactors_matrix {
565 35     35 1 100 my ($mat) = @_;
566              
567 35 50       87 return undef unless is_square_matrix($mat);
568              
569 35         97 my ($n_r, $n_c) = order_of_matrix($mat);
570              
571 35         63 my @cofactors;
572 35         123 foreach my $i (0..$n_r-1) {
573 94         2111 foreach my $j (0..$n_c-1) {
574            
575             # calculate minor matrix
576 262         5896 my @minor;
577 262         367 my $x_i = 0;
578 262         536 X_LOOP: foreach my $x (0..$n_r-1) {
579 754 100       1529 next X_LOOP if $x == $i;
580 492         633 my $y_i = 0;
581 492         808 Y_LOOP: foreach my $y (0..$n_c-1) {
582 1476 100       2496 next Y_LOOP if $y == $j;
583 984         1634 $minor[$x_i][$y_i] = $mat->[$x][$y];
584 984         1296 $y_i++;
585             }
586 492         652 $x_i++;
587             }
588              
589             # calculate determinant of that
590 262         723 my $minor = det @minor;
591              
592 262         28955 my $sign = (-1)**($i+$j);
593            
594 262         705 $cofactors[$i][$j] = Math::Symbolic::Operator->new('*', Math::Symbolic::Constant->new($sign), $minor);
595             }
596             }
597              
598 35         1371 return \@cofactors;
599             }
600              
601             =head2 adjugate_matrix
602              
603             Pass in an array reference to a matrix.
604              
605             Returns an array reference to the adjugate of the matrix.
606              
607             =cut
608              
609             sub adjugate_matrix {
610 35     35 1 104 my ($mat) = @_;
611              
612 35 50       99 return undef unless is_square_matrix($mat);
613              
614 35         166 return transpose_matrix(cofactors_matrix($mat));
615             }
616              
617             =head2 invert_matrix
618              
619             Will attempt to invert the passed in matrix. Requires the
620             determinant to be non-zero; of course if the matrix has variables
621             then that won't necessarily be known until using the inverted
622             matrix later.
623              
624             Pass in an array reference to a matrix.
625              
626             Returns an array reference to the inverted matrix.
627              
628             =cut
629            
630             sub invert_matrix {
631 35     35 1 101 my ($mat) = @_;
632              
633 35 50       142 return undef unless is_square_matrix($mat);
634              
635             # the determinant
636 35         62 my $det = det @{$mat};
  35         268  
637 35         16686 my $s_det = $det->simplify();
638              
639 35         106721 my $s_det_v = $s_det->value();
640 35 50 66     2238 return undef if defined($s_det_v) && ($s_det_v == 0);
641              
642 35         124 my $one = Math::Symbolic::Constant->new(1);
643 35         561 my $det_reciprocal = Math::Symbolic::Operator->new('/', $one, $s_det);
644              
645             # the adjugate
646 35         992 my $adj = adjugate_matrix($mat);
647 35 50       169 return undef unless defined $adj;
648              
649             # complete the inversion
650 35         154 my $inv = scalar_multiply_matrix($det_reciprocal, $adj);
651            
652 35         737 return simplify_matrix($inv);
653             }
654              
655             =head2 is_square_matrix
656              
657             Pass in an array ref to a matrix.
658              
659             Returns 1 if the matrix is square, 0 otherwise.
660              
661             =cut
662              
663             sub is_square_matrix {
664 105     105 1 197 my ($mat) = @_;
665              
666 105         240 my ($r, $c) = order_of_matrix($mat);
667 105 50       489 return 1 if $r == $c;
668 0         0 return 0;
669             }
670              
671             =head2 is_equals_matrix
672              
673             Pass in two array references for the matrices to compare.
674              
675             Returns 1 if the matrices are equal (in terms of string expression),
676             0 otherwise.
677              
678             =cut
679              
680             sub is_equals_matrix {
681 42     42 1 150 my ($m_a, $m_b) = @_;
682              
683 42         165 my @ao = order_of_matrix($m_a);
684 42         122 my @bo = order_of_matrix($m_b);
685            
686 42 50 33     328 return 0 unless ($ao[0] == $bo[0]) && ($ao[1] == $bo[1]);
687              
688 42         176 my $a_s = simplify_matrix($m_a);
689 42         141 my $b_s = simplify_matrix($m_b);
690              
691 42         152 foreach my $i (0..$ao[0]-1) {
692 115         3076 foreach my $j (0..$ao[1]-1) {
693             # FIXME: is_identical() (?)
694 316 50       7450 return 0 unless $m_a->[$i][$j]->to_string() eq $m_b->[$i][$j]->to_string();
695             }
696             }
697              
698 42         2703 return 1;
699             }
700              
701             =head2 is_symmetric_matrix
702              
703             Pass in an array reference to a matrix.
704              
705             Returns 1 if the matrix is symmetric, 0 otherwise.
706              
707             =cut
708              
709             sub is_symmetric_matrix {
710 0     0 1   my ($mat) = @_;
711              
712 0 0         return 0 unless is_square_matrix($mat);
713 0           return is_equals_matrix($mat, transpose_matrix($mat));
714             }
715              
716             =head2 is_skew_symmetric_matrix
717              
718             Pass in an array reference to a matrix.
719              
720             Returns 1 if the matrix is skew-symmetric, 0 otherwise.
721              
722             =cut
723              
724             sub is_skew_symmetric_matrix {
725 0     0 1   my ($mat) = @_;
726              
727 0 0         return 0 unless is_square_matrix($mat);
728 0           return is_equals_matrix($mat, simplify_matrix(scalar_multiply_matrix(-1, transpose_matrix($mat))) );
729             }
730              
731             =head1 SEE ALSO
732              
733             L
734              
735             =head1 AUTHOR
736              
737             Matt Johnson, C<< >>
738              
739             =head1 ACKNOWLEDGEMENTS
740              
741             Steffen Mueller, author of Math::Symbolic
742              
743             =head1 LICENSE AND COPYRIGHT
744              
745             This software is copyright (c) 2024 by Matt Johnson.
746              
747             This is free software; you can redistribute it and/or modify it under
748             the same terms as the Perl 5 programming language system itself.
749              
750             =cut
751              
752              
753             1;
754             __END__