ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rmtxop.c
(Generate patch)

Comparing ray/src/util/rmtxop.c (file contents):
Revision 2.3 by greg, Sat Aug 2 17:10:43 2014 UTC vs.
Revision 2.39 by greg, Fri Apr 4 18:18:06 2025 UTC

# Line 5 | Line 5 | static const char RCSid[] = "$Id$";
5   * General component matrix operations.
6   */
7  
8 < #include <stdio.h>
9 < #include <stdlib.h>
8 > #include <errno.h>
9   #include "rtio.h"
11 #include "resolu.h"
10   #include "rmatrix.h"
11 + #include "platform.h"
12  
13 < #define MAXCOMP         50              /* #components we support */
15 <
13 > /* Unary matrix operation(s) */
14   typedef struct {
17        double          sca[MAXCOMP];           /* scalar coefficients */
18        int             nsf;                    /* number of scalars */
15          double          cmat[MAXCOMP*MAXCOMP];  /* component transformation */
16 <        int             clen;                   /* number of coefficients */
17 <        int             transpose;              /* do transpose? */
18 <        int             op;                     /* '*' or '+' */
19 < } ROPERAT;                              /* matrix operation */
16 >        double          sca[MAXCOMP];           /* scalar coefficients */
17 >        const char      *csym;                  /* symbolic coefs or file */
18 >        short           clen;                   /* number of coefficients */
19 >        short           nsf;                    /* number of scalars */
20 >        short           transpose;              /* do transpose? */
21 > } RUNARYOP;
22  
23 < int     outfmt = DTfromHeader;          /* output format */
23 > /* Matrix input source and requested operation(s) */
24 > typedef struct {
25 >        const char      *inspec;                /* input specification */
26 >        RMPref          rmp;                    /* matrix preference */
27 >        RUNARYOP        preop;                  /* unary operation(s) */
28 >        RMATRIX         *mtx;                   /* original matrix if loaded */
29 >        int             binop;                  /* binary op with next (or 0) */
30 > } ROPMAT;
31 >
32   int     verbose = 0;                    /* verbose reporting? */
33  
34 < static void
35 < op_default(ROPERAT *op)
34 > /* Load matrix */
35 > int
36 > loadmatrix(ROPMAT *rop)
37   {
38 <        memset(op, 0, sizeof(ROPERAT));
39 <        op->op = '*';
38 >        if (rop->mtx != NULL)           /* already loaded? */
39 >                return(0);
40 >
41 >        rop->mtx = rmx_load(rop->inspec, rop->rmp);
42 >
43 >        return(!rop->mtx ? -1 : 1);
44   }
45  
46 < static RMATRIX *
47 < operate(RMATRIX *mleft, ROPERAT *op, const char *fname)
46 > extern int      checksymbolic(ROPMAT *rop);
47 >
48 > /* Check/set transform based on a reference input file */
49 > int
50 > checkreffile(ROPMAT *rop)
51   {
52 <        RMATRIX *mright = rmx_load(fname);
53 <        RMATRIX *mtmp;
54 <        int     i;
52 >        static const char       *curRF = NULL;
53 >        static RMATRIX          refm;
54 >        const int               nc = rop->mtx->ncomp;
55 >        int                     i;
56  
57 <        if (fname == NULL)
58 <                fname = "<stdin>";
59 <        if (mright == NULL) {
60 <                fputs(fname, stderr);
61 <                fputs(": cannot load matrix\n", stderr);
62 <                return(NULL);
57 >        if (!curRF || strcmp(rop->preop.csym, curRF)) {
58 >                FILE    *fp = fopen(rop->preop.csym, "rb");
59 >                if (!rmx_load_header(&refm, fp)) {
60 >                        fprintf(stderr, "%s: cannot read info header\n",
61 >                                        rop->preop.csym);
62 >                        curRF = NULL;
63 >                        if (fp) fclose(fp);
64 >                        return(-1);
65 >                }
66 >                fclose(fp);
67 >                curRF = rop->preop.csym;
68          }
69 <        if (op->transpose) {            /* transpose matrix? */
70 <                mtmp = rmx_transpose(mright);
71 <                if (mtmp == NULL) {
72 <                        fputs(fname, stderr);
73 <                        fputs(": transpose failed\n", stderr);
74 <                        rmx_free(mright);
75 <                        return(NULL);
69 >        if (refm.ncomp == 3) {
70 >                rop->preop.csym = (refm.dtype == DTxyze) ? "XYZ" : "RGB";
71 >                return(checksymbolic(rop));
72 >        }
73 >        if (refm.ncomp == 2) {
74 >                fprintf(stderr, "%s: cannot convert to 2 components\n",
75 >                                curRF);
76 >                return(-1);
77 >        }
78 >        if (refm.ncomp == 1) {
79 >                rop->preop.csym = "Y";          /* XXX big assumption */
80 >                return(checksymbolic(rop));
81 >        }
82 >        if (refm.ncomp == nc &&
83 >                        !memcmp(refm.wlpart, rop->mtx->wlpart, sizeof(refm.wlpart)))
84 >                return(0);                      /* nothing to do */
85 >
86 >        if ((nc <= 3) | (nc > MAXCSAMP) | (refm.ncomp > MAXCSAMP)) {
87 >                fprintf(stderr, "%s: cannot resample from %d to %d components\n",
88 >                                curRF, nc, refm.ncomp);
89 >                return(-1);
90 >        }
91 >        rop->preop.clen = refm.ncomp * nc;      /* compute spec to ref */
92 >
93 >        for (i = 0; i < nc; i++) {
94 >                SCOLOR  scstim, scresp;
95 >                int     j;
96 >                memset(scstim, 0, sizeof(COLORV)*nc);
97 >                scstim[i] = 1.f;
98 >                convertscolor(scresp, refm.ncomp, refm.wlpart[0], refm.wlpart[3],
99 >                                scstim, nc, rop->mtx->wlpart[0], rop->mtx->wlpart[3]);
100 >                for (j = refm.ncomp; j-- > 0; )
101 >                        rop->preop.cmat[j*nc + i] = scresp[j];
102 >        }
103 >        memcpy(rop->mtx->wlpart, refm.wlpart, sizeof(rop->mtx->wlpart));
104 >        return(0);
105 > }
106 >
107 > /* Compute conversion row from spectrum to one channel of RGB */
108 > void
109 > rgbrow(ROPMAT *rop, int r, int p)
110 > {
111 >        const int       nc = rop->mtx->ncomp;
112 >        const float *   wlp = rop->mtx->wlpart;
113 >        int             i;
114 >
115 >        for (i = nc; i--; ) {
116 >                int     nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
117 >                int     nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
118 >                COLOR   crgb;
119 >                spec_rgb(crgb, nmStart, nmEnd);
120 >                rop->preop.cmat[r*nc+i] = crgb[p];
121 >        }
122 > }
123 >
124 > /* Compute conversion row from spectrum to one channel of XYZ */
125 > void
126 > xyzrow(ROPMAT *rop, int r, int p)
127 > {
128 >        const int       nc = rop->mtx->ncomp;
129 >        const float *   wlp = rop->mtx->wlpart;
130 >        int             i;
131 >
132 >        for (i = nc; i--; ) {
133 >                int     nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
134 >                int     nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
135 >                COLOR   cxyz;
136 >                spec_cie(cxyz, nmStart, nmEnd);
137 >                rop->preop.cmat[r*nc+i] = cxyz[p];
138 >        }
139 > }
140 >
141 > /* Use the spectral sensitivity function to compute matrix coefficients */
142 > void
143 > sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
144 > {
145 >        const int       nc = rop->mtx->ncomp;
146 >        int             i;
147 >
148 >        for (i = nc; i--; ) {
149 >                SCOLOR  sclr;
150 >                memset(sclr, 0, sizeof(COLORV)*nc);
151 >                sclr[i] = 1.f;
152 >                rop->preop.cmat[r*nc+i] = (*sf)(sclr, nc, rop->mtx->wlpart);
153 >        }
154 > }
155 >
156 > /* Check/set symbolic transform */
157 > int
158 > checksymbolic(ROPMAT *rop)
159 > {
160 >        const int       nc = rop->mtx->ncomp;
161 >        const int       dt = rop->mtx->dtype;
162 >        double          cf = 1;
163 >        int             i, j;
164 >                                        /* check suffix => reference file */
165 >        if (strchr(rop->preop.csym, '.') > rop->preop.csym)
166 >                return(checkreffile(rop));
167 >
168 >        if (nc < 3) {
169 >                fprintf(stderr, "%s: -c '%s' requires at least 3 components\n",
170 >                                rop->inspec, rop->preop.csym);
171 >                return(-1);
172 >        }
173 >        rop->preop.clen = strlen(rop->preop.csym) * nc;
174 >        if (rop->preop.clen > MAXCOMP*MAXCOMP) {
175 >                fprintf(stderr, "%s: -c '%s' results in too many components\n",
176 >                                rop->inspec, rop->preop.csym);
177 >                return(-1);
178 >        }
179 >        for (j = 0; rop->preop.csym[j]; j++) {
180 >                int     comp = 0;
181 >                switch (rop->preop.csym[j]) {
182 >                case 'B':
183 >                case 'b':
184 >                        ++comp;
185 >                        /* fall through */
186 >                case 'G':
187 >                case 'g':
188 >                        ++comp;
189 >                        /* fall through */
190 >                case 'R':
191 >                case 'r':
192 >                        if (rop->preop.csym[j] <= 'Z')
193 >                                cf = 1./WHTEFFICACY;
194 >                        if (dt == DTxyze) {
195 >                                for (i = 3; i--; )
196 >                                        rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
197 >                        } else if (nc == 3)
198 >                                rop->preop.cmat[j*nc+comp] = 1.;
199 >                        else
200 >                                rgbrow(rop, j, comp);
201 >                        break;
202 >                case 'Z':
203 >                case 'z':
204 >                        ++comp;
205 >                        /* fall through */
206 >                case 'Y':
207 >                case 'y':
208 >                        ++comp;
209 >                        /* fall through */
210 >                case 'X':
211 >                case 'x':
212 >                        if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
213 >                                cf = WHTEFFICACY;
214 >                        if (dt == DTxyze) {
215 >                                rop->preop.cmat[j*nc+comp] = 1.;
216 >                        } else if (nc == 3) {
217 >                                for (i = 3; i--; )
218 >                                        rop->preop.cmat[j*nc+i] =
219 >                                                        rgb2xyzmat[comp][i];
220 >                        } else if (comp == CIEY)
221 >                                sensrow(rop, j, scolor2photopic);
222 >                        else
223 >                                xyzrow(rop, j, comp);
224 >
225 >                        for (i = nc*(cf != 1); i--; )
226 >                                rop->preop.cmat[j*nc+i] *= cf;
227 >                        break;
228 >                case 'S':               /* scotopic (il)luminance */
229 >                        cf = WHTSCOTOPIC;
230 >                        /* fall through */
231 >                case 's':
232 >                        sensrow(rop, j, scolor2scotopic);
233 >                        for (i = nc*(cf != 1); i--; )
234 >                                rop->preop.cmat[j*nc+i] *= cf;
235 >                        break;
236 >                case 'M':               /* melanopic (il)luminance */
237 >                        cf = WHTMELANOPIC;
238 >                        /* fall through */
239 >                case 'm':
240 >                        sensrow(rop, j, scolor2melanopic);
241 >                        for (i = nc*(cf != 1); i--; )
242 >                                rop->preop.cmat[j*nc+i] *= cf;
243 >                        break;
244 >                case 'A':               /* average component */
245 >                case 'a':
246 >                        for (i = nc; i--; )
247 >                                rop->preop.cmat[j*nc+i] = 1./(double)nc;
248 >                        break;
249 >                default:
250 >                        fprintf(stderr, "%s: -c '%c' unsupported\n",
251 >                                rop->inspec, rop->preop.csym[j]);
252 >                        return(-1);
253                  }
57                if (verbose) {
58                        fputs(fname, stderr);
59                        fputs(": transposed rows and columns\n", stderr);
60                }
61                rmx_free(mright);
62                mright = mtmp;
254          }
255 <        if (op->nsf > 0) {              /* apply scalar(s) */
256 <                if (op->clen > 0) {
257 <                        fputs("Options -s and -c are exclusive\n", stderr);
258 <                        rmx_free(mright);
259 <                        return(NULL);
255 >                                        /* return recommended output type */
256 >        if (!strcasecmp(rop->preop.csym, "XYZ")) {
257 >                if (dt <= DTspec)
258 >                        return(DTxyze);
259 >        } else if (!strcasecmp(rop->preop.csym, "RGB")) {
260 >                if (dt <= DTspec)
261 >                        return(DTrgbe);
262 >        } else if (dt == DTspec)
263 >                return(DTfloat);        /* probably not actual spectrum */
264 >        return(0);
265 > }
266 >
267 > /* Get matrix and perform unary operations */
268 > RMATRIX *
269 > loadop(ROPMAT *rop)
270 > {
271 >        int     outtype = 0;
272 >        RMATRIX *mres;
273 >        int     i, j;
274 >
275 >        if (loadmatrix(rop) < 0)                /* make sure we're loaded */
276 >                return(NULL);
277 >
278 >        if (rop->preop.csym &&                  /* symbolic transform? */
279 >                        (outtype = checksymbolic(rop)) < 0)
280 >                goto failure;
281 >        if (rop->preop.clen > 0) {              /* apply component transform? */
282 >                if (rop->preop.clen % rop->mtx->ncomp) {
283 >                        fprintf(stderr, "%s: -c must have N x %d coefficients\n",
284 >                                        rop->inspec, rop->mtx->ncomp);
285 >                        goto failure;
286                  }
287 <                if (op->nsf == 1) {
288 <                        for (i = mright->ncomp; --i; )
289 <                                op->sca[i] = op->sca[0];
290 <                } else if (op->nsf != mright->ncomp) {
287 >                if (rop->preop.nsf > 0) {       /* scale transform, first */
288 >                        if (rop->preop.nsf == 1) {
289 >                                for (i = rop->preop.clen; i--; )
290 >                                        rop->preop.cmat[i] *= rop->preop.sca[0];
291 >                        } else if (rop->preop.nsf*rop->mtx->ncomp != rop->preop.clen) {
292 >                                fprintf(stderr, "%s: -s must have one or %d factors\n",
293 >                                                rop->inspec,
294 >                                                rop->preop.clen/rop->mtx->ncomp);
295 >                                goto failure;
296 >                        } else {
297 >                                for (i = rop->preop.nsf; i--; )
298 >                                        for (j = rop->mtx->ncomp; j--; )
299 >                                                rop->preop.cmat[i*rop->mtx->ncomp+j]
300 >                                                                *= rop->preop.sca[i];
301 >                        }
302 >                }
303 >                mres = rmx_transform(rop->mtx, rop->preop.clen/rop->mtx->ncomp,
304 >                                        rop->preop.cmat);
305 >                if (mres == NULL) {
306 >                        fprintf(stderr, "%s: matrix transform failed\n",
307 >                                                rop->inspec);
308 >                        goto failure;
309 >                }
310 >                if (verbose)
311 >                        fprintf(stderr, "%s: applied %d x %d transform%s\n",
312 >                                        rop->inspec, mres->ncomp,
313 >                                        rop->mtx->ncomp,
314 >                                        rop->preop.nsf ? " (* scalar)" : "");
315 >                rop->preop.nsf = 0;             /* now folded in */
316 >                if ((mres->ncomp > 3) & (mres->dtype <= DTspec))
317 >                        outtype = DTfloat;      /* probably not actual spectrum */
318 >                rmx_free(rop->mtx);
319 >                rop->mtx = mres;
320 >        }
321 >        if (rop->preop.nsf > 0) {               /* apply scalar(s)? */
322 >                if (rop->preop.nsf == 1) {
323 >                        for (i = rop->mtx->ncomp; --i; )
324 >                                rop->preop.sca[i] = rop->preop.sca[0];
325 >                } else if (rop->preop.nsf != rop->mtx->ncomp) {
326                          fprintf(stderr, "%s: -s must have one or %d factors\n",
327 <                                        fname, mright->ncomp);
328 <                        rmx_free(mright);
77 <                        return(NULL);
327 >                                        rop->inspec, rop->mtx->ncomp);
328 >                        goto failure;
329                  }
330 <                if ((mleft == NULL) | (op->op != '+') &&
331 <                                !rmx_scale(mright, op->sca)) {
81 <                        fputs(fname, stderr);
330 >                if (!rmx_scale(rop->mtx, rop->preop.sca)) {
331 >                        fputs(rop->inspec, stderr);
332                          fputs(": scalar operation failed\n", stderr);
333 <                        rmx_free(mright);
84 <                        return(NULL);
333 >                        goto failure;
334                  }
335                  if (verbose) {
336 <                        fputs(fname, stderr);
336 >                        fputs(rop->inspec, stderr);
337                          fputs(": applied scalar (", stderr);
338 <                        for (i = 0; i < op->nsf; i++)
339 <                                fprintf(stderr, " %f", op->sca[i]);
338 >                        for (i = 0; i < rop->preop.nsf; i++)
339 >                                fprintf(stderr, " %f", rop->preop.sca[i]);
340                          fputs(" )\n", stderr);
341                  }
342          }
343 <        if (op->clen > 0) {             /* apply transform */
344 <                if (op->clen % mright->ncomp) {
345 <                        fprintf(stderr, "%s: -c must have N x %d coefficients\n",
346 <                                        fname, mright->ncomp);
347 <                        rmx_free(mright);
99 <                        return(NULL);
343 >        if (rop->preop.transpose) {             /* transpose matrix? */
344 >                if (!rmx_transpose(rop->mtx)) {
345 >                        fputs(rop->inspec, stderr);
346 >                        fputs(": transpose failed\n", stderr);
347 >                        goto failure;
348                  }
349 <                mtmp = rmx_transform(mright, op->clen/mright->ncomp, op->cmat);
350 <                if (mtmp == NULL) {
351 <                        fprintf(stderr, "%s: matrix transform failed\n", fname);
104 <                        rmx_free(mright);
105 <                        return(NULL);
349 >                if (verbose) {
350 >                        fputs(rop->inspec, stderr);
351 >                        fputs(": transposed rows and columns\n", stderr);
352                  }
107                if (verbose)
108                        fprintf(stderr, "%s: applied %d x %d transform\n",
109                                        fname, mtmp->ncomp, mright->ncomp);
110                rmx_free(mright);
111                mright = mtmp;
353          }
354 <        if (mleft == NULL)              /* just one matrix */
355 <                return(mright);
356 <        if (op->op == '*') {            /* concatenate */
357 <                RMATRIX *mres = rmx_multiply(mleft, mright);
354 >        mres = rop->mtx;
355 >        rop->mtx = NULL;
356 >        if (outtype)
357 >                mres->dtype = outtype;
358 >        return(mres);
359 > failure:
360 >        rmx_free(rop->mtx);
361 >        return(rop->mtx = NULL);
362 > }
363 >
364 > /* Execute binary operation, free matrix arguments and return new result */
365 > RMATRIX *
366 > binaryop(const char *inspec, RMATRIX *mleft, int op, RMATRIX *mright)
367 > {
368 >        RMATRIX *mres = NULL;
369 >        int     i;
370 >
371 >        if ((mleft == NULL) | (mright == NULL))
372 >                return(NULL);
373 >        switch (op) {
374 >        case '.':                       /* concatenate */
375 >                if (mleft->ncomp != mright->ncomp) {
376 >                        fputs(inspec, stderr);
377 >                        fputs(": # components do not match\n", stderr);
378 >                } else if (mleft->ncols != mright->nrows) {
379 >                        fputs(inspec, stderr);
380 >                        fputs(": mismatched dimensions\n",
381 >                                        stderr);
382 >                } else
383 >                        mres = rmx_multiply(mleft, mright);
384 >                rmx_free(mleft);
385 >                rmx_free(mright);
386                  if (mres == NULL) {
387 <                        fputs(fname, stderr);
388 <                        if (mleft->ncols != mright->nrows)
120 <                                fputs(": mismatched dimensions for multiply\n",
121 <                                                stderr);
122 <                        else
123 <                                fputs(": concatenation failed\n", stderr);
124 <                        rmx_free(mright);
387 >                        fputs(inspec, stderr);
388 >                        fputs(": concatenation failed\n", stderr);
389                          return(NULL);
390                  }
391                  if (verbose) {
392 <                        fputs(fname, stderr);
392 >                        fputs(inspec, stderr);
393                          fputs(": concatenated matrix\n", stderr);
394                  }
395 <                rmx_free(mright);
396 <                rmx_free(mleft);
397 <                mleft = mres;
398 <        } else if (op->op == '+') {
135 <                if (!rmx_sum(mleft, mright, op->nsf ? op->sca : (double *)NULL)) {
136 <                        fputs(fname, stderr);
395 >                break;
396 >        case '+':
397 >                if (!rmx_sum(mleft, mright, NULL)) {
398 >                        fputs(inspec, stderr);
399                          fputs(": matrix sum failed\n", stderr);
400 +                        rmx_free(mleft);
401                          rmx_free(mright);
402                          return(NULL);
403                  }
404                  if (verbose) {
405 <                        fputs(fname, stderr);
405 >                        fputs(inspec, stderr);
406                          fputs(": added in matrix\n", stderr);
407                  }
408                  rmx_free(mright);
409 <        } else {
410 <                fprintf(stderr, "%s: unknown operation '%c'\n", fname, op->op);
409 >                mres = mleft;
410 >                break;
411 >        case '*':
412 >        case '/': {
413 >                const char *    tnam = (op == '/') ?
414 >                                        "division" : "multiplication";
415 >                errno = 0;
416 >                if (!rmx_elemult(mleft, mright, (op == '/'))) {
417 >                        fprintf(stderr, "%s: element-wise %s failed\n",
418 >                                        inspec, tnam);
419 >                        rmx_free(mleft);
420 >                        rmx_free(mright);
421 >                        return(NULL);
422 >                }
423 >                if (errno)
424 >                        fprintf(stderr,
425 >                                "%s: warning - error during element-wise %s\n",
426 >                                        inspec, tnam);
427 >                else if (verbose)
428 >                        fprintf(stderr, "%s: element-wise %s\n", inspec, tnam);
429                  rmx_free(mright);
430 +                mres = mleft;
431 +                } break;
432 +        default:
433 +                fprintf(stderr, "%s: unknown operation '%c'\n", inspec, op);
434 +                rmx_free(mleft);
435 +                rmx_free(mright);
436                  return(NULL);
437          }
438 +        return(mres);
439 + }
440 +
441 + /* Perform matrix operations from left to right */
442 + RMATRIX *
443 + op_left2right(ROPMAT *mop)
444 + {
445 +        RMATRIX *mleft = loadop(mop);
446 +
447 +        while (mop->binop) {
448 +                if (mleft == NULL)
449 +                        break;
450 +                mleft = binaryop(mop[1].inspec,
451 +                                mleft, mop->binop, loadop(mop+1));
452 +                mop++;
453 +        }
454          return(mleft);
455   }
456  
457 < static int
457 > /* Perform matrix operations from right to left */
458 > RMATRIX *
459 > op_right2left(ROPMAT *mop)
460 > {
461 >        RMATRIX *mright;
462 >        int     rpos = 0;
463 >                                        /* find end of list */
464 >        while (mop[rpos].binop)
465 >                if (mop[rpos++].binop != '.') {
466 >                        fputs(
467 >                "Right-to-left evaluation only for matrix multiplication!\n",
468 >                                        stderr);
469 >                        return(NULL);
470 >                }
471 >        mright = loadop(mop+rpos);
472 >        while (rpos-- > 0) {
473 >                if (mright == NULL)
474 >                        break;
475 >                mright = binaryop(mop[rpos+1].inspec,
476 >                                loadop(mop+rpos), mop[rpos].binop, mright);
477 >        }
478 >        return(mright);
479 > }
480 >
481 > #define t_nrows(mop)    ((mop)->preop.transpose ? (mop)->mtx->ncols \
482 >                                                : (mop)->mtx->nrows)
483 > #define t_ncols(mop)    ((mop)->preop.transpose ? (mop)->mtx->nrows \
484 >                                                : (mop)->mtx->ncols)
485 >
486 > /* Should we prefer concatenating from rightmost matrix towards left? */
487 > int
488 > prefer_right2left(ROPMAT *mop)
489 > {
490 >        int     mri = 0;
491 >
492 >        while (mop[mri].binop)          /* find rightmost matrix */
493 >                if (mop[mri++].binop != '.')
494 >                        return(0);      /* pre-empt reversal for other ops */
495 >
496 >        if (mri <= 1)
497 >                return(0);              /* won't matter */
498 >
499 >        if (loadmatrix(mop+mri) < 0)    /* load rightmost cat */
500 >                return(1);              /* fail will bail in a moment */
501 >
502 >        if (t_ncols(mop+mri) == 1)
503 >                return(1);              /* definitely better R->L */
504 >
505 >        if (t_ncols(mop+mri) >= t_nrows(mop+mri))
506 >                return(0);              /* ...probably worse */
507 >
508 >        if (loadmatrix(mop) < 0)        /* load leftmost */
509 >                return(0);              /* fail will bail in a moment */
510 >
511 >        return(t_ncols(mop+mri) < t_nrows(mop));
512 > }
513 >
514 > int
515   get_factors(double da[], int n, char *av[])
516   {
517          int     ac;
# Line 161 | Line 521 | get_factors(double da[], int n, char *av[])
521          return(ac);
522   }
523  
524 + ROPMAT *
525 + resize_moparr(ROPMAT *mop, int n2alloc)
526 + {
527 +        int     nmats = 0;
528 +        int     i;
529 +
530 +        while (mop[nmats++].binop)
531 +                ;
532 +        for (i = nmats; i >= n2alloc; i--)
533 +                rmx_free(mop[i].mtx);
534 +        mop = (ROPMAT *)realloc(mop, n2alloc*sizeof(ROPMAT));
535 +        if (mop == NULL) {
536 +                fputs("Out of memory in resize_moparr()\n", stderr);
537 +                exit(1);
538 +        }
539 +        if (n2alloc > nmats)
540 +                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
541 +        return(mop);
542 + }
543 +
544   /* Load one or more matrices and operate on them, sending results to stdout */
545   int
546   main(int argc, char *argv[])
547   {
548 <        RMATRIX *mres = NULL;
549 <        ROPERAT op;
550 <        long    nbw;
551 <        int     i;
552 <                                        /* initialize */
553 <        op_default(&op);
548 >        int             outfmt = DTfromHeader;
549 >        const char      *defCsym = NULL;
550 >        int             nall = 2;
551 >        ROPMAT          *mop = (ROPMAT *)calloc(nall, sizeof(ROPMAT));
552 >        int             nmats = 0;
553 >        RMATRIX         *mres = NULL;
554 >        int             stdin_used = 0;
555 >        int             i;
556                                          /* get options and arguments */
557 <        for (i = 1; i < argc; i++)
558 <                if (argv[i][0] == '+' && !argv[i][1]) {
559 <                        op.op = '+';
560 <                } else if (argv[i][0] != '-' || !argv[i][1]) {
561 <                        char    *fname = NULL;  /* load matrix */
562 <                        if (argv[i][0] != '-')
563 <                                fname = argv[i];
564 <                        mres = operate(mres, &op, fname);
183 <                        if (mres == NULL) {
184 <                                fprintf(stderr, "%s: operation failed on '%s'\n",
185 <                                                argv[0], argv[i]);
186 <                                return(0);
557 >        for (i = 1; i < argc; i++) {
558 >                if (argv[i][0] && !argv[i][1] &&
559 >                                strchr(".+*/", argv[i][0]) != NULL) {
560 >                        if (!nmats || mop[nmats-1].binop) {
561 >                                fprintf(stderr,
562 >                        "%s: missing matrix argument before '%c' operation\n",
563 >                                                argv[0], argv[i][0]);
564 >                                return(1);
565                          }
566 <                        op_default(&op);        /* reset operator */
566 >                        mop[nmats-1].binop = argv[i][0];
567 >                } else if (argv[i][0] != '-' || !argv[i][1]) {
568 >                        if (argv[i][0] == '-') {
569 >                                if (stdin_used++) {
570 >                                        fprintf(stderr,
571 >                        "%s: standard input used for more than one matrix\n",
572 >                                                argv[0]);
573 >                                        return(1);
574 >                                }
575 >                                mop[nmats].inspec = stdin_name;
576 >                        } else
577 >                                mop[nmats].inspec = argv[i];
578 >                        if (!mop[nmats].preop.csym)
579 >                                mop[nmats].preop.csym = defCsym;
580 >                        if (nmats > 0 && !mop[nmats-1].binop)
581 >                                mop[nmats-1].binop = '.';
582 >                        nmats++;
583                  } else {
584                          int     n = argc-1 - i;
585                          switch (argv[i][1]) {   /* get option */
586                          case 'v':
587 <                                verbose = !verbose;
587 >                                verbose++;
588                                  break;
589                          case 'f':
590                                  switch (argv[i][2]) {
# Line 211 | Line 605 | main(int argc, char *argv[])
605                                  }
606                                  break;
607                          case 't':
608 <                                op.transpose = 1;
608 >                                mop[nmats].preop.transpose = 1;
609                                  break;
610                          case 's':
611                                  if (n > MAXCOMP) n = MAXCOMP;
612 <                                op.nsf = get_factors(op.sca, n, argv+i+1);
613 <                                i += op.nsf;
612 >                                i += mop[nmats].preop.nsf =
613 >                                        get_factors(mop[nmats].preop.sca,
614 >                                                        n, argv+i+1);
615 >                                if (mop[nmats].preop.nsf <= 0) {
616 >                                        fprintf(stderr, "%s: -s missing arguments\n",
617 >                                                        argv[0]);
618 >                                        goto userr;
619 >                                }
620                                  break;
621 +                        case 'C':
622 +                                if (!n || isflt(argv[i+1]))
623 +                                        goto userr;
624 +                                defCsym = mop[nmats].preop.csym = argv[++i];
625 +                                mop[nmats].preop.clen = 0;
626 +                                break;
627                          case 'c':
628 +                                if (n && !isflt(argv[i+1])) {
629 +                                        mop[nmats].preop.csym = argv[++i];
630 +                                        mop[nmats].preop.clen = 0;
631 +                                        break;
632 +                                }
633                                  if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
634 <                                op.clen = get_factors(op.cmat, n, argv+i+1);
635 <                                i += op.clen;
634 >                                i += mop[nmats].preop.clen =
635 >                                        get_factors(mop[nmats].preop.cmat,
636 >                                                        n, argv+i+1);
637 >                                if (mop[nmats].preop.clen <= 0) {
638 >                                        fprintf(stderr, "%s: -c missing arguments\n",
639 >                                                        argv[0]);
640 >                                        goto userr;
641 >                                }
642 >                                mop[nmats].preop.csym = NULL;
643                                  break;
644 +                        case 'r':
645 +                                if (argv[i][2] == 'f')
646 +                                        mop[nmats].rmp = RMPreflF;
647 +                                else if (argv[i][2] == 'b')
648 +                                        mop[nmats].rmp = RMPreflB;
649 +                                else
650 +                                        goto userr;
651 +                                break;
652                          default:
653                                  fprintf(stderr, "%s: unknown operation '%s'\n",
654                                                  argv[0], argv[i]);
655                                  goto userr;
656                          }
657                  }
658 <        if (mres == NULL)               /* check that we got something */
658 >                if (nmats >= nall)
659 >                        mop = resize_moparr(mop, nall += 2);
660 >        }
661 >        if (mop[0].inspec == NULL)      /* nothing to do? */
662                  goto userr;
663 <                                        /* write result to stdout */
664 <        newheader("RADIANCE", stdout);
665 <        printargs(argc, argv, stdout);
666 <        nbw = rmx_write(mres, outfmt, stdout);
238 <        /* rmx_free(mres); mres = NULL; */
239 <        if (nbw <= 0) {
240 <                fprintf(stderr, "%s: error writing result matrix\n", argv[0]);
663 >        if (mop[nmats-1].binop) {
664 >                fprintf(stderr,
665 >                        "%s: missing matrix argument after '%c' operation\n",
666 >                                argv[0], mop[nmats-1].binop);
667                  return(1);
668          }
669 <        if (verbose)
670 <                fprintf(stderr, "%s: %ld bytes written\n", argv[0], nbw);
671 <        return(0);
669 >                                        /* favor quicker concatenation */
670 >        mop[nmats].mtx = prefer_right2left(mop) ? op_right2left(mop)
671 >                                                : op_left2right(mop);
672 >        if (mop[nmats].mtx == NULL)
673 >                return(1);
674 >                                        /* apply trailing unary operations */
675 >        mop[nmats].inspec = "trailing_ops";
676 >        mres = loadop(mop+nmats);
677 >        if (mres == NULL)
678 >                return(1);
679 >        if (outfmt == DTfromHeader)     /* check data type */
680 >                outfmt = mres->dtype;
681 >        if (outfmt == DTrgbe) {
682 >                if (mres->ncomp > 3)
683 >                        outfmt = DTspec;
684 >                else if (mres->dtype == DTxyze)
685 >                        outfmt = DTxyze;
686 >        }
687 > #if DTrmx_native==DTfloat
688 >        if (outfmt == DTdouble)
689 >                fprintf(stderr,
690 >                        "%s: warning - writing float result as double\n",
691 >                                argv[0]);
692 > #endif
693 >        newheader("RADIANCE", stdout);  /* write result to stdout */
694 >        printargs(argc, argv, stdout);
695 >        return(rmx_write(mres, outfmt, stdout) ? 0 : 1);
696   userr:
697          fprintf(stderr,
698 <        "Usage: %s [-v][-f[adfc][-t][-s sf .. | -c ce ..] m1 [+] .. > mres\n",
698 >        "Usage: %s [-v][-f{adfc}][-t][-s sf .. | -c ce ..][-rf|-rb] m1 [.+*/] .. > mres\n",
699                          argv[0]);
700          return(1);
701   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines