void Tensor::Slice(Tensor& result_tensor, int fixed_mode, int fixed_index) { vector<int> result_dims; vector<int> free_modes; vector<int> fixed_mode_vec = VectorPlus::CreateSingleton(fixed_mode); vector<int> fixed_index_vec = VectorPlus::CreateSingleton(fixed_index); VectorPlus::SetDiff(free_modes, *all_modes, fixed_mode_vec); VectorPlus::Subset(result_dims, *dims, free_modes); result_tensor.Initialize(result_dims); if (result_tensor.NumElements() == 1) { assert(fixed_mode == 1); result_tensor.Set(0, this->At(fixed_index)); return; } FastIndexer indexer(result_dims); int i = 0; while (indexer.HasNext()) // for (int i = 0; i < result_tensor.NumElements(); ++i) { vector<int>& indices = indexer.GetNext(); // vector<int> indices; vector<int> total_indices; // result_tensor.ComputeIndexArray(indices, i); MergeIndices(total_indices, free_modes, fixed_mode_vec, indices, fixed_index_vec); result_tensor.Set(i++, this->At(total_indices)); } }
void Tensor::Divide(Tensor& result_tensor, Tensor& t1, double val) { result_tensor.Initialize(t1.Dims()); for (int i = 0; i < t1.NumElements(); ++i) { result_tensor.Set(i, t1.At(i) / val); } }
// add two tensors, store result in result_tensor which is assumed // to be uninitialized void Tensor::Add(Tensor& result_tensor, Tensor& t1, Tensor& t2) { assert(t1.NumElements() == t2.NumElements()); result_tensor.Initialize(t1.Dims()); for (int i = 0; i < result_tensor.NumElements(); ++i) { result_tensor.Set(i, t1.At(i) + t2.At(i)); } }
void Tensor::Slice(Tensor& result_tensor, vector<int>& fixed_modes, vector<int>& fixed_indices) { vector<int> free_modes; vector<int> free_dims; VectorPlus::SetDiff(free_modes, *all_modes, fixed_modes); VectorPlus::Subset(free_dims, *dims, free_modes); result_tensor.Initialize(free_dims); int i = 0; FastIndexer indexer(free_dims); while (indexer.HasNext()) // for (int i = 0; i < result_tensor.NumElements(); ++i) { // vector<int> result_indices; // result_tensor.ComputeIndexArray(result_indices, i); vector<int>& result_indices = indexer.GetNext(); vector<int> orig_indices; MergeIndices(orig_indices, free_modes, fixed_modes, result_indices, fixed_indices); result_tensor.Set(i++, this->At(orig_indices)); } }
void Tensor::Rearrange(Tensor& result_tensor, Tensor& orig_tensor, vector<int>& old_to_new_modes) { vector<int> new_dims; VectorPlus::Rearrange(new_dims, orig_tensor.Dims(), old_to_new_modes); result_tensor.Initialize(new_dims); int i = 0; FastIndexer indexer(orig_tensor.Dims()); while (indexer.HasNext()) //for (int i = 0; i < orig_tensor.NumElements(); ++i) { vector<int>& orig_indices = indexer.GetNext(); // vector<int> orig_indices; // orig_tensor.ComputeIndexArray(orig_indices, i); vector<int> new_indices; VectorPlus::Rearrange(new_indices, orig_indices, old_to_new_modes); result_tensor.Set(new_indices, orig_tensor.At(i++)); } }
void Tensor::Select(Tensor& result_tensor, vector<int>& fixed_modes, vector<int>& fixed_indices) { result_tensor.Initialize(*dims); int i = 0; FastIndexer indexer(*dims); while (indexer.HasNext()) // for (int i = 0; i < result_tensor.NumElements(); ++i) { vector<int>& i_indices = indexer.GetNext(); // vector<int> i_indices; // result_tensor.ComputeIndexArray(i_indices, i); vector<int> fixed_i_indices; VectorPlus::Subset(fixed_i_indices, i_indices, fixed_modes); if (VectorPlus::Equals(fixed_i_indices, fixed_indices)) result_tensor.Set(i, this->At(i)); else result_tensor.Set(i, 0); i++; } }
bool Tensor::Inverse(Tensor& Umat, Tensor& result_tensor, vector<int>& mult_modes, int nonzerovals) { int num_sing_vals = (int)pow((double)nonzerovals, (double)mult_modes.size()); vector<int> free_modes; vector<int> mult_dims; vector<int> free_dims; vector<int> mult_offsets; vector<int> free_offsets; VectorPlus::SetDiff(free_modes, *all_modes, mult_modes); VectorPlus::Subset(mult_dims, *dims, mult_modes); VectorPlus::CSubset(free_dims, *dims, mult_modes); ComputeOffsets(mult_offsets, mult_dims); ComputeOffsets(free_offsets, free_dims); vector<int> usmalldims(free_modes.size(), nonzerovals); vector<int> udims; vector<int> usmall_offsets; ComputeOffsets(usmall_offsets, usmalldims); VectorPlus::Concat(udims, free_dims, usmalldims); Umat.Initialize(udims); vector<int> result_dims; VectorPlus::Concat(result_dims, free_dims, usmalldims); result_tensor.Initialize(result_dims); /* int numMultElements = VectorPlus::Product(mult_dims); int numFreeElements = VectorPlus::Product(free_dims); assert(numMultElements == numFreeElements); Eigen::MatrixXd matricized_tensor(numFreeElements,numMultElements); cout << "copy start 1\n"; for (int i = 0; i < numFreeElements; ++i) { vector<int> free_indices; ComputeIndexArray(free_indices, free_offsets, i); for (int j = 0; j < numMultElements; ++j) { vector<int> mult_indices; ComputeIndexArray(mult_indices, mult_offsets, j); vector<int> total_indices; VectorPlus::Concat(total_indices, free_indices, mult_indices); matricized_tensor(i,j) = this->At(total_indices); } } cout << "copy end 1\n"; // MatrixXd matricized_inverse = matricized_tensor.inverse(); // cout << matricized_inverse; // cout << "\n"; //compute pseudoinverse cout << "svd start 1\n"; Eigen::JacobiSVD<Eigen::MatrixXd> svd(matricized_tensor, Eigen::ComputeFullU); Eigen::MatrixXd U = svd.matrixU(); cout << "svd end 1\n"; Eigen::MatrixXd thinU = U.leftCols(num_sing_vals); /* MatrixXd reduced_matrix = thinU.transpose() * matricized_tensor; JacobiSVD<MatrixXd> svd2(reduced_matrix, ComputeFullU | ComputeFullV); U = svd2.matrixU(); MatrixXd Uleft = U.leftCols(num_sing_vals); MatrixXd V = svd2.matrixV(); MatrixXd Vleft = V.leftCols(num_sing_vals); VectorXd s_vals = svd2.singularValues(); MatrixXd Sigma(num_sing_vals, num_sing_vals); for (int i = 0; i < num_sing_vals; ++i) { for (int j = 0; j < num_sing_vals; ++j) { Sigma(i,j) = 0; } } for (int s = 0; s < num_sing_vals; ++s) { cout << s_vals(s); cout << "\n"; if (abs(s_vals(s)) < .00000000001) assert(0); Sigma(s,s) = 1.0 / s_vals(s); } MatrixXd pinverse_temp = Vleft * Sigma; MatrixXd matricized_inverse = pinverse_temp * Uleft.transpose(); */ // rearrange into tensor /* vector<int> result_dims; VectorPlus::Concat(result_dims, free_dims, usmalldims); result_tensor.Initialize(result_dims); /* for (int i = 0; i < matricized_inverse.rows(); ++i) { vector<int> left_indices; ComputeIndexArray(left_indices, free_offsets, i); for (int j = 0; j < matricized_inverse.cols(); ++j) { vector<int> right_indices; ComputeIndexArray(right_indices, usmall_offsets, j); vector<int> total_indices; VectorPlus::Concat(total_indices, left_indices, right_indices); result_tensor.Set(total_indices, matricized_inverse(i, j)); } } */ /* VectorPlus::Concat(udims, free_dims, usmalldims); Umat.Initialize(udims); vector<int> semi_dims; semi_dims.push_back(thinU.rows()); semi_dims.push_back(thinU.cols()); cout << "copy start 2 \n"; for (int i = 0; i < thinU.rows(); ++i) { vector<int> left_indices; ComputeIndexArray(left_indices, free_offsets, i); for (int j = 0; j < thinU.cols(); ++j) { vector<int> right_indices; ComputeIndexArray(right_indices, usmall_offsets, j); vector<int> indices; VectorPlus::Concat(indices, left_indices, right_indices); // Umat.Set(indices, rand_matrix.At(i,j)); Umat.Set(indices, thinU(i,j)); if (thinU.rows() == thinU.cols()) { if (VectorPlus::Equals(left_indices, right_indices)) { Umat.Set(indices, 1); } else { Umat.Set(indices, 0); } } } } cout << "copy end 2 \n"; */ return true; }
// multiply two tensors, store result in result_tensor which is assumed to be uninitialized void Tensor::Multiply(Tensor& result_tensor, Tensor& t1, Tensor& t2, vector<int>& mult_modes1, vector<int>& mult_modes2) { assert(mult_modes1.size() == mult_modes2.size()); if (t1.Order() == mult_modes1.size() && t2.Order() == mult_modes2.size()) { double val = InnerProduct(t1, t2); vector<int> fake_dims; result_tensor.Initialize(fake_dims); result_tensor.Set(0, val); return; } int numMultElements = 1; vector<int> mult_dims(mult_modes1.size(), 0); for (int i = 0; i < mult_modes1.size(); ++i) { assert(t1.Dim(mult_modes1[i]) == t2.Dim(mult_modes2[i])); mult_dims[i] = t1.Dim(mult_modes1[i]); numMultElements = numMultElements * mult_dims[i]; } vector<int> mult_offsets; ComputeOffsets(mult_offsets, mult_dims); int result_order = t1.Order() + t2.Order() - mult_modes1.size() - mult_modes2.size(); if (result_order == 0) assert(0); vector<int> result_dims; vector<int> free_modes1; vector<int> free_modes2; // find free indices from t1 for (int i = 0; i < t1.Order(); ++i) { if (!VectorPlus::Contains(mult_modes1, i)) { result_dims.push_back(t1.Dim(i)); free_modes1.push_back(i); } } // find free indices from t2 for (int i = 0; i < t2.Order(); ++i) { if (!VectorPlus::Contains(mult_modes2, i)) { result_dims.push_back(t2.Dim(i)); free_modes2.push_back(i); } } // initialize result_tensor result_tensor.Initialize(result_dims); // fill in elements from result tensor FastIndexer result_indexer(result_dims); for (int n = 0; n < result_tensor.NumElements(); ++n) { vector<int>& indices = result_indexer.GetNext(); vector<int> free_indices1; vector<int> free_indices2; // result_tensor.ComputeIndexArray(indices, n); for (int i = 0; i < result_tensor.Order(); ++i) { if (i < free_modes1.size()) free_indices1.push_back(indices[i]); else free_indices2.push_back(indices[i]); } // sum over elementwise products of mult-mode elements double temp_sum = 0; FastIndexer mult_indexer(mult_dims); for (int k = 0; k < numMultElements; ++k) { vector<int>& mult_indices = mult_indexer.GetNext(); // ComputeIndexArray(mult_indices, mult_offsets, k); vector<int> indices1; vector<int> indices2; MergeIndices(indices1, mult_modes1, free_modes1, mult_indices, free_indices1); MergeIndices(indices2, mult_modes2, free_modes2, mult_indices, free_indices2); temp_sum += t1.At(indices1) * t2.At(indices2); } result_tensor.Set(n, temp_sum); } }
void Tensor::ElementwiseMultiply(Tensor& result_tensor, Tensor& t1, Tensor& t2, vector<int>& mult_modes1, vector<int>& mult_modes2) { assert(mult_modes1.size() == mult_modes2.size()); int numMultElements = 1; vector<int> mult_dims(mult_modes1.size(), 0); for (int i = 0; i < mult_modes1.size(); ++i) { assert(t1.Dim(mult_modes1[i]) == t2.Dim(mult_modes2[i])); mult_dims[i] = t1.Dim(mult_modes1[i]); numMultElements = numMultElements * mult_dims[i]; } vector<int> mult_offsets; ComputeOffsets(mult_offsets, mult_dims); int result_order = t1.Order() + t2.Order() - mult_modes2.size(); if (result_order == 0) assert(0); vector<int> result_dims; vector<int> free_modes1; vector<int> free_modes2; // find free indices from t1 for (int i = 0; i < t1.Order(); ++i) { if (!VectorPlus::Contains(mult_modes1, i)) { free_modes1.push_back(i); } } // find free indices from t2 for (int i = 0; i < t2.Order(); ++i) { if (!VectorPlus::Contains(mult_modes2, i)) { free_modes2.push_back(i); } } int curr_index = 0; for (int i = 0; i < result_order; ++i) { if (i < t1.Order()) { result_dims.push_back(t1.Dim(i)); } else { result_dims.push_back(t2.Dim(free_modes2[curr_index++])); } } // initialize result_tensor result_tensor.Initialize(result_dims); // fill in elements from result tensor FastIndexer indexer(result_dims); int n = 0; while (indexer.HasNext()) { vector<int>& indices = indexer.GetNext(); vector<int> indices1(t1.Order(), 0); vector<int> free_indices2; // result_tensor.ComputeIndexArray(indices, n); for (int i = 0; i < result_tensor.Order(); ++i) { if (i < t1.Order()) indices1[i] = indices[i]; else free_indices2.push_back(indices[i]); } vector<int> mult_indices; VectorPlus::Subset(mult_indices, indices1, mult_modes1); vector<int> indices2; MergeIndices(indices2, mult_modes2, free_modes2, mult_indices, free_indices2); double val = 0; double val1 = t1.At(indices1); if (val1 != 0) { val = val1 * t2.At(indices2); } result_tensor.Set(n++, val); } }
bool Tensor::ComputeJointSVD(Tensor& Umat, vector<Tensor*>& extra_tensor_list, vector<int>& mult_modes, int nonzerovals) { int num_sing_vals = (int)pow((double)nonzerovals, (double)mult_modes.size()); vector<int> free_modes; vector<int> mult_dims; vector<int> free_dims; vector<int> mult_offsets; vector<int> free_offsets; Tensor& temp_tensor = *(extra_tensor_list.at(0)); VectorPlus::SetDiff(free_modes, temp_tensor.Modes(), mult_modes); VectorPlus::Subset(mult_dims, temp_tensor.Dims(), mult_modes); VectorPlus::CSubset(free_dims, temp_tensor.Dims(), mult_modes); ComputeOffsets(mult_offsets, mult_dims); ComputeOffsets(free_offsets, free_dims); vector<int> usmalldims(free_modes.size(), nonzerovals); vector<int> udims; vector<int> usmall_offsets; ComputeOffsets(usmall_offsets, usmalldims); int numMultElements = VectorPlus::Product(mult_dims); int numFreeElements = VectorPlus::Product(free_dims); assert(numMultElements == numFreeElements); Eigen::MatrixXd matricized_tensor(numFreeElements,extra_tensor_list.size() * numMultElements); //cout << "copy start 1\n"; for (int z = 0; z < extra_tensor_list.size(); ++z) { int z_offset = z * numMultElements; FastIndexer i_indexer(free_dims); for (int i = 0; i < numFreeElements; ++i) { vector<int>& free_indices = i_indexer.GetNext(); // ComputeIndexArray(free_indices, free_offsets, i); FastIndexer j_indexer(mult_dims); for (int j = 0; j < numMultElements; ++j) { vector<int>& mult_indices = j_indexer.GetNext(); // ComputeIndexArray(mult_indices, mult_offsets, j); vector<int> total_indices; VectorPlus::Concat(total_indices, free_indices, mult_indices); matricized_tensor(i,z_offset + j) = extra_tensor_list.at(z)->At(total_indices); } } } // cout << "copy end 1\n"; // MatrixXd matricized_inverse = matricized_tensor.inverse(); // cout << matricized_inverse; // cout << "\n"; //compute pseudoinverse //cout << "svd start 1\n"; Eigen::JacobiSVD<Eigen::MatrixXd> svd(matricized_tensor, Eigen::ComputeFullU); Eigen::MatrixXd U = svd.matrixU(); // cout << "svd end 1\n"; Eigen::MatrixXd thinU = U.leftCols(num_sing_vals); VectorPlus::Concat(udims, free_dims, usmalldims); Umat.Initialize(udims); vector<int> semi_dims; semi_dims.push_back(thinU.rows()); semi_dims.push_back(thinU.cols()); // cout << "copy start 2 \n"; FastIndexer i_indexer(free_dims); for (int i = 0; i < thinU.rows(); ++i) { vector<int>& left_indices = i_indexer.GetNext(); // ComputeIndexArray(left_indices, free_offsets, i); FastIndexer j_indexer(usmalldims); for (int j = 0; j < thinU.cols(); ++j) { vector<int>& right_indices = j_indexer.GetNext(); // ComputeIndexArray(right_indices, usmall_offsets, j); vector<int> indices; VectorPlus::Concat(indices, left_indices, right_indices); // Umat.Set(indices, rand_matrix.At(i,j)); Umat.Set(indices, thinU(i,j)); if (thinU.rows() == thinU.cols()) { if (VectorPlus::Equals(left_indices, right_indices)) { Umat.Set(indices, 1); } else { Umat.Set(indices, 0); } } } } // cout << "copy end 2 \n"; return true; }