Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MatrixSize.hpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // For more information, please see: http://www.nektar.info
4 //
5 // The MIT License
6 //
7 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
8 // Department of Aeronautics, Imperial College London (UK), and Scientific
9 // Computing and Imaging Institute, University of Utah (USA).
10 //
11 // License for the specific language governing rights and limitations under
12 // Permission is hereby granted, free of charge, to any person obtaining a
13 // copy of this software and associated documentation files (the "Software"),
14 // to deal in the Software without restriction, including without limitation
15 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 // and/or sell copies of the Software, and to permit persons to whom the
17 // Software is furnished to do so, subject to the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be included
20 // in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 // DEALINGS IN THE SOFTWARE.
29 //
30 ///////////////////////////////////////////////////////////////////////////////
31 
32 #ifndef NEKTAR_LIBUTILITIES_LINEAR_ALGEBRA_MATRIX_SIZE_HPP
33 #define NEKTAR_LIBUTILITIES_LINEAR_ALGEBRA_MATRIX_SIZE_HPP
34 
35 #ifdef NEKTAR_USE_EXPRESSION_TEMPLATES
36 
37 #include <boost/utility/enable_if.hpp>
38 #include <boost/mpl/or.hpp>
39 #include <boost/tuple/tuple.hpp>
40 
41 #include <ExpressionTemplates/Node.hpp>
42 #include <ExpressionTemplates/Operators.hpp>
43 
44 namespace Nektar
45 {
46  /// \brief Determines the size of a matrix from a matrix expression, as
47  /// well as the required buffer size for the largest intermediate matrix
48  /// in the expression.
49  template<typename NodeType, typename Indices, unsigned int index>
50  struct MatrixSize;
51 
52  /// \brief Specialization for a constant matrix node.
53  template<typename T, typename Indices, unsigned int index>
54  struct MatrixSize<expt::Node<T, void, void>, Indices, index>
55  {
56  static const unsigned int MappedIndex = boost::mpl::at_c<Indices, index>::type::value;
57 
58  template<typename R>
59  static unsigned int GetRequiredRowsFromMatrix(const R& matrix,
60  typename boost::enable_if<IsMatrix<R> >::type* dummy = 0)
61  {
62  return matrix.GetRows();
63  }
64 
65  template<typename R>
66  static unsigned int GetRequiredColumnsFromMatrix(const R& matrix,
67  typename boost::enable_if<IsMatrix<R> >::type* dummy = 0)
68  {
69  return matrix.GetColumns();
70  }
71 
72  template<typename R>
73  static unsigned int GetRequiredRowsFromMatrix(const R& matrix,
74  typename boost::enable_if<IsVector<R> >::type* dummy = 0)
75  {
76  return matrix.GetRows();
77  }
78 
79  template<typename R>
80  static unsigned int GetRequiredColumnsFromMatrix(const R& matrix,
81  typename boost::enable_if<IsVector<R> >::type* dummy = 0)
82  {
83  return 1;
84  }
85 
86  template<typename R>
87  static unsigned int GetRequiredRowsFromMatrix(const R& matrix,
88  typename boost::disable_if
89  <
90  boost::mpl::or_
91  <
92  IsMatrix<R> ,
93  IsVector<R>
94  >
95  >::type* dummy = 0)
96  {
97  return 1;
98  }
99 
100 
101  template<typename R>
102  static unsigned int GetRequiredColumnsFromMatrix(const R& matrix,
103  typename boost::disable_if
104  <
105  boost::mpl::or_
106  <
107  IsMatrix<R> ,
108  IsVector<R>
109  >
110  >::type* dummy = 0)
111  {
112  return 1;
113  }
114 
115  template<typename ArgumentVectorType>
116  static boost::tuple<unsigned int, unsigned int, unsigned int>
117  GetRequiredSize(const ArgumentVectorType& args)
118  {
119  unsigned int rows = GetRequiredRowsFromMatrix(boost::fusion::at_c<MappedIndex>(args));
120  unsigned int columns = GetRequiredColumnsFromMatrix(boost::fusion::at_c<MappedIndex>(args));
121 
122  return boost::make_tuple(rows, columns, rows*columns);
123  }
124 
125 
126  };
127 
128 
129  template<typename ChildType,
130  typename Op,
131  typename Indices, unsigned int index>
132  struct MatrixSize<expt::Node<ChildType, Op, void>, Indices, index>
133  {
134  template<typename ArgumentVectorType>
135  static boost::tuple<unsigned int, unsigned int, unsigned int>
136  GetRequiredSize(const ArgumentVectorType& args)
137  {
138  return MatrixSize<ChildType, Indices, index>::GetRequiredSize(args);
139  }
140 
141  template<typename ArgumentVectorType>
142  static unsigned int
143  GetRequiredRows(const ArgumentVectorType& args)
144  {
145  boost::tuple<unsigned int, unsigned int, unsigned int> values = GetRequiredSize(args);
146  return values.get<0>();
147  }
148  };
149 
150 
151  /// \brief Calculates the size of the given matrix expression, as well as the
152  /// largest intermediate buffer size, assuming multiplication.
153  template<typename LeftNodeType, typename RightNodeType, typename Indices, unsigned int index>
154  struct CalculateLargestRequiredSize
155  {
156  template<typename ArgumentVectorType>
157  static boost::tuple<unsigned int, unsigned int, unsigned int>
158  GetRequiredSize(const ArgumentVectorType& args)
159  {
160  boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
161  MatrixSize<LeftNodeType, Indices, index>::GetRequiredSize(args);
162 
163  boost::tuple<unsigned int, unsigned int, unsigned int> rhsSizes =
164  MatrixSize<RightNodeType, Indices, index + LeftNodeType::TotalCount>::GetRequiredSize(args);
165 
166  unsigned int leftRows = lhsSizes.get<0>();
167  unsigned int rightColumns = rhsSizes.get<1>();
168 
169  unsigned int matrixSize = leftRows*rightColumns;
170  unsigned int bufferSize = std::max(std::max(lhsSizes.get<2>(), rhsSizes.get<2>()), matrixSize);
171 
172  return boost::make_tuple(leftRows, rightColumns, bufferSize);
173  }
174  };
175 
176 
177  template<typename LhsType, typename OpType, typename RhsType, typename Indices, unsigned int index, typename enabled=void>
178  struct BinaryMatrixSizeEvaluator;
179 
180  // Addition or subtraction.
181  template<typename LhsType, typename OpType, typename RhsType,typename Indices, unsigned int index>
182  struct BinaryMatrixSizeEvaluator<LhsType, OpType, RhsType, Indices, index,
183  typename boost::enable_if
184  <
185  boost::mpl::or_
186  <
187  boost::is_same<OpType, expt::AddOp>,
188  boost::is_same<OpType, expt::SubtractOp>
189  >
190  >::type>
191  {
192  template<typename ArgumentVectorType>
193  static boost::tuple<unsigned int, unsigned int, unsigned int>
194  GetRequiredSize(const ArgumentVectorType& args)
195  {
196  boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
197  MatrixSize<LhsType, Indices, index>::GetRequiredSize(args);
198  return lhsSizes;
199  }
200  };
201 
202  // Multiplication with double lhs.
203  template<typename LhsType, typename OpType, typename RhsType,typename Indices, unsigned int index>
204  struct BinaryMatrixSizeEvaluator<LhsType, OpType, RhsType, Indices, index,
205  typename boost::enable_if
206  <
207  boost::mpl::and_
208  <
209  expt::IsConstantNode<LhsType>,
210  boost::is_same<typename LhsType::ResultType, double>
211  >
212  >::type>
213  {
214  template<typename ArgumentVectorType>
215  static boost::tuple<unsigned int, unsigned int, unsigned int>
216  GetRequiredSize(const ArgumentVectorType& args)
217  {
218  boost::tuple<unsigned int, unsigned int, unsigned int> rhsSizes =
219  MatrixSize<RhsType, Indices, index + LhsType::TotalCount>::GetRequiredSize(args);
220  return rhsSizes;
221  }
222  };
223 
224 
225  // Double rhs
226  template<typename LhsType, typename OpType, typename RhsType,typename Indices, unsigned int index>
227  struct BinaryMatrixSizeEvaluator<LhsType, OpType, RhsType, Indices, index,
228  typename boost::enable_if
229  <
230  boost::mpl::and_
231  <
232  expt::IsConstantNode<RhsType>,
233  boost::is_same<typename RhsType::ResultType, double>
234  >
235  >::type>
236  {
237  template<typename ArgumentVectorType>
238  static boost::tuple<unsigned int, unsigned int, unsigned int>
239  GetRequiredSize(const ArgumentVectorType& args)
240  {
241  boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
242  MatrixSize<LhsType, Indices, index>::GetRequiredSize(args);
243  return lhsSizes;
244  }
245  };
246 
247  // Multiplication.
248  template<typename LhsType, typename RhsType,typename Indices, unsigned int index>
249  struct BinaryMatrixSizeEvaluator<LhsType, expt::MultiplyOp, RhsType, Indices, index,
250  typename boost::enable_if
251  <
252  boost::mpl::and_
253  <
254  // Test for both nodes being constant matrices.
255  // Negate to account for the next specialization.
256  boost::mpl::not_<boost::mpl::and_
257  <
258  boost::mpl::and_
259  <
260  expt::IsConstantNode<RhsType>,
261  boost::mpl::not_<boost::is_same<typename RhsType::ResultType, double> >
262  >,
263  boost::mpl::and_
264  <
265  expt::IsConstantNode<LhsType>,
266  boost::mpl::not_<boost::is_same<typename LhsType::ResultType, double> >
267  >
268  > >,
269 
270  // Tests to make sure if either is constant, it is a matrix.
271  boost::mpl::not_<boost::mpl::and_
272  <
273  expt::IsConstantNode<RhsType>,
274  boost::is_same<typename RhsType::ResultType, double>
275  > >,
276  boost::mpl::not_<boost::mpl::and_
277  <
278  expt::IsConstantNode<LhsType>,
279  boost::is_same<typename LhsType::ResultType, double>
280  > >
281  >
282  >::type>
283  {
284  template<typename ArgumentVectorType>
285  static boost::tuple<unsigned int, unsigned int, unsigned int>
286  GetRequiredSize(const ArgumentVectorType& args)
287  {
288  return CalculateLargestRequiredSize<LhsType, RhsType, Indices, index>::GetRequiredSize(args);
289  }
290  };
291 
292  template<typename LhsType, typename RhsType,typename Indices, unsigned int index>
293  struct BinaryMatrixSizeEvaluator<LhsType, expt::MultiplyOp, RhsType, Indices, index,
294  typename boost::enable_if
295  <
296  // Test for both nodes being constant matrices.
297  boost::mpl::and_
298  <
299  boost::mpl::and_
300  <
301  expt::IsConstantNode<RhsType>,
302  boost::mpl::not_<boost::is_same<typename RhsType::ResultType, double> >
303  >,
304  boost::mpl::and_
305  <
306  expt::IsConstantNode<LhsType>,
307  boost::mpl::not_<boost::is_same<typename LhsType::ResultType, double> >
308  >
309  >
310  >::type>
311  {
312  template<typename ArgumentVectorType>
313  static boost::tuple<unsigned int, unsigned int, unsigned int>
314  GetRequiredSize(const ArgumentVectorType& args)
315  {
316  boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
317  MatrixSize<LhsType, Indices, index>::GetRequiredSize(args);
318 
319  boost::tuple<unsigned int, unsigned int, unsigned int> rhsSizes =
320  MatrixSize<RhsType, Indices, index + LhsType::TotalCount>::GetRequiredSize(args);
321 
322  unsigned int leftRows = lhsSizes.get<0>();
323  unsigned int rightColumns = rhsSizes.get<1>();
324 
325  unsigned int bufferSize = leftRows*rightColumns;
326 
327  return boost::make_tuple(leftRows, rightColumns, bufferSize);
328  }
329  };
330 
331  ///// \brief Implementation of the MatrixSize class for binary nodes.
332  ///// The code is slightly cleaner by moving the evaluation to this class
333  ///// instead of creating the specializations in the MatrixSize class.
334  //template<typename L1, typename LOp, typename L2,
335  // typename Op,
336  // typename R1, typename ROp, typename R2,
337  // typename Indices, unsigned int index,
338  // typename enabled = void>
339  //struct BinaryMatrixSizeEvaluator;
340 
341  ///// \brief Matrix sizes for two constant children with addition/subtraction.
342  //template<typename L, typename Op, typename R, typename Indices, unsigned int index>
343  //struct BinaryMatrixSizeEvaluator<L, void, void, Op, R, void, void, Indices, index>
344  //{
345  // typedef expt::Node<L, void, void> LeftNodeType;
346  // typedef expt::Node<R, void, void> RightNodeType;
347  //
348  // template<typename ArgumentVectorType>
349  // static boost::tuple<unsigned int, unsigned int, unsigned int>
350  // GetRequiredSize(const ArgumentVectorType& args)
351  // {
352  // boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
353  // MatrixSize<LeftNodeType, Indices, index>::GetRequiredSize(args);
354  // return lhsSizes;
355  // }
356  //};
357 
358  ///// \brief Matrix sizes for two constant children with multiplication.
359  //template<typename L, typename R, typename Indices, unsigned int index>
360  //struct BinaryMatrixSizeEvaluator<L, void, void, expt::MultiplyOp, R, void, void, Indices, index>
361  //{
362  // typedef expt::Node<L, void, void> LeftNodeType;
363  // typedef expt::Node<R, void, void> RightNodeType;
364  //
365  // template<typename ArgumentVectorType>
366  // static boost::tuple<unsigned int, unsigned int, unsigned int>
367  // GetRequiredSize(const ArgumentVectorType& args)
368  // {
369  // boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
370  // MatrixSize<LeftNodeType, Indices, index>::GetRequiredSize(args);
371 
372  // boost::tuple<unsigned int, unsigned int, unsigned int> rhsSizes =
373  // MatrixSize<RightNodeType, Indices, index + LeftNodeType::TotalCount>::GetRequiredSize(args);
374 
375  // unsigned int leftRows = lhsSizes.get<0>();
376  // unsigned int rightColumns = rhsSizes.get<1>();
377 
378  // unsigned int bufferSize = leftRows*rightColumns;
379  //
380  // return boost::make_tuple(leftRows, rightColumns, bufferSize);
381  // }
382  //};
383 
384  //template<typename R, typename Indices, unsigned int index>
385  //struct BinaryMatrixSizeEvaluator<NekDouble, void, void, expt::MultiplyOp, R, void, void, Indices, index>
386  //{
387  // typedef expt::Node<NekDouble, void, void> LeftNodeType;
388  // typedef expt::Node<R, void, void> RightNodeType;
389  //
390  // template<typename ArgumentVectorType>
391  // static boost::tuple<unsigned int, unsigned int, unsigned int>
392  // GetRequiredSize(const ArgumentVectorType& args)
393  // {
394  // boost::tuple<unsigned int, unsigned int, unsigned int> rhsSizes =
395  // MatrixSize<RightNodeType, Indices, index + LeftNodeType::TotalCount>::GetRequiredSize(args);
396  // return rhsSizes;
397  // }
398  //};
399 
400  //template<typename L, typename Indices, unsigned int index>
401  //struct BinaryMatrixSizeEvaluator<L, void, void, expt::MultiplyOp, NekDouble, void, void, Indices, index>
402  //{
403  // typedef expt::Node<L, void, void> LeftNodeType;
404  // typedef expt::Node<NekDouble, void, void> RightNodeType;
405  //
406  // template<typename ArgumentVectorType>
407  // static boost::tuple<unsigned int, unsigned int, unsigned int>
408  // GetRequiredSize(const ArgumentVectorType& args)
409  // {
410  // boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
411  // MatrixSize<LeftNodeType, Indices, index>::GetRequiredSize(args);
412  // return lhsSizes;
413  // }
414  //};
415 
416 
417  //template<typename L1, typename LOp, typename L2, typename Op, typename Indices, unsigned int index>
418  //struct BinaryMatrixSizeEvaluator<L1, LOp, L2, Op, NekDouble, void, void, Indices, index,
419  // typename boost::enable_if
420  // <
421  // boost::mpl::and_
422  // <
423  // boost::mpl::not_<boost::is_same<LOp, void> >,
424  // boost::mpl::not_<boost::is_same<L1, void> >
425  // >
426  // >::type >
427  //{
428  // typedef expt::Node<L1, LOp, L2> LeftNodeType;
429  //
430  // template<typename ArgumentVectorType>
431  // static boost::tuple<unsigned int, unsigned int, unsigned int>
432  // GetRequiredSize(const ArgumentVectorType& args)
433  // {
434  // boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
435  // MatrixSize<LeftNodeType, Indices, index>::GetRequiredSize(args);
436  // return lhsSizes;
437  // }
438  //};
439 
440  //template<typename L1, typename LOp, typename L2, typename Op, typename R, typename Indices, unsigned int index>
441  //struct BinaryMatrixSizeEvaluator<L1, LOp, L2, Op, R, void, void, Indices, index,
442  // typename boost::enable_if
443  // <
444  // boost::mpl::and_
445  // <
446  // boost::mpl::not_<boost::is_same<LOp, void> >,
447  // boost::mpl::not_<boost::is_same<L1, void> >
448  // >
449  // >::type >
450  //{
451  // typedef expt::Node<R, void, void> RightNodeType;
452  // typedef expt::Node<L1, LOp, L2> LeftNodeType;
453  //
454  // template<typename ArgumentVectorType>
455  // static boost::tuple<unsigned int, unsigned int, unsigned int>
456  // GetRequiredSize(const ArgumentVectorType& args)
457  // {
458  // return CalculateLargestRequiredSize<LeftNodeType, RightNodeType, Indices, index>::GetRequiredSize(args);
459  // }
460  //};
461 
462  //template<typename Op, typename R1, typename ROp, typename R2, typename Indices, unsigned int index>
463  //struct BinaryMatrixSizeEvaluator<NekDouble, void, void, Op, R1, ROp, R2, Indices, index,
464  // typename boost::enable_if
465  // <
466  // boost::mpl::and_
467  // <
468  // boost::mpl::not_<boost::is_same<ROp, void> >,
469  // boost::mpl::not_<boost::is_same<R1, void> >
470  // >
471  // >::type >
472  //{
473  // typedef expt::Node<R1, ROp, R2> RightNodeType;
474  //
475  // template<typename ArgumentVectorType>
476  // static boost::tuple<unsigned int, unsigned int, unsigned int>
477  // GetRequiredSize(const ArgumentVectorType& args)
478  // {
479  // boost::tuple<unsigned int, unsigned int, unsigned int> rhsSizes =
480  // MatrixSize<RightNodeType, Indices, index+1>::GetRequiredSize(args);
481  // return rhsSizes;
482  // }
483  //};
484 
485  //template<typename L, typename Op, typename R1, typename ROp, typename R2, typename Indices, unsigned int index>
486  //struct BinaryMatrixSizeEvaluator<L, void, void, Op, R1, ROp, R2, Indices, index,
487  // typename boost::enable_if
488  // <
489  // boost::mpl::and_
490  // <
491  // boost::mpl::not_<boost::is_same<ROp, void> >,
492  // boost::mpl::not_<boost::is_same<R1, void> >
493  // >
494  // >::type >
495  //{
496  // typedef expt::Node<L, void, void> LeftNodeType;
497  // typedef expt::Node<R1, ROp, R2> RightNodeType;
498  //
499  // template<typename ArgumentVectorType>
500  // static boost::tuple<unsigned int, unsigned int, unsigned int>
501  // GetRequiredSize(const ArgumentVectorType& args)
502  // {
503  // return CalculateLargestRequiredSize<LeftNodeType, RightNodeType, Indices, index>::GetRequiredSize(args);
504  // }
505  //};
506 
507  //template<typename L1, typename LOp, typename L2,
508  // typename Op,
509  // typename R1, typename ROp, typename R2, typename Indices, unsigned int index>
510  //struct BinaryMatrixSizeEvaluator<L1, LOp, L2, Op, R1, ROp, R2, Indices, index,
511  // typename boost::enable_if
512  // <
513  // boost::mpl::and_
514  // <
515  // boost::mpl::not_<boost::is_same<ROp, void> >,
516  // boost::mpl::not_<boost::is_same<R2, void> >,
517  // boost::mpl::not_<boost::is_same<LOp, void> >,
518  // boost::mpl::not_<boost::is_same<L2, void> >
519  // >
520  // >::type >
521  //{
522  // typedef expt::Node<L1, LOp, L2> LeftNodeType;
523  // typedef expt::Node<R1, ROp, R2> RightNodeType;
524  //
525  // template<typename ArgumentVectorType>
526  // static boost::tuple<unsigned int, unsigned int, unsigned int>
527  // GetRequiredSize(const ArgumentVectorType& args)
528  // {
529  // boost::tuple<unsigned int, unsigned int, unsigned int> lhsSizes =
530  // MatrixSize<LeftNodeType, Indices, index>::GetRequiredSize(args);
531  // return lhsSizes;
532  // }
533  //};
534 
535  //template<typename L1, typename LOp, typename L2,
536  // typename R1, typename ROp, typename R2, typename Indices, unsigned int index>
537  //struct BinaryMatrixSizeEvaluator<L1, LOp, L2, expt::MultiplyOp, R1, ROp, R2, Indices, index,
538  // typename boost::enable_if
539  // <
540  // boost::mpl::and_
541  // <
542  // boost::mpl::not_<boost::is_same<ROp, void> >,
543  // boost::mpl::not_<boost::is_same<R2, void> >,
544  // boost::mpl::not_<boost::is_same<LOp, void> >,
545  // boost::mpl::not_<boost::is_same<L2, void> >
546  // >
547  // >::type >
548  //{
549  // typedef expt::Node<L1, LOp, L2> LeftNodeType;
550  // typedef expt::Node<R1, ROp, R2> RightNodeType;
551  //
552  // template<typename ArgumentVectorType>
553  // static boost::tuple<unsigned int, unsigned int, unsigned int>
554  // GetRequiredSize(const ArgumentVectorType& args)
555  // {
556  // return CalculateLargestRequiredSize<LeftNodeType, RightNodeType, Indices, index>::GetRequiredSize(args);
557  // }
558  //};
559 
560  template<typename L1, typename LOp, typename L2,
561  typename Op,
562  typename R1, typename ROp, typename R2,
563  typename Indices, unsigned int index>
564  struct MatrixSize<expt::Node<expt::Node<L1, LOp, L2>, Op, expt::Node<R1, ROp, R2> >, Indices, index>
565  {
566  typedef expt::Node<L1, LOp, L2> LhsType;
567  typedef expt::Node<R1, ROp, R2> RhsType;
568 
569  template<typename ArgumentVectorType>
570  static boost::tuple<unsigned int, unsigned int, unsigned int>
571  GetRequiredSize(const ArgumentVectorType& args)
572  {
573  return BinaryMatrixSizeEvaluator<LhsType, Op, RhsType, Indices, index>::GetRequiredSize(args);
574  }
575 
576  template<typename ArgumentVectorType>
577  static unsigned int
578  GetRequiredRows(const ArgumentVectorType& args)
579  {
580  boost::tuple<unsigned int, unsigned int, unsigned int> values = GetRequiredSize(args);
581  return values.get<0>();
582  }
583  };
584 
585 }
586 
587 #endif //NEKTAR_USE_EXPRESSION_TEMPLATES
588 #endif //NEKTAR_LIBUTILITIES_LINEAR_ALGEBRA_MATRIX_SIZE_HPP
589