1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
#!/usr/bin/perl
# Always use these two lines for every perl script:
use strict;
use warnings;
=pod
The line above starts a multi-line comment.
We want to load two files $file1 and $file2 containing matrices
and we want to compute the percentage difference
element by element, and then print it.
The line below ends this multi-line comment:
=cut
# This is the label we need to look for in $file1:
my $label1="OperatorC:";
# This is the label we need to look for in $file2:
my $label2="Energy=";
# The line below reads the command line in the array @ARGV:
# and places the first word in $file1 and the second in $file2
my ($file1,$file2) = @ARGV;
# These are the two matrices.
# Note that perl has no matrix data type, so we use vectors, and
# store matrix element $m($i,$j) in $matrix[$i + $j*$rows], this is called
# linear ordering
my @matrix1;
my @matrix2;
# Usually, we would use a single load function, but here
# the matrices have different formats, so we need to load functions:
my $cols1 = loadMatrix1(\@matrix1,$file1);
print STDERR "Matrix1 in file $file1 has $cols1 columns\n";
my $cols2=loadMatrix2(\@matrix2,$file2);
print STDERR "Matrix2 in file $file2 has $cols2 columns\n";
# After that we compute the percentage difference.
# But before doing this we have to get rid of the signs since
# I haven't been careful with them for cicj, sorry.
# so we construct absolute values of matrix1 into matrix1abs
my @matrix1abs;
matrixKillSign(\@matrix1abs,\@matrix1);
#and same for 2:
my @matrix2abs;
matrixKillSign(\@matrix2abs,\@matrix2);
my @matrixPd; # <-- this matrix will contain the perc. diff.
percentageDiff(\@matrixPd,\@matrix1abs,\@matrix2abs,$cols1);
# Finally we print it:
printMatrix(\@matrixPd,$cols2);
# Now we need to write the functions we used above.
# Let's start with printMatrix, which is the easiest:
sub printMatrix
{
my ($m,$cols)=@_; # Read the arguments
my $col = 0; # column counter
foreach my $x (@$m) {
print "$x ";
# increment column count
$col++;
# start a new line if new row:
#print STDERR "$col\n";
if ($col==$cols) {
print "\n";
$col=0; # and reset the column counter
}
}
}
sub loadMatrix1
{
my ($m,$f)=@_; # Read the arguments
open(FILE, "<", $f) or die "Cannot open file $f: $!\n";
# Note that $! above contains the error message
# Read up to let's say "OperatorC:", which is contained in $label
while(<FILE>) {
last if (/^$label1/);
}
$_=<FILE>; # read the rows and columns, like 3 6...
#... and store them:
my @temp=split; # this splits a space separated line into an array
my $rows = $temp[0];
my $cols = $temp[1];
# now read the rest of the matrix:
my $i = 0; # row counter
while(<FILE>) {
@temp=split; # this splits a space separated line into an array
#save this row:
my $cols = $#temp+1;
for (my $j=0;$j<$cols;$j++) {
$m->[$j+$i*$cols]=$temp[$j];
}
#increment the row
$i++;
# exit if we're done:
last if ($i==$rows);
}
close(FILE);
return $#temp+1; # return the number of columns
}
# Now for loading the second matrix. Again we need a different
# function because the matrix formats are different,
# compare file1.txt with file2.txt
sub loadMatrix2
{
my ($m,$f)=@_; # Read the arguments
open(FILE, "<", $f) or die "Cannot open file $f: $!\n";
# Read up to let's say "Energy=", which is contained in $label2
while(<FILE>) {
last if (/^$label2/);
}
# now read the rest of the matrix:
my $i = 0; # row counter
my $cols=0; # number of columns
while(<FILE>) {
my @temp=split; # this splits a space separated line into an array
#save this row:
$cols = $#temp+1;
for (my $j=0;$j<$cols;$j++) {
$m->[$j+$i*$cols]=realPartOf($temp[$j]);
}
#increment the row
$i++;
# exit if we're done:
last if ($i==$cols);
}
close(FILE);
return $cols; # return the number of columns
}
# This little function returns $x, if given ($x,$y):
sub realPartOf
{
my ($xy)=@_;
$_=$xy;
s/\(//; # kill the starting parens
s/,.*$//; # kill everything from the comma to the end
return $_;
}
sub percentageDiff
{
my ($mpdiff,$m1,$m2,$cols1)=@_;
# First we do mdiff=m1-m2
my @mdiff;
matrixDiff(\@mdiff,$m1,$m2,$cols1);
# Then we divide mdiff by m2:
matrixDivide($mpdiff,\@mdiff,$m2,$cols1);
#Now we kill the sign and multiply by 100%:
# and also adjust the precision to .xx
my $counter=0;
foreach my $x (@$mpdiff) {
$mpdiff->[$counter++]=int(abs($x)*10000)/100;
}
}
sub matrixDiff
{
my ($mdiff,$ma,$mb,$cols)=@_;
my $rows = $cols; # matrix is square:
for (my $i=0;$i<$rows;$i++) {
for (my $j=0;$j<$cols;$j++) {
next if (!defined($ma->[$j+$i*$cols]));
next if (!defined($mb->[$j+$i*$cols]));
$mdiff->[$j+$i*$cols]=$ma->[$j+$i*$cols]-$mb->[$j+$i*$cols];
}
}
}
sub matrixDivide
{
my ($mdiv,$ma,$mb,$cols)=@_;
my $rows = $cols; # matrix is square:
for (my $i=0;$i<$rows;$i++) {
for (my $j=0;$j<$cols;$j++) {
next if (!defined($ma->[$j+$i*$cols]));
next if (!defined($mb->[$j+$i*$cols]));
next if ($mb->[$j+$i*$cols]==0);
$mdiv->[$j+$i*$cols]=$ma->[$j+$i*$cols]/$mb->[$j+$i*$cols];
}
}
}
# This does: dest(i,j) = |src(i,j)| for each element i,j
sub matrixKillSign
{
my ($dest,$src)=@_;
my $counter=0;
foreach my $x (@$src) {
$dest->[$counter++]=abs($x);
}
}
|