3
// VoxBo matrix multiplication
4
// Copyright (c) 1998-2002 by The VoxBo Development Team
6
// VoxBo is free software: you can redistribute it and/or modify it
7
// under the terms of the GNU General Public License as published by
8
// the Free Software Foundation, either version 3 of the License, or
9
// (at your option) any later version.
11
// VoxBo is distributed in the hope that it will be useful, but
12
// WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
// General Public License for more details.
16
// You should have received a copy of the GNU General Public License
17
// along with VoxBo. If not, see <http://www.gnu.org/licenses/>.
19
// For general information on VoxBo, including the latest complete
20
// source code and binary distributions, manual, and associated files,
21
// see the VoxBo home page at: http://www.voxbo.org/
23
// original version written by Dan Kimberg
29
// This code provides some simple matrix operations for VoxBo.
30
// Some of the functions are optimized to operate in parallel
31
// and/or on large matrices that won't fit in memory. The
32
// implementation notes below are strictly for your entertainment.
34
#define MIN(a,b) ((a) < (b) ? (a) : (b))
35
#define MAX(a,b) ((a) < (b) ? (b) : (a))
48
void do_print(tokenlist &args);
49
void do_printsub(tokenlist &args);
50
void do_compare(tokenlist &args);
51
int do_ident(tokenlist &args);
52
int do_zeros(tokenlist &args);
53
int do_random(tokenlist &args);
54
int do_invert(tokenlist &args);
55
int do_add(tokenlist &args);
56
int do_subtract(tokenlist &args);
57
int do_xyt(tokenlist &args);
58
int do_xy(tokenlist &args);
59
int do_imxy(tokenlist &args);
60
int do_f3(tokenlist &args);
61
int do_pinv(tokenlist &args);
62
int do_pca(tokenlist &args);
63
int do_assemblecols(tokenlist &args);
64
int do_assemblerows(tokenlist &args);
65
int do_xyz(tokenlist &args);
69
main(int argc,char *argv[])
75
args.Transfer(argc-1,argv+1);
86
else if (cmd=="-imxy")
90
else if (cmd=="-pinv")
100
else if (cmd=="-subtract")
101
err=do_subtract(args);
102
else if (cmd=="-invert")
104
else if (cmd=="-ident")
106
else if (cmd=="-zeros")
108
else if (cmd=="-assemblecols")
109
err=do_assemblecols(args);
110
else if (cmd=="-assemblerows")
111
err=do_assemblerows(args);
112
else if (cmd=="-random")
114
else if (cmd=="-print")
116
else if (cmd=="-printsub")
118
else if (cmd=="-compare")
124
// ident args: name size
127
do_ident(tokenlist &args)
131
if (args.size() < 2) {
132
printf("[E] vbmm2: need a name and a size to create a matrix.\n");
138
printf("[E] vbmm2: size for identity matrix must be > 0.\n");
142
printf("[I] vbmm2: creating identity matrix %s of size %d.\n",args[0].c_str(),r);
144
VBMatrix target(r,r);
146
if (target.WriteMAT1(args[0]))
147
printf("[E] vbmm2: identity matrix %s (%dx%d) not created.\n",args[0].c_str(),r,r);
149
printf("[I] vbmm2: identity matrix %s (%dx%d) created.\n",args[0].c_str(),r,r);
153
// zeros args: name size
156
do_zeros(tokenlist &args)
158
if (args.size() < 2) {
159
printf("[E] vbmm2: need a name and a size to create a matrix.\n");
164
c = r = strtol(args[1]);
165
if (args.size() > 2) // needed only if it's not square
167
if (r < 0 || c < 0) {
168
printf("[E] vbmm2: dimensions for zero matrix must be > 0.\n");
172
printf("vbmm2: creating %dx%d zero matrix %s.\n",r,c,args[0].c_str());
174
VBMatrix target(c,r);
176
if (target.WriteMAT1(args[0]))
177
printf("vbmm2: zero matrix %s (%dx%d) not created.\n",args[0].c_str(),r,c);
179
printf("vbmm2: zero matrix %s (%dx%d) created.\n",args[0].c_str(),r,c);
184
do_random(tokenlist &args)
186
if (args.size() < 2) {
187
printf("[E] vbmm2: need a name and a size to create a matrix.\n");
191
c = r = strtol(args[1]);
192
if (args.size() > 2) // needed only if it's not square
194
if (r < 0 || c < 0) {
195
printf("[E] vbmm2: dimensions for random matrix must be > 0.\n");
199
printf("vbmm2: creating random %dx%d matrix %s.\n",r,c,args[0].c_str());
201
VBMatrix target(r,c);
203
if (target.WriteMAT1(args[0]))
204
printf("[E] vbmm2: error writing random %dx%d matrix %s\n",r,c,args[0].c_str());
206
printf("[I] vbmm2: random %dx%d matrix %s created\n",r,c,args[0].c_str());
213
do_subtract(tokenlist &args)
215
if (args.size() != 3) {
216
printf("[E] vbmm2: usage: vbmm2 -subtract in1 in2 out\n");
220
VBMatrix mat1(args[0]);
221
VBMatrix mat2(args[1]);
223
if (mat1.m == 0 || mat1.n == 0) {
224
printf("[E] vbmm2: first matrix was bad.\n");
227
if (mat2.m == 0 || mat2.n == 0) {
228
printf("[E] vbmm2: second matrix was bad.\n");
231
if (mat1.m != mat2.m || mat1.n != mat2.n) {
232
fprintf(stderr,"[E] vbmm2: matrix dimensions don't match.\n");
235
printf("[I] vbmm2: subtracting matrix %s from matrix %s.\n",args[1].c_str(),args[0].c_str());
237
mat1.WriteMAT1(args[2]);
238
printf("[I] vbmm2: done.\n");
244
do_add(tokenlist &args)
246
if (args.size() != 3) {
247
printf("[E] vbmm2: usage: vbmms -add in1 in2 out\n");
251
VBMatrix mat1(args[0]);
252
VBMatrix mat2(args[1]);
254
if (mat1.m == 0 || mat1.n == 0) {
255
printf("[E] vbmm2: first matrix was bad.\n");
258
if (mat2.m == 0 || mat2.n == 0) {
259
printf("[E] vbmm2: second matrix was bad.\n");
262
if (mat1.m != mat2.m || mat1.n != mat2.n) {
263
fprintf(stderr,"[E] vbmm2: matrix dimensions don't match.\n");
268
printf("[I] vbmm2: adding matrix %s and matrix %s.\n",args[0].c_str(),args[1].c_str());
270
mat1.WriteMAT1(args[2]);
271
printf("[I] vbmm2: done.\n");
277
do_compare(tokenlist &args)
279
if (args.size()!=2) {
280
printf("[E] vbmm2: usage: vbmm2 -compare <mat1> <mat2>\n");
283
VBMatrix mat1(args[0]);
284
VBMatrix mat2(args[1]);
285
if (mat1.m!=mat2.m) {
286
printf("[E] vbmm2: matrices have different row count\n");
289
if (mat1.n!=mat2.n) {
290
printf("[E] vbmm2: matrices have different column count\n");
293
int diffs_all=0,diffs_diag=0,diffs_off=0;
294
double totals_all=0.0,totals_diag=0.0,totals_off=0.0;
295
double max_all=0.0,max_diag=0.0,max_off=0.0;
298
for (int i=0; i<mat1.m; i++) {
299
for (int j=0; j<mat1.n; j++) {
300
diff=fabs(mat1(i,j)-mat2(i,j));
301
if (diff==0.0) continue;
304
if (diff>max_all) max_all=diff;
308
if (diff>max_diag) max_diag=diff;
313
if (diff>max_off) max_off=diff;
318
totals_all/=(double)diffs_all;
320
totals_diag/=(double)diffs_diag;
322
totals_off/=(double)diffs_off;
324
printf("[I] vbmm2: matrices are identical\n");
326
printf("[I] vbmm2: %d total cells\n",mat1.m*mat1.n);
327
printf("[I] vbmm2: total: %d different cells, mean abs diff %g, max diff %g\n",diffs_all,totals_all,max_all);
328
printf("[I] vbmm2: diagonal: %d different cells, mean abs diff %g, max diff %g\n",diffs_diag,totals_diag,max_diag);
329
printf("[I] vbmm2: off-diag: %d different cells, mean abs diff %g, max diff %g\n",diffs_off,totals_off,max_off);
333
// xy args: in1 in2 out [col1 col2]
336
do_xy(tokenlist &args)
340
if (args.size() != 3 && args.size() != 5) {
341
printf("[E] vbmm2: usage: vbmm2 -xy in1 in2 out [c1 c2]\n");
345
mat1.ReadMAT1Header(args[0]);
346
mat2.ReadMAT1Header(args[1]);
347
if (mat1.m==0||mat1.n==0||mat2.m==0||mat2.n==0) {
348
printf("[E] vbmm2: couldn't read matrix headers\n");
351
if (mat1.ReadMAT1(args[0])) {
352
printf("[E] vbmm2: first matrix was bad.\n");
356
if (args.size()==5) {
357
c1 = strtol(args[3]);
358
c2 = strtol(args[4]);
365
// figure out the outfile name for this part, if we're not doing the whole thing
366
string outname=args[2];
368
if (c1!=0 || c2!=mat2.cols-1) {
369
sprintf(tmps,"_%08d_%08d",c1,c2);
373
if (mat2.ReadMAT1(args[1],-1,-1,c1,c2)) {
374
printf("[E] vbmm2: second matrix was bad.\n");
378
printf("vbmm2: multiplying matrix %s by matrix %s (cols %d to %d).\n",
379
args[0].c_str(),args[1].c_str(),c1,c2);
381
if (mat1.WriteMAT1(outname))
382
printf("[E] vbmm2: failed!\n");
384
printf("[I] vbmm2: done.\n");
390
do_xyt(tokenlist &args)
394
if (args.size() != 3 && args.size() != 5) {
395
printf("[E] vbmm2: usage: vbmm2 -xy in1 in2 out [c1 c2]\n");
400
mat1.ReadMAT1Header(args[0]);
401
mat2.ReadMAT1Header(args[1]);
402
if (mat1.m==0||mat1.n==0||mat2.m==0||mat2.n==0) {
403
printf("[E] vbmm2: couldn't read matrix headers\n");
407
if (mat1.ReadMAT1(args[0])) {
408
printf("[E] vbmm2: first matrix was bad.\n");
411
if (args.size()==5) {
412
c1 = strtol(args[3]);
413
c2 = strtol(args[4]);
420
// figure out the outfile name
421
string outname=args[2];
423
if (c1!=0 || c2!=mat2.rows-1) {
424
sprintf(tmps,"_%05d_%05d",c1,c2);
428
if (mat2.ReadMAT1(args[1],c1,c2,-1,-1)) {
429
printf("[E] vbmm2: second matrix was bad\n");
433
printf("[I] vbmm2: multiplying matrix %s by matrix %s (cols %d to %d).\n",
434
args[0].c_str(),args[1].c_str(),c1,c2);
437
if (mat1.WriteMAT1(outname))
438
printf("[E] vbmm2: failed\n");
440
printf("[I] vbmm2: done\n");
446
do_xyz(tokenlist &args)
448
if (args.size() != 4) {
449
printf("vbmm2: usage: vbmm2 -xyz in1 in2 in3 out\n");
453
VBMatrix mat1(args[0]);
454
VBMatrix mat2(args[1]);
456
if (!(mat1.dataValid() && mat2.dataValid())) {
457
printf("[E] vbmm2: bad input matrix\n");
460
if (mat1.n != mat2.m) {
461
printf("[E] vbmm2: bad matrix dimensions for xyz.\n");
465
printf("vbmm2: multiplying matrix %s by matrix %s.\n",args(0),args(1));
467
printf("vbmm2: multiplying matrix %s by matrix %s.\n",args(1),args(2));
468
VBMatrix mat3(args[2]);
469
if (mat1.n != mat3.m) {
470
printf("[E] vbmm2: bad matrix dimensions for xyz.\n");
474
printf("vbmm2: done.\n");
476
mat1.WriteMAT1(args[3]);
482
do_assemblerows(tokenlist &)
484
return (100); // error!
485
return (0); // no error!
489
do_assemblecols(tokenlist &args)
491
vglob vg(args[0]+"_*_*");
493
printf("[E] vbmm2: no parts found for %s\n",args(0));
496
vector<VBMatrix *> mats;
498
// first read all the headers
499
for (size_t i=0; i<vg.size(); i++) {
501
tmp.ReadMAT1Header(vg[i]);
502
if (!tmp.headerValid()) {
503
printf("[E] vbmm2: invalid matrix in assemble list\n");
510
printf("[E] vbmm2: wrong-sized matrix %s in assemble list\n",vg[i].c_str());
514
if (rows < 1 || cols < 1) {
515
printf("[E] vbmm2: invalid size for assembled matrix: %d x %d\n",rows,cols);
518
VBMatrix newmat(rows,cols);
521
for (size_t i=0; i<vg.size(); i++) {
523
for (int j=0; j<tmp.n; j++) {
524
VB_Vector vv=tmp.GetColumn(j);
525
newmat.SetColumn(ind,vv);
529
// try to unlink the actual files now that we're merged
530
for (size_t i=0; i<vg.size(); i++)
531
unlink(vg[i].c_str());
532
newmat.WriteMAT1(args[0]);
533
return (0); // no error!
537
do_imxy(tokenlist &args)
539
if (args.size() != 3 && args.size() != 5) {
540
printf("[E] vbmm2: usage: vbmm -imxy in1 in2 out\n");
544
VBMatrix mat1(args[0]);
545
VBMatrix mat2(args[1]);
547
if (mat1.m <= 0 || mat1.n <= 0) {
548
printf("[E] vbmm2: first matrix was bad.\n");
551
if (mat2.m == 0 || mat2.n == 0) {
552
printf("[E] vbmm2: second matrix was bad.\n");
555
if (mat1.n != mat2.m) {
556
printf("[E] vbmm2: incompatible matrix dimensions for I-XY.\n");
560
printf("vbmm2: I-XYing matrix %s by matrix %s.\n",
561
args[0].c_str(),args[1].c_str());
563
for (int i=0; i<mat1.m; i++) {
564
VB_Vector tmp=mat1.GetRow(i);
565
for (int j=0; j<mat1.n; j++) {
566
tmp[j]*=(double)-1.0;
572
printf("vbmm2: done.\n");
573
mat1.WriteMAT1(args[2]);
578
do_f3(tokenlist &args)
580
if (args.size() != 3) {
581
printf("[E] vbmm2: usage: vbmm -f3 v kg out\n");
584
printf("[I] vbmm2: creating F3 matrix (V*KG*invert(KGtKG))\n");
585
printf("[I] vbmm2: V: %s\n",args(0));
586
printf("[I] vbmm2: KG: %s\n",args(1));
588
VBMatrix kg(args[1]);
592
if (v.m==0 || kg.m==0 || kgt.m==0) {
593
printf("[E] vbmm2: couldn't read matrices\n");
597
printf("[E] vbmm2: incompatible matrix dimensions\n");
605
kgt.clear(); // free mem
607
kg.clear(); // free mem
609
v.WriteMAT1(args[2]);
610
printf("[I] vbmm2: wrote F3 matrix %s\n",args(2));
616
do_invert(tokenlist &args)
618
if (args.size() != 2) {
619
printf("[E] vbmm2: usage: vbmm -invert in out\n");
623
VBMatrix mat(args[0]);
625
if (mat.m <= 0 || mat.n <= 0 || mat.m != mat.n) {
626
printf("[E] vbmm2: input matrix for invert was bad.\n");
629
VBMatrix target(mat.m,mat.m);
630
printf("vbmm2: inverting matrix %s.\n",args[0].c_str());
632
printf("vbmm2: done.\n");
633
target.WriteMAT1(args[1]);
637
// do_pinv() computes the pseudo-inverse, which is
638
// inverse(KGtKG) ## KGt
641
do_pinv(tokenlist &args)
643
if (args.size() != 2) {
644
printf("[E] vbmm2: usage: vbmm -pinv in out\n");
648
VBMatrix mat(args[0]);
650
if (mat.m <= 0 || mat.n <= 0) {
651
printf("[E] vbmm2: input matrix for pinv was bad.\n");
655
VBMatrix target(mat.n,mat.m);
656
printf("vbmm2: pinv'ing matrix %s.\n",args[0].c_str());
658
printf("vbmm2: done.\n");
659
target.WriteMAT1(args[1]);
663
// do_pca() calculates the principle components
666
do_pca(tokenlist &args)
668
if (args.size() != 2) {
669
printf("[E] vbmm2: usage: vbmm -pca in out\n");
673
VBMatrix mat(args[0]);
675
if (mat.m <= 0 || mat.n <= 0) {
676
printf("[E] vbmm2: input matrix for pinv was bad.\n");
683
printf("vbmm2: pca'ing matrix %s.\n",args[0].c_str());
684
pca(mat,lambdas,pcs,E);
686
printf("vbmm2: done.\n");
687
pcs.WriteMAT1(args[1]);
692
do_print(tokenlist &args)
696
for (int i=0; i<args.size(); i++) {
697
VBMatrix tmp(args[i]);
701
printf("[E] vbmm2: couldn't open matrix %s to print.\n",args(i));
707
do_printsub(tokenlist &args)
709
if (args.size() != 5)
711
int r1=strtol(args[1]);
712
int r2=strtol(args[2]);
713
int c1=strtol(args[3]);
714
int c2=strtol(args[4]);
715
VBMatrix mat(args[0],r1,r2,c1,c2);
717
printf("[E] vbmm2: couldn't read data\n");
720
printf("[I] vbmm: read rows %d-%d and cols %d-%d of %s\n",
721
r1,r2,c1,c2,args(0));
728
printf("\nVoxBo vbmm2 (v%s)\n",vbversion.c_str());
729
printf("| vbmm does various bits of matrix arithmetic with MAT1 files.\n");
730
printf("| below, in and out refer to the input and output matrices. c1 and c2\n");
731
printf("| refer to the start and end columns to be produced (for parallelization).\n");
732
printf("| usage:\n");
733
printf(" vbmm -xyt <in1> <in2> <out> <c1> <c2 > do part of XYt\n");
734
printf(" vbmm -xy <in1> <in2> <out> <c1> <c2> do part of XY\n");
735
printf(" vbmm -imxy <in1> <in2> <out> I-XY in core\n");
736
printf(" vbmm -f3 <v> <kg> <out> V*KG*invert(KTtKG)\n");
737
printf(" vbmm -xyz <in1> <in2> <in3> <out> XYZ in core\n");
738
printf(" vbmm -assemblecols <out> assemble out from available parts\n");
739
// printf(" vbmm -assemblerows <out> assemble out from available parts\n");
740
printf(" vbmm -add <in1> <in2> <out> add two matrices\n");
741
printf(" vbmm -subtract <in1> <in2> <out> subtract in2 from in1\n");
742
printf(" vbmm -invert <in> <out> invert in\n");
743
printf(" vbmm -pinv <in> <out> pseudo-inverse, in core\n");
744
printf(" vbmm -pca <in> <out> calculte pca\n");
745
printf(" vbmm -ident <name> <size> create an identity matrix\n");
746
printf(" vbmm -zeros <name> <cols> [rows] create a zero matrix\n");
747
printf(" vbmm -random <name> <cols> [rows] create a matrix of random numbers\n");
748
printf(" vbmm -print <name> display a matrix\n");
749
printf(" vbmm -printsub <name> <r1> <r2> <c1> <c2> display part of a matrix\n");
750
printf(" vbmm -compare <mat1> <mat2> compare two matrices\n");