casa  5.7.0-16
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Slicer.h
Go to the documentation of this file.
1 //# Slicer.h: specify which elements to extract from an n-dimensional array
2 //# Copyright (C) 1994,1995,1997,1999
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 CASA_SLICER_H
29 #define CASA_SLICER_H
30 
31 
32 //# Includes
33 #include <casacore/casa/aips.h>
35 
36 namespace casacore { //# NAMESPACE CASACORE - BEGIN
37 
38 //# Forward Declarations
39 class Slice;
40 
41 
42 // <summary>
43 // Specify which elements to extract from an n-dimensional array
44 // </summary>
45 
46 // <reviewed reviewer="Paul Shannon" date="1994/07/07" tests="tSlicer">
47 // The review and modification of this class were undertaken, in part,
48 // with the aim of making this class header an example -- this is what
49 // the Casacore project thinks a class header should look like.
50 // </reviewed>
51 
52 // <prerequisite>
53 // You should have at least a preliminary understanding of these classes:
54 // <li> <linkto class=IPosition>IPosition</linkto>
55 // <li> <linkto class=Array>Array</linkto>
56 // <li> <linkto class=Slice>Slice</linkto>
57 // </prerequisite>
58 
59 // <etymology>
60 // The class name "Slicer" may be thought of as a short form
61 // of "n-Dimensional Slice Specifier." Some confusion is possible
62 // between class "Slice" and this class.
63 // </etymology>
64 //
65 // <synopsis>
66 // If you need to extract or operate upon a portion of an array,
67 // the Slicer class is the best way to specify the subarray you are
68 // interested in.
69 //
70 // Slicer has many constructors. Of these, some require that the
71 // programmer supply a full specification of the array elements he
72 // wants to extract; other constructors make do with partial information.
73 // In the latter case, the constructor will assume sensible default values or,
74 // when directed, infer missing information from the array that's getting
75 // sliced (hereafter, the "source" array).
76 //
77 // <h4> Constructing With Full Information </h4>
78 //
79 // To fully specify a subarray, you must supply three pieces of information
80 // for each axis of the subarray:
81 //
82 // <ol>
83 // <li> where to start
84 // <li> how many elements to extract
85 // <li> what stride (or "increment" or "interval") to use: a stride of
86 // "n" means pick extract only every "nth" element along an axis
87 // </ol>
88 //
89 // The most basic constructor for Slicer illustrates this. To create
90 // an Slicer for getting selected elements from a 3D array:
91 //
92 // <srcblock>
93 // IPosition start (3,0,0,0), length (3,10,10,10), stride (3,3,3,3);
94 // Slicer slicer (start, length, stride);
95 // // assume proper declarations, and meaningful values in the source array
96 // subArray = sourceArray (slicer);
97 // </srcblock>
98 // It gets elements 0,3,6,9,12,15,18,21,24,27 for each dimension.
99 //
100 // <note role=caution> If you wish to extract elements from the array
101 // at intervals, these intervals must be regular. The interval is one
102 // constant integer for each dimension of the array: it cannot be a function.
103 // </note>
104 //
105 // <note role=caution> "length", the second parameter to the Slicer
106 // constructor above, may actually be used in two ways. In normal
107 // (and default) use, it specifies how many elements to select from the
108 // source. In the alternative use, it specifies the index of the last element
109 // to extract from the source array. This ambiguity (does "end" mean
110 // "length" or does it mean "last index"?) is handled by a default
111 // fourth parameter to the constructor. This code fragment will
112 // extract the same subarray as the example above:
113 // <srcblock>
114 // IPosition start (3,0,0,0), end (3,27,27,27), stride (3,3,3,3);
115 // Slicer slicer (start, end, stride, Slicer::endIsLast);
116 // subArray = sourceArray (slicer);
117 // </srcblock>
118 // Note that in this example end(3,28,29,28) gives the same result.
119 // (We use "end" as the name of the formal parameter because it supports
120 // both meanings -- "last index" or "length." You may wish to use a
121 // clarifying name for the actual parameter in your code, as we have
122 // above when we used "length".)
123 // </note>
124 // Similar to Python it is possible to address the start and/or end value
125 // from the end by giving a negative value (-1 means the last value).
126 // However, a length and stride cannot be negative.
127 // Unlike Python the end value is inclusive (as discussed above).
128 // For example,
129 // <srcblock>
130 // Slicer slicer (IPosition(1,-4), IPosition(1,-2), Slicer::endIsLast)
131 // Slicer slicer (IPosition(1,6), IPosition(1,8), Slicer::endIsLast)
132 // </srcblock>
133 // Both Slicers give the same result when used on a Vector with length 10.
134 //
135 // <h4> Constructing with Partial Information </h4>
136 //
137 // Some of the constructors don't require complete information: Slicer
138 // either calculates sensible default values or deduces them from the
139 // source array. If you do not specify a "stride" argument, for example,
140 // a value of 1 will be used for all dimensions. If you specify a "start"
141 // but nothing else, a stride of 1, and (perhaps against expectation)
142 // a length of 1 will be used.
143 //
144 // Note that using a negative start or end is also partial information.
145 // The actual array shape is needed to derive the exact start or end value.
146 //
147 // To instruct the Slicer to get otherwise unspecified information
148 // from the source array, you can create an IPosition like "end"
149 // as shown here:
150 //
151 // <srcblock>
152 // IPosition start (3,0,0,0), stride (3,3,3,3);
153 // IPosition end (3,Slicer::MimicSource, Slicer::MimicSource,
154 // Slicer::MimicSource);
155 // Slicer smartSlicer (start, end, stride);
156 // // assume proper declarations...
157 // subArray = sourceArray (smartSlicer)
158 // </srcblock>
159 //
160 // If you are a library programmer, and write a class that can be sliced
161 // by the Slicer class, you need to understand the mechanism for
162 // completing the information which the application programmer, in using
163 // your class, specified incompletely. (If you are an application
164 // programmer, who wants to slice a library class, this explanation will
165 // be only of academic interest.)
166 //
167 // When the source array (the library class you provide) gets the Slicer --
168 // which typically comes when the source array is asked to return a
169 // reference to a subarray -- the source does a callback to the Slicer
170 // object. The source array passes its own shape as one of the arguments
171 // to the Slicer callback and asks the Slicer to fill in the missing
172 // values from that shape.
173 //
174 // In use, and with an imagined class "MyVector", code would look
175 // like this:
176 // <srcblock>
177 // // first, a fragment from the application program:
178 // IPosition start (1,10), end (1, Slicer::MimicSource);
179 // Slicer slicer (start, end);
180 // MyVector <Int> v0 (100);
181 // MyVector <Int> v1 = v0 (slicer);
182 // //....
183 // // second, a fragment from a constructor of the library class "MyVector":
184 // // the MyVector class will construct v1 as a reference to
185 // // selected elements of v0, using (among other things) a
186 // // callback to the slicer it was passed (above, in the
187 // // construction of v1.
188 // //
189 // IPosition start, end, stride;
190 // fullSliceInformation =
191 // slicer.inferShapeFromSource (MyVector::shape(), start, end, stride);
192 // // now the MyVector instance knows everything it needs to
193 // // construct the instance.
194 // </srcblock>
195 // Please note that v1 will have a length of 90, and refer to elements
196 // 10-99 of v0.
197 //
198 // <note role=warning> An exception will be thrown if the positions
199 // defined in the Slicer exceed the source array's shape.
200 // </note>
201 // </synopsis>
202 //
203 // <example>
204 // Given a large image, 4k on a side, extract (by sampling) an image
205 // 1k on a side, but covering the same region as the original.
206 //
207 // <srcblock>
208 // Image <Float> image ("N5364.fits"); // a 4-d VLA map, 4096 x 4096 x 3 x 1
209 // IPosition start (4,0,0,0,0), stride (4,4,4,1,1);
210 // IPosition end (4, Slicer::MimicSource, Slicer::MimicSource,
211 // Slicer::MimicSource, Slicer::MimicSource);
212 // Slicer smartSlicer (start, end, stride);
213 // // assume proper declarations...
214 // Image <Float> subImage = image (smartSlicer);
215 // </srcblock>
216 //
217 // </example>
218 
219 // <motivation>
220 // Slicer is particularly convenient for designers of other library
221 // classes: Array and Image, for example. (In fact, this convenience
222 // was the original motivation for the class.) The benefit
223 // is this: the application programmer, who needs a slice of an Array,
224 // may provide slicing specifications in many different ways, but the
225 // Array class author needs to provide only one member function to
226 // return the slice. The Slicer class, in effect, and with its
227 // many constructors, provides a way to funnel all of the variety
228 // into a single member function call to the array or image class.
229 //
230 // For example, imagine a 100 x 100 x 100 array from which you want to
231 // extract various subarrays. Here are some of the ways you might
232 // specify the the subarray in the -absence- of Slicer.
233 //
234 // <srcblock>
235 // // preliminaries: create a cube and assign values to all elements --
236 // // this will be "source" array
237 // Cube <Int> bigCube (IPosition (3, 100, 100, 100));
238 // assignValues (bigCube);
239 // // declare a smaller cube, the destination array.
240 // Cube <Int> smallCube (IPosition (3, 10, 10, 10));
241 //
242 // // example 1: use Slice objects to extract a subcube -- the first
243 // // ten elements along each axis
244 // Slice xIndices (0,10,1), yIndices (0,10,1), zIndices (0,10,1);
245 // smallCube = bigCube (xIndices, yIndices, zIndices);
246 //
247 // // example 2: get the same subcube using three IPosition arguments
248 // IPosition start (3,0,0,0), end (3,10,10,10), stride (3,1,1,1);
249 // smallCube = bigCube (start, end, stride);
250 //
251 // // example 3: use 2 IPositions, letting the 3rd (stride) default to
252 // // IPosition (3,1,1,1)
253 // smallCube = bigCube (start, end);
254 // </srcblock>
255 //
256 // So the Cube class (together with its base class) must define three separate
257 // member functions for the essentially identical operation of
258 // extracting a subcube. The same replication is also required of
259 // Image, Array, and the other Array subclasses (Matrix and Vector).
260 //
261 // The Slicer class collapses all of this into a single member
262 // function per class:
263 //
264 // <srcblock>
265 // Slicer slicer = (call the constructor that best suits your problem)
266 // smallCube = bigCube (slicer);
267 // </srcblock>
268 //
269 // Since there are many constructors available for Slicer, you
270 // can still specify the subarray that you may want in a number of
271 // different ways, by constructing the Slicer in the way most natural
272 // to your circumstances. You then pass the Slicer to the array, and
273 // you will get back the slice you want.
274 //
275 // This class also offers the application programmer considerable
276 // flexibility by allowing the shape of the source array to determine
277 // some of the slice specification. This benefit is explained and
278 // demonstrated above.
279 // </motivation>
280 
281 // <todo asof="1994/07/01">
282 // <li> This class, and the TableArray, Array and Image classes,
283 // could allow for the extraction of a subarray with fewer axes than the
284 // source array. At present, for example, you cannot, directly slice
285 // a matrix from a cube.
286 // </todo>
287 
288 
289 class Slicer
290 {
291 public:
292 
293  // Define the "MimicSource" value which defines the open start or end.
294  // This value should be different from MIN_INT in IPosition.h.
295  // It should also not be the lowest possible value, since that
296  // will probably be used as an undefined value.
297  // It must be a negative number.
298  enum {MimicSource= -2147483646};
299 
300  // Define the possible interpretations of the end-value.
302  // The end-values given in the constructor define the lengths.
304  // The end-values given in the constructor define the trc.
306  };
307 
308  // Construct a 1-dimensional Slicer.
309  // Start and end are inferred from the source; stride=1.
310  // "endIsLength" and "endIsLast" are identical here, so there's
311  // no need to discriminate between them by using a default parameter.
312  Slicer();
313 
314  // The member function <src>inferShapeFromSource</src>
315  // (invoked as a callback by the
316  // source array) will use the shape of the source array for the
317  // unspecified values: IPosition elements with the value
318  // Slicer::MimicSource
319  // <thrown>
320  // <li> ArraySlicerError
321  // </thrown>
322  // Create a Slicer with a given start, end (or length), and stride.
323  // An exception will be thrown if a negative length or non-positive
324  // stride is given or if the IPositions start, end, and stride
325  // do not have the same dimensionality.
326  // If length or stride is not given, they default to 1.
327  // <br> It is possible to leave values in start and end undefined
328  // by giving the value <src>MimicSource</src>. They can be filled
329  // in later with the actual array shape using function
330  // <src>inferShapeFromSource</src>.
331  // <group>
332  Slicer (const IPosition& start, const IPosition& end,
333  const IPosition& stride,
334  LengthOrLast endInterpretation = endIsLength);
335  Slicer (const IPosition& start, const IPosition& end,
336  LengthOrLast endInterpretation = endIsLength);
337  explicit Slicer (const IPosition& start);
338  // </group>
339 
340  // Create a Slicer object from Slice objects.
341  // In a Slice object one defines the start, length, and stride for
342  // one axis.
343  // The default Slice constructor (called with no arguments) creates
344  // a Slice with start and length equal to zero, and an undefined stride.
345  // <group>
346  // Create a Slicer for a 1-dimensional array.
347  Slicer (const Slice& x, LengthOrLast endInterpretation = endIsLength);
348 
349  // Create a Slicer for a 2-dim array.
350  Slicer (const Slice& x, const Slice& y,
351  LengthOrLast endInterpretation = endIsLength);
352 
353  // Create a Slicer for a 3-dim array.
354  Slicer (const Slice& x, const Slice& y, const Slice& z,
355  LengthOrLast endInterpretation = endIsLength);
356  // </group>
357 
358  // Copy constructor (copy semantics).
359  Slicer (const Slicer&);
360 
361  // Assignment (copy semantics).
362  Slicer& operator= (const Slicer&);
363 
364  // Equality
365  Bool operator==(const Slicer&) const;
366 
367  // Return the number of dimensions of the Slicer.
368  uInt ndim() const;
369 
370  // This function checks all of the start, length (or end),
371  // and stride IPositions, and fills in missing values by
372  // getting the corresponding values from the shape of the
373  // source array.
374  // These will first be resized, if necessary.
375  // If, for a given axis, (end < start) , it means that a
376  // length of zero was specified.
377  // An exception is thrown if the
378  // start, end, or length exceeds the array shape or if the
379  // dimensionality of the array and Slicer do not conform.
380  // <thrown>
381  // <li> ArraySlicerError
382  // </thrown>
384  (const IPosition& shape, IPosition& startResult,
385  IPosition& endResult, IPosition& strideResult) const;
386 
387  // Report the defined starting position.
388  const IPosition& start() const;
389 
390  // Report the defined ending position.
391  const IPosition& end() const;
392 
393  // Report the defined stride.
394  const IPosition& stride() const;
395 
396  // Report the length of the resulting axes.
397  const IPosition& length() const;
398 
399  // Are all values fixed (i.e., no MimicSource given)?
400  Bool isFixed() const;
401 
402  // Set the start and end positions. No explicit checking is done that
403  // the input parameters make sense, so you must be certain if you
404  // call these. These are useful if you have a loop with many iterations
405  // and you do not wish the overhead of creating a new Slicer object
406  // for each iteration if the only thing you are doing is adjusting
407  // the start and end positions. Other than for performance reasons,
408  // these methods should not be called and you should prefer the
409  // error checking provided by constructing a new Slicer object.
410  // Note that the length is not updated, so in principle care should
411  // be taken that the length does not change.
412  // <group>
413  void setStart (const IPosition& start)
414  { start_p = start; }
415  void setEnd (const IPosition& end)
416  { end_p = end; }
417  // </group>
418 
419 
420 private:
425  IPosition len_p; // Length of input
426  Bool fixed_p; // no MimicSource used
427 
428  // Define a private constructor taking an ssize_t.
429  // This is to prevent the user from the unexpected and meaningless
430  // Slicer that would result when the ssize_t argument is promoted to
431  // an IPosition.
432  Slicer (ssize_t);
433 
434  // Check the given start, end/length and stride.
435  // Fill in the length or end.
436  // It also calls <src>fillFixed</src> to fill the fixed flag.
437  void fillEndLen();
438 
439  // Fill in start, len and stride from a Slice.
440  void fillSlice (const Slice&, ssize_t& start, ssize_t& length,
441  ssize_t& stride);
442 
443  // Fill the fixed flag.
444  void fillFixed();
445 };
446 
447 
448 // <summary>IO functions for Slicer's</summary>
449 // <group name="Slicer IO">
450 // Print the contents of the specified Slicer to the specified stream.
451 std::ostream& operator << (std::ostream& stream, const Slicer& slicer);
452 // </group>
453 
454 
455 
456 inline uInt Slicer::ndim() const
457  { return start_p.nelements(); }
458 
459 inline const IPosition& Slicer::start() const
460  { return start_p; }
461 
462 inline const IPosition& Slicer::end() const
463  { return end_p; }
464 
465 inline const IPosition& Slicer::stride() const
466  { return stride_p; }
467 
468 inline const IPosition& Slicer::length() const
469  { return len_p; }
470 
471 inline Bool Slicer::isFixed() const
472  { return fixed_p; }
473 
474 
475 
476 } //# NAMESPACE CASACORE - END
477 
478 #endif
479 
A Vector of integers, for indexing into Array&lt;T&gt; objects.
Definition: IPosition.h:119
uInt ndim() const
Return the number of dimensions of the Slicer.
Definition: Slicer.h:456
IPosition len_p
Definition: Slicer.h:425
IPosition stride_p
Definition: Slicer.h:424
void fillEndLen()
Check the given start, end/length and stride.
IPosition start_p
Definition: Slicer.h:422
ostream & operator<<(ostream &os, const std::pair< T, U > &p)
const IPosition & end() const
Report the defined ending position.
Definition: Slicer.h:462
The end-values given in the constructor define the lengths.
Definition: Slicer.h:303
void setEnd(const IPosition &end)
Definition: Slicer.h:415
Bool isFixed() const
Are all values fixed (i.e., no MimicSource given)?
Definition: Slicer.h:471
void setStart(const IPosition &start)
Set the start and end positions.
Definition: Slicer.h:413
define a (start,length,increment) along an axis
Definition: Slice.h:93
void fillFixed()
Fill the fixed flag.
Slicer & operator=(const Slicer &)
Assignment (copy semantics).
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
LengthOrLast
Define the possible interpretations of the end-value.
Definition: Slicer.h:301
const IPosition & length() const
Report the length of the resulting axes.
Definition: Slicer.h:468
const IPosition & start() const
Report the defined starting position.
Definition: Slicer.h:459
const IPosition & stride() const
Report the defined stride.
Definition: Slicer.h:465
TableExprNode shape(const TableExprNode &array)
Function operating on any scalar or array resulting in a Double array containing the shape...
Definition: ExprNode.h:1944
LengthOrLast asEnd_p
Definition: Slicer.h:421
Specify which elements to extract from an n-dimensional array.
Definition: Slicer.h:289
IPosition end_p
Definition: Slicer.h:423
Slicer()
Construct a 1-dimensional Slicer.
IPosition inferShapeFromSource(const IPosition &shape, IPosition &startResult, IPosition &endResult, IPosition &strideResult) const
This function checks all of the start, length (or end), and stride IPositions, and fills in missing v...
uInt nelements() const
The number of elements in this IPosition.
Definition: IPosition.h:544
Bool operator==(const Slicer &) const
Equality.
The end-values given in the constructor define the trc.
Definition: Slicer.h:305
unsigned int uInt
Definition: aipstype.h:51
void fillSlice(const Slice &, ssize_t &start, ssize_t &length, ssize_t &stride)
Fill in start, len and stride from a Slice.
#define casacore
&lt;X11/Intrinsic.h&gt; #defines true, false, casacore::Bool, and String.
Definition: X11Intrinsic.h:42