📄 arrays-slicing.texi
字号:
@node Array slicing, Slicing combo, Array ctors, Arrays@section Indexing, subarrays, and slicingThis section describes how to access the elements of an array. There arethree main ways:@itemize @bullet@item @strong{Indexing} obtains a single element @item Creating a @strong{subarray} which refers to a smaller portion ofan array @item @strong{Slicing} to produce a smaller-dimensional view of a portionof an array @end itemizeIndexing, subarrays and slicing all use the overloaded parenthesis@code{operator()}.As a running example, we'll consider the three dimensional array picturedbelow, which has index ranges (0..7, 0..7, 0..7). Shaded portions of thearray show regions which have been obtained by indexing, creating asubarray, and slicing.@center @image{slice}@center Examples of array indexing, subarrays, and slicing.@subsection Indexing@cindex Array indexing@cindex indexing an arrayThere are two ways to get a single element from an array. The simplest isto provide a set of integer operands to @code{operator()}:@exampleA(7,0,0) = 5; cout << "A(7,0,0) = " << A(7,0,0) << endl;@end exampleThis version of indexing is available for arrays of rank one through eleven.If the array object isn't @code{const}, the return type of@code{operator()} is a reference; if the array object is @code{const}, thereturn type is a value.You can also get an element by providing an operand of type@code{TinyVector<int,N_rank>} where @code{N_rank} is the rank of the arrayobject:@exampleTinyVector<int,3> index;index = 7, 0, 0;A(index) = 5;cout << "A(7,0,0) = " << A(index) << endl;@end exampleThis version of @code{operator()} is also available in a const-overloadedversion.It's possible to use fewer than @code{N_rank} indices. However, missingindices are @strong{assumed to be zero}, which will cause bounds errors ifthe valid index range does not include zero (e.g. Fortran arrays). For thisreason, and for code clarity, it's a bad idea to omit indices.@subsection Subarrays@cindex Array subarrays@cindex subarrays@cindex Range objectsYou can obtain a subarray by providing @code{Range} operands to@code{operator()}. A @code{Range} object represents a set of regularlyspaced index values. For example,@exampleArray<int,3> B = A(Range(5,7), Range(5,7), Range(0,2));@end exampleThe object B now refers to elements (5..7,5..7,0..2) of the array A.The returned subarray is of type @code{Array<T_numtype,N_rank>}. This meansthat subarrays can be used wherever arrays can be: in expressions, aslvalues, etc. Some examples:@example// A three-dimensional stencil (used in solving PDEs)Range I(1,6), J(1,6), K(1,6);B = (A(I,J,K) + A(I+1,J,K) + A(I-1,J,K) + A(I,J+1,K) + A(I,J-1,K) + A(I,J+1,K) + A(I,J,K+1) + A(I,J,K-1)) / 7.0;// Set a subarray of A to zeroA(Range(5,7), Range(5,7), Range(5,7)) = 0.;@end exampleThe bases of the subarray are equal to the bases of the original array:@exampleArray<int,2> D(Range(1,5), Range(1,5)); // 1..5, 1..5Array<int,2> E = D(Range(2,3), Range(2,3)); // 1..2, 1..2@end exampleAn array can be used on both sides of an expression only if the subarraysdon't overlap. If the arrays overlap, the result may depend on the order inwhich the array is traversed. @subsection RectDomain and StridedDomain@cindex RectDomain@findex RectDomain@cindex StridedDomain@findex StridedDomain@cindex TinyVector of Range (use @code{RectDomain})The classes @code{RectDomain} and @code{StridedDomain}, defined in@code{blitz/domain.h}, offer a dimension-independent notation for subarrays.@code{RectDomain} and @code{StridedDomain} can be thought of as a@code{TinyVector<Range,N>}. Both have a vector of lower- and upper-bounds;@code{StridedDomain} has a stride vector. For example, the subarray:@exampleArray<int,2> B = A(Range(4,7), Range(8,11)); // 4..7, 8..11@end examplecould be obtained using @code{RectDomain} this way:@exampleTinyVector<int,2> lowerBounds(4, 8);TinyVector<int,2> upperBounds(7, 11);RectDomain<2> subdomain(lowerBounds, upperBounds);Array<int,2> B = A(subdomain);@end exampleHere are the prototypes of @code{RectDomain} and @code{StridedDomain}.@exampletemplate<int N_rank>class RectDomain @{public: RectDomain(const TinyVector<int,N_rank>& lbound, const TinyVector<int,N_rank>& ubound); const TinyVector<int,N_rank>& lbound() const; int lbound(int i) const; const TinyVector<int,N_rank>& ubound() const; int ubound(int i) const; Range operator[](int rank) const; void shrink(int amount); void shrink(int dim, int amount); void expand(int amount); void expand(int dim, int amount);@};template<int N_rank>class StridedDomain @{public: StridedDomain(const TinyVector<int,N_rank>& lbound, const TinyVector<int,N_rank>& ubound, const TinyVector<int,N_rank>& stride); const TinyVector<int,N_rank>& lbound() const; int lbound(int i) const; const TinyVector<int,N_rank>& ubound() const; int ubound(int i) const; const TinyVector<int,N_rank>& stride() const; int stride(int i) const; Range operator[](int rank) const; void shrink(int amount); void shrink(int dim, int amount); void expand(int amount); void expand(int dim, int amount);@};@end example@node Slicing combo, Array debug, Array slicing, Arrays@subsection Slicing@cindex Array slicing@cindex slicing arraysA combination of integer and Range operands produces a @strong{slice}. Eachinteger operand reduces the rank of the array by one. For example:@exampleArray<int,2> F = A(Range::all(), 2, Range::all());Array<int,1> G = A(2, 7, Range::all());@end exampleRange and integer operands can be used in any combination, for arraysup to rank 11.@strong{Note:} Using a combination of integer and Range operands requires anewer language feature (partial ordering of member templates) which not allcompilers support. If your compiler does provide this feature,@code{BZ_PARTIAL_ORDERING} will be defined in @code{<blitz/config.h>}. Ifnot, you can use this workaround:@exampleArray<int,3> F = A(Range::all(), Range(2,2), Range::all());Array<int,3> G = A(Range(2,2), Range(7,7), Range::all());@end example@subsection More about Range objects@cindex Range objectsA @code{Range} object represents an ordered set of uniformly spacedintegers. Here are some examples of using Range objects to obtainsubarrays:@smallexample@include examples/range.texi@end smallexampleThe optional third constructor argument specifies a stride. For example,@code{Range(1,5,2)} refers to elements [1 3 5]. Strides can also benegative: @code{Range(5,1,-2)} refers to elements [5 3 1].Note that if you use the same Range frequently, you can just construct oneobject and use it multiple times. For example:@exampleRange all = Range::all();A(0,all,all) = A(N-1,all,all);A(all,0,all) = A(all,N-1,all);A(all,all,0) = A(all,all,N-1);@end exampleHere's an example of using strides with a two-dimensionalarray:@smallexample@include examples/strideslice.texi@end smallexampleHere's an illustration of the @code{B} subarray:@center @image{strideslice}@center Using strides to create non-contiguous subarrays.And the program output:@smallexample@include examples/strideslice.out@end smallexample@subsection A note about assignment@cindex Array =, meaning of@cindex =, meaning of@cindex shallow copies, see also reference()@cindex assignment operatorThe assignment operator (@code{=}) always results in the expression on theright-hand side (rhs) being @emph{copied} to the lhs (i.e.@: the data on thelhs is overwritten with the result from the rhs). This is different fromsome array packages in which the assignment operator makes the lhs areference (or alias) to the rhs. To further confuse the issue, the copyconstructor for arrays @emph{does} have reference semantics. Here's anexample which should clarify things:@exampleArray<int,1> A(5), B(10);A = B(Range(0,4)); // Statement 1Array<int,1> C = B(Range(0,4)); // Statement 2@end exampleStatement 1 results in a portion of @code{B}'s data being copied into@code{A}. After Statement 1, both @code{A} and @code{B} have their own(nonoverlapping) blocks of data. Contrast this behaviour with that ofStatement 2, which is @strong{not} an assignment (it uses the copyconstructor). After Statement 2 is executed, the array @code{C} is areference (or alias) to @code{B}'s data.So to summarize: If you want to copy the rhs, use an assignment operator.If you want to reference (or alias) the rhs, use the copy constructor (oralternately, the @code{reference()} member function in @ref{Array members}).@strong{Very important:} whenever you have an assignment operator (@code{=},@code{+=}, @code{-=}, etc.) the lhs @strong{must} have the same shape as the@strong{rhs}. If you want the array on the left hand side to be resized tothe proper shape, you must do so by calling the @code{resize} method, forexample:@exampleA.resize(B.shape()); // Make A the same size as BA = B;@end example@subsection An example@smallexample@include examples/slicing.texi@end smallexampleThe output:@smallexample@include examples/slicing.out@end smallexample
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -