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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rmtxop.c,v 2.16 2019/08/12 20:38:19 greg Exp $";
3 #endif
4 /*
5 * General component matrix operations.
6 */
7
8 #include <stdlib.h>
9 #include <errno.h>
10 #include "rtio.h"
11 #include "resolu.h"
12 #include "rmatrix.h"
13 #include "platform.h"
14
15 #define MAXCOMP 16 /* #components we support */
16
17 static const char stdin_name[] = "<stdin>";
18
19 /* unary matrix operation(s) */
20 typedef struct {
21 double sca[MAXCOMP]; /* scalar coefficients */
22 double cmat[MAXCOMP*MAXCOMP]; /* component transformation */
23 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
36 int verbose = 0; /* verbose reporting? */
37
38 /* Load matrix */
39 static int
40 loadmatrix(ROPMAT *rop)
41 {
42 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 }
54
55 /* Get matrix and perform unary operations */
56 static RMATRIX *
57 loadop(ROPMAT *rop)
58 {
59 RMATRIX *mres;
60 int i;
61
62 if (loadmatrix(rop) < 0) /* make sure we're loaded */
63 return(NULL);
64
65 if (rop->preop.nsf > 0) { /* apply scalar(s) */
66 if (rop->preop.clen > 0) {
67 fputs("Options -s and -c are exclusive\n", stderr);
68 goto failure;
69 }
70 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 fprintf(stderr, "%s: -s must have one or %d factors\n",
75 rop->inspec, rop->mtx->ncomp);
76 goto failure;
77 }
78 if (!rmx_scale(rop->mtx, rop->preop.sca)) {
79 fputs(rop->inspec, stderr);
80 fputs(": scalar operation failed\n", stderr);
81 goto failure;
82 }
83 if (verbose) {
84 fputs(rop->inspec, stderr);
85 fputs(": applied scalar (", stderr);
86 for (i = 0; i < rop->preop.nsf; i++)
87 fprintf(stderr, " %f", rop->preop.sca[i]);
88 fputs(" )\n", stderr);
89 }
90 }
91 if (rop->preop.clen > 0) { /* apply transform */
92 if (rop->preop.clen % rop->mtx->ncomp) {
93 fprintf(stderr, "%s: -c must have N x %d coefficients\n",
94 rop->inspec, rop->mtx->ncomp);
95 goto failure;
96 }
97 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 }
104 if (verbose)
105 fprintf(stderr, "%s: applied %d x %d transform\n",
106 rop->inspec, mres->ncomp,
107 rop->mtx->ncomp);
108 rmx_free(rop->mtx);
109 rop->mtx = mres;
110 }
111 if (rop->preop.transpose) { /* transpose matrix? */
112 mres = rmx_transpose(rop->mtx);
113 if (mres == NULL) {
114 fputs(rop->inspec, stderr);
115 fputs(": transpose failed\n", stderr);
116 goto failure;
117 }
118 if (verbose) {
119 fputs(rop->inspec, stderr);
120 fputs(": transposed rows and columns\n", stderr);
121 }
122 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 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 rmx_free(mleft);
154 rmx_free(mright);
155 if (mres == NULL) {
156 fputs(inspec, stderr);
157 fputs(": concatenation failed\n", stderr);
158 return(NULL);
159 }
160 if (verbose) {
161 fputs(inspec, stderr);
162 fputs(": concatenated matrix\n", stderr);
163 }
164 break;
165 case '+':
166 if (!rmx_sum(mleft, mright, NULL)) {
167 fputs(inspec, stderr);
168 fputs(": matrix sum failed\n", stderr);
169 rmx_free(mleft);
170 rmx_free(mright);
171 return(NULL);
172 }
173 if (verbose) {
174 fputs(inspec, stderr);
175 fputs(": added in matrix\n", stderr);
176 }
177 rmx_free(mright);
178 mres = mleft;
179 break;
180 case '*':
181 case '/': {
182 const char * tnam = (op == '/') ?
183 "division" : "multiplication";
184 errno = 0;
185 if (!rmx_elemult(mleft, mright, (op == '/'))) {
186 fprintf(stderr, "%s: element-wise %s failed\n",
187 inspec, tnam);
188 rmx_free(mleft);
189 rmx_free(mright);
190 return(NULL);
191 }
192 if (errno)
193 fprintf(stderr,
194 "%s: warning - error during element-wise %s\n",
195 inspec, tnam);
196 else if (verbose)
197 fprintf(stderr, "%s: element-wise %s\n", inspec, tnam);
198 rmx_free(mright);
199 mres = mleft;
200 } break;
201 default:
202 fprintf(stderr, "%s: unknown operation '%c'\n", inspec, op);
203 rmx_free(mleft);
204 rmx_free(mright);
205 return(NULL);
206 }
207 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 return(mleft);
224 }
225
226 /* 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 if (mop[rpos++].binop != '.') {
235 fputs(
236 "Right-to-left evaluation only for matrix multiplication!\n",
237 stderr);
238 return(NULL);
239 }
240 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 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 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 /* Load one or more matrices and operate on them, sending results to stdout */
311 int
312 main(int argc, char *argv[])
313 {
314 int outfmt = DTfromHeader;
315 int nall = 2;
316 ROPMAT *mop = (ROPMAT *)calloc(nall, sizeof(ROPMAT));
317 int nmats = 0;
318 RMATRIX *mres = NULL;
319 int stdin_used = 0;
320 int i;
321 /* get options and arguments */
322 for (i = 1; i < argc; i++) {
323 if (argv[i][0] && !argv[i][1] &&
324 strchr(".+*/", argv[i][0]) != NULL) {
325 if (!nmats || mop[nmats-1].binop) {
326 fprintf(stderr,
327 "%s: missing matrix argument before '%c' operation\n",
328 argv[0], argv[i][0]);
329 return(1);
330 }
331 mop[nmats-1].binop = argv[i][0];
332 } else if (argv[i][0] != '-' || !argv[i][1]) {
333 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 } else {
347 int n = argc-1 - i;
348 switch (argv[i][1]) { /* get option */
349 case 'v':
350 verbose++;
351 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 mop[nmats].preop.transpose = 1;
372 break;
373 case 's':
374 if (n > MAXCOMP) n = MAXCOMP;
375 i += mop[nmats].preop.nsf =
376 get_factors(mop[nmats].preop.sca,
377 n, argv+i+1);
378 break;
379 case 'c':
380 if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
381 i += mop[nmats].preop.clen =
382 get_factors(mop[nmats].preop.cmat,
383 n, argv+i+1);
384 break;
385 default:
386 fprintf(stderr, "%s: unknown operation '%s'\n",
387 argv[0], argv[i]);
388 goto userr;
389 }
390 }
391 if (nmats >= nall)
392 mop = grow_moparray(mop, nall += 2);
393 }
394 if (mop[0].inspec == NULL) /* nothing to do? */
395 goto userr;
396 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 /* favor quicker concatenation */
403 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 return(1);
412 /* write result to stdout */
413 if (outfmt == DTfromHeader)
414 outfmt = mres->dtype;
415 if (outfmt != DTascii)
416 SET_FILE_BINARY(stdout);
417 newheader("RADIANCE", stdout);
418 printargs(argc, argv, stdout);
419 if (!rmx_write(mres, outfmt, stdout)) {
420 fprintf(stderr, "%s: error writing result matrix\n", argv[0]);
421 return(1);
422 }
423 /* rmx_free(mres); free(mop); */
424 return(0);
425 userr:
426 fprintf(stderr,
427 "Usage: %s [-v][-f[adfc][-t][-s sf .. | -c ce ..] m1 [.+*/] .. > mres\n",
428 argv[0]);
429 return(1);
430 }