source: trunk/MATRICE/cmapply.pro @ 2

Last change on this file since 2 was 2, checked in by opalod, 22 years ago

Initial revision

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 KB
Line 
1;+
2; NAME:
3;   CMAPPLY
4;
5; AUTHOR:
6;   Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
7;   craigm@lheamail.gsfc.nasa.gov
8;
9; PURPOSE:
10;   Applies a function to specified dimensions of an array
11;
12; MAJOR TOPICS:
13;   Arrays
14;
15; CALLING SEQUENCE:
16;   XX = CMAPPLY(OP, ARRAY, DIMS, [/DOUBLE], [TYPE=TYPE])
17;
18; DESCRIPTION:
19;   CMAPPLY will apply one of a few select functions to specified
20;   dimensions of an array.  Unlike some IDL functions, you *do* have
21;   a choice of which dimensions that are to be "collapsed" by this
22;   function.  Iterative loops are avoided where possible, for
23;   performance reasons.
24;
25;   The possible functions are:             (and number of loop iterations:)
26;     +     - Performs a sum (as in TOTAL)       number of collapsed dimensions
27;     *     - Performs a product                 same
28;     AND   - Finds LOGICAL "AND" (not bitwise)  same
29;     OR    - Finds LOGICAL "OR"  (not bitwise)  same
30;
31;     MIN   - Finds the minimum value            number of output elements
32;     MAX   - Finds the maximum value            same
33;
34; INPUTS:
35;
36;   OP - The operation to perform, as a string.  May be upper or lower
37;        case.
38;
39;   ARRAY - An array of values to be operated on.  Must not be of type
40;           STRING (7) or STRUCTURE (8).
41;
42; OPTIONAL INPUTS:
43;
44;   DIMS - An array of dimensions that are to be "collapsed", where
45;          the the first dimension starts with 1 (ie, same convention
46;          as IDL function TOTAL).  Whereas TOTAL only allows one
47;          dimension to be added, you can specify multiple dimensions
48;          to CMAPPLY.  Order does not matter, since all operations
49;          are associative and transitive.  NOTE: the dimensions refer
50;          to the *input* array, not the output array.  IDL allows a
51;          maximum of 8 dimensions.
52;          DEFAULT: 1 (ie, first dimension)
53;
54; KEYWORDS:
55;
56;   DOUBLE - Set this if you wish the internal computations to be done
57;            in double precision if necessary.  If ARRAY is double
58;            precision (real or complex) then DOUBLE=1 is implied.
59;            DEFAULT: not set
60;
61;   TYPE - Set this to the IDL code of the desired output type (refer
62;          to documentation of SIZE()).  Internal results will be
63;          rounded to the nearest integer if the output type is an
64;          integer type.
65;          DEFAULT: same is input type
66;
67; RETURN VALUE:
68;
69;   An array of the required TYPE, whose elements are the result of
70;   the requested operation.  Depending on the operation and number of
71;   elements in the input array, the result may be vulnerable to
72;   overflow or underflow.
73;
74; EXAMPLES:
75;   Shows how CMAPPLY can be used to total the second dimension of the
76;   array called IN.  This is equivalent to OUT = TOTAL(IN, 2)
77;
78;   IDL> IN  = INDGEN(5,5)
79;   IDL> OUT = CMAPPLY('+', IN, [2])
80;   IDL> HELP, OUT
81;   OUT             INT       = Array[5]
82;
83;   Second example.  Input is assumed to be an 5x100 array of 1's and
84;   0's indicating the status of 5 detectors at 100 points in time.
85;   The desired output is an array of 100 values, indicating whether
86;   all 5 detectors are on (=1) at one time.  Use the logical AND
87;   operation.
88;
89;   IDL> IN = detector_status             ; 5x100 array
90;   IDL> OUT = CMAPPLY('AND', IN, [1])    ; collapses 1st dimension
91;   IDL> HELP, OUT
92;   OUT             BYTE      = Array[100]
93;
94;   (note that MIN could also have been used in this particular case,
95;   although there would have been more loop iterations).
96;
97;   Third example.  Shows sum over first and third dimensions in an
98;   array with dimensions 4x4x4:
99;
100;   IDL> IN = INDGEN(4,4,4)
101;   IDL> OUT = CMAPPLY('+', IN, [1,3])
102;   IDL> PRINT, OUT
103;        408     472     536     600
104;
105; MODIFICATION HISTORY:
106;   Mar 1998, Written, CM
107;
108;-
109
110function cmapply, op, array, dimapply, double=dbl, type=type
111
112  if n_params() LT 2 then begin
113      message, "USAGE: XX = CMAPPLY('OP',ARRAY,2)", /info
114      message, '       where OP is +, *, AND, OR, MIN, MAX'
115      return, -1L
116  endif
117
118  ;; Parameter checking
119  ;; 1) the dimensions of the array
120  sz = size(array)
121  if sz(0) EQ 0 then $
122    message, 'ERROR: ARRAY must be an array!'
123
124  ;; 2) The type of the array
125  if sz(sz(0)+1) EQ 0 OR sz(sz(0)+1) EQ 7 OR sz(sz(0)+1) EQ 8 then $
126    message, 'ERROR: Cannot apply to UNDEFINED, STRING, or STRUCTURE'
127  if n_elements(type) EQ 0 then type = sz(sz(0)+1)
128
129  ;; 3) The type of the operation
130  szop = size(op)
131  if szop(szop(0)+1) NE 7 then $
132    message, 'ERROR: operation OP was not a string'
133
134  ;; 4) The dimensions to apply (default is to apply to first dim)
135  if n_params() EQ 2 then dimapply = 1
136  dimapply = [ dimapply ]
137  dimapply = dimapply(sort(dimapply))   ; Sort in ascending order
138  napply = n_elements(dimapply)
139
140  ;; 5) Use double precision if requested or if needed
141  if n_elements(dbl) EQ 0 then begin
142      dbl=0
143      if type EQ 5 OR type EQ 9 then dbl=1
144  endif
145
146  newop = strupcase(op)
147  newarr = array
148  newarr = reform(newarr, sz(1:sz(0)), /overwrite)
149  case 1 of
150
151      ;; *** Addition
152      (newop EQ '+'): begin
153          for i = 0, napply-1 do begin
154              newarr = total(temporary(newarr), dimapply(i)-i, double=dbl)
155          endfor
156      end
157
158      ;; *** Multiplication
159      (newop EQ '*'): begin ;; Multiplication (by summation of logarithms)
160          dummy = check_math(1, 1)  ;; Disable printing of messages
161          ;; The following step seems to be the slowest
162          newarr = alog(abs(dcomplex(temporary(newarr))))
163          for i = 0, napply-1 do begin
164              newarr = total(temporary(newarr), dimapply(i)-i, double=1)
165          endfor
166          newarr = exp(temporary(newarr))
167          dummy = check_math(0, 0)  ;; Enable printing of messages
168      end
169
170      ;; *** LOGICAL AND or OR
171      ((newop EQ 'AND') OR (newop EQ 'OR')): begin
172          newarr = temporary(newarr) NE 0
173          totelt = 1L
174          for i = 0, napply-1 do begin
175              newarr = total(temporary(newarr), dimapply(i)-i)
176              totelt = totelt * sz(dimapply(i))
177          endfor
178          if newop EQ 'AND' then return, (round(newarr) EQ totelt)
179          if newop EQ 'OR'  then return, (round(newarr) NE 0)
180      end
181
182      ;; *** Operations requiring element by element access ... ho hum
183      ((newop EQ 'MAX') OR (newop EQ 'MIN')): begin
184          ;; First task: rearrange dimensions so that the dimensions
185          ;; that are "kept" (ie, uncollapsed) are at the back
186          dimkeep = where(histogram(dimapply,min=1,max=sz(0)) ne 1, count)
187          if count EQ 0 then begin
188              case newop of
189                  'MAX': return, max(newarr)
190                  'MIN': return, min(newarr)
191              endcase
192          endif
193          newarr = transpose( temporary(newarr), [ dimapply-1, dimkeep ])
194          ;; totcol is the total number of collapsed elements
195          totcol = exp(total(alog(sz(dimapply))))
196          totkeep = exp(total(alog(sz(dimkeep+1))))
197          ;; this new array has two dimensions:
198          ;;   * the first, all elements that will be collapsed
199          ;;   * the second, all dimensions that will be preserved
200          ;; (the ordering is so that all elements to be collapsed are
201          ;;  adjacent in memory)
202          newarr = reform(newarr, round([totcol, totkeep]), /overwrite)
203         
204          ;; Next task: create result array
205          result = make_array(dimension=sz(dimkeep+1), type=type)
206
207          ;; Finally, compute the result, element by element
208          case newop of
209              'MAX': for i = 0, totkeep-1 do result(i) = max(newarr(*,i))
210              'MIN': for i = 0, totkeep-1 do result(i) = min(newarr(*,i))
211          endcase
212          return, result
213      end
214             
215  endcase
216
217  newsz = size(newarr)
218  if type EQ newsz(newsz(0)+1) then return, newarr
219
220  ;; Cast the result into the desired type, if necessary
221  castfns = ['UNDEF', 'BYTE', 'FIX', 'LONG', 'FLOAT', $
222             'DOUBLE', 'COMPLEX', 'UNDEF', 'UNDEF', 'DCOMPLEX' ]
223  if type GE 1 AND type LE 3 then $
224    return, call_function(castfns(type), round(newarr)) $
225  else $
226    return, call_function(castfns(type), newarr)
227end
Note: See TracBrowser for help on using the repository browser.