Bad matrix inversion algorithm, or implemented incorrectly? - perl

Trying to implement matrix inversion in Perl myself, I found An Efficient and Simple Algorithm for Matrix Inversion (only two pages of the article).
After my attempt to implement it in Perl, I see that it does not work.
I had spend a lot of time trying to find out what's wrong, so I concluded that
either the algorithm is not correct
I misinterpreted the algorithm
my implementation is not correct
Before presenting the code, here's a debug session with an example from Wikipedia: Inverse Matrix:
DB<229> $m=[[2,5],[1,3]]
DB<230> x invert($m)
pe[0] == 2
(pivot row 0) 2x2:
2.000 2.500
1.000 3.000
(pivot column 0) 2x2:
2.000 2.500
-0.500 3.000
(rest 0) 2x2:
2.000 2.500
-0.500 1.750
(pivot 0) 2x2:
0.500 2.500
-0.500 1.750
pe[1] == 1.75
(pivot row 1) 2x2:
0.500 2.500
-0.286 1.750
(pivot column 1) 2x2:
0.500 -1.429
-0.286 1.750
(rest 1) 2x2:
0.908 -1.429
-0.286 1.750
(pivot 1) 2x2:
0.908 -1.429
-0.286 0.571
0 1
1 3.5
DB<231>
So here's the code I wrote:
#!/usr/bin/perl -w
use 5.026;
use strict;
# invert matrix
# An Efficient and Simple Algorithm for Matrix Inversion
# Ahmad Farooq, King Khalid University, Saudi Arabia
# Khan Hamid, National University of Computer and Emerging Sciences (NUCES),
# Pakistan
sub invert($)
{
my $m = shift; # matrix is an array of rows
my ($pp, $det);
my ($rp, $pe);
my $n = scalar(#$m);
for ($pp = 0, $det = 1.0; $pp < $n; ++$pp) {
$rp = $m->[$pp]; # pivot row
$pe = $rp->[$pp]; # pivot element
print "pe[$pp] == $pe\n";
last if ($pe == 0); # Epsilon test?
$det *= $pe;
# calculate pivot row
for (my $j = 0; $j < $n; ++$j) {
next if ($j == $pp);
$rp->[$j] /= $pe;
}
pm($m, "pivot row $pp");
# calculate pivot column
for (my $i = 0; $i < $n; ++$i) {
next if ($i == $pp);
$m->[$i]->[$pp] /= -$pe;
}
pm($m, "pivot column $pp");
for (my $j = 0; $j < $n; ++$j) {
next if ($j == $pp);
for (my ($i, $rj) = (0, $m->[$j]); $i < $n; ++$i) {
next if ($i == $pp);
$rj->[$i] += $rp->[$j] * $m->[$i]->[$pp];
}
}
pm($m, "rest $pp");
$rp->[$pp] = 1.0 / $pe;
pm($m, "pivot $pp");
}
return ($pe != 0.0, $det);
}
The pm() function is just a "print matrix" for debugging purposes:
# print matrix
sub pm($;$)
{
my ($m, $label) = #_;
my $n = scalar(#$m);
print "($label) " if ($label);
print "${n}x${n}:\n";
for (my $i = 0; $i < $n; ++$i) {
for (my $j = 0; $j < $n; ++$j) {
if (defined(my $v = $m->[$i]->[$j])) {
printf('%8.3f', $v);
} else {
print ' ???????';
}
}
print "\n";
}
}
Any insights?
Hint for Reproduction (added 2019-08-28)
I had thought it was obvious, but just in case:
If you want to reproduce the output shown in the debug session, maybe just add these two lines at the end of the code:
my $m=[[2,5],[1,3]]; # matrix to invert
print join(', ', invert($m)), "\n"; # invert $m, printing result
Note (added 2019-09-02):
The algorithm fails for the 3x3 matrix given in the Wikipedia article ($m = [[1, 2, 0], [2, 4, 1], [2, 1, 0]]), so real implementations should head towards the improved algorithm (that can select pivot elements outside the diagonal).

When in doubt, write tests.
First, put your code into a module (lib/My/Matrix.pm or whatever you want to call it):
package My::Matrix; # this must match the file name
use strict;
use warnings;
use Exporter qw(import);
our #EXPORT_OK = qw( invert pm );
# your code here ...
1; # at end of module
There is a lot of documentation regarding writing modules, not sure if perldoc perlmod is a good starting point.
Now write a test - documentation is here (t/001-invert.t):
#!perl
use strict;
use warnings;
use Test::More;
use Matrix qw(invert);
ok_invert( [[1,0], [0,1]], [[1,0], [0,1]], "unit matrix" );
# insert more matrices here
done_testing;
sub ok_invert {
my ($input, $output, $msg) = #_;
invert( $output );
is_deeply $input, $output, $msg
or diag "got: ", explain $input, "expected: ", explain $output;
};
Run the test as perl -Ilib t/001-invert.t or prove -Ilib t if you want to run multiple tests.
You can now add simple corner cases to the test until the problem is isolated.
Of course, finding the correct inverse matrix by hand is tedious, so you may want to use multiplication instead. So the next steps to improve your code would be:
make sure invert does not modify its input and returns the inverted matrix instead;
Sidenote. It's generally a good idea to make sure a function returns the desired value and does not modify its arguments. It's not always possible but when it is, it saves a ton of debugging time.
implement multiplication;
implement is_unit_matrix check;
rewrite the test function as follows (the next snippet was not tested):
sub ok_invert {
my ($input, $msg) = #_;
my ($invert, $det) = invert( $input );
ok is_unit_matrix( multiply( $invert, $input ) ), $msg
or diag explain $invert, " is not the inverse of ", explain $input;
}
Hope this helps.

The pseudocode in the original paper is not correct.
Steps I have done so far:
inserted the pseudocode into the Perl source
used the naming of the pseudocode
test cases
tested the test cases
tested with Math::Matrix as a reference
reviewed (many times)
At least I read the note in paper:
Note that in step 7 of the following algorithm a'[i, p]
on the LHS means that the latest value of the pivot row
is to be used in the calculations.
This note is not really precise. After additional attempts I gave up, wanted to post my findings here, and read the answer of Håkon Hægland. Yes, his solution works and he earns the honor.
If the steps in the pseudocode are reordered it passes my 3 tests:
Step 1
Step 2
Step 3
Step 4
Step 6
Step 7
Step 5
Step 8
Step 9
Step 10
Here is the version with pseudocode included and using the original naming:
sub invert_corr($) {
my $A = shift; # matrix is an array of rows
my $n = scalar(#$A);
# Step 1: Let p = 0, d = 1;
my $p = 0;
my $det;
# Step 2: p <= p +1
for (my $pi = 0,$det = 1.0; $pi < $n; ++$pi) {
$p = $pi;
# Step 3: If a[p,p] == 0 then cannot calculate inverse, go to step 10.
if ($A->[$p]->[$p] == 0) { last; }
# Step 4: d <= d x a[p, p]
$det = $det * $A->[$p]->[$p];
# Step 6: Calculate the new elements of the pivot column by:
# a_new[i,p] <= -(a[i,p] / a[p,p]) where i = 1 .. n, i != p
STEP6: for (my $i = 0; $i < $n; ++$i) {
if ($i == $p) { next STEP6; }
$A->[$i]->[$p] = -($A->[$i]->[$p] / $A->[$p]->[$p]);
}
# Step 7: Calculate the rest of the new elements by:
# a_new[i,j] <= a[i,j] + a[p,j] x a_new[i,p]
# where i = 1 .. n, j = 1 .. n, & i,j != p
OUTER7: for (my $i = 0; $i < $n; ++$i) {
if ($i == $p) { next OUTER7; }
INNER7: for (my $j = 0; $j < $n; ++$j) {
if ($j == $p) { next INNER7; }
# Note that in step 7 of the following algorithm a'[i, p]
# on the LHS means that the latest value of the pivot row
# is to be used in the calculations.
$A->[$i]->[$j] = $A->[$i]->[$j] + $A->[$p]->[$j] * $A->[$i]->[$p];
}
}
# Step 5: Calculate the new elements of the pivot row by:
# a_new[p,j] <= a[p,j] / a[p,p] where j = 1 .. n, j != p
STEP5: for (my $j = 0; $j < $n; ++$j) {
# next if ($j == $p);
if ($j == $p) { next STEP5; }
$A->[$p]->[$j] = $A->[$p]->[$j] / $A->[$p]->[$p];
}
# Step 8: Calculate the new value of the current pivot location:
# a_new[p,p] <= 1 / a_new[p,p]
$A->[$p]->[$p] = 1.0 / $A->[$p]->[$p];
# Step 9: If p < n go to step 2 (n the dimension of the matrix A).
}
# Step 10: Stop. If inverse exists, A contains the inverse and d is the determinant.
if ($A->[$p]->[$p] != 0.0) {
return ($A->[$p]->[$p] != 0.0, $det, $A);
}
return ($A->[$p]->[$p] != 0.0);
}
The complete code including tests is available on github, maybe useful for debugging.

According to the referred to paper, step #7 should be computed with the old pivot row values, so the following seems to work for me:
sub invert($)
{
my $m = shift; # matrix is an array of rows
my ($pp, $det);
my ($rp, $pe);
my $n = scalar(#$m);
for ($pp = 0, $det = 1.0; $pp < $n; ++$pp) {
$rp = $m->[$pp]; # pivot row
$pe = $rp->[$pp]; # pivot element
last if ($pe == 0); # Epsilon test?
$det *= $pe;
# calculate pivot column
for (my $i = 0; $i < $n; ++$i) {
next if ($i == $pp);
$m->[$i][$pp] /= -$pe;
}
for (my $j = 0; $j < $n; ++$j) { # row index
next if ($j == $pp);
for (my ($i, $rj) = (0, $m->[$j]); $i < $n; ++$i) {
next if ($i == $pp);
$rj->[$i] += $rp->[$i] * $m->[$j]->[$pp];
}
}
# calculate pivot row
for (my $j = 0; $j < $n; ++$j) {
next if ($j == $pp);
$rp->[$j] /= $pe;
}
$rp->[$pp] = 1.0 / $pe;
}
return ($pe != 0.0, $det);
}
Fix required to match result in Wikipedia:
--- newinvert.pl~ 2019-08-29 21:22:16.135160055 +0200
+++ newinvert.pl 2019-08-29 21:32:10.995144732 +0200
## -20,7 +20,7 ##
next if ($j == $pp);
for (my ($i, $rj) = (0, $m->[$j]); $i < $n; ++$i) {
next if ($i == $pp);
- $rj->[$i] += $rp->[$i] * $m->[$j]->[$pp];
+ $rj->[$i] += $rp->[$j] * $m->[$i]->[$pp];
}
}
# calculate pivot row
Sample session (inluding my pm()):
> perl -d printmatrix.pl
Loading DB routines from perl5db.pl version 1.51
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(printmatrix.pl:20): 1;
DB<1> require "./newinvert.pl" # this is ungly, forgive!
./newinvert.pl did not return a true value at (eval 6)[/usr/lib/perl5/5.26.1/perl5db.pl:738] line 2.
DB<2> $m=[[2,5],[1,3]]
DB<4> pm($m)
2x2:
2.000 5.000
1.000 3.000
DB<5> x invert($m)
0 1
1 1
DB<6> pm($m)
2x2:
3.000 -5.000
-1.000 2.000
Result of regression tests:
# https://github.com/wollmers/matrix-inverse-Farooq/blob/master/matrix_inversion_new.pl
$ perl matrix_inversion_new.pl
[...]
(invert_hakon 01_wiki input $A) 2x2:
2.000 5.000
1.000 3.000
(invert_hakon 01_wiki result $C) 2x2:
3.000 -5.000
-1.000 2.000
ok 10 - 01_wiki invert_hakon Ainv
ok 11 - 01_wiki invert_hakon det: 1
(invert_hakon 02_wiki input $A) 2x2:
2.000 3.000
1.000 2.000
(invert_hakon 02_wiki result $C) 2x2:
2.000 -3.000
-1.000 2.000
ok 12 - 02_wiki invert_hakon Ainv
ok 13 - 02_wiki invert_hakon det: 1
(invert_hakon 03_author_1 input $A) 3x3:
1.000 1.000 3.000
1.000 3.000 -3.000
-2.000 -4.000 -4.000
(invert_hakon 03_author_1 result $C) 3x3:
3.000 1.000 1.500
-1.250 -0.250 -0.750
-0.250 -0.250 -0.250
ok 14 - 03_author_1 invert_hakon Ainv
ok 15 - 03_author_1 invert_hakon det: -8
[...]

One of the problems when implementing a mathematical formula like (actually from Step 5)
in a loop is: When will the "new" a' become the "old" a?
Before the next step, before the next assignment, or before the next loop iteration?
In a mathematical sense a' and a are different variables all the time, but in procedural programming languages the memory address for a is reused at some time.
So the assignments from Step 5 need to be delayed after Step 7 (), it seems.
As a computer scientist I had always felt that mathematical algorithms are described in a somewhat imprecise way. Maybe that's exactly the reason why programming languages were invented ;-)

Related

How can I modify my program to print out Pascal's triangle?

So first of all Pascal's Triangle looks like this:
The first row that you see is the zero-ith row.
That's nothing unusual
when you are a computer scientist.
Each term in Pascal's triangle can be predicted with a combination with the formula:
C(n, k) = n! / [k! * (n - k)!], where "n" is the row and "k" is any integer from zero to n.
So thus it follows that Pascal's triangle can be predicted with (n, k) combinations:
And that's what you are seeing in the figure above.
Pascal's triangle is basically binomial probability:
(H + T)^n # You flip a two sided coin "n" times and it lands on "heads" or "tails" and you collect the frequency of each in a set of coefficients, for n = 3, we get the expansion:
(H + T)^3 = 1(H^3) + 3(H^2)(T) + 3(H)(T^2) + 1(T^3), where those coefficients:
1, 3, 3, 1 are in row 3 of Pascal's triangle.
I defined a factorial (!), and a combination and was able to get the
coefficient numbers on any row of Pascal's triangle with some looping Perl code:
use strict;
use warnings;
# Note the first row is row 0.
print("\nWhich row of Pascal's triangle to display: ");
my $row = <STDIN>; # The row that you want to display # This is also n.
my $terms = $row + 1; # The number of terms is one more than the row number.
Pascal_Row($row); # Print the Pascal numbers for that row.
# Function displays the numbers for a row of Pascal's triangle.
#######################################################
sub Pascal_Row
{
my $row = shift; # Row is passed in.
for(my $k = 0; $k < $row + 1; $k++) # k alternates, but not the row which is n.
{
print(combination($row, $k), "\t") # Print each row.
}
print("\n"); # Print a newline after each time this function is called.
}
# This computes the factorial of a number.
###########################################
sub factorial
{
my $number = shift; # argument.
my $factorial_number = 1; # initalize the factorial.
for(my $i = 1; $i <= $number; $i++)
{
$factorial_number *= $i; # compute the factorial, by multiplying all terms up to and including number.
}
return $factorial_number; # Return the factorial number.
}
# Computes a matehmatical combination usually denoted as C(n, k)
# where n is the row number, and k is each item in a row of Pascal's traingle
sub combination
{
my($n, $k) = #_; # from input.
# This is the mathematical formula for a combination.
my $combination_number = factorial($n) / (factorial($k) * factorial($n - $k));
return $combination_number # And returning it.
}
If I run the code and ask for row 8 of Pascal's triangle I get this:
Which row of Pascal's triangle to display: 8
1 8 28 56 70 56 28 8 1
That's entirely true for row 8 of Pascal's triangle. If I were to loop this from row 0 to the row 8 of Pascal's triangle I would get all correct rows of Pascal's triangle, but it wouldn't look like a triangle (it would look more like a box), so how could I modify my code to adjust the indenting.
How do I decide how much to indent the first row if I want 8 rows of Pascal's triangle displayed? How can I make a "triangle"?
Left-aligned triangle:
my $MAX_VAL_SIZE = 5;
for my $n (0...$N) {
my #row;
for my $k (0..$n) {
push #row, C($n, $k);
}
say join " ", map sprintf("%*d", $MAX_VAL_SIZE, $_), #row;
}
Centered triangle:
sub center {
my ($n, $s) = #_;
my $pad_len = $n - length($s);
my $pad_len_l = int($pad_len/2);
my $pad_len_r = $pad_len - $pad_len_l;
return ( " " x $pad_len_l ) . $s . ( " " x $pad_len_r );
}
my $MAX_VAL_SIZE = 5;
for my $n (0...$N) {
my #row;
for my $k (0..$n) {
push #row, C($n, $k);
}
my $row = join " ", map center($MAX_VAL_SIZE, $_), #row;
say center(($N+1)*($MAX_VAL_SIZE+2)-2, $row);
}
This is tricky since the varying width of numbers matters for layout.
Each row need be indented by half the separation between numbers in the row, suitably multiplied (zero for last row, rows-1 for first) -- that is, if numbers themselves were all of equal width.
But this isn't the case, except for the first few rows; the numbers take varying amount of space. One remedy is to use fixed-width for numbers and adjust indent and separation using that width.
All rows are computed first so that the maximum width of a number can be found.
use warnings;
use strict;
use feature 'say';
use List::Util qw(max);
my $max_row = (shift || 8);
my #rows = map { pascal_row($_) } 0..$max_row-1;
my $max_num_wd = max map { length } #{$rows[-1]};
my $pad = 1; # choice (must be non-zero)
my $sep = ' ' x ($max_num_wd + 2*$pad);
my $lead_sp = ' ' x ($max_num_wd + $pad);
for my $n (0..$#rows) {
say $lead_sp x ($max_row-1-$n),
join $sep, map { sprintf "%${max_num_wd}d", $_ } #{$rows[$n]};
}
sub pascal_row {
my ($row) = #_;
return [ map { n_over_k($row, $_) } 0..$row ];
}
sub n_over_k {
my ($n, $k) = #_;
return factorial($n) / (factorial($k) * factorial($n - $k));
}
sub factorial {
my ($n) = #_;
my $fact = 1;
$fact *= $_ for 2..$n;
return $fact;
}
This prints the correct layout. The $pad is an arbitrary integer for extra space over the maximum number width, for indent and separation; it must be >0 to coordinate them. (Separation needs that space both left and right of the centered number in the row above, thus the factor of 2.)
Original code, printing as it computes so $max_num_wd is set ahead by hand
# (includes and subs same as above except for List::Util)
my $max_row = (shift || 8);
my $max_num_wd = 4; # maximum width of numbers
my $pad = 1; # choice (non-zero)
my $sep = ' ' x ($max_num_wd + 2*$pad);
my $lead_sp = ' ' x ($max_num_wd + $pad);
for my $n (0..$max_row-1) {
my #row = #{ pascal_row($n) };
say $lead_sp x ($max_row-1-$n),
join $sep, map { sprintf "%${max_num_wd}d", $_ } #row;
}
This prints a correct layout with numbers up to 4-digits wide, or $max_num_wd need be adjusted.
Here is another way of doing it:
use strict;
use warnings;
sub fact {
my $n = shift;
return 1 if $n < 1;
return $n * fact($n - 1);
}
sub n_over_k {
my $n = shift;
my $k = shift;
return fact($n) / ( fact($k) * fact($n - $k) );
}
sub pascal_row {
my $n = shift;
return map { n_over_k($n - 1, $_) } (0 .. $n - 1);
}
my $n = shift || 8;
# $maxw is the first odd width where the biggest number will fit
my $max = 0;
map { $max = $_ if $_ > $max } pascal_row($n);
my $maxw = length('' . $max);
$maxw += ($maxw + 1) % 2;
# Print the Pascal´s triangle
foreach my $i (1..$n) {
print ' ' x ( ( $maxw + 1 ) * ($n - $i) / 2 );
foreach my $j ( pascal_row($i) ) {
printf "%${maxw}d ", $j;
}
print "\n";
}
How is it done? Fit each number within the first odd width where the max of the numbers to print will fit. That´s because numbers are separated with a space and that will make each width even (and so divisible by two for odd-valued triangle rows.) Then use printf to format the numbers. For instance %5d will right align the number within 5 characters. Precede each line except the last with the necessary spaces using ' ' x N which generates a string of N spaces.
Pascal's triangle of 8:
# pascal.pl 8
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
Pascal's triangle of 13:
# pascal.pl 13
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
You can generate the triangle without any combinatoric formulas.
The reason to do it this way is that this is the most effective method.
The basic idea is to employ the observation, that the value in the next
row is the sum of 2 elements located above.
This solution is also a good example of how to work with an array of
(references to) arrays.
An interesting feature is that the indent is computed from the
middle element in the last row (with the greatest value).
To provide pretty look of the triangle, the cell size must be an even number.
The "basic" indent is the half of this size.
The actual indent for each row is this basic size, multiplied by a respective
number, derived from the row index and the total number of rows.
The whole script is given below:
use strict;
use warnings;
use feature qw(say);
use POSIX qw(ceil);
my $rowCnt = 14; # How many rows
say "Pascal Triangle with $rowCnt rows:";
# Rows container, filled with a single row (containing single 1)
my #rows = ([ 1 ]);
my ($lastRow, $row, $ind);
# Generate / add further rows
for ($ind = 1; $ind < $rowCnt; $ind++) {
$lastRow = $rows[$#rows]; # Last row gathered so far
push(#rows, getNextRow($lastRow));
}
$lastRow = $rows[$#rows];
# Middle elem. of the last row
my $midElem = $$lastRow[($rowCnt - 1) / 2];
# No of digits + separator, rounded up to even
my $elemSize = ceil((length($midElem) + 1) / 2) * 2;
my $shf = $elemSize / 2; # Shift size for a sigle step
# Print rows
for ($ind = 0; $ind < $rowCnt; $ind++) {
my $row = $rows[$ind];
my $spc = $shf * ($rowCnt - $ind - 1);
printRow($spc, $row, $elemSize);
}
sub getNextRow { # Create the next row and return the reference to it
my $lastRow = $_[0]; # Read param
my #row = (1); # Start the new row from a single 1
for (my $i = 0; $i < $#$lastRow; $i++) {
push(#row, $$lastRow[$i] + $$lastRow[$i + 1]);
}
push(#row, 1); # Add terminating 1
return \#row; # Result - reference to the created row
}
sub printRow { # Print a row of the triangle
my ($leadSpc, $row, $elemSize) = #_; # Read params
# Leading spaces and the initial element (always 1)
printf("%s1", ' ' x $leadSpc);
# Print the rest of the row
for (my $i = 1; $i <= $#$row; $i++) {
printf("%*d", $elemSize, $$row[$i]);
}
print("\n");
}

Perl - Determinant of Matrix Containing Variables

I have a Perl program containing the following methods:
det To find the determinant of a matrix.
identityMatrix Return an n by n identity matrix (1s on the main diagnal, rest 0s).
matrixAdd To add two matrices together.
matrixScalarMultiply To multiply an integer by a matrix.
I can easily find the determinant of, for example, a matrix A - I where
(It is 0)
But what if I want to find the determinant of A - RI?
In this case, I want my program to solve for the characteristic polynomial solution (a.k.a. the determinant containing variables) along these lines instead of an integer value:
Any suggestions on how to handle this? Code below:
#!/usr/bin/perl
#perl Solver.pl
use strict;
use warnings;
### solve the characteristic polynomial det(A - RI)
my #A = ( # 3x3, det = -3
[1, 3, -3],
[1, 0, 0],
[0, 1, 0],
);
# test_matrix = A - I
my $test_matrix = matrixAdd( \#A,
matrixScalarMultiply( identityMatrix(3), -1 ) );
print "\nTest:\n";
for( my $i = 0; $i <= $#$test_matrix; $i++ ){
print "[";
for( my $j = 0; $j <= $#$test_matrix; $j++ ){
$j == $#$test_matrix ? print $test_matrix->[$i][$j], "]\n" :
print $test_matrix->[$i][$j], ", ";
}
}
my $dd = det ($test_matrix);
print "det = $dd \n";
# recursively find determinant of a real square matrix
# only call on n by n matrices where n >= 2
#
# arg0 = matrix reference
sub det{
my ($A) = #_;
#base: 2x2 matrix
if( $#$A + 1 == 2 ){ #recall $#$A == last index of A
return $A->[0][0]*$A->[1][1] - $A->[1][0]*$A->[0][1];
}
#cofactor expansion for matrices > 2x2
my $answer = 0;
for( my $col = 0; $col <= $#$A; $col++ ){
my $m = (); #sub matrix
my $multiplier = $A->[0][$col];
if( $col % 2 == 1 ){ #+, -, +, -, ...
$multiplier *= -1;
}
for( my $i = 1; $i <= $#$A; $i++ ){
#j is indexer for A, k for m
for( my ($j, $k) = (0, 0); $j <= $#$A; $j++ ){
$m->[$i-1][$k++] = $A->[$i][$j] unless $j == $col;
}
}
$answer += $multiplier*det( $m );
}#end cofactor expansion
return $answer;
}#end det()
# return reference to an n by n identity matrix
# can do this in Perl!
#
# arg0 = dimension 'n'
sub identityMatrix{
my $n = shift;
my #ret;
for (my $i = 0; $i < $n; $i++ ){
for (my $j = 0; $j < $n; $j++ ){
$ret[$i][$j] = $i == $j ? 1 : 0;
}
}
return \#ret;
}
# return reference to an n by n matrix which is the sum
# of two different n by n matrices, "a" and "b"
#
# arg0, 1 = references to the pair of matrices to add
sub matrixAdd{
my #ret;
my ($a, $b) = ($_[0], $_[1]);
for (my $i = 0; $i <= $#$a; $i++ ){
for (my $j = 0; $j <= $#$a; $j++ ){
$ret[$i][$j] = $a->[$i][$j] + $b->[$i][$j];
}
}
return \#ret;
}
# return reference to a matrix multiplied by a given scalar
#
# arg0 = reference to matrix
# arg1 = scalar to multiply by
sub matrixScalarMultiply{
my #ret;
my ($a, $multiplier) = ($_[0], $_[1]);
for (my $i = 0; $i <= $#$a; $i++ ){
for (my $j = 0; $j <= $#$a; $j++ ){
$ret[$i][$j] = $a->[$i][$j] * $multiplier;
}
}
return \#ret;
}
This is called symbolic math and is in the wheelhouse of tools like Mathematica. For Perl, there are packages like Math::Synbolic but I couldn't tell you how easy they are to use.
On the other hand, if you are just interested in what values of R have a determinant of zero and not that interested in what the characteristic polynomial looks like, then you are looking for the eigenvalues of A. There are some Perl libraries for that, too.

Using perl, given an array of any size, how do I randomly pick 1/4 of the list

For clarification, if I had a list of 8 elements, i would want to randomly pick 2. If I had a list of 20 elements, I would want to randomly pick 5. I would also like to assure (though not needed) that two elements don't touch, i.e. if possible not the 3 and then 4 element. Rather, 3 and 5 would be nicer.
The simplest solution:
Shuffle the list
select the 1st quarter.
Example implementation:
use List::Util qw/shuffle/;
my #nums = 1..20;
my #pick = (shuffle #nums)[0 .. 0.25 * $#nums];
say "#pick";
Example output: 10 2 18 3 19.
Your additional restriction “no neighboring numbers” actually makes this less random, and should be avoided if you want actual randomness. To avoid that two neighboring elements are included in the output, I would iteratively splice unwanted elements out of the list:
my #nums = 1..20;
my $size = 0.25 * #nums;
my #pick;
while (#pick < $size) {
my $i = int rand #nums;
push #pick, my $num = $nums[$i];
# check and remove neighbours
my $len = 1;
$len++ if $i < $#nums and $num + 1 == $nums[$i + 1];
$len++, $i-- if 0 < $i and $num - 1 == $nums[$i - 1];
splice #nums, $i, $len;
}
say "#pick";
use strict;
use warnings;
sub randsel {
my ($fact, $i, #r) = (1.0, 0);
while (#r * 4 < #_) {
if (not grep { $_ == $i } #r) {
$fact = 1.0;
# make $fact = 0.0 if you really don't want
# consecutive elements
$fact = 0.1 if grep { abs($i - $_) == 1 } #r;
push(#r, $i) if (rand() < 0.25 * $fact);
}
$i = ($i + 1) % #_;
}
return map { $_[$_] } sort { $a <=> $b } #r;
}
my #l;
$l[$_] = $_ for (0..19);
print join(" ", randsel(#l)), "\n";

Print Armstrong numbers between 1 to 10 million

How to write a logic using for loop or while loop for printing Armstrong numbers?
Someone kindly explain how to print Armstrong numbers between 1 to 1,00,00,000.
This the algorithm that I followed
step 1 : initializing variable min,max,n,sum,r,t
step 2 : my $n = <>;
step 3 : to find base of $n
step 4 : using for loop
( for (n = min; n < max ; n++ )
step 5 : some logic like
n=t,sum =0,r=t%10,t=n/10,
step 6 :
sum = sum + (n ^ base );
step 6 :
if ( sum == num ) print Armstrong numbers else not.
I tried to code this my code look like this
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
my $n;
chomp($n);
my $min = 1;
my $max = 10000000
my $r;
my $sum;
my $t;
my $base = length($n);
print "base is $base\n";
for ($n = $min; $n <= $max; $n++) {
$t = $n;
$sum = 0;
while ($t != 0) {
$r = $t % 10;
$t = $t / 10;
{
$sum = $sum + ($base * $r);
}
if ($sum == $n) {
print "$n\n";
}
}
}
Several things:
It's bad practice to declare something with my until you need it.
You must remember that numbers are also strings, and can be manipulated by string functions like split.
C-like loops are discouraged in Perl because they're hard to read.
Constants should be ...well... constant.
Here's my attempt. I use split to split up my digits into an array of digits. This is a lot easier than dividing constantly by ten. I can get the number of digits by simply taking the scalar value of my #digits array.
I can then loop through #digits, taking each one to the power of $power and adding it to sum. I use the map command for this loop, but I could have used another for loop too.
#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
use constant {
MIN => 1,
MAX => 1_000_000,
};
for my $number ( (+MIN..+MAX) ) {
my #digits = split //, $number;
my $power = #digits;
my $sum = 0;
map { $sum += $_**$power } #digits;
if ( $sum == $number ) {
say "$number is an Armstrong number";
}
}
And my output:
1 is an Armstrong number
2 is an Armstrong number
3 is an Armstrong number
4 is an Armstrong number
5 is an Armstrong number
6 is an Armstrong number
7 is an Armstrong number
8 is an Armstrong number
9 is an Armstrong number
153 is an Armstrong number
370 is an Armstrong number
371 is an Armstrong number
407 is an Armstrong number
1634 is an Armstrong number
8208 is an Armstrong number
9474 is an Armstrong number
54748 is an Armstrong number
92727 is an Armstrong number
93084 is an Armstrong number
548834 is an Armstrong number
Took a bit over five seconds to run.
Instead of map, I could have done this loop:
for my $digit ( #digits ) {
$sum = $sum + ( $digit ** $power);
}
Did this one at university...
I dug out the one I made in C and converted it to perl for you (it may not be the best way to do this, but it is the way I did it):
#!/usr/bin/env perl
use strict;
use warnings;
my $min = 1;
my $max = 10000000;
for (my $number = $min; $number <= $max; $number++) {
my #digits = split('', $number);
my $sum = 0;
foreach my $digit (#digits) {
$sum += $digit**length($number);
}
if ($sum == $number) {
print "$number\n";
}
}
(Demo - 1 to 9999 due to execution time limit)
Your code seems to be right, but you have some kind of problems with your start. For example you dont read from STDIN or from #ARGV. Would you do that, you just have a small problem with your calculating of the exponential calculation. In most Programming Languages, the syntax for a exponential calculation is ** or a pow() function.
I really dont understand, for what this part is:
while ($t != 0) {
$r = $t % 10;
$t = $t / 10;
{
$sum = $sum + ($base * $r);
}
if ($sum == $n) {
print "$n\n";
}
}
For what is the naked block? Why do you use the modulus? .. Well i give you a small code for calculating the armstrong numbers with bases of 1..100, between 0 and 10million:
#!/usr/bin/perl
use strict;
use warnings;
foreach my $base (0..100) { # use the foreach loop as base
for my $num (0..10_000_000) { # and use numbers between this range
my $ce=0; # ce = calculated exp.
foreach my $num2 (split //,$num ) { # split each number for calc each
$ce += $num2 ** $base; # exp. and adding it (see algorithm)
}
if ($num == $ce) { # when the exp. num and the number
print "$base => $num\n"; # itself equals, its a armstrong number
} # print that
}
}

Trying to figure out if there's a shorter/better way to implement a conditional-sum-like function

Warning: Project Euler Problem 1 Spoiler
I recently discovered Project Euler and decided to try a few of the problems. The first problem was to sum the numbers from 0-999 that are multiples of 3 or 5.
My first, "java-like" solution was:
print threeAndFive(1000)."\n";
# Returns the sum of the numbers less than $max that are multiples of 3 or 5
sub threeAndFive
{
my $max = shift;
my $sum = 0;
for (my $i=; $i < $max; $i++)
{
$sum+=$i if (validate($i));
}
return $sum;
}
sub validate
{
my $num = shift;
if ($num % 3 == 0 || $num % 5 == 0)
{
return 1;
}
return undef;
}
I then rewrote it in a more perlish fashion:
print eval(join ('+', map {($_ % 3 == 0 || $_ % 5 == 0) ? $_ : ()} (1 .. 999)));
While this is obviously way more concise than the original code, I feel that it can probably be shorter or done in a better fashion. For example, in Python, one can do:
print sum([i for i in range(1,1000) if i%3==0 or i%5==0])
Are there more concise/better/clearer ways to do this? Or other equivalent ways that use different functions? I'm interested in learning as much perl as I can, so the more solutions, the merrier.
Thanks in advance.
The Straightforward Approach
To answer your question, List::Util provides sum.
use List::Util qw( sum );
Or you could write your own
sub sum { my $acc; $acc += $_ for #_; $acc }
Then you get:
say sum grep { $_ % 3 == 0 || $_ % 5 == 0 } 0..999;
Of course, that's an unoptimised approach.
The Optimised Approach
You can easily reduce the above to Ω(1) memory from Ω(N) by using a counting loop.
my $acc;
for (1..999) { $acc += $_ if $_ % 3 == 0 || $_ % 5 == 0; }
say $acc;
But that's far from the best, since the result can be obtained in Ω(1) time and memory!
This is done by adding the sum of the multiples of 3 to the sum of the multiples of 5, then subtracting the sum of the multiples of 15, because the sums of the multiples of $x can be calculated using
( sum 1..floor($n/$x) ) * $x # e.g. 3+6+9+... = (1+2+3+...)*3
which can take advantage of the formula
sum 1..$n = $n * ($n+1) * 0.5
Less concise, but faster:
sub sum1toN { my $N = int(shift); ($N * ($N+1)) / 2; }
my $N = 999;
print sum1toN($N/3)*3 + sum1toN($N/5)*5 - sum1toN($N/15)*15, "\n";
The sum1toN function computes the sum of integers from 1 to N.
Since:
3 + 6 + 9 + 12 ... + 999
Equals:
(1 + 2 + 3 + ... 333 ) * 3
We can computes sum of multiples of 3 using sum1toN(N/3) * 3. And the same applies to 5. Note that since we count the multiples of by 15 in both cases, a subtraction of sum1toN(N/15)*15 is needed.