/* * Copyright © 2004 Ondra Kamenik * Copyright © 2019-2023 Dynare Team * * This file is part of Dynare. * * Dynare 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. * * Dynare 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 Dynare. If not, see . */ // Full symmetry tensor. /* Here we define folded and unfolded tensors for full symmetry. All tensors from here are identifying the multidimensional index with columns. */ #ifndef FS_TENSOR_H #define FS_TENSOR_H #include "int_power.hh" #include "symmetry.hh" #include "tensor.hh" class FGSTensor; class UGSTensor; class FRSingleTensor; class FSSparseTensor; /* Folded tensor with full symmetry maintains only information about number of symmetrical variables nv. Further, we implement what is left from the super class FTensor. We implement getOffset() which should be used with care since its complexity. We implement a method adding a given general symmetry tensor to the full symmetry tensor supposing the variables of the general symmetry tensor are stacked giving only one variable of the full symmetry tensor. ⎛y⎞ For instance, if x= ⎝u⎠, then we can add tensor [g_y²u] to tensor [g_x³]. This is done in method addSubTensor(). Consult FGSTensor class declaration to know what is general symmetry tensor. Note that the past-the-end index is of the form (nv,…,nv), because of the specific implementation of FFSTensor::increment(). */ class UFSTensor; class FFSTensor : public FTensor { int nv; public: /* Constructs given the number of rows (explicit since the tensor is column-oriented), the number of variables in each dimension, and the number of dimensions */ FFSTensor(int r, int nvar, int d) : FTensor(indor::along_col, IntSequence(d, nvar), r, calcMaxOffset(nvar, d), d), nv(nvar) { } /* Constructs a tensor by one-dimensional contraction from the higher dimensional tensor t. This is, it constructs a tensor [g_yⁿ]_α₁…αₙ = [t_yⁿ⁺¹]_α₁…αₙβ [x]^β See the implementation for details. */ FFSTensor(const FFSTensor& t, const ConstVector& x); /* Converts from sparse tensor (which is fully symmetric and folded by nature). */ explicit FFSTensor(const FSSparseTensor& t); FFSTensor(const FFSTensor&) = default; FFSTensor(FFSTensor&&) = default; // Constructs from unfolded fully symmetric explicit FFSTensor(const UFSTensor& ut); // Constructs a subtensor of selected rows FFSTensor(int first_row, int num, FFSTensor& t) : FTensor(first_row, num, t), nv(t.nv) { } void increment(IntSequence& v) const override; void decrement(IntSequence& v) const override; [[nodiscard]] std::unique_ptr unfold() const override; [[nodiscard]] Symmetry getSym() const { return Symmetry {dimen()}; } [[nodiscard]] int getOffset(const IntSequence& v) const override; void addSubTensor(const FGSTensor& t); [[nodiscard]] int nvar() const { return nv; } static int calcMaxOffset(int nvar, int d); }; /* Unfolded fully symmetric tensor is almost the same in structure as FFSTensor, but the method unfoldData(). It takes columns which also exist in folded version and copies them to all their symmetrical locations. This is useful when constructing unfolded tensor from folded one. */ class UFSTensor : public UTensor { int nv; public: UFSTensor(int r, int nvar, int d) : UTensor(indor::along_col, IntSequence(d, nvar), r, calcMaxOffset(nvar, d), d), nv(nvar) { } UFSTensor(const UFSTensor& t, const ConstVector& x); UFSTensor(const UFSTensor&) = default; UFSTensor(UFSTensor&&) = default; explicit UFSTensor(const FFSTensor& ft); UFSTensor(int first_row, int num, UFSTensor& t) : UTensor(first_row, num, t), nv(t.nv) { } void increment(IntSequence& v) const override; void decrement(IntSequence& v) const override; [[nodiscard]] std::unique_ptr fold() const override; [[nodiscard]] Symmetry getSym() const { return Symmetry {dimen()}; } [[nodiscard]] int getOffset(const IntSequence& v) const override; void addSubTensor(const UGSTensor& t); [[nodiscard]] int nvar() const { return nv; } static int calcMaxOffset(int nvar, int d) { return power(nvar, d); } private: void unfoldData(); }; #endif