1 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
2 "http://www.w3.org/TR/html4/loose.dtd">
5 == Copyright 2002 The Trustees of Indiana University.
7 == Use, modification and distribution is subject to the Boost Software
8 == License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 == http://www.boost.org/LICENSE_1_0.txt)
11 == Boost.MultiArray Library
12 == Authors: Ronald Garcia
15 == See http://www.boost.org/libs/multi_array for documentation.
18 <title>The Boost Multidimensional Array Library (Boost.MultiArray)
</title>
24 <img src=
"../../../boost.png" alt=
"boost logo"
25 width=
"277" align=
"middle" height=
"86">
26 <br>The Boost Multidimensional Array Library
27 <br>(Boost.MultiArray)
33 The Boost Multidimensional Array Library provides a class template for
34 multidimensional arrays, as well as semantically equivalent
35 adaptors for arrays of contiguous data. The classes in this library
36 implement a common interface, formalized as a generic programming
37 concept. The interface design is in line with the precedent set by the
38 C++ Standard Library containers. Boost MultiArray is a more efficient
39 and convenient way to express N-dimensional arrays than existing
40 alternatives (especially the
41 <tt>std::vector
<std::vector
<...
>></tt> formulation
42 of N-dimensional arrays). The arrays provided by the library may be
43 accessed using the familiar syntax of native C++ arrays. Additional
44 features, such as resizing, reshaping, and creating views are
45 available (and described below).
48 <h2>Table of Contents
</h2>
51 <li><a href=
"#sec_introduction">Introduction
</a>
53 <li><a href=
"#sec_example">Short Example
</a>
55 <li><a href=
"#sec_components">MultiArray Components
</a>
57 <li><a href=
"#sec_assignment">Construction and Assignment
</a>
59 <li><a href=
"#sec_generators">Array View and Subarray Type Generators
</a>
61 <li><a href=
"#sec_dimensions">Specifying Array Dimensions
</a>
63 <li><a href=
"#sec_access">Accessing Elements
</a>
65 <li><a href=
"#sec_views">Creating Views
</a>
67 <li><a href=
"#sec_storage">Storage Ordering
</a>
69 <li><a href=
"#sec_base">Setting the Array Base
</a>
71 <li><a href=
"#sec_reshape">Changing an Array's Shape
</a>
73 <li><a href=
"#sec_resize">Resizing an Array
</a>
75 <li><a href=
"#sec_concepts">MultiArray Concept
</a>
77 <li><a href=
"#sec_testcases">Test Cases
</a>
79 <li><a href=
"#sec_related">Related Work
</a>
80 <li><a href=
"#sec_credits">Credits
</a>
84 <a name=
"sec_introduction"></a>
88 The C++ standard library provides several generic containers, but it
89 does not provide any multidimensional array types. The
90 <tt>std::vector
</tt> class template can be used to implement
91 N-dimensional arrays, for example expressing a
2-dimensional array of
92 <tt>double
</tt> elements using the type
93 <tt>std::vector
<std::vector
<double
>></tt>, but the
94 resulting interface is unwieldy and the memory overhead can be quite
95 high. Native C++ arrays (i.e.
<tt>int arr[
2][
2][
2];
</tt>) do not
96 immediately interoperate well with the C++ Standard Library, and they
97 also lose information at function call boundaries (specifically the
98 extent of the last dimension). Finally, a dynamically allocated
99 contiguous block of elements can be treated as an array, though this
100 method requires manual bookkeeping that is error prone and obfuscates
101 the intent of the programmer.
105 The Boost MultiArray library enhances the C++ standard containers with
106 versatile multi-dimensional array abstractions. It includes a general
107 array class template and native array adaptors that support idiomatic
108 array operations and interoperate with C++ Standard Library containers
109 and algorithms. The arrays share a common interface, expressed as a
110 generic programming in terms of which generic array algorithms can be
115 This document is meant to provide an introductory tutorial and user's
116 guide for the most basic and common usage patterns of MultiArray
117 components. The
<a href=
"./reference.html">reference manual
</a>
118 provides more complete and formal documentation of library features.
121 <a name=
"sec_example"></a>
122 <h2>Short Example
</h2>
123 What follows is a brief example of the use of
<tt>multi_array
</tt>:
127 #include
"boost/multi_array.hpp"
128 #include
<cassert
>
132 // Create a
3D array that is
3 x
4 x
2
133 typedef boost::multi_array
<double,
3> array_type;
134 typedef array_type::index index;
135 array_type A(boost::extents[
3][
4][
2]);
137 // Assign values to the elements
139 for(index i =
0; i !=
3; ++i)
140 for(index j =
0; j !=
4; ++j)
141 for(index k =
0; k !=
2; ++k)
142 A[i][j][k] = values++;
146 for(index i =
0; i !=
3; ++i)
147 for(index j =
0; j !=
4; ++j)
148 for(index k =
0; k !=
2; ++k)
149 assert(A[i][j][k] == verify++);
156 <a name=
"sec_components"></a>
157 <h2>MultiArray Components
</h2>
159 Boost.MultiArray's implementation (boost/multi_array.hpp) provides three user-level class templates:
162 <li><a href=
"./reference.html#multi_array"><tt>multi_array
</tt></a>,
164 <li><a href=
"./reference.html#multi_array_ref"><tt>multi_array_ref
</tt></a>, and
166 <li><a href=
"./reference.html#const_multi_array_ref"><tt>const_multi_array_ref
</tt></a>
169 <tt>multi_array
</tt> is a container template. When instantiated, it
170 allocates space for the number of elements corresponding to the
171 dimensions specified at construction time. A
<tt>multi_array
</tt> may
172 also be default constructed and resized as needed.
175 <tt>multi_array_ref
</tt> adapts an existing array of data to provide
176 the
<tt>multi_array
</tt> interface.
<tt>multi_array_ref
</tt> does not own the
180 <tt>const_multi_array_ref
</tt> is similar to
<tt>multi_array_ref
</tt>
181 but guarantees that the contents of the array are immutable. It can
182 thus wrap pointers of type
<i>T const*
</i>.
185 The three components exhibit very similar behavior. Aside from
186 constructor parameters,
<tt>multi_array
</tt> and
187 <tt>multi_array_ref
</tt> export the same interface.
188 <tt>const_multi_array_ref
</tt> provides only the constness-preserving
189 portions of the
<tt>multi_array_ref
</tt> interface.
191 <a name=
"sec_assignment"></a>
192 <h2>Construction and Assignment
</h2>
193 <p>Each of the array types -
194 <a href=
"./reference.html#multi_array"><tt>multi_array
</tt></a>,
195 <a href=
"./reference.html#multi_array_ref"><tt>multi_array_ref
</tt></a>, and
196 <a href=
"./reference.html#const_multi_array_ref"><tt>const_multi_array_ref
</tt></a> -
197 provides a specialized set of constructors. For further information,
198 consult their reference pages.
200 <p>All of the non-const array types in this library provide assignment
201 operators
<tt>operator=()
</tt>. Each of the array types
<tt>multi_array
</tt>,
202 <tt>multi_array_ref
</tt>,
<tt>subarray
</tt>, and
203 <tt>array_view
</tt> can be assigned from any
204 of the others, so long as their shapes match. The
205 const variants,
<tt>const_multi_array_ref
</tt>,
206 <tt>const_subarray
</tt>, and
<tt>const_array_view
</tt>, can be the
207 source of a copy to an array with matching shape.
208 Assignment results in a deep (element by element) copy of the data
209 contained within an array.
211 <a name=
"sec_generators"></a>
212 <h2>Array View and Subarray Type Generators
</h2>
213 In some situations, the use of nested generators for array_view and
214 subarray types is inconvenient. For example, inside a
215 function template parameterized upon array type, the extra
216 "template" keywords can be obfuscating. More likely though, some
217 compilers cannot handle templates nested within template parameters.
218 For this reason the type generators,
<tt>subarray_gen
</tt>,
219 <tt>const_subarray_gen
</tt>,
<tt>array_view_gen
</tt>, and
220 <tt>const_array_view_gen
</tt> are provided. Thus, the two typedefs
221 in the following example result in the same type:
224 template
<typename Array
>
226 typedef typename Array::template array_view
<3>::type view1_t;
227 typedef typename boost::array_view_gen
<Array,
3>::type view2_t;
233 <a name=
"sec_dimensions"></a>
234 <h2>Specifying Array Dimensions
</h2>
235 When creating most of the Boost.MultiArray components, it is necessary
236 to specify both the number of dimensions and the extent of each
237 (
<tt>boost::multi_array
</tt> also provides a default constructor).
238 Though the number of dimensions is always specified as a template
239 parameter, two separate mechanisms have been provided to specify the
241 <p>The first method involves passing a
242 <a href=
"../../utility/Collection.html">
243 Collection
</a> of extents to a
244 constructor, most commonly a
<tt>boost::array
</tt>. The constructor
245 will retrieve the beginning iterator from the container and retrieve N
246 elements, corresponding to extents for the N dimensions. This is
247 useful for writing dimension-independent code.
251 typedef boost::multi_array
<double,
3> array_type;
252 boost::array
<array_type::index,
3> shape = {{
3,
4,
2 }};
257 <p>The second method involves passing the constructor an
<tt>extent_gen
</tt>
258 object, specifying the matrix dimensions. The
<tt>extent_gen
</tt> type
259 is defined in the
<tt>multi_array_types
</tt> namespace and as a
260 member of every array type, but by default, the library constructs a
261 global
<tt>extent_gen
</tt> object
<tt>boost::extents
</tt>. In case of
262 concern about memory used by these objects, defining
263 <tt>BOOST_MULTI_ARRAY_NO_GENERATORS
</tt> before including the library
264 header inhibits its construction.
269 typedef boost::multi_array
<double,
3> array_type;
270 array_type A(boost::extents[
3][
4][
2]);
274 <a name=
"sec_access"></a>
275 <h2>Accessing Elements
</h2>
276 The Boost.MultiArray components provide two ways of accessing
277 specific elements within a container. The first uses the traditional
278 C array notation, provided by
<tt>operator[]
</tt>.
282 typedef boost::multi_array
<double,
3> array_type;
283 array_type A(boost::extents[
3][
4][
2]);
285 assert(A[
0][
0][
0] ==
3.14);
289 <p> The second method involves passing a
290 <a href=
"../../utility/Collection.html">
291 Collection
</a> of indices to
<tt>operator()
</tt>. N indices will be retrieved
292 from the Collection for the N dimensions of the container.
296 typedef boost::multi_array
<double,
3> array_type;
297 array_type A(boost::extents[
3][
4][
2]);
298 boost::array
<array_type::index,
3> idx = {{
0,
0,
0}};
300 assert(A(idx) ==
3.14);
303 This can be useful for writing dimension-independent code, and under
304 some compilers may yield higher performance than
<tt>operator[].
</tt>
307 By default, both of the above element access methods perform range
308 checking. If a supplied index is out of the range defined for an
309 array, an assertion will abort the program. To disable range
310 checking (for performance reasons in production releases), define
311 the
<tt>BOOST_DISABLE_ASSERTS
</tt> preprocessor macro prior to
312 including multi_array.hpp in your application.
314 <a name=
"sec_views"></a>
315 <h2>Creating Views
</h2>
316 Boost.MultiArray provides the facilities for creating a sub-view of an
317 already existing array component. It allows you to create a sub-view that
318 retains the same number of dimensions as the original array or one
319 that has less dimensions than the original as well.
321 <p>Sub-view creation occurs by placing a call to operator[], passing
322 it an
<tt>index_gen
</tt> type. The
<tt>index_gen
</tt> is populated by
323 passing
<tt>index_range
</tt> objects to its
<tt>operator[]
</tt>.
324 The
<tt>index_range
</tt> and
<tt>index_gen
</tt> types are defined in
325 the
<tt>multi_array_types
</tt> namespace and as nested members of
326 every array type. Similar to
<tt>boost::extents
</tt>, the library by
327 default constructs the object
<tt>boost::indices
</tt>. You can
328 suppress this object by
329 defining
<tt>BOOST_MULTI_ARRAY_NO_GENERATORS
</tt> before including the
330 library header. A simple sub-view creation example follows.
335 // myarray =
2 x
3 x
4
338 // array_view dims: [base,bound) (dimension striding default =
1)
341 // dim
2: [
0,
4) (strided by
2),
344 typedef boost::multi_array_types::index_range range;
345 // OR typedef array_type::index_range range;
346 array_type::array_view
<3>::type myview =
347 myarray[ boost::indices[range(
0,
2)][range(
1,
3)][range(
0,
4,
2)] ];
349 for (array_type::index i =
0; i !=
2; ++i)
350 for (array_type::index j =
0; j !=
2; ++j)
351 for (array_type::index k =
0; k !=
2; ++k)
352 assert(myview[i][j][k] == myarray[i][j+
1][k*
2]);
357 <p>By passing an integral value to the index_gen, one may create a
358 subview with fewer dimensions than the original array component (also
363 // myarray =
2 x
3 x
4
367 // [base,stride,bound)
368 // [
0,
1,
2),
1, [
0,
2,
4)
371 typedef boost::multi_array_types::index_range range;
372 array_type::index_gen indices;
373 array_type::array_view
<2>::type myview =
374 myarray[ indices[range(
0,
2)][
1][range(
0,
4,
2)] ];
376 for (array_type::index i =
0; i !=
2; ++i)
377 for (array_type::index j =
0; j !=
2; ++j)
378 assert(myview[i][j] == myarray[i][
1][j*
2]);
382 <h3>More on
<tt>index_range
</tt></h3>
383 The
<tt>index_range
</tt> type provides several methods of specifying
384 ranges for subview generation. Here are a few range instantiations
385 that specify the same range.
389 // [base,stride,bound)
392 typedef boost::multi_array_types::index_range range;
394 a_range = range(
0,
4,
2);
395 a_range = range().start(
0).finish(
4).stride(
2);
396 a_range = range().start(
0).stride(
2).finish(
4);
397 a_range =
0 <= range().stride(
2)
< 4;
398 a_range =
0 <= range().stride(
2)
<=
3;
402 An
<tt>index_range
</tt> object passed to a slicing operation will
403 inherit its start and/or finish value from the array being sliced if
404 you do not supply one. This conveniently prevents you from having to
405 know the bounds of the array dimension in certain cases. For example,
406 the default-constructed range will take the full extent of the
407 dimension it is used to specify.
412 typedef boost::multi_array_types::index_range range;
415 // All elements in this dimension
418 // indices i where
3 <= i
419 a_range = range().start(
3)
420 a_range =
3 <= range();
421 a_range =
2 < range();
423 // indices i where i
< 7
424 a_range = range().finish(
7)
425 a_range = range()
< 7;
426 a_range = range()
<=
6;
430 The following example slicing operations exhibit some of the
431 alternatives shown above
434 // take all of dimension
1
435 // take i
< 5 for dimension
2
436 // take
4 <= j
<=
7 for dimension
3 with stride
2
437 myarray[ boost::indices[range()][range()
< 5 ][
4 <= range().stride(
2)
<=
7] ];
441 <a name=
"sec_storage"></a>
442 <h2>Storage Ordering
</h2>
443 Each array class provides constructors that accept a storage ordering
444 parameter. This is most
445 useful when interfacing with legacy codes that require an ordering
446 different from standard C, such as FORTRAN. The possibilities are
447 <tt>c_storage_order
</tt>,
<tt>fortran_storage_order
</tt>, and
448 <tt>general_storage_order
</tt>.
450 <p><tt>c_storage_order
</tt>, which is the default, will store elements
451 in memory in the same order as a C array would, that is, the
452 dimensions are stored from last to first.
454 <p><tt>fortran_storage_order
</tt> will store elements in memory in the same order
455 as FORTRAN would: from the first dimension to
456 the last. Note that with use of this parameter, the array
457 indices will remain zero-based.
461 typedef boost::multi_array
<double,
3> array_type;
462 array_type A(boost::extents[
3][
4][
2],boost::fortran_storage_order());
463 call_fortran_function(A.data());
467 <p><tt>general_storage_order
</tt> allows one to customize both the order in
468 which dimensions are stored in memory and whether dimensions are
469 stored in ascending or descending order.
473 typedef boost::general_storage_order
<3> storage;
474 typedef boost::multi_array
<int,
3> array_type;
476 // Store last dimension, then first, then middle
477 array_type::size_type ordering[] = {
2,
0,
1};
479 // Store the first dimension(dimension
0) in descending order
480 bool ascending[] = {false,true,true};
482 array_type A(extents[
3][
4][
2],storage(ordering,ascending));
487 <a name=
"sec_base"></a>
488 <h2>Setting The Array Base
</h2>
489 In some situations, it may be inconvenient or awkward to use an
490 array that is zero-based.
491 the Boost.MultiArray components provide two facilities for changing the
492 bases of an array. One may specify a pair of range values, with
493 the
<tt>extent_range
</tt> type, to
494 the
<tt>extent_gen
</tt> constructor in order to set the base value.
499 typedef boost::multi_array
<double,
3> array_type;
500 typedef boost::multi_array_types::extent_range range;
501 // OR typedef array_type::extent_range range;
503 array_type::extent_gen extents;
505 // dimension
0:
0-based
506 // dimension
1:
1-based
507 // dimension
2: -
1 - based
508 array_type A(extents[
2][range(
1,
4)][range(-
1,
3)]);
513 An alternative is to first construct the array normally then
514 reset the bases. To set all bases to the same value, use the
515 <tt>reindex
</tt> member function, passing it a single new index value.
519 typedef boost::multi_array
<double,
3> array_type;
521 array_type::extent_gen extents;
523 array_type A(extents[
2][
3][
4]);
530 An alternative is to set each base separately using the
531 <tt>reindex
</tt> member function, passing it a Collection of index bases.
535 typedef boost::multi_array
<double,
3> array_type;
537 array_type::extent_gen extents;
539 // dimension
0:
0-based
540 // dimension
1:
1-based
541 // dimension
2: (-
1)-based
542 array_type A(extents[
2][
3][
4]);
543 boost::array
<array_type::index,ndims
> bases = {{
0,
1, -
1}};
549 <a name=
"sec_reshape"></a>
550 <h2>Changing an Array's Shape
</h2>
551 The Boost.MultiArray arrays provide a reshape operation. While the
552 number of dimensions must remain the same, the shape of the array may
553 change so long as the total number of
554 elements contained remains the same.
558 typedef boost::multi_array
<double,
3> array_type;
560 array_type::extent_gen extents;
561 array_type A(extents[
2][
3][
4]);
562 boost::array
<array_type::index,ndims
> dims = {{
4,
3,
2}};
568 Note that reshaping an array does not affect the indexing.
570 <a name=
"sec_resize"></a>
571 <h2>Resizing an Array
</h2>
573 The
<tt>boost::multi_array
</tt> class provides an element-preserving
574 resize operation. The number of dimensions must remain the same, but
575 the extent of each dimension may be increased and decreased as
576 desired. When an array is made strictly larger, the existing elements
577 will be preserved by copying them into the new underlying memory and
578 subsequently destructing the elements in the old underlying memory.
579 Any new elements in the array are default constructed. However, if
580 the new array size shrinks some of the dimensions, some elements will
581 no longer be available.
586 typedef boost::multi_array
<int,
3> array_type;
588 array_type::extent_gen extents;
589 array_type A(extents[
3][
3][
3]);
592 A.resize(extents[
2][
3][
4]);
593 assert(A[
0][
0][
0] ==
4);
594 // A[
2][
2][
2] is no longer valid.
599 <a name=
"sec_concepts"></a>
600 <h2>MultiArray Concept
</h2>
601 Boost.MultiArray defines and uses the
602 <a href=
"./reference.html#MultiArray">MultiArray
</a>
603 concept. It specifies an interface for N-dimensional containers.
605 <a name=
"sec_testcases"></a>
607 Boost.MultiArray comes with a suite of test cases meant to exercise
608 the features and semantics of the library. A description of the test
609 cases can be found
<a href=
"./test_cases.html">here
</a>.
611 <a name=
"sec_related"></a>
612 <h2>Related Work
</h2>
614 <a href=
"../../array/index.html">boost::array
</a>
615 and
<a href=
"http://www.sgi.com/tech/stl/Vector.html">std::vector
</a> are
616 one-dimensional containers of user data. Both manage their own
617 memory.
<tt>std::valarray
</tt> is a low-level
618 C++ Standard Library component
619 meant to provide portable high performance for numerical applications.
620 <a href=
"http://www.oonumerics.org/blitz/">Blitz++
</a> is
621 an array library developed by Todd
623 advanced C++ techniques to provide near-Fortran performance for
624 array-based numerical applications.
625 <b>array_traits
</b> is a beta library, formerly distributed with
626 Boost, that provides a means to create iterators over native C++
629 This library is analogous to
630 <a href=
"../../array/index.html">boost::array
</a> in that it augments C style N-dimensional
631 arrays, as
<tt>boost::array
</tt> does for C one-dimensional arrays.
634 <a name=
"sec_credits"></a>
638 <li><a href=
"mailto:garcia@osl.iu.edu">Ronald Garcia
</a>
639 is the primary author of the library.
641 <li><a href=
"http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek
</a>
642 helped with the library and provided a sounding board for ideas,
643 advice, and assistance porting to Microsoft Visual C++.
645 <li><a href=
"mailto:gbavestrelli@yahoo.com">Giovanni Bavestrelli
</a>
646 provided an early implementation of an
647 N-dimensional array which inspired feedback from the
648 <a href=
"http://www.boost.org/">Boost
</a> mailing list
649 members. Some design decisions in this work were based upon this
650 implementation and the comments it elicited.
652 <li><a href=
"mailto:tveldhui@acm.org">Todd Veldhuizen
</a> wrote
653 <a href=
"http://oonumerics.org/blitz/">Blitz++
</a>, which
654 inspired some aspects of this design. In addition, he supplied
655 feedback on the design and implementation of the library.
657 <li><a href=
"mailto:jewillco@osl.iu.edu">Jeremiah Willcock
</a>
658 provided feedback on the implementation and design of the
659 library and some suggestions for features.
661 <li><a href=
"mailto:bdawes@acm.org">Beman Dawes
</a>
662 helped immensely with porting the library to Microsoft Windows
669 <a href=
"mailto:garcia@.cs.indiana.edu">Ronald Garcia
</a>
671 <!-- Created: Fri Jun 29 10:53:07 EST 2001 -->
672 <!-- hhmts start -->Last modified: Tue Feb
7 17:
15:
50 EST
2006 <!-- hhmts end -->