TiledArray  0.7.0
eigen.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Justus Calvin
19  * Department of Chemistry, Virginia Tech
20  *
21  * eigen.h
22  * May 02, 2015
23  *
24  */
25 
26 #ifndef TILEDARRAY_CONVERSIONS_EIGEN_H__INCLUDED
27 #define TILEDARRAY_CONVERSIONS_EIGEN_H__INCLUDED
28 
29 #include <cstdint>
30 #include <tiledarray_fwd.h>
31 #include <TiledArray/tensor.h>
32 #include <TiledArray/error.h>
33 #include <TiledArray/math/eigen.h>
34 #include <TiledArray/madness.h>
36 #include "TiledArray/dist_array.h"
37 
38 namespace TiledArray {
39 
40  // Convenience typedefs
43  typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> EigenMatrixXcd;
44  typedef Eigen::Matrix<std::complex<float>, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> EigenMatrixXcf;
53 
54 
56 
64  template <typename T, typename A>
66  eigen_map(const Tensor<T, A>& tensor, const std::size_t m, const std::size_t n) {
67  TA_ASSERT((m * n) == tensor.size());
68 
69  return Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic,
70  Eigen::RowMajor>, Eigen::AutoAlign>(tensor.data(), m, n);
71  }
72 
74 
82  template <typename T, typename A>
84  eigen_map(Tensor<T, A>& tensor, const std::size_t m, const std::size_t n) {
85  TA_ASSERT((m * n) == tensor.size());
86 
87  return Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic,
88  Eigen::RowMajor>, Eigen::AutoAlign>(tensor.data(), m, n);
89  }
90 
92 
99  template <typename T, typename A>
101  eigen_map(const Tensor<T, A>& tensor, const std::size_t n) {
102  TA_ASSERT(n == tensor.size());
103 
105  Eigen::AutoAlign>(tensor.data(), n);
106  }
107 
109 
116  template <typename T, typename A>
117  inline Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1>, Eigen::AutoAlign>
118  eigen_map(Tensor<T, A>& tensor, const std::size_t n) {
119  TA_ASSERT(n == tensor.size());
120 
122  Eigen::AutoAlign>(tensor.data(), n);
123  }
124 
126 
133  template <typename T, typename A>
135  eigen_map(const Tensor<T, A>& tensor) {
136  TA_ASSERT((tensor.range().rank() == 2u) || (tensor.range().rank() == 1u));
137  const auto* MADNESS_RESTRICT const tensor_extent = tensor.range().extent_data();
138  return eigen_map(tensor, tensor_extent[0],
139  (tensor.range().rank() == 2u ? tensor_extent[1] : 1ul));
140  }
141 
143 
149  template <typename T, typename A>
152  TA_ASSERT((tensor.range().rank() == 2u) || (tensor.range().rank() == 1u));
153  const auto* MADNESS_RESTRICT const tensor_extent = tensor.range().extent_data();
154  return eigen_map(tensor, tensor_extent[0],
155  (tensor.range().rank() == 2u ? tensor_extent[1] : 1ul));
156  }
157 
159 
171  template <typename T, typename A, typename Derived>
172  inline void eigen_submatrix_to_tensor(const Eigen::MatrixBase<Derived>& matrix, Tensor<T, A>& tensor) {
173  typedef typename Tensor<T, A>::size_type size_type;
174  TA_ASSERT((tensor.range().rank() == 2u) || (tensor.range().rank() == 1u));
175 
176  // Get pointers to the tensor range data
177  const auto* MADNESS_RESTRICT const tensor_lower = tensor.range().lobound_data();
178  const auto* MADNESS_RESTRICT const tensor_upper = tensor.range().upbound_data();
179  const auto* MADNESS_RESTRICT const tensor_extent = tensor.range().extent_data();
180 
181  if(tensor.range().rank() == 2u) {
182  // Get tensor range data
183  const std::size_t tensor_lower_0 = tensor_lower[0];
184  const std::size_t tensor_lower_1 = tensor_lower[1];
185  const std::size_t tensor_upper_0 = tensor_upper[0];
186  const std::size_t tensor_upper_1 = tensor_upper[1];
187  const std::size_t tensor_extent_0 = tensor_extent[0];
188  const std::size_t tensor_extent_1 = tensor_extent[1];
189 
190  TA_ASSERT(tensor_upper_0 <= size_type(matrix.rows()));
191  TA_ASSERT(tensor_upper_1 <= size_type(matrix.cols()));
192 
193  // Copy matrix
194  eigen_map(tensor, tensor_extent_0, tensor_extent_1) =
195  matrix.block(tensor_lower_0, tensor_lower_1,
196  tensor_extent_0, tensor_extent_1);
197  } else {
198  // Get tensor range data
199  const std::size_t tensor_lower_0 = tensor_lower[0];
200  const std::size_t tensor_upper_0 = tensor_upper[0];
201  const std::size_t tensor_extent_0 = tensor_extent[0];
202 
203  // Check that matrix is a vector.
204  TA_ASSERT((matrix.rows() == 1) || (matrix.cols() == 1));
205 
206  if(matrix.rows() == 1) {
207  TA_ASSERT(tensor_upper_0 <= size_type(matrix.cols()));
208 
209  // Copy the row vector to tensor
210  eigen_map(tensor, 1, tensor_extent_0) =
211  matrix.block(0, tensor_lower_0, 1, tensor_extent_0);
212  } else {
213  TA_ASSERT(tensor_upper_0 <= size_type(matrix.rows()));
214 
215  // Copy the column vector to tensor
216  eigen_map(tensor, tensor_extent_0, 1) =
217  matrix.block(tensor_lower_0, 0, tensor_extent_0, 1);
218  }
219  }
220  }
221 
223 
235  template <typename T, typename A, typename Derived>
236  inline void tensor_to_eigen_submatrix(const Tensor<T, A>& tensor, Eigen::MatrixBase<Derived>& matrix) {
237  typedef typename Tensor<T, A>::size_type size_type;
238  TA_ASSERT((tensor.range().rank() == 2u) || (tensor.range().rank() == 1u));
239 
240  // Get pointers to the tensor range data
241  const auto* MADNESS_RESTRICT const tensor_lower = tensor.range().lobound_data();
242  const auto* MADNESS_RESTRICT const tensor_upper = tensor.range().upbound_data();
243  const auto* MADNESS_RESTRICT const tensor_extent = tensor.range().extent_data();
244 
245  if(tensor.range().rank() == 2) {
246  // Get tensor range data
247  const std::size_t tensor_lower_0 = tensor_lower[0];
248  const std::size_t tensor_lower_1 = tensor_lower[1];
249  const std::size_t tensor_upper_0 = tensor_upper[0];
250  const std::size_t tensor_upper_1 = tensor_upper[1];
251  const std::size_t tensor_extent_0 = tensor_extent[0];
252  const std::size_t tensor_extent_1 = tensor_extent[1];
253 
254  TA_ASSERT(tensor_upper_0 <= size_type(matrix.rows()));
255  TA_ASSERT(tensor_upper_1 <= size_type(matrix.cols()));
256 
257  // Copy tensor into matrix
258  matrix.block(tensor_lower_0, tensor_lower_1,
259  tensor_extent_0, tensor_extent_1) =
260  eigen_map(tensor, tensor_extent_0, tensor_extent_1);
261  } else {
262  // Get tensor range data
263  const std::size_t tensor_lower_0 = tensor_lower[0];
264  const std::size_t tensor_upper_0 = tensor_upper[0];
265  const std::size_t tensor_extent_0 = tensor_extent[0];
266 
267  TA_ASSERT((matrix.rows() == 1) || (matrix.cols() == 1));
268 
269  if(matrix.rows() == 1) {
270  TA_ASSERT(tensor_upper_0 <= size_type(matrix.cols()));
271 
272  // Copy tensor into row vector
273  matrix.block(0, tensor_lower_0, 1, tensor_extent_0) =
274  eigen_map(tensor, 1, tensor_extent_0);
275  } else {
276  TA_ASSERT(tensor_upper_0 <= size_type(matrix.rows()));
277 
278  // Copy tensor into column vector
279  matrix.block(tensor_lower_0, 0, tensor_extent_0, 1) =
280  eigen_map(tensor, tensor_extent_0, 1);
281  }
282  }
283  }
284 
285  namespace detail {
286 
288 
295  template <typename A, typename Derived>
296  void counted_eigen_submatrix_to_tensor(const Eigen::MatrixBase<Derived>* matrix,
297  A* array, const typename A::size_type i, madness::AtomicInt* counter)
298  {
299  typename A::value_type tensor(array->trange().make_tile_range(i));
300  eigen_submatrix_to_tensor(*matrix, tensor);
301  array->set(i, tensor);
302  (*counter)++;
303  }
304 
306 
312  template <typename Derived, typename T>
313  void counted_tensor_to_eigen_submatrix(const T& tensor,
314  Eigen::MatrixBase<Derived>* matrix, madness::AtomicInt* counter)
315  {
316  tensor_to_eigen_submatrix(tensor, *matrix);
317  (*counter)++;
318  }
319 
320  } // namespace detail
321 
323 
360  template <typename A, typename Derived>
361  A eigen_to_array(World& world, const typename A::trange_type& trange,
362  const Eigen::MatrixBase<Derived>& matrix, bool replicated = false)
363  {
364  typedef typename A::size_type size_type;
365  // Check that trange matches the dimensions of other
366  if((matrix.cols() > 1) && (matrix.rows() > 1)) {
367  TA_USER_ASSERT(trange.tiles_range().rank() == 2,
368  "TiledArray::eigen_to_array(): The number of dimensions in trange is not equal to that of the Eigen matrix.");
369  TA_USER_ASSERT(trange.elements_range().extent(0) == size_type(matrix.rows()),
370  "TiledArray::eigen_to_array(): The number of rows in trange is not equal to the number of rows in the Eigen matrix.");
371  TA_USER_ASSERT(trange.elements_range().extent(1) == size_type(matrix.cols()),
372  "TiledArray::eigen_to_array(): The number of columns in trange is not equal to the number of columns in the Eigen matrix.");
373  } else {
374  TA_USER_ASSERT(trange.tiles_range().rank() == 1,
375  "TiledArray::eigen_to_array(): The number of dimensions in trange must match that of the Eigen matrix.");
376  TA_USER_ASSERT(trange.elements_range().extent(0) == size_type(matrix.size()),
377  "TiledArray::eigen_to_array(): The size of trange must be equal to the matrix size.");
378  }
379 
380  // Check that this is not a distributed computing environment
381  if(! replicated)
382  TA_USER_ASSERT(world.size() == 1,
383  "An array cannot be assigned with an Eigen::Matrix when the number of World ranks is greater than 1.");
384 
385  // Create a new tensor
386  A array = (replicated && (world.size() > 1)
387  ? A(world, trange,
388  std::static_pointer_cast<typename A::pmap_interface>(
389  std::make_shared<detail::ReplicatedPmap>(
390  world, trange.tiles_range().volume())))
391  : A(world, trange));
392 
393  // Spawn tasks to copy Eigen to an Array
394  madness::AtomicInt counter;
395  counter = 0;
396  std::int64_t n = 0;
397  for(std::size_t i = 0; i < array.size(); ++i) {
398  world.taskq.add(& detail::counted_eigen_submatrix_to_tensor<A, Derived>,
399  &matrix, &array, i, &counter);
400  ++n;
401  }
402 
403  // Wait until the write tasks are complete
404  array.world().await([&counter,n] () { return counter == n; });
405 
406  return array;
407  }
408 
410 
432  template <typename Tile, typename Policy,
433  unsigned int EigenStorageOrder = Eigen::ColMajor>
434  Eigen::Matrix<typename Tile::value_type, Eigen::Dynamic, Eigen::Dynamic,
435  EigenStorageOrder>
437  typedef Eigen::Matrix<typename Tile::value_type, Eigen::Dynamic,
438  Eigen::Dynamic, EigenStorageOrder>
439  EigenMatrix;
440 
441  const auto rank = array.trange().tiles_range().rank();
442 
443  // Check that the array will fit in a matrix or vector
444  TA_USER_ASSERT((rank == 2u) || (rank == 1u),
445  "TiledArray::array_to_eigen(): The array dimensions must be equal to 1 or 2.");
446 
447  // Check that this is not a distributed computing environment or that the
448  // array is replicated
449  if(! array.pmap()->is_replicated())
450  TA_USER_ASSERT(array.world().size() == 1,
451  "TiledArray::array_to_eigen(): Array cannot be assigned with an Eigen::Matrix when the number of World ranks is greater than 1.");
452 
453  // Construct the Eigen matrix
454  const auto* MADNESS_RESTRICT const array_extent = array.trange().elements_range().extent_data();
455  // if array is sparse must initialize to zero
456  EigenMatrix matrix = EigenMatrix::Zero(array_extent[0], (rank == 2 ? array_extent[1] : 1));
457 
458  // Spawn tasks to copy array tiles to the Eigen matrix
459  madness::AtomicInt counter;
460  counter = 0;
461  int n = 0;
462  for(std::size_t i = 0; i < array.size(); ++i) {
463  if(! array.is_zero(i)) {
464  array.world().taskq.add(
467  array.find(i), &matrix, &counter);
468  ++n;
469  }
470  }
471 
472  // Wait until the above tasks are complete. Tasks will be processed by this
473  // thread while waiting.
474  array.world().await([&counter,n] () { return counter == n; });
475 
476  return matrix;
477  }
478 
480 
519  template <typename A>
520  inline A row_major_buffer_to_array(World& world, const typename A::trange_type& trange,
521  const typename A::value_type::value_type* buffer, const std::size_t m,
522  const std::size_t n, const bool replicated = false)
523  {
524  TA_USER_ASSERT(trange.elements_range().extent(0) == m,
525  "TiledArray::eigen_to_array(): The number of rows in trange is not equal to m.");
526  TA_USER_ASSERT(trange.elements_range().extent(1) == n,
527  "TiledArray::eigen_to_array(): The number of columns in trange is not equal to n.");
528 
529  typedef Eigen::Matrix<typename A::value_type::value_type, Eigen::Dynamic,
530  Eigen::Dynamic, Eigen::RowMajor> matrix_type;
531  return eigen_to_array(world, trange, Eigen::Map<const matrix_type,
532  Eigen::AutoAlign>(buffer, m, n), replicated);
533  }
534 
536 
575  template <typename A>
576  inline A column_major_buffer_to_array(World& world, const typename A::trange_type& trange,
577  const typename A::value_type::value_type* buffer, const std::size_t m,
578  const std::size_t n, const bool replicated = false)
579  {
580  TA_USER_ASSERT(trange.elements_range().extent(0) == m,
581  "TiledArray::eigen_to_array(): The number of rows in trange is not equal to m.");
582  TA_USER_ASSERT(trange.elements_range().extent(1) == n,
583  "TiledArray::eigen_to_array(): The number of columns in trange is not equal to n.");
584 
585  typedef Eigen::Matrix<typename A::value_type::value_type, Eigen::Dynamic,
586  Eigen::Dynamic, Eigen::ColMajor> matrix_type;
587  return eigen_to_array(world, trange, Eigen::Map<const matrix_type,
588  Eigen::AutoAlign>(buffer, m, n), replicated);
589  }
590 
591 } // namespace TiledArray
592 
593 #endif // TILEDARRAY_CONVERSIONS_EIGEN_H__INCLUDED
void counted_tensor_to_eigen_submatrix(const T &tensor, Eigen::MatrixBase< Derived > *matrix, madness::AtomicInt *counter)
Task function for assigning a tensor to an Eigen submatrix.
Definition: eigen.h:313
A row_major_buffer_to_array(World &world, const typename A::trange_type &trange, const typename A::value_type::value_type *buffer, const std::size_t m, const std::size_t n, const bool replicated=false)
Convert a row-major matrix buffer into an Array object.
Definition: eigen.h:520
Future< value_type > find(const Index &i) const
Find local or remote tile.
Definition: dist_array.h:324
An N-dimensional tensor object.
Definition: foreach.h:40
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > EigenMatrixXd
Definition: eigen.h:41
const range_type & range() const
Tensor range object accessor.
Definition: tensor.h:310
Eigen::Matrix< long, Eigen::Dynamic, 1 > EigenVectorXl
Definition: eigen.h:52
const trange_type & trange() const
Tiled range accessor.
Definition: dist_array.h:547
Eigen::Matrix< std::complex< float >, 1, Eigen::Dynamic > EigenVectorXcf
Definition: eigen.h:50
Eigen::Matrix< std::complex< double >, 1, Eigen::Dynamic > EigenVectorXcd
Definition: eigen.h:49
void tensor_to_eigen_submatrix(const Tensor< T, A > &tensor, Eigen::MatrixBase< Derived > &matrix)
Copy the content of a tensor into an Eigen matrix block.
Definition: eigen.h:236
const_pointer data() const
Data direct access.
Definition: tensor.h:416
bool is_zero(const Index &i) const
Check for zero tiles.
Definition: dist_array.h:723
Eigen::Map< const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor >, Eigen::AutoAlign > eigen_map(const Tensor< T, A > &tensor, const std::size_t m, const std::size_t n)
Construct a const Eigen::Map object for a given Tensor object.
Definition: eigen.h:66
Eigen::Matrix< typename Tile::value_type, Eigen::Dynamic, Eigen::Dynamic, EigenStorageOrder > array_to_eigen(const DistArray< Tile, Policy > &array)
Convert an Array object into an Eigen matrix object.
Definition: eigen.h:436
Forward declarations.
Definition: clone.h:32
#define TA_ASSERT(a)
Definition: error.h:107
World & world() const
World accessor.
Definition: dist_array.h:633
A column_major_buffer_to_array(World &world, const typename A::trange_type &trange, const typename A::value_type::value_type *buffer, const std::size_t m, const std::size_t n, const bool replicated=false)
Convert a column-major matrix buffer into an Array object.
Definition: eigen.h:576
A eigen_to_array(World &world, const typename A::trange_type &trange, const Eigen::MatrixBase< Derived > &matrix, bool replicated=false)
Convert an Eigen matrix into an Array object.
Definition: eigen.h:361
Eigen::Matrix< float, Eigen::Dynamic, 1 > EigenVectorXf
Definition: eigen.h:48
void counted_eigen_submatrix_to_tensor(const Eigen::MatrixBase< Derived > *matrix, A *array, const typename A::size_type i, madness::AtomicInt *counter)
Task function for converting Eigen submatrix to a tensor.
Definition: eigen.h:296
range_type::size_type size_type
size type
Definition: tensor.h:39
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > EigenMatrixXf
Definition: eigen.h:42
size_type size() const
Tensor dimension size accessor.
Definition: tensor.h:317
Eigen::Matrix< int, Eigen::Dynamic, 1 > EigenVectorXi
Definition: eigen.h:51
Eigen::Matrix< double, Eigen::Dynamic, 1 > EigenVectorXd
Definition: eigen.h:47
#define TA_USER_ASSERT(a, m)
Definition: error.h:123
void eigen_submatrix_to_tensor(const Eigen::MatrixBase< Derived > &matrix, Tensor< T, A > &tensor)
Copy a block of an Eigen matrix into a tensor.
Definition: eigen.h:172
size_type size() const
Definition: dist_array.h:573
Eigen::Matrix< std::complex< float >, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > EigenMatrixXcf
Definition: eigen.h:44
Eigen::Matrix< std::complex< double >, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > EigenMatrixXcd
Definition: eigen.h:43
An N-dimensional shallow copy wrapper for tile objects.
Definition: tile.h:80
Eigen::Matrix< long, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > EigenMatrixXl
Definition: eigen.h:46
Eigen::Matrix< int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > EigenMatrixXi
Definition: eigen.h:45
const std::shared_ptr< pmap_interface > & pmap() const
Process map accessor.
Definition: dist_array.h:647