casacore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LatticeStepper.h
Go to the documentation of this file.
1 //# LatticeStepper.h: provides 'natural' traversal, by cursor shape
2 //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001
3 //# Associated Universities, Inc. Washington DC, USA.
4 //#
5 //# This library is free software; you can redistribute it and/or modify it
6 //# under the terms of the GNU Library General Public License as published by
7 //# the Free Software Foundation; either version 2 of the License, or (at your
8 //# option) any later version.
9 //#
10 //# This library is distributed in the hope that it will be useful, but WITHOUT
11 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 //# License for more details.
14 //#
15 //# You should have received a copy of the GNU Library General Public License
16 //# along with this library; if not, write to the Free Software Foundation,
17 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 //#
19 //# Correspondence concerning AIPS++ should be addressed as follows:
20 //# Internet email: aips2-request@nrao.edu.
21 //# Postal address: AIPS++ Project Office
22 //# National Radio Astronomy Observatory
23 //# 520 Edgemont Road
24 //# Charlottesville, VA 22903-2475 USA
25 //#
26 //# $Id$
27 
28 #ifndef LATTICES_LATTICESTEPPER_H
29 #define LATTICES_LATTICESTEPPER_H
30 
31 //# Includes
32 #include <casacore/casa/aips.h>
36 
37 
38 namespace casacore { //# NAMESPACE CASACORE - BEGIN
39 
40 // <summary>
41 // Traverse a Lattice by cursor shape
42 // </summary>
43 
44 // <use visibility=export>
45 
46 // <reviewed reviewer="Peter Barnes" date="1999/10/30" tests="tLatticeStepper.cc">
47 // </reviewed>
48 
49 // <prerequisite>
50 // <li> <linkto class=LatticeNavigator> LatticeNavigator </linkto>
51 // </prerequisite>
52 
53 // <etymology>
54 // LatticeStepper is so-called because it performs the calculations
55 // necessary to step through a Lattice. The next position is always one
56 // simple step forward from the current position. The step-size is
57 // calculated directly from the size of the LatticeIterator's cursor or
58 // window.
59 // </etymology>
60 
61 // <synopsis>
62 // When you wish to traverse a Lattice (say, a PagedArray or an Image) you
63 // will usually create a LatticeIterator. Once created, you must attach a
64 // LatticeNavigator to the iterator. A LatticeStepper, is a concrete class
65 // derived from the abstract LatticeNavigator that allows you to move
66 // sequentially through the Lattice.
67 // <p>
68 // In constructing a LatticeStepper, you specify the Lattice shape and the
69 // shape of the "cursor" used to step through the data. The cursor position
70 // can be incremented or decremented to retrieve the next portion of the
71 // Lattice.
72 // The specified cursor shape can (and often will) have fewer dimensions
73 // that the Lattice itself. For example if we have a 4-dimensional Lattice
74 // with <src>latticeShape = IPosition(4,64,64,4,16)</src>, then specifying a
75 // cursor of <src>cursorShape = IPosition(1,64)</src>, will step through the
76 // hypercube row by row. When the cursor shape has fewer dimensions than the
77 // Lattice degenerate dimensions are added to the end of the cursor so that
78 // in the above example the specified cursor is assumed to mean
79 // <src>cursorShape = IPosition(4,64,1,1,1)</src>. To access the data
80 // spectrum by spectrum (assuming the last axis is the spectral axis), you
81 // must use a 1-dimensional cursor of <src>IPosition(4,1,1,1,16)</src>. The
82 // <src>cursorShape</src> function always returns a shape with as many
83 // dimensions as the underlying Lattice.
84 // <p>
85 // It is an error (and an exception will be thrown) if the cursor has more
86 // dimensions than the Lattice or if it is larger on any axis than the
87 // Lattice shape.
88 // <br>
89 // Also the cursor shape on all axes must be less than or equal to the Lattice
90 // shape on that axis. Otherwise an exception will be thrown.
91 // <p>
92 // In principle cursor axes with length 1 are degenerate axes. They
93 // are removed from the lattice cursor if the
94 // <linkto class=LatticeIterator>LatticeIterator</linkto> cursor is accessed
95 // using e.g. the <src>matrixCursor</src> function.
96 // Using a special LatticeStepper constructor it is, however, possible
97 // to specify which cursor axes with length 1 have to be treated as
98 // normal axes. In that way one can be sure that a cursor is, for
99 // example, always 2D, even if an axis happens to have length 1.
100 // <srcblock>
101 // IPosition latticeShape(4,20,16,1,4);
102 // IPosition cursorAxes(2,1,2);
103 // IPosition cursorShape(2,16,1);
104 // IPosition axisPath;
105 // LatticeStepper stepper(latticeShape, cursorShape,
106 // cursorAxes, axisPath);
107 // </srcblock>
108 // This results in a cursor with shape [1,16,1,1]. The first and last
109 // axis are degenerate, so the cursor can also be accessed using
110 // <src>matrixCursor</src> (with shape [16,1]).
111 // Note that the cursor shape could also be specified as [1,16,1,1].
112 // <p>
113 // The "path" of the cursor through the Lattice can be controlled by
114 // specifying an axisPath during construction of the class. This is an
115 // IPosition which has exactly as many elements as the Lattice
116 // dimension. Each element must contain an integer between
117 // 0 -- Lattice_Dimension-1, and must be unique. For example,
118 // <srcblock>
119 // axisPath = IPosition(4,0,1,2,3) or
120 // axisPath = IPosition(4,3,1,2,0)
121 // </srcblock>
122 // are valid but
123 // <srcblock>
124 // axisPath = IPosition(4,1,2,3,4) or
125 // axisPath = IPosition(4,0,1,1,3)
126 // </srcblock>
127 // are not, given the latticeShape specified above. An exception is thrown
128 // if the AxisPath is bad.
129 // <br>
130 // The "axis path" defines which axis will be iterated through fastest as
131 // the cursor moves through the Lattice. With the above mentioned
132 // 4-dimensional Lattice and a single element cursor
133 // (<src>cursorShape=IPosition(4,1,1,1,1)</src>) setting an
134 // <src>axisPath=IPosition(4,0,1,2,3)</src> will move the cursor through all
135 // the columns, and then onto the next row, and again through all the
136 // columns in the second row. Once all the rows in the first plane have
137 // been exhausted the cursor will then iterate to the next plane, and
138 // eventually to the next spectral channel. If, however, the axisPath was
139 // <src>axisPath=IPosition(4,3,0,1,2)</src> then the cursor would iterate
140 // through each spectral channel first, before moving onto the next column in
141 // the first row.
142 // <p>
143 // The cursor never changes dimensionality as it traverses the Lattice. But it
144 // may change shape if the cursor shape is not a factor of the Lattice
145 // shape. A cursor shape is not a factor of the Lattice shape if the Lattice
146 // shape is not an integer multiple of the cursor shape on all axes.
147 // The integer multiplier need not to be the same for each axes.
148 // For example, for a Lattice of shape [10,10,10] a cursor of shape [8,5,2]
149 // is not a factor but one with a shape of [10,5,1] is.
150 // <br>
151 // When the cursor is not congruent with the Lattice moving the cursor through
152 // the Lattice will sometimes result in part of the cursor hanging over the
153 // edge of the Lattice. When this occurs the hangOver member function will
154 // return True. What to do in these situtations is specified by the
155 // hangOverPolicy enumerator.
156 // <ol>
157 // <li>
158 // If the LatticeStepper::PAD option (the default) is used at construction time
159 // the cursor shape does not change. The parts of the cursor that hang over the
160 // edge of the Lattice are filled with a default value, usually zero, that is
161 // defined by the particular LatticeIterator used.
162 // <li>
163 // If the LatticeStepper::RESIZE option is used at construction time the cursor
164 // shape does change to a smaller value when near the edge of the Lattice so
165 // that it is just big enough. For example with a Lattice shape of 10x10 and a
166 // cursor of 8x8 the cursor shape will initally be 8x8, then resize to 2x8 on
167 // the first step, then resize to 8x2 on the second step and finally resize to
168 // 2x2. The hangover function will return True for the last three steps, even
169 // though the cursor has resized.
170 // </ol>
171 // The portion of the Lattice that the cursor will traverse can be
172 // restricted to a region defined by a top right corner, bottom left corner
173 // and a step size. This is done using the <src>subSection</src> function,
174 // which also resets the cursor position to the origin of the sub-Lattice.
175 // The cursor shape will remain unchanged. It is no error when the cursor
176 // shape exceeds the sub-Lattice shape (instead it is a hangover state).
177 // <br>
178 // If a sub-Lattice is defined then cursor positions relative
179 // to the sub-Lattice origins can be obtained using the
180 // <src>relativePosition</src> function rather than the
181 // <src>position</src> function, which always returns positions relative to
182 // the origin of the main Lattice.
183 // <br>
184 // To change the size of the sub-Lattice simply call the
185 // <src>subSection</src> function again with a different trc, blc &
186 // inc. This first clears the old sub-Lattice, then imposes the newly
187 // specified one, and finally moves the cursor to the origin of the
188 // new sub-Lattice.
189 // </synopsis>
190 
191 // <example>
192 // This example is of a global function that will iterate through a
193 // 4-dimensional Lattice. It is assumed that the axes are RA, Dec, Stokes &
194 // Frequency, and it will calculate the average flux in the I polarization
195 // on each frequency channel. Imagine it is passed a data set (ie. Lattice)
196 // of size 256 x 256 x 4 x 1024. This corresponds to 1GByte of data. However
197 // the iterator will page through this data using a cursor of size 256 x 256
198 // (or 256kByte) and will only read (because of subsectioning) the relevant
199 // quarter of the data set. It is usually a good idea to set up the axis
200 // path as this is gives hints to data cache about which data to retrieve in
201 // advance.
202 // <srcblock>
203 // void averageFluxByChannel(const Lattice<Float>& data)
204 // {
205 // // for convenience, get the shape into a local variable
206 // IPosition latticeShape = data.shape();
207 // cout << "Data has shape: " << latticeShape << endl;
208 //
209 // // check that the data has 4 axes.
210 // DebugAssert(latticeShape.nelements() == 4, AipsError);
211 //
212 // // specify the cursor, or window shape. Here the cursor is a matrix
213 // // that is the shape of the first plane of our Lattice.
214 // // For convenience, get the first two axis lengths into local vars
215 // uInt nCols = latticeShape(0);
216 // uInt nRows = latticeShape(1);
217 // IPosition cursorShape(2, nCols, nRows);
218 //
219 // // construct a stepper, which needs to know the shape of the lattice
220 // // and the shape of the iterator's cursor. By using cursorShape, which
221 // // is directly determined by the lattice's shape, we can be sure
222 // // that the cursor is a factor of the lattice, and thus that
223 // // all elements will be picked up efficiently during the traversal.
224 // // Because we will not be iterating through the stokes axis this axis
225 // // is made the slowest moving one.
226 // IPosition axisPath(4, 0, 1, 3, 2)
227 // LatticeStepper stepper(latticeShape, cursorShape, axisPath);
228 //
229 // // Subsection the stepper so that it only iterates through the I
230 // // Stokes parameter (assumed to be when the third axis is zero)
231 // uInt nFreqs = latticeShape(3);
232 // IPosition blc(4, 0, 0, 0, 0), trc(4, nCols-1, nRows-1, 0, nFreqs-1);
233 // stepper.subSection(blc, trc);
234 //
235 // // construct the iterator. Since we only want to read the Data,
236 // // use the read-only class, which disallows writing back to the cursor
237 // // (and hence is more efficient).
238 // RO_LatticeIterator<Float> iterator(data, stepper);
239 //
240 // Vector<Float> spectrum(nFreqs);
241 // spectrum = 0.0;
242 // uInt channel = 0;
243 // for (iterator.reset(); !iterator.atEnd(); iterator++) {
244 // const Matrix<Float>& cursor = iterator.matrixCursor();
245 // for (uInt col = 0; col < nCols; col++) {
246 // for (uInt row = 0; row < nRows; row++) {
247 // spectrum(channel) += cursor(col, row);
248 // }
249 // }
250 // channel++;
251 // } // for iterator
252 // cout << "Average spectrum is: "
253 // << spectrum / cursorShape.product() << endl;
254 // }
255 // </srcblock>
256 // </example>
257 
258 // <motivation>
259 // Moving through a Lattice by equal sized chunks, and without regard
260 // to the nature of the data, is a basic and common procedure.
261 // </motivation>
262 
263 //# <todo asof="1995/08/28">
264 //# </todo>
265 
266 
268 {
269 public:
270 
271  // The hangOverPolicy enumerator is used in the constructors to indicate
272  // what this class should do when the cursor shape hangs over the edge
273  // of the Lattice.
275  // PAD is the default and means that the cursor size supplied by the user is
276  // kept fixed. But if the cursor overhangs the Lattice the part that
277  // overhangs is filled with a default value that is specified by the
278  // Iterator. Currently the default value is zero.
280  // RESIZE means that the cursor shape is adjusted whenever it approaches the
281  // edges of the Lattice so that it is always the right size to include only
282  // the parts of the Lattice that are available. The user specified cursor
283  // shape now becomes the default and largest possible cursor shape.
285 
286  // The first argument is the shape of the Lattice to be iterated and the
287  // second argument is the shape of the cursor. The cursor will increment
288  // initially along first axis, then the second and then the third
289  // (ie. axisPath = IPosition(ndim,0,1,2,...))
290  // The dimensionality of the cursorShape can be less than the
291  // dimensionality of the lattice. It will be padded with 1s.
292  // <br>The cursorShape axes with length > 1 are seen as the true cursor axes.
293  // The other axes are degenerated and are removed by the functions
294  // <src>vectorCursor()</src>, etc., in class
295  // <linkto class=RO_LatticeIterator>(RO_)LatticeIterator</linkto>.
297  const uInt hangOverPolicy=PAD);
298 
299  // Same as the above constructor except that the axis path is explicitly
300  // specified. The axis path is described in the synopsis above.
302  const IPosition& axisPath, const uInt hangOverPolicy=PAD);
303 
304  // Same as the above constructor except that the cursor axes are
305  // explicitly specified. This can be useful to avoid that cursor axes
306  // with length=1 are treated as degenerated axes by the Iterator classes.
307  // The following rules have to be obeyed:
308  // <br>- <src>cursorAxes.nelements() <= latticeShape.nelements()</src>
309  // <br>- <src>cursorShape.nelements() == latticeShape.nelements()</src>
310  // <br>or <src>cursorShape.nelements() == cursorAxes.nelements()</src>
311  // The latter means that the cursorShape contains the axes mentioned in
312  // cursorAxes.
313  // <br>See also the example in the synopsis.
315  const IPosition& cursorAxes,
316  const IPosition& axisPath, const uInt hangOverPolicy=PAD);
317 
318  // The copy constructor uses copy semantics.
319  LatticeStepper (const LatticeStepper& other);
320 
321  ~LatticeStepper();
322 
323  // The assignment operator uses copy semantics.
325 
326  // Increment operator (postfix version) - move the cursor
327  // forward one step. Returns True if the cursor was moved.
328  virtual Bool operator++(int);
329 
330  // Decrement operator (postfix version) - move the cursor
331  // backwards one step. Returns True if the cursor was moved.
332  virtual Bool operator--(int);
333 
334  // Function to move the cursor to the beginning of the (sub)-Lattice. Also
335  // resets the number of steps (<src>nsteps</src> function) to zero.
336  virtual void reset();
337 
338  // Function which returns "True" if the cursor is at the beginning of the
339  // (sub)-Lattice, otherwise, returns "False"
340  virtual Bool atStart() const;
341 
342  // Function which returns "True" if an attempt has been made to increment
343  // the cursor beyond the end of the (sub)-Lattice.
344  virtual Bool atEnd() const;
345 
346  // Function to return the number of steps (increments & decrements) taken
347  // since construction (or since last reset). This is a running count of
348  // all cursor movement (operator++ or operator--), even though
349  // N-increments followed by N-decrements will ALWAYS leave the cursor in
350  // the original position.
351  virtual uInt nsteps() const;
352 
353  // Functions which return the current position of the beginning of the
354  // cursor. The <src>position</src> function is relative to the origin
355  // in the main Lattice and the <src>relativePosition</src> function is
356  // relative to the origin and increment used in the sub-Lattice (defined
357  // using the <src>subSection</src> function). If no sub-Lattice is defined
358  // the two functions return identical positions.
359  // <group>
360  virtual IPosition position() const;
361  virtual IPosition relativePosition() const;
362  // </group>
363 
364  // Functions which return the current position of the end of the
365  // cursor. The <src>endPosition</src> function is relative to the origin
366  // in the main Lattice and the <src>relativeEndPosition</src> function
367  // is relative to the origin and increment used in the sub-Lattice
368  // (defined using the <src>subSection</src> function). If no sub-Lattice
369  // is defined the two functions return identical positions.
370  // <note role=caution> It returns the end position in the lattice and
371  // does not take overhang into account. </note>
372  // <group>
373  virtual IPosition endPosition() const;
374  virtual IPosition relativeEndPosition() const;
375  // </group>
376 
377  // Functions which return the shape of the Lattice being iterated
378  // through. <src>latticeShape</src> always returns the shape of the main
379  // Lattice while <src>subLatticeShape</src> returns the shape of any
380  // sub-Lattice defined using the <src>subSection</src> function.
381  // <group>
382  virtual IPosition latticeShape() const;
383  virtual IPosition subLatticeShape() const;
384  // </group>
385 
386  // Functions to change the cursor shape to a new one. They always reset
387  // the cursor to the beginning of the Lattice (and reset the number of
388  // steps to zero).
389  // <group>
390  void setCursorShape (const IPosition& cursorShape);
391  void setCursorShape (const IPosition& cursorShape,
392  const IPosition& cursorAxes);
393  // </group>
394 
395  // Function which returns the shape of the cursor. This always includes
396  // all axes (ie. it includes degenerates axes)
397  virtual IPosition cursorShape() const;
398 
399  // Function which returns the axes of the cursor.
400  virtual IPosition cursorAxes() const;
401 
402  // Function which returns "True" if the increment/decrement operators have
403  // moved the cursor position such that part of the cursor beginning or end
404  // is hanging over the edge of the (sub)-Lattice.
405  virtual Bool hangOver() const;
406 
407  // Functions to specify a "section" of the Lattice to step over. A section
408  // is defined in terms of the Bottom Left Corner (blc), Top Right Corner
409  // (trc), and step size (inc), on ALL of its axes, including degenerate
410  // axes. The step size defaults to one if not specified.
411  // <group>
412  virtual void subSection (const IPosition& blc, const IPosition& trc);
413  virtual void subSection (const IPosition& blc, const IPosition& trc,
414  const IPosition& inc);
415  // </group>
416 
417  // Return the bottom left hand corner (blc), top right corner (trc) or
418  // step size (increment) used by the current sub-Lattice. If no
419  // sub-Lattice has been defined (with the <src>subSection</src> function)
420  // these functions return blc=0, trc=latticeShape-1, increment=1, ie. the
421  // entire Lattice.
422  // <group>
423  virtual IPosition blc() const;
424  virtual IPosition trc() const;
425  virtual IPosition increment() const;
426  // </group>
427 
428  // Return the axis path.
429  virtual const IPosition& axisPath() const;
430 
431  // Function which returns a pointer to dynamic memory of an exact copy
432  // of this instance. The pointer returned by this function must
433  // be deleted externally.
434  virtual LatticeNavigator* clone() const;
435 
436  // Function which checks the internal data of this class for correct
437  // dimensionality and consistant values.
438  // Returns True if everything is fine otherwise returns False
439  virtual Bool ok() const;
440 
441  // Calculate the cache size (in tiles) for this type of access to a lattice
442  // in the given row of the tiled hypercube.
443  virtual uInt calcCacheSize (const IPosition& cubeShape,
444  const IPosition& tileShape,
445  uInt maxCacheSize, uInt bucketSize) const;
446 
447 private:
448  // Prevent the default constructor from being used.
449  LatticeStepper();
450  // Pad the cursor to the right number of dimensions.
451  void padCursor();
452  // Check if the cursor shape is a factor of the Lattice shape.
453  Bool niceFit() const;
454 
455 
456  LatticeIndexer itsIndexer;//# Knows about the (sub)-Lattice shape and how
457  //# to traverse it.
458  IPosition itsCursorAxes; //# the cursor axes
459  IPosition itsCursorShape; //# The shape of the cursor
460  IPosition itsCursorPos; //# The current position of the iterator.
461  IPosition itsAxisPath; //# the heading to follow for the cursor
462  uInt itsNsteps; //# the number of iterator steps taken thus far;
463  //# set to 0 on reset ()
464  Bool itsEnd; //# is the cursor beyond the end?
465  Bool itsStart; //# is the cursor at the beginning?
466  Bool itsNiceFit; //# if the cursor shape is a sub-multiple of the
467  //# Lattice shape then set this to True. Used to
468  //# avoid needing to test for a cursor hanging
469  //# over the edge of the lattice.
470  Bool itsHangover; //# this data member is set by the increment and
471  //# decrement operators if itsNiceFit == False. It
472  //# is used to tell if the cursor "Hangs over"
473  //# the edge of the lattice shape.
474  uInt itsPolicy; //# what to do if the cursor does hang over
475 };
476 
477 
478 
479 } //# NAMESPACE CASACORE - END
480 
481 #endif
A Vector of integers, for indexing into Array&lt;T&gt; objects.
Definition: IPosition.h:118
virtual IPosition cursorAxes() const
Function which returns the axes of the cursor.
virtual const IPosition & axisPath() const
Return the axis path.
virtual IPosition trc() const
virtual Bool atStart() const
Function which returns &quot;True&quot; if the cursor is at the beginning of the (sub)-Lattice, otherwise, returns &quot;False&quot;.
void padCursor()
Pad the cursor to the right number of dimensions.
virtual IPosition cursorShape() const
Function which returns the shape of the cursor.
virtual LatticeNavigator * clone() const
Function which returns a pointer to dynamic memory of an exact copy of this instance.
virtual uInt nsteps() const
Function to return the number of steps (increments &amp; decrements) taken since construction (or since l...
LatticeStepper()
Prevent the default constructor from being used.
A helper class for stepping through Lattices.
virtual Bool atEnd() const
Function which returns &quot;True&quot; if an attempt has been made to increment the cursor beyond the end of t...
Traverse a Lattice by cursor shape.
virtual IPosition relativeEndPosition() const
PAD is the default and means that the cursor size supplied by the user is kept fixed.
virtual Bool ok() const
Function which checks the internal data of this class for correct dimensionality and consistant value...
virtual uInt calcCacheSize(const IPosition &cubeShape, const IPosition &tileShape, uInt maxCacheSize, uInt bucketSize) const
Calculate the cache size (in tiles) for this type of access to a lattice in the given row of the tile...
virtual Bool hangOver() const
Function which returns &quot;True&quot; if the increment/decrement operators have moved the cursor position suc...
virtual void reset()
Function to move the cursor to the beginning of the (sub)-Lattice.
LatticeStepper & operator=(const LatticeStepper &other)
The assignment operator uses copy semantics.
void setCursorShape(const IPosition &cursorShape)
Functions to change the cursor shape to a new one.
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
virtual IPosition subLatticeShape() const
virtual IPosition increment() const
RESIZE means that the cursor shape is adjusted whenever it approaches the edges of the Lattice so tha...
virtual IPosition position() const
Functions which return the current position of the beginning of the cursor.
virtual IPosition latticeShape() const
Functions which return the shape of the Lattice being iterated through.
virtual IPosition blc() const
Return the bottom left hand corner (blc), top right corner (trc) or step size (increment) used by the...
virtual IPosition endPosition() const
Functions which return the current position of the end of the cursor.
Bool niceFit() const
Check if the cursor shape is a factor of the Lattice shape.
hangOverPolicy
The hangOverPolicy enumerator is used in the constructors to indicate what this class should do when ...
virtual void subSection(const IPosition &blc, const IPosition &trc)
Functions to specify a &quot;section&quot; of the Lattice to step over.
virtual IPosition relativePosition() const
unsigned int uInt
Definition: aipstype.h:51
Abstract base class to steer lattice iterators.