2019-06-19 14:34:30 +02:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2004 Ondra Kamenik
|
2024-01-05 18:12:32 +01:00
|
|
|
|
* Copyright © 2019-2024 Dynare Team
|
2019-06-19 14:34:30 +02:00
|
|
|
|
*
|
|
|
|
|
* 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
|
2021-06-09 17:33:48 +02:00
|
|
|
|
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
2019-06-19 14:34:30 +02:00
|
|
|
|
*/
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
// General symmetry tensor.
|
|
|
|
|
|
|
|
|
|
/* Here we define tensors for general symmetry. All tensors from here are
|
|
|
|
|
identifying the multidimensional index with columns. Thus all
|
|
|
|
|
symmetries regard to columns. The general symmetry here is not the most
|
|
|
|
|
general. It captures all symmetries of indices which are given by
|
|
|
|
|
continuous partitioning of indices. Two items are symmetric if they
|
|
|
|
|
belong to the same group. The continuity implies that if two items
|
|
|
|
|
belong to one group, then all items between them belong to that
|
|
|
|
|
group. This continuous partitioning of indices is described by
|
2019-03-29 18:46:52 +01:00
|
|
|
|
Symmetry class.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
The dimension of the tensors here are described (besides the symmetry)
|
|
|
|
|
also by number of variables for each group. This is dealt in the class
|
|
|
|
|
for tensor dimensions defined also here. */
|
|
|
|
|
|
2023-12-13 16:50:28 +01:00
|
|
|
|
#ifndef GS_TENSOR_HH
|
|
|
|
|
#define GS_TENSOR_HH
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
#include "fs_tensor.hh"
|
|
|
|
|
#include "rfs_tensor.hh"
|
2023-11-29 19:00:21 +01:00
|
|
|
|
#include "symmetry.hh"
|
|
|
|
|
#include "tensor.hh"
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
class FGSTensor;
|
|
|
|
|
class UGSTensor;
|
|
|
|
|
class FSSparseTensor;
|
|
|
|
|
|
|
|
|
|
/* This class encapsulates symmetry information for the general
|
2019-03-29 18:46:52 +01:00
|
|
|
|
symmetry tensor. It maintains a vector of variable numbers ‘nvs’, and
|
|
|
|
|
symmetry ‘sym’. For example, let the symmetry be y²u³, and
|
|
|
|
|
variable numbers be 10 for y, and 5 for u. Then the ‘nvs’ is
|
|
|
|
|
(10,5), and ‘sym’ is (2,3). Also it maintains ‘nvmax’ unfolded ‘nvs’ with
|
|
|
|
|
respect to the symmetry, this is (10,10,5,5,5).
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
The class is able to calculate number of offsets (columns or rows depending
|
|
|
|
|
what matrix coordinate we describe) in unfolded and folded tensors
|
|
|
|
|
with the given symmetry. */
|
|
|
|
|
|
|
|
|
|
class TensorDimens
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
IntSequence nvs;
|
|
|
|
|
Symmetry sym;
|
|
|
|
|
IntSequence nvmax;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2023-11-29 19:00:21 +01:00
|
|
|
|
TensorDimens(Symmetry s, IntSequence nvars) :
|
|
|
|
|
nvs(std::move(nvars)), sym(std::move(s)), nvmax(nvs.unfold(sym))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2019-02-27 19:07:01 +01:00
|
|
|
|
// Full-symmetry special case
|
2023-11-29 19:00:21 +01:00
|
|
|
|
TensorDimens(int nvar, int dimen) : nvs {nvar}, sym {dimen}, nvmax(dimen, nvar)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2019-02-27 19:07:01 +01:00
|
|
|
|
// Constructs the tensor dimensions for slicing (see the implementation for details)
|
2023-11-29 19:00:21 +01:00
|
|
|
|
TensorDimens(const IntSequence& ss, const IntSequence& coor);
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
2024-01-09 13:04:33 +01:00
|
|
|
|
[[nodiscard]] bool
|
2023-11-29 19:00:21 +01:00
|
|
|
|
operator==(const TensorDimens& td) const
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
return nvs == td.nvs && sym == td.sym;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2019-01-08 16:09:25 +01:00
|
|
|
|
dimen() const
|
|
|
|
|
{
|
|
|
|
|
return sym.dimen();
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getNVX(int i) const
|
|
|
|
|
{
|
|
|
|
|
return nvmax[i];
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] const IntSequence&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getNVS() const
|
|
|
|
|
{
|
|
|
|
|
return nvs;
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] const IntSequence&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getNVX() const
|
|
|
|
|
{
|
|
|
|
|
return nvmax;
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] const Symmetry&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getSym() const
|
|
|
|
|
{
|
|
|
|
|
return sym;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int calcUnfoldMaxOffset() const;
|
|
|
|
|
[[nodiscard]] int calcFoldMaxOffset() const;
|
|
|
|
|
[[nodiscard]] int calcFoldOffset(const IntSequence& v) const;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void decrement(IntSequence& v) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Here is a class for folded general symmetry tensor. It only contains
|
|
|
|
|
tensor dimensions, it defines types for indices, implement virtual
|
2019-03-29 18:46:52 +01:00
|
|
|
|
methods of super class FTensor. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
class GSSparseTensor;
|
|
|
|
|
class FGSTensor : public FTensor
|
|
|
|
|
{
|
|
|
|
|
friend class UGSTensor;
|
|
|
|
|
|
|
|
|
|
const TensorDimens tdims;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FGSTensor(int r, TensorDimens td) :
|
|
|
|
|
FTensor(indor::along_col, td.getNVX(), r, td.calcFoldMaxOffset(), td.dimen()),
|
|
|
|
|
tdims(std::move(td))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FGSTensor(const FGSTensor&) = default;
|
|
|
|
|
FGSTensor(FGSTensor&&) = default;
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FGSTensor(int first_row, int num, FGSTensor& t) : FTensor(first_row, num, t), tdims(t.tdims)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
|
|
|
|
// Constructs a slice from a fully symmetric sparse tensor
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FGSTensor(const FSSparseTensor& t, const IntSequence& ss, const IntSequence& coor,
|
|
|
|
|
TensorDimens td);
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
|
|
|
|
// Constructs a slice from a fully symmetric dense tensor
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FGSTensor(const FFSTensor& t, const IntSequence& ss, const IntSequence& coor, TensorDimens td);
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
|
|
|
|
// Converting constructors
|
2023-11-29 19:00:21 +01:00
|
|
|
|
explicit FGSTensor(const UGSTensor& ut);
|
|
|
|
|
explicit FGSTensor(const GSSparseTensor& sp);
|
|
|
|
|
explicit FGSTensor(FFSTensor& t) : FTensor(0, t.nrows(), t), tdims(t.nvar(), t.dimen())
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 14:36:35 +01:00
|
|
|
|
~FGSTensor() override = default;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void increment(IntSequence& v) const override;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
decrement(IntSequence& v) const override
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
tdims.decrement(v);
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] std::unique_ptr<UTensor> unfold() const override;
|
|
|
|
|
[[nodiscard]] const TensorDimens&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getDims() const
|
|
|
|
|
{
|
|
|
|
|
return tdims;
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] const Symmetry&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getSym() const
|
|
|
|
|
{
|
|
|
|
|
return getDims().getSym();
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-29 18:46:52 +01:00
|
|
|
|
/* Performs a contraction of one variable in the tensor. This is, for
|
|
|
|
|
instance:
|
|
|
|
|
|
|
|
|
|
[r_xⁱzᵏ]_α₁…αᵢγ₁…γₖ = [t_xⁱyʲzᵏ]_α₁…αᵢβ₁…βⱼγ₁…γₖ·[c]^β₁…βⱼ
|
|
|
|
|
*/
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void contractAndAdd(int i, FGSTensor& out, const FRSingleTensor& col) const;
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2023-11-29 19:00:21 +01:00
|
|
|
|
getOffset(const IntSequence& v) const override
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
return tdims.calcFoldOffset(v);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-03-29 18:46:52 +01:00
|
|
|
|
/* Besides similar things that has FGSTensor, we have here also
|
|
|
|
|
method unfoldData(), and helper method getFirstIndexOf()
|
2019-01-08 16:09:25 +01:00
|
|
|
|
which corresponds to sorting coordinates in fully symmetric case (here
|
|
|
|
|
the action is more complicated, so we put it to the method). */
|
|
|
|
|
|
|
|
|
|
class UGSTensor : public UTensor
|
|
|
|
|
{
|
|
|
|
|
friend class FGSTensor;
|
|
|
|
|
|
|
|
|
|
const TensorDimens tdims;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UGSTensor(int r, TensorDimens td) :
|
|
|
|
|
UTensor(indor::along_col, td.getNVX(), r, td.calcUnfoldMaxOffset(), td.dimen()),
|
|
|
|
|
tdims(std::move(td))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UGSTensor(const UGSTensor&) = default;
|
|
|
|
|
UGSTensor(UGSTensor&&) = default;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UGSTensor(int first_row, int num, UGSTensor& t) : UTensor(first_row, num, t), tdims(t.tdims)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
|
|
|
|
// Constructs a slice from fully symmetric sparse tensor
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UGSTensor(const FSSparseTensor& t, const IntSequence& ss, const IntSequence& coor,
|
|
|
|
|
TensorDimens td);
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
|
|
|
|
// Constructs a slice from fully symmetric dense unfolded tensor
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UGSTensor(const UFSTensor& t, const IntSequence& ss, const IntSequence& coor, TensorDimens td);
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
|
|
|
|
// Converting constructors
|
2023-11-29 19:00:21 +01:00
|
|
|
|
explicit UGSTensor(const FGSTensor& ft);
|
|
|
|
|
explicit UGSTensor(UFSTensor& t) : UTensor(0, t.nrows(), t), tdims(t.nvar(), t.dimen())
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2019-02-27 19:07:01 +01:00
|
|
|
|
|
2019-02-20 14:36:35 +01:00
|
|
|
|
~UGSTensor() override = default;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void increment(IntSequence& v) const override;
|
|
|
|
|
void decrement(IntSequence& v) const override;
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] std::unique_ptr<FTensor> fold() const override;
|
|
|
|
|
[[nodiscard]] const TensorDimens&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getDims() const
|
|
|
|
|
{
|
|
|
|
|
return tdims;
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] const Symmetry&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getSym() const
|
|
|
|
|
{
|
|
|
|
|
return getDims().getSym();
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void contractAndAdd(int i, UGSTensor& out, const URSingleTensor& col) const;
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int getOffset(const IntSequence& v) const override;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
private:
|
|
|
|
|
void unfoldData();
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] index getFirstIndexOf(const index& in) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|