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