ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rmtxop.c
Revision: 2.17
Committed: Sat Dec 28 18:05:14 2019 UTC (4 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.16: +1 -2 lines
Log Message:
Removed redundant include files

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.17 static const char RCSid[] = "$Id: rmtxop.c,v 2.16 2019/08/12 20:38:19 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * General component matrix operations.
6     */
7    
8     #include <stdlib.h>
9 greg 2.11 #include <errno.h>
10 greg 2.1 #include "rtio.h"
11     #include "resolu.h"
12     #include "rmatrix.h"
13 greg 2.10 #include "platform.h"
14 greg 2.1
15 greg 2.13 #define MAXCOMP 16 /* #components we support */
16 greg 2.1
17 greg 2.13 static const char stdin_name[] = "<stdin>";
18    
19     /* unary matrix operation(s) */
20 greg 2.1 typedef struct {
21     double sca[MAXCOMP]; /* scalar coefficients */
22     double cmat[MAXCOMP*MAXCOMP]; /* component transformation */
23 greg 2.13 short nsf; /* number of scalars */
24     short clen; /* number of coefficients */
25     short transpose; /* do transpose? */
26     } RUNARYOP;
27    
28     /* matrix input source and requested operation(s) */
29     typedef struct {
30     const char *inspec; /* input specification */
31     RUNARYOP preop; /* unary operation(s) */
32     RMATRIX *mtx; /* original matrix if loaded */
33     int binop; /* binary op with next (or 0) */
34     } ROPMAT;
35 greg 2.1
36     int verbose = 0; /* verbose reporting? */
37    
38 greg 2.13 /* Load matrix */
39     static int
40     loadmatrix(ROPMAT *rop)
41 greg 2.1 {
42 greg 2.13 if (rop->mtx != NULL)
43     return(0);
44    
45     rop->mtx = rmx_load(rop->inspec == stdin_name ?
46     (const char *)NULL : rop->inspec);
47     if (rop->mtx == NULL) {
48     fputs(rop->inspec, stderr);
49     fputs(": cannot load matrix\n", stderr);
50     return(-1);
51     }
52     return(1);
53 greg 2.1 }
54    
55 greg 2.13 /* Get matrix and perform unary operations */
56 greg 2.1 static RMATRIX *
57 greg 2.13 loadop(ROPMAT *rop)
58 greg 2.1 {
59 greg 2.13 RMATRIX *mres;
60 greg 2.1 int i;
61    
62 greg 2.13 if (loadmatrix(rop) < 0) /* make sure we're loaded */
63 greg 2.1 return(NULL);
64 greg 2.13
65     if (rop->preop.nsf > 0) { /* apply scalar(s) */
66     if (rop->preop.clen > 0) {
67 greg 2.1 fputs("Options -s and -c are exclusive\n", stderr);
68 greg 2.13 goto failure;
69 greg 2.1 }
70 greg 2.13 if (rop->preop.nsf == 1) {
71     for (i = rop->mtx->ncomp; --i; )
72     rop->preop.sca[i] = rop->preop.sca[0];
73     } else if (rop->preop.nsf != rop->mtx->ncomp) {
74 greg 2.1 fprintf(stderr, "%s: -s must have one or %d factors\n",
75 greg 2.13 rop->inspec, rop->mtx->ncomp);
76     goto failure;
77 greg 2.1 }
78 greg 2.13 if (!rmx_scale(rop->mtx, rop->preop.sca)) {
79     fputs(rop->inspec, stderr);
80 greg 2.1 fputs(": scalar operation failed\n", stderr);
81 greg 2.13 goto failure;
82 greg 2.1 }
83     if (verbose) {
84 greg 2.13 fputs(rop->inspec, stderr);
85 greg 2.1 fputs(": applied scalar (", stderr);
86 greg 2.13 for (i = 0; i < rop->preop.nsf; i++)
87     fprintf(stderr, " %f", rop->preop.sca[i]);
88 greg 2.1 fputs(" )\n", stderr);
89     }
90     }
91 greg 2.13 if (rop->preop.clen > 0) { /* apply transform */
92     if (rop->preop.clen % rop->mtx->ncomp) {
93 greg 2.1 fprintf(stderr, "%s: -c must have N x %d coefficients\n",
94 greg 2.13 rop->inspec, rop->mtx->ncomp);
95     goto failure;
96 greg 2.1 }
97 greg 2.13 mres = rmx_transform(rop->mtx, rop->preop.clen/rop->mtx->ncomp,
98     rop->preop.cmat);
99     if (mres == NULL) {
100     fprintf(stderr, "%s: matrix transform failed\n",
101     rop->inspec);
102     goto failure;
103 greg 2.1 }
104     if (verbose)
105     fprintf(stderr, "%s: applied %d x %d transform\n",
106 greg 2.13 rop->inspec, mres->ncomp,
107     rop->mtx->ncomp);
108     rmx_free(rop->mtx);
109     rop->mtx = mres;
110 greg 2.1 }
111 greg 2.13 if (rop->preop.transpose) { /* transpose matrix? */
112     mres = rmx_transpose(rop->mtx);
113     if (mres == NULL) {
114     fputs(rop->inspec, stderr);
115 greg 2.12 fputs(": transpose failed\n", stderr);
116 greg 2.13 goto failure;
117 greg 2.12 }
118     if (verbose) {
119 greg 2.13 fputs(rop->inspec, stderr);
120 greg 2.12 fputs(": transposed rows and columns\n", stderr);
121     }
122 greg 2.13 rmx_free(rop->mtx);
123     rop->mtx = mres;
124     }
125     mres = rop->mtx;
126     rop->mtx = NULL;
127     return(mres);
128     failure:
129     rmx_free(rop->mtx);
130     return(rop->mtx = NULL);
131     }
132    
133     /* Execute binary operation, free matrix arguments and return new result */
134     static RMATRIX *
135     binaryop(const char *inspec, RMATRIX *mleft, int op, RMATRIX *mright)
136     {
137     RMATRIX *mres = NULL;
138     int i;
139    
140     if ((mleft == NULL) | (mright == NULL))
141     return(NULL);
142     switch (op) {
143     case '.': /* concatenate */
144 greg 2.16 if (mleft->ncomp != mright->ncomp) {
145     fputs(inspec, stderr);
146     fputs(": # components do not match\n", stderr);
147     } else if (mleft->ncols != mright->nrows) {
148     fputs(inspec, stderr);
149     fputs(": mismatched dimensions\n",
150     stderr);
151     } else
152     mres = rmx_multiply(mleft, mright);
153 greg 2.13 rmx_free(mleft);
154 greg 2.12 rmx_free(mright);
155 greg 2.1 if (mres == NULL) {
156 greg 2.13 fputs(inspec, stderr);
157 greg 2.16 fputs(": concatenation failed\n", stderr);
158 greg 2.1 return(NULL);
159     }
160     if (verbose) {
161 greg 2.13 fputs(inspec, stderr);
162 greg 2.1 fputs(": concatenated matrix\n", stderr);
163     }
164 greg 2.13 break;
165     case '+':
166     if (!rmx_sum(mleft, mright, NULL)) {
167     fputs(inspec, stderr);
168 greg 2.1 fputs(": matrix sum failed\n", stderr);
169 greg 2.13 rmx_free(mleft);
170 greg 2.1 rmx_free(mright);
171     return(NULL);
172     }
173     if (verbose) {
174 greg 2.13 fputs(inspec, stderr);
175 greg 2.1 fputs(": added in matrix\n", stderr);
176     }
177     rmx_free(mright);
178 greg 2.13 mres = mleft;
179     break;
180     case '*':
181     case '/': {
182     const char * tnam = (op == '/') ?
183 greg 2.11 "division" : "multiplication";
184     errno = 0;
185 greg 2.13 if (!rmx_elemult(mleft, mright, (op == '/'))) {
186 greg 2.11 fprintf(stderr, "%s: element-wise %s failed\n",
187 greg 2.13 inspec, tnam);
188     rmx_free(mleft);
189 greg 2.11 rmx_free(mright);
190     return(NULL);
191     }
192     if (errno)
193     fprintf(stderr,
194     "%s: warning - error during element-wise %s\n",
195 greg 2.13 inspec, tnam);
196 greg 2.11 else if (verbose)
197 greg 2.13 fprintf(stderr, "%s: element-wise %s\n", inspec, tnam);
198 greg 2.11 rmx_free(mright);
199 greg 2.13 mres = mleft;
200     } break;
201     default:
202     fprintf(stderr, "%s: unknown operation '%c'\n", inspec, op);
203     rmx_free(mleft);
204 greg 2.1 rmx_free(mright);
205     return(NULL);
206     }
207 greg 2.13 return(mres);
208     }
209    
210     /* Perform matrix operations from left to right */
211     static RMATRIX *
212     op_left2right(ROPMAT *mop)
213     {
214     RMATRIX *mleft = loadop(mop);
215    
216     while (mop->binop) {
217     if (mleft == NULL)
218     break;
219     mleft = binaryop(mop[1].inspec,
220     mleft, mop->binop, loadop(mop+1));
221     mop++;
222     }
223 greg 2.1 return(mleft);
224     }
225    
226 greg 2.13 /* Perform matrix operations from right to left */
227     static RMATRIX *
228     op_right2left(ROPMAT *mop)
229     {
230     RMATRIX *mright;
231     int rpos = 0;
232     /* find end of list */
233     while (mop[rpos].binop)
234 greg 2.14 if (mop[rpos++].binop != '.') {
235     fputs(
236     "Right-to-left evaluation only for matrix multiplication!\n",
237     stderr);
238     return(NULL);
239     }
240 greg 2.13 mright = loadop(mop+rpos);
241     while (rpos-- > 0) {
242     if (mright == NULL)
243     break;
244     mright = binaryop(mop[rpos].inspec,
245     loadop(mop+rpos), mop[rpos].binop, mright);
246     }
247     return(mright);
248     }
249    
250     #define t_nrows(mop) ((mop)->preop.transpose ? (mop)->mtx->ncols \
251     : (mop)->mtx->nrows)
252     #define t_ncols(mop) ((mop)->preop.transpose ? (mop)->mtx->nrows \
253     : (mop)->mtx->ncols)
254    
255     /* Should we prefer concatenating from rightmost matrix towards left? */
256     static int
257     prefer_right2left(ROPMAT *mop)
258     {
259     int mri = 0;
260    
261     while (mop[mri].binop) /* find rightmost matrix */
262     if (mop[mri++].binop != '.')
263     return(0); /* pre-empt reversal for other ops */
264    
265     if (mri <= 1)
266     return(0); /* won't matter */
267    
268     if (loadmatrix(mop+mri) < 0) /* load rightmost cat */
269     return(1); /* fail will bail in a moment */
270    
271     if (t_ncols(mop+mri) == 1)
272     return(1); /* definitely better R->L */
273    
274     if (t_ncols(mop+mri) >= t_nrows(mop+mri))
275     return(0); /* ...probably worse */
276    
277     if (loadmatrix(mop) < 0) /* load leftmost */
278     return(0); /* fail will bail in a moment */
279    
280     return(t_ncols(mop+mri) < t_nrows(mop));
281     }
282    
283 greg 2.1 static int
284     get_factors(double da[], int n, char *av[])
285     {
286     int ac;
287    
288     for (ac = 0; ac < n && isflt(av[ac]); ac++)
289     da[ac] = atof(av[ac]);
290     return(ac);
291     }
292    
293 greg 2.13 static ROPMAT *
294     grow_moparray(ROPMAT *mop, int n2alloc)
295     {
296     int nmats = 0;
297    
298     while (mop[nmats++].binop)
299     ;
300     mop = (ROPMAT *)realloc(mop, n2alloc*sizeof(ROPMAT));
301     if (mop == NULL) {
302     fputs("Out of memory in grow_moparray()\n", stderr);
303     exit(1);
304     }
305     if (n2alloc > nmats)
306     memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
307     return(mop);
308     }
309    
310 greg 2.1 /* Load one or more matrices and operate on them, sending results to stdout */
311     int
312     main(int argc, char *argv[])
313     {
314 greg 2.7 int outfmt = DTfromHeader;
315 greg 2.13 int nall = 2;
316     ROPMAT *mop = (ROPMAT *)calloc(nall, sizeof(ROPMAT));
317     int nmats = 0;
318 greg 2.1 RMATRIX *mres = NULL;
319 greg 2.13 int stdin_used = 0;
320 greg 2.1 int i;
321     /* get options and arguments */
322 greg 2.13 for (i = 1; i < argc; i++) {
323 greg 2.11 if (argv[i][0] && !argv[i][1] &&
324 greg 2.13 strchr(".+*/", argv[i][0]) != NULL) {
325 greg 2.15 if (!nmats || mop[nmats-1].binop) {
326 greg 2.14 fprintf(stderr,
327 greg 2.15 "%s: missing matrix argument before '%c' operation\n",
328 greg 2.14 argv[0], argv[i][0]);
329 greg 2.13 return(1);
330     }
331 greg 2.15 mop[nmats-1].binop = argv[i][0];
332 greg 2.1 } else if (argv[i][0] != '-' || !argv[i][1]) {
333 greg 2.13 if (argv[i][0] == '-') {
334     if (stdin_used++) {
335     fprintf(stderr,
336     "%s: standard input used for more than one matrix\n",
337     argv[0]);
338     return(1);
339     }
340     mop[nmats].inspec = stdin_name;
341     } else
342     mop[nmats].inspec = argv[i];
343     if (nmats > 0 && !mop[nmats-1].binop)
344     mop[nmats-1].binop = '.';
345     nmats++;
346 greg 2.1 } else {
347     int n = argc-1 - i;
348     switch (argv[i][1]) { /* get option */
349     case 'v':
350 greg 2.14 verbose++;
351 greg 2.1 break;
352     case 'f':
353     switch (argv[i][2]) {
354     case 'd':
355     outfmt = DTdouble;
356     break;
357     case 'f':
358     outfmt = DTfloat;
359     break;
360     case 'a':
361     outfmt = DTascii;
362     break;
363     case 'c':
364     outfmt = DTrgbe;
365     break;
366     default:
367     goto userr;
368     }
369     break;
370     case 't':
371 greg 2.13 mop[nmats].preop.transpose = 1;
372 greg 2.1 break;
373     case 's':
374     if (n > MAXCOMP) n = MAXCOMP;
375 greg 2.13 i += mop[nmats].preop.nsf =
376     get_factors(mop[nmats].preop.sca,
377     n, argv+i+1);
378 greg 2.1 break;
379     case 'c':
380     if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
381 greg 2.13 i += mop[nmats].preop.clen =
382     get_factors(mop[nmats].preop.cmat,
383     n, argv+i+1);
384 greg 2.1 break;
385     default:
386     fprintf(stderr, "%s: unknown operation '%s'\n",
387     argv[0], argv[i]);
388     goto userr;
389     }
390     }
391 greg 2.14 if (nmats >= nall)
392     mop = grow_moparray(mop, nall += 2);
393 greg 2.13 }
394     if (mop[0].inspec == NULL) /* nothing to do? */
395 greg 2.1 goto userr;
396 greg 2.15 if (mop[nmats-1].binop) {
397     fprintf(stderr,
398     "%s: missing matrix argument after '%c' operation\n",
399     argv[0], mop[nmats-1].binop);
400     return(1);
401     }
402 greg 2.13 /* favor quicker concatenation */
403 greg 2.14 mop[nmats].mtx = prefer_right2left(mop) ? op_right2left(mop)
404     : op_left2right(mop);
405     if (mop[nmats].mtx == NULL)
406     return(1);
407     /* apply trailing unary operations */
408     mop[nmats].inspec = "trailing_ops";
409     mres = loadop(mop+nmats);
410     if (mres == NULL)
411 greg 2.13 return(1);
412 greg 2.1 /* write result to stdout */
413 greg 2.6 if (outfmt == DTfromHeader)
414     outfmt = mres->dtype;
415 greg 2.4 if (outfmt != DTascii)
416 greg 2.10 SET_FILE_BINARY(stdout);
417 greg 2.1 newheader("RADIANCE", stdout);
418     printargs(argc, argv, stdout);
419 greg 2.5 if (!rmx_write(mres, outfmt, stdout)) {
420 greg 2.1 fprintf(stderr, "%s: error writing result matrix\n", argv[0]);
421     return(1);
422     }
423 greg 2.13 /* rmx_free(mres); free(mop); */
424 greg 2.1 return(0);
425     userr:
426     fprintf(stderr,
427 greg 2.13 "Usage: %s [-v][-f[adfc][-t][-s sf .. | -c ce ..] m1 [.+*/] .. > mres\n",
428 greg 2.1 argv[0]);
429     return(1);
430     }