Line data Source code
1 : /************************************************************************* 2 : * 3 : * Project 4 : * _____ _____ __ __ _____ 5 : * / ____| __ \| \/ | __ \ 6 : * ___ _ __ ___ _ __ | | __| |__) | \ / | |__) | 7 : * / _ \| '_ \ / _ \ '_ \| | |_ | ___/| |\/| | ___/ 8 : *| (_) | |_) | __/ | | | |__| | | | | | | | 9 : * \___/| .__/ \___|_| |_|\_____|_| |_| |_|_| 10 : * | | 11 : * |_| 12 : * 13 : * Copyright (C) Akiel Aries, <akiel@akiel.org>, et al. 14 : * 15 : * This software is licensed as described in the file LICENSE, which 16 : * you should have received as part of this distribution. The terms 17 : * among other details are referenced in the official documentation 18 : * seen here : https://akielaries.github.io/openGPMP/ along with 19 : * important files seen in this project. 20 : * 21 : * You may opt to use, copy, modify, merge, publish, distribute 22 : * and/or sell copies of the Software, and permit persons to whom 23 : * the Software is furnished to do so, under the terms of the 24 : * LICENSE file. As this is an Open Source effort, all implementations 25 : * must be of the same methodology. 26 : * 27 : * 28 : * 29 : * This software is distributed on an AS IS basis, WITHOUT 30 : * WARRANTY OF ANY KIND, either express or implied. 31 : * 32 : ************************************************************************/ 33 : #include <openGPMP/linalg/tensor.hpp> 34 : #include <stdexcept> 35 : 36 : // Constructors 37 : 38 0 : gpmp::linalg::Tensor::Tensor() : data_({{{}}}), dimensions_{0, 0, 0} { 39 0 : } 40 : 41 0 : gpmp::linalg::Tensor::Tensor(const std::vector<size_t> &dimensions) { 42 0 : if (dimensions.empty()) { 43 0 : throw std::invalid_argument("Error: Tensor dimensions are empty."); 44 : } 45 : 46 : // Assign values to dimensions_ 47 0 : for (size_t i = 0; i < 3; ++i) { 48 0 : dimensions_[i] = dimensions[i]; 49 : } 50 : 51 0 : size_t totalSize = 1; 52 0 : for (size_t dim : dimensions) { 53 0 : totalSize *= dim; 54 : } 55 0 : data_ = std::vector<std::vector<std::vector<double>>>( 56 : dimensions_[0], 57 0 : std::vector<std::vector<double>>( 58 : dimensions_[1], 59 0 : std::vector<double>(dimensions_[2], 0.0))); 60 0 : } 61 : 62 0 : gpmp::linalg::Tensor::Tensor( 63 0 : const std::vector<std::vector<std::vector<double>>> &data) 64 0 : : data_(data) { 65 0 : if (data.empty() || data[0].empty()) { 66 0 : throw std::invalid_argument("Error: Tensor data is empty."); 67 : } 68 : 69 0 : dimensions_[0] = data.size(); 70 0 : dimensions_[1] = data[0].size(); 71 0 : dimensions_[2] = data[0][0].size(); 72 0 : } 73 : 74 : gpmp::linalg::Tensor 75 0 : gpmp::linalg::Tensor::add(const gpmp::linalg::Tensor &other) const { 76 0 : if (dimensions_[0] != other.dimensions_[0] || 77 0 : dimensions_[1] != other.dimensions_[1] || 78 0 : dimensions_[2] != other.dimensions_[2]) { 79 0 : throw std::invalid_argument( 80 0 : "Error: Tensor dimensions do not match for addition."); 81 : } 82 : 83 0 : gpmp::linalg::Tensor result; 84 0 : result.data_ = data_; 85 : 86 0 : for (size_t i = 0; i < dimensions_[0]; ++i) { 87 0 : for (size_t j = 0; j < dimensions_[1]; ++j) { 88 0 : for (size_t k = 0; k < dimensions_[2]; ++k) { 89 0 : result.data_[i][j][k] += other.data_[i][j][k]; 90 : } 91 : } 92 : } 93 : 94 0 : return result; 95 0 : } 96 : 97 0 : gpmp::linalg::Tensor gpmp::linalg::Tensor::multiply(double scalar) const { 98 0 : gpmp::linalg::Tensor result; 99 0 : result.data_ = data_; 100 : 101 0 : for (size_t i = 0; i < dimensions_[0]; ++i) { 102 0 : for (size_t j = 0; j < dimensions_[1]; ++j) { 103 0 : for (size_t k = 0; k < dimensions_[2]; ++k) { 104 0 : result.data_[i][j][k] *= scalar; 105 : } 106 : } 107 : } 108 : 109 0 : return result; 110 0 : } 111 : 112 0 : gpmp::linalg::Tensor gpmp::linalg::Tensor::multiply(const Tensor &other) const { 113 0 : if (dimensions_[2] != other.dimensions_[1]) { 114 0 : throw std::invalid_argument( 115 0 : "Error: Tensor dimensions do not match for multiplication."); 116 : } 117 : 118 0 : gpmp::linalg::Tensor result; 119 0 : result.dimensions_[0] = dimensions_[0]; 120 0 : result.dimensions_[1] = dimensions_[1]; 121 0 : result.dimensions_[2] = other.dimensions_[2]; 122 : 123 0 : result.data_ = std::vector<std::vector<std::vector<double>>>( 124 0 : dimensions_[0], 125 0 : std::vector<std::vector<double>>( 126 0 : dimensions_[1], 127 0 : std::vector<double>(other.dimensions_[2], 0.0))); 128 : 129 0 : for (size_t i = 0; i < dimensions_[0]; ++i) { 130 0 : for (size_t j = 0; j < dimensions_[1]; ++j) { 131 0 : for (size_t k = 0; k < other.dimensions_[2]; ++k) { 132 0 : for (size_t l = 0; l < dimensions_[2]; ++l) { 133 0 : result.data_[i][j][k] += 134 0 : data_[i][j][l] * other.data_[l][j][k]; 135 : } 136 : } 137 : } 138 : } 139 : 140 0 : return result; 141 0 : } 142 : 143 0 : double gpmp::linalg::Tensor::get(const std::vector<size_t> &indices) const { 144 0 : if (indices.size() != 3) { 145 0 : throw std::out_of_range( 146 0 : "Error: Invalid number of indices for tensor access."); 147 : } 148 : 149 0 : for (size_t i = 0; i < 3; ++i) { 150 0 : if (indices[i] >= dimensions_[i]) { 151 0 : throw std::out_of_range( 152 0 : "Error: Index out of bounds for tensor access."); 153 : } 154 : } 155 : 156 0 : return data_[indices[0]][indices[1]][indices[2]]; 157 : } 158 : 159 0 : void gpmp::linalg::Tensor::set(const std::vector<size_t> &indices, 160 : double value) { 161 0 : if (indices.size() != 3) { 162 0 : throw std::out_of_range( 163 0 : "Error: Invalid number of indices for tensor access."); 164 : } 165 : 166 0 : for (size_t i = 0; i < 3; ++i) { 167 0 : if (indices[i] >= dimensions_[i]) { 168 0 : throw std::out_of_range( 169 0 : "Error: Index out of bounds for tensor access."); 170 : } 171 : } 172 : 173 0 : data_[indices[0]][indices[1]][indices[2]] = value; 174 0 : } 175 : 176 0 : void gpmp::linalg::Tensor::display() const { 177 0 : for (size_t i = 0; i < dimensions_[0]; ++i) { 178 0 : for (size_t j = 0; j < dimensions_[1]; ++j) { 179 0 : for (size_t k = 0; k < dimensions_[2]; ++k) { 180 0 : std::cout << data_[i][j][k] << " "; 181 : } 182 0 : std::cout << "\n"; 183 : } 184 0 : std::cout << "\n"; 185 : } 186 0 : }