source: XMLIO_V2/external/include/blitz/array/methods.cc @ 80

Last change on this file since 80 was 80, checked in by ymipsl, 14 years ago

ajout lib externe

File size: 12.2 KB
Line 
1#ifndef BZ_ARRAYMETHODS_CC
2#define BZ_ARRAYMETHODS_CC
3
4#ifndef BZ_ARRAY_H
5 #error <blitz/array/methods.cc> must be included via <blitz/array.h>
6#endif
7
8BZ_NAMESPACE(blitz)
9
10template<typename P_numtype, int N_rank> template<typename T_expr>
11Array<P_numtype,N_rank>::Array(_bz_ArrayExpr<T_expr> expr)
12{
13    // Determine extent of the array expression
14
15    TinyVector<int,N_rank> lbound, extent, ordering;
16    TinyVector<bool,N_rank> ascendingFlag;
17    TinyVector<bool,N_rank> in_ordering;
18    in_ordering = false;
19
20    int j = 0;
21    for (int i=0; i < N_rank; ++i)
22    {
23        lbound(i) = expr.lbound(i);
24        int ubound = expr.ubound(i);
25        extent(i) = ubound - lbound(i) + 1;
26        int orderingj = expr.ordering(i);
27        if (orderingj != INT_MIN && orderingj < N_rank &&
28            !in_ordering( orderingj )) { // unique value in ordering array
29            in_ordering( orderingj ) = true;
30            ordering(j++) = orderingj;
31        }
32        int ascending = expr.ascending(i);
33        ascendingFlag(i) = (ascending == 1);
34
35#ifdef BZ_DEBUG
36        if ((lbound(i) == INT_MIN) || (ubound == INT_MAX) 
37          || (ordering(i) == INT_MIN) || (ascending == INT_MIN))
38        {
39          BZPRECHECK(0,
40           "Attempted to construct an array from an expression " << endl
41           << "which does not have a shape.  To use this constructor, "
42           << endl
43           << "the expression must contain at least one array operand.");
44          return;
45        }
46#endif
47    }
48
49    // It is possible that ordering is not a permutation of 0,...,N_rank-1.
50    // In that case j will be less than N_rank. We fill in ordering with the
51    // usused values in decreasing order.
52    for (int i = N_rank-1; j < N_rank; ++j) {
53        while (in_ordering(i))
54          --i;
55        ordering(j) = i--;
56    }
57
58    Array<T_numtype,N_rank> A(lbound,extent,
59        GeneralArrayStorage<N_rank>(ordering,ascendingFlag));
60    A = expr;
61    reference(A);
62}
63
64template<typename P_numtype, int N_rank>
65Array<P_numtype,N_rank>::Array(const TinyVector<int, N_rank>& lbounds,
66    const TinyVector<int, N_rank>& extent,
67    const GeneralArrayStorage<N_rank>& storage)
68    : storage_(storage)
69{
70    length_ = extent;
71    storage_.setBase(lbounds);
72    setupStorage(N_rank - 1);
73}
74
75
76/*
77 * This routine takes the storage information for the array
78 * (ascendingFlag_[], base_[], and ordering_[]) and the size
79 * of the array (length_[]) and computes the stride vector
80 * (stride_[]) and the zero offset (see explanation in array.h).
81 */
82template<typename P_numtype, int N_rank>
83_bz_inline2 void Array<P_numtype, N_rank>::computeStrides()
84{
85    if (N_rank > 1)
86    {
87      int stride = 1;
88
89      // This flag simplifies the code in the loop, encouraging
90      // compile-time computation of strides through constant folding.
91      bool allAscending = storage_.allRanksStoredAscending();
92
93      // BZ_OLD_FOR_SCOPING
94      int n;
95      for (n=0; n < N_rank; ++n)
96      {
97          int strideSign = +1;
98
99          // If this rank is stored in descending order, then the stride
100          // will be negative.
101          if (!allAscending)
102          {
103            if (!isRankStoredAscending(ordering(n)))
104                strideSign = -1;
105          }
106
107          // The stride for this rank is the product of the lengths of
108          // the ranks minor to it.
109          stride_[ordering(n)] = stride * strideSign;
110
111          stride *= length_[ordering(n)];
112      }
113    }
114    else {
115        // Specialization for N_rank == 1
116        // This simpler calculation makes it easier for the compiler
117        // to propagate stride values.
118
119        if (isRankStoredAscending(0))
120            stride_[0] = 1;
121        else
122            stride_[0] = -1;
123    }
124
125    calculateZeroOffset();
126}
127
128template<typename P_numtype, int N_rank>
129void Array<P_numtype, N_rank>::calculateZeroOffset()
130{
131    // Calculate the offset of (0,0,...,0)
132    zeroOffset_ = 0;
133
134    // zeroOffset_ = - sum(where(ascendingFlag_, stride_ * base_,
135    //     (length_ - 1 + base_) * stride_))
136    for (int n=0; n < N_rank; ++n)
137    {
138        if (!isRankStoredAscending(n))
139            zeroOffset_ -= (length_[n] - 1 + base(n)) * stride_[n];
140        else
141            zeroOffset_ -= stride_[n] * base(n);
142    }
143}
144
145template<typename P_numtype, int N_rank>
146bool Array<P_numtype, N_rank>::isStorageContiguous() const
147{
148    // The storage is contiguous if for the set
149    // { | stride[i] * extent[i] | }, i = 0..N_rank-1,
150    // there is only one value which is not in the set
151    // of strides; and if there is one stride which is 1.
152
153    // This algorithm is quadratic in the rank.  It is hard
154    // to imagine this being a serious problem.
155
156    int numStridesMissing = 0;
157    bool haveUnitStride = false;
158
159    for (int i=0; i < N_rank; ++i)
160    {
161        int stride = BZ_MATHFN_SCOPE(abs)(stride_[i]);
162        if (stride == 1)
163            haveUnitStride = true;
164
165        int vi = stride * length_[i];
166
167        int j = 0;
168        for (j=0; j < N_rank; ++j)
169            if (BZ_MATHFN_SCOPE(abs)(stride_[j]) == vi)
170                break;
171
172        if (j == N_rank)
173        {
174            ++numStridesMissing;
175            if (numStridesMissing == 2)
176                return false;
177        }
178    }
179
180    return haveUnitStride;
181}
182
183template<typename P_numtype, int N_rank>
184void Array<P_numtype, N_rank>::dumpStructureInformation(ostream& os) const
185{
186    os << "Dump of Array<" << BZ_DEBUG_TEMPLATE_AS_STRING_LITERAL(P_numtype) 
187       << ", " << N_rank << ">:" << endl
188       << "ordering_      = " << storage_.ordering() << endl
189       << "ascendingFlag_ = " << storage_.ascendingFlag() << endl
190       << "base_          = " << storage_.base() << endl
191       << "length_        = " << length_ << endl
192       << "stride_        = " << stride_ << endl
193       << "zeroOffset_    = " << zeroOffset_ << endl
194       << "numElements()  = " << numElements() << endl
195       << "isStorageContiguous() = " << isStorageContiguous() << endl;
196}
197
198/*
199 * Make this array a view of another array's data.
200 */
201template<typename P_numtype, int N_rank>
202void Array<P_numtype, N_rank>::reference(const Array<P_numtype, N_rank>& array)
203{
204    storage_ = array.storage_;
205    length_ = array.length_;
206    stride_ = array.stride_;
207    zeroOffset_ = array.zeroOffset_;
208
209    MemoryBlockReference<P_numtype>::changeBlock(array.noConst());
210}
211
212/*
213 * Modify the Array storage.  Array must be unallocated.
214 */
215template<typename P_numtype, int N_rank>
216void Array<P_numtype, N_rank>::setStorage(GeneralArrayStorage<N_rank> x)
217{
218#ifdef BZ_DEBUG
219    if (size() != 0) {
220        BZPRECHECK(0,"Cannot modify storage format of an Array that has already been allocated!" << endl);
221        return;
222    }
223#endif
224    storage_ = x;
225    return;
226}
227
228/*
229 * This method is called to allocate memory for a new array. 
230 */
231template<typename P_numtype, int N_rank>
232_bz_inline2 void Array<P_numtype, N_rank>::setupStorage(int lastRankInitialized)
233{
234    TAU_TYPE_STRING(p1, "Array<T,N>::setupStorage() [T="
235        + CT(P_numtype) + ",N=" + CT(N_rank) + "]");
236    TAU_PROFILE(" ", p1, TAU_BLITZ);
237
238    /*
239     * If the length of some of the ranks was unspecified, fill these
240     * in using the last specified value.
241     *
242     * e.g. Array<int,3> A(40) results in a 40x40x40 array.
243     */
244    for (int i=lastRankInitialized + 1; i < N_rank; ++i)
245    {
246        storage_.setBase(i, storage_.base(lastRankInitialized));
247        length_[i] = length_[lastRankInitialized];
248    }
249
250    // Compute strides
251    computeStrides();
252
253    // Allocate a block of memory
254    int numElem = numElements();
255    if (numElem==0)
256        MemoryBlockReference<P_numtype>::changeToNullBlock();
257    else
258        MemoryBlockReference<P_numtype>::newBlock(numElem);
259
260    // Adjust the base of the array to account for non-zero base
261    // indices and reversals
262    data_ += zeroOffset_;
263}
264
265template<typename P_numtype, int N_rank>
266Array<P_numtype, N_rank> Array<P_numtype, N_rank>::copy() const
267{
268    if (numElements())
269    {
270        Array<T_numtype, N_rank> z(length_, storage_);
271        z = *this;
272        return z;
273    }
274    else {
275        // Null array-- don't bother allocating an empty block.
276        return *this;
277    }
278}
279
280template<typename P_numtype, int N_rank>
281void Array<P_numtype, N_rank>::makeUnique()
282{
283    if (numReferences() > 1)
284    {
285        T_array tmp = copy();
286        reference(tmp);
287    }
288}
289
290template<typename P_numtype, int N_rank>
291Array<P_numtype, N_rank> Array<P_numtype, N_rank>::transpose(int r0, int r1, 
292    int r2, int r3, int r4, int r5, int r6, int r7, int r8, int r9, int r10)
293{
294    T_array B(*this);
295    B.transposeSelf(r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10);
296    return B;
297}
298
299template<typename P_numtype, int N_rank>
300void Array<P_numtype, N_rank>::transposeSelf(int r0, int r1, int r2, int r3,
301    int r4, int r5, int r6, int r7, int r8, int r9, int r10)
302{
303    BZPRECHECK(r0+r1+r2+r3+r4+r5+r6+r7+r8+r9+r10 == N_rank * (N_rank-1) / 2,
304        "Invalid array transpose() arguments." << endl
305        << "Arguments must be a permutation of the numerals (0,...,"
306        << (N_rank - 1) << ")");
307
308    // Create a temporary reference copy of this array
309    Array<T_numtype, N_rank> x(*this);
310
311    // Now reorder the dimensions using the supplied permutation
312    doTranspose(0, r0, x);
313    doTranspose(1, r1, x);
314    doTranspose(2, r2, x);
315    doTranspose(3, r3, x);
316    doTranspose(4, r4, x);
317    doTranspose(5, r5, x);
318    doTranspose(6, r6, x);
319    doTranspose(7, r7, x);
320    doTranspose(8, r8, x);
321    doTranspose(9, r9, x);
322    doTranspose(10, r10, x);
323}
324
325template<typename P_numtype, int N_rank>
326void Array<P_numtype, N_rank>::doTranspose(int destRank, int sourceRank,
327    Array<T_numtype, N_rank>& array)
328{
329    // BZ_NEEDS_WORK: precondition check
330
331    if (destRank >= N_rank)
332        return;
333
334    length_[destRank] = array.length_[sourceRank];
335    stride_[destRank] = array.stride_[sourceRank];
336    storage_.setAscendingFlag(destRank, 
337        array.isRankStoredAscending(sourceRank));
338    storage_.setBase(destRank, array.base(sourceRank));
339
340    // BZ_NEEDS_WORK: Handling the storage ordering is currently O(N^2)
341    // but it can be done fairly easily in linear time by constructing
342    // the appropriate permutation.
343
344    // Find sourceRank in array.storage_.ordering_
345    int i=0;
346    for (; i < N_rank; ++i)
347        if (array.storage_.ordering(i) == sourceRank)
348            break;
349
350    storage_.setOrdering(i, destRank);
351}
352
353template<typename P_numtype, int N_rank>
354void Array<P_numtype, N_rank>::reverseSelf(int rank)
355{
356    BZPRECONDITION(rank < N_rank);
357
358    storage_.setAscendingFlag(rank, !isRankStoredAscending(rank));
359
360    int adjustment = stride_[rank] * (lbound(rank) + ubound(rank));
361    zeroOffset_ += adjustment;
362    data_ += adjustment;
363    stride_[rank] *= -1;
364}
365
366template<typename P_numtype, int N_rank>
367Array<P_numtype, N_rank> Array<P_numtype,N_rank>::reverse(int rank)
368{
369    T_array B(*this);
370    B.reverseSelf(rank);
371    return B;
372}
373
374template<typename P_numtype, int N_rank> template<typename P_numtype2>
375Array<P_numtype2,N_rank> Array<P_numtype,N_rank>::extractComponent(P_numtype2, 
376    int componentNumber, int numComponents) const
377{
378    BZPRECONDITION((componentNumber >= 0) 
379        && (componentNumber < numComponents));
380
381    TinyVector<int,N_rank> stride2;
382    for (int i=0; i < N_rank; ++i)
383      stride2(i) = stride_(i) * numComponents;
384    const P_numtype2* dataFirst2 = 
385        ((const P_numtype2*)dataFirst()) + componentNumber;
386    return Array<P_numtype2,N_rank>(const_cast<P_numtype2*>(dataFirst2), 
387        length_, stride2, storage_);
388}
389
390/*
391 * These routines reindex the current array to use a new base vector.
392 * The first reindexes the array, the second just returns a reindex view
393 * of the current array, leaving the current array unmodified.
394 * (Contributed by Derrick Bass)
395 */
396template<typename P_numtype, int N_rank>
397_bz_inline2 void Array<P_numtype, N_rank>::reindexSelf(const 
398    TinyVector<int, N_rank>& newBase) 
399{
400    int delta = 0;
401    for (int i=0; i < N_rank; ++i)
402      delta += (base(i) - newBase(i)) * stride_(i);
403
404    data_ += delta;
405
406    // WAS: dot(base() - newBase, stride_);
407
408    storage_.setBase(newBase);
409    calculateZeroOffset();
410}
411
412template<typename P_numtype, int N_rank>
413_bz_inline2 Array<P_numtype, N_rank> 
414Array<P_numtype, N_rank>::reindex(const TinyVector<int, N_rank>& newBase) 
415{
416    T_array B(*this);
417    B.reindexSelf(newBase);
418    return B;
419}
420
421BZ_NAMESPACE_END
422
423#endif // BZ_ARRAY_CC
424
Note: See TracBrowser for help on using the repository browser.