/usr/include/TiledArray/math/gemm_helper.h is in libtiledarray-dev 0.6.0-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | /*
* This file is a part of TiledArray.
* Copyright (C) 2014 Virginia Tech
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Justus Calvin
* Department of Chemistry, Virginia Tech
*
* gemm_helper.h
* Jan 20, 2014
*
*/
#ifndef TILEDARRAY_MATH_GEMM_HELPER_H__INCLUDED
#define TILEDARRAY_MATH_GEMM_HELPER_H__INCLUDED
#include <TiledArray/error.h>
#include <TiledArray/madness.h>
namespace TiledArray {
namespace math {
/// Contraction to *GEMM helper
/// This object is used to convert tensor contraction to *GEMM operations by
/// providing information on how to fuse dimensions
class GemmHelper {
private:
madness::cblas::CBLAS_TRANSPOSE left_op_;
///< Transpose operation that is applied to the left-hand argument
madness::cblas::CBLAS_TRANSPOSE right_op_;
///< Transpose operation that is applied to the right-hand argument
unsigned int result_rank_; ///< The rank of the result tensor
/// Contraction argument range data
/// The range data held by this object is the range of the inner and outer
/// dimensions of the argument tensor. It is assumed that the inner and
/// outer dimensions are contiguous.
struct ContractArg {
unsigned int inner[2]; ///< The inner dimension range
unsigned int outer[2]; ///< The outer dimension range
unsigned int rank; ///< Rank of the argument tensor
}
left_, ///< Left-hand argument range data
right_; ///< Right-hand argument range data
public:
GemmHelper(const madness::cblas::CBLAS_TRANSPOSE left_op,
const madness::cblas::CBLAS_TRANSPOSE right_op,
const unsigned int result_rank, const unsigned int left_rank,
const unsigned int right_rank) :
left_op_(left_op), right_op_(right_op),
result_rank_(result_rank), left_(), right_()
{
// Compute the number of contracted dimensions in left and right.
TA_ASSERT(((left_rank + right_rank - result_rank) % 2u) == 0u);
left_.rank = left_rank;
right_.rank = right_rank;
const unsigned int contract_size = num_contract_ranks();
// Store the inner and outer dimension ranges for the left-hand argument.
if(left_op == madness::cblas::NoTrans) {
left_.outer[0] = 0u;
left_.outer[1] = left_.inner[0] = left_rank - contract_size;
left_.inner[1] = left_rank;
} else {
left_.inner[0] = 0ul;
left_.inner[1] = left_.outer[0] = contract_size;
left_.outer[1] = left_rank;
}
// Store the inner and outer dimension ranges for the right-hand argument.
if(right_op == madness::cblas::NoTrans) {
right_.inner[0] = 0u;
right_.inner[1] = right_.outer[0] = contract_size;
right_.outer[1] = right_rank;
} else {
right_.outer[0] = 0u;
right_.outer[1] = right_.inner[0] = right_rank - contract_size;
right_.inner[1] = right_rank;
}
}
/// Functor copy constructor
/// Shallow copy of this functor
/// \param other The functor to be copied
GemmHelper(const GemmHelper& other) :
left_op_(other.left_op_), right_op_(other.right_op_),
result_rank_(other.result_rank_),
left_(other.left_), right_(other.right_)
{ }
/// Functor assignment operator
/// \param other The functor to be copied
GemmHelper& operator=(const GemmHelper& other) {
left_op_ = other.left_op_;
right_op_ = other.right_op_;
result_rank_ = other.result_rank_;
left_ = other.left_;
right_ = other.right_;
return *this;
}
/// Compute the number of contracted ranks
/// \return The number of ranks that are summed by this operation
unsigned int num_contract_ranks() const {
return (left_.rank + right_.rank - result_rank_) >> 1;
}
/// Result rank accessor
/// \return The rank of the result tile
unsigned int result_rank() const { return result_rank_; }
/// Left-hand argument rank accessor
/// \return The rank of the left-hand tile
unsigned int left_rank() const { return left_.rank; }
/// Right-hand argument rank accessor
/// \return The rank of the right-hand tile
unsigned int right_rank() const { return right_.rank; }
unsigned int left_inner_begin() const { return left_.inner[0]; }
unsigned int left_inner_end() const { return left_.inner[1]; }
unsigned int left_outer_begin() const { return left_.outer[0]; }
unsigned int left_outer_end() const { return left_.outer[1]; }
unsigned int right_inner_begin() const { return right_.inner[0]; }
unsigned int right_inner_end() const { return right_.inner[1]; }
unsigned int right_outer_begin() const { return right_.outer[0]; }
unsigned int right_outer_end() const { return right_.outer[1]; }
/// Construct a result range based on \c left and \c right ranges
/// \tparam R The result range type
/// \tparam Left The left-hand range type
/// \tparam Right The right-hand range type
/// \param left The left-hand range
/// \param right The right-hand range
/// \return A range object that can be used in a tensor contraction
/// defined by this object
template <typename R, typename Left, typename Right>
R make_result_range(const Left& left, const Right& right) const {
// Get pointers to lower and upper bounds of left and right.
const auto* restrict const left_lower = left.lobound_data();
const auto* restrict const left_upper = left.upbound_data();
const auto* restrict const right_lower = right.lobound_data();
const auto* restrict const right_upper = right.upbound_data();
// Create the start and finish indices
std::vector<std::size_t> lower, upper;
lower.reserve(result_rank_);
upper.reserve(result_rank_);
// Copy left-hand argument outer dimensions to start and finish
for(unsigned int i = left_.outer[0]; i < left_.outer[1]; ++i) {
lower.push_back(left_lower[i]);
upper.push_back(left_upper[i]);
}
// Copy right-hand argument outer dimensions to start and finish
for(unsigned int i = right_.outer[0]; i < right_.outer[1]; ++i) {
lower.push_back(right_lower[i]);
upper.push_back(right_upper[i]);
}
// Construct the result tile
return R(lower, upper);
}
/// Test that the outer dimensions of left are coformal with that of the result tensor
/// This function can test the start, finish, or size arrays of range
/// objects.
/// \tparam Left The left-hand size array type
/// \tparam Result The result size array type
/// \param left The left-hand size array to be tested
/// \param result The result size array to be tested
/// \return \c true if The outer dimensions of left are coformal with that
/// of result
template <typename Left, typename Result>
bool left_result_coformal(const Left& left, const Result& result) const {
return std::equal(left + left_.outer[0], left + left_.outer[1], result);
}
/// Test that the outer dimensions of right are coformal with that of the result tensor
/// This function can test the start, finish, or size arrays of range
/// objects.
/// \tparam Right The right-hand size array type
/// \tparam Result The result size array type
/// \param right The right-hand size array to be tested
/// \param result The result size array to be tested
/// \return \c true if The outer dimensions of right are coformal with that
/// of result
template <typename Right, typename Result>
bool right_result_coformal(const Right& right, const Result& result) const {
return std::equal(right + right_.outer[0], right + right_.outer[1],
result + (left_.outer[1] - left_.outer[0]));
}
/// Test that the inner dimensions of left are coformal with that of right
/// This function can test the start, finish, or size arrays of range
/// objects.
/// \tparam Left The left-hand size array type
/// \tparam Right The right-hand size array type
/// \param left The left-hand size array to be tested
/// \param right The right-hand size array to be tested
/// \return \c true if the outer dimensions of \c left are coformal with
/// that of \c right, other \c false.
template <typename Left, typename Right>
bool left_right_coformal(const Left& left, const Right& right) const {
return std::equal(left + left_.inner[0], left + left_.inner[1],
right + right_.inner[0]);
}
/// Compute the matrix dimension that can be used in a *GEMM call
/// \tparam Left The left-hand range type
/// \tparam Right The right-hand range type
/// \param[out] m The number of rows in left-hand and result matrices
/// \param[out] n The number of columns in the right-hand result matrices
/// \param[out] k The number of columns in the left-hand matrix and the
/// number of rows in the right-hand matrix
/// \param[in] left The left-hand range object
/// \param[in] right The right-hand range object
template <typename Left, typename Right>
void compute_matrix_sizes(integer& m, integer& n, integer& k,
const Left& left, const Right& right) const
{
// Check that the arguments are not empty and have the correct ranks
TA_ASSERT(left.rank() == left_.rank);
TA_ASSERT(right.rank() == right_.rank);
const auto* restrict const left_extent = left.extent_data();
const auto* restrict const right_extent = right.extent_data();
// Compute fused dimension sizes
m = 1;
for(unsigned int i = left_.outer[0]; i < left_.outer[1]; ++i)
m *= left_extent[i];
k = 1;
for(unsigned int i = left_.inner[0]; i < left_.inner[1]; ++i)
k *= left_extent[i];
n = 1;
for(unsigned int i = right_.outer[0]; i < right_.outer[1]; ++i)
n *= right_extent[i];
}
madness::cblas::CBLAS_TRANSPOSE left_op() const { return left_op_; }
madness::cblas::CBLAS_TRANSPOSE right_op() const { return right_op_; }
}; // class GemmHelper
} // namespace math
} // namespace TiledArray
#endif // TILEDARRAY_MATH_GEMM_HELPER_H__INCLUDED
|