2019-06-19 14:34:30 +02:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2004 Ondra Kamenik
|
2023-09-20 16:30:02 +02:00
|
|
|
|
* Copyright © 2019-2023 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
|
|
|
|
|
|
|
|
|
// Multiplying stacked tensor columns.
|
|
|
|
|
|
|
|
|
|
/* We need to calculate the following tensor product:
|
2019-04-05 18:39:47 +02:00
|
|
|
|
ⱼ ₗ
|
2019-05-06 18:43:54 +02:00
|
|
|
|
[f_sʲ]_α₁…αⱼ = ∑ [f_zˡ]_β₁…βₗ ∑ ∏ [z_{s^|cₘ|}]_cₘ(α)^βₘ
|
2019-04-05 18:39:47 +02:00
|
|
|
|
ˡ⁼¹ c∈ℳₗ,ₖ ᵐ⁼¹
|
|
|
|
|
where s=(y,u,u′,σ), and z is a composition of four variables, say (v,w,y,u).
|
|
|
|
|
Note that z ends with y and u, and the only non-zero derivative of the
|
|
|
|
|
trailing part of z involving y or u is the first derivative and is the unit
|
|
|
|
|
matrix y_y=(1) or uᵤ=(1). Also, we suppose that the dependence of v, and w
|
|
|
|
|
on s is such that whenever derivative of w is nonzero, then also of v. This
|
|
|
|
|
means that there for any derivative and any index there is a continuous part
|
|
|
|
|
of derivatives of v and optionally of w followed by column of zeros
|
|
|
|
|
containing at most one 1.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
This structure can be modelled and exploited with some costs at
|
|
|
|
|
programming. For example, let us consider the following product:
|
2019-04-05 18:39:47 +02:00
|
|
|
|
|
|
|
|
|
[B_y²u³]_α₁α₂β₁β₂β₃ = … + [f_z³]_γ₁γ₂γ₃ [z_yu]^γ₁_α₁β₁ [z_y]^γ₂_α₂ [zᵤᵤ]^γ₃_β₂β₃ + …
|
|
|
|
|
|
|
|
|
|
The term corresponds to equivalence { {0,2}, {1}, {3,4} }. For the fixed
|
|
|
|
|
index α₁α₂β₁β₂β₃ we have to make a Kronecker product of the columns
|
|
|
|
|
|
|
|
|
|
[z_yu]_α₁β₁ ⊗ [z_y]_α₂ ⊗ [zᵤᵤ]_β₂β₃
|
|
|
|
|
|
|
|
|
|
which can be written as:
|
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
⎛[v_yu]_α₁β₁⎞ ⎛[v_y]_α₂⎞ ⎛[vᵤᵤ]_β₂β₃⎞
|
|
|
|
|
⎢[w_yu]_α₁β₁⎥ ⎢[w_y]_α₂⎥ ⎢[wᵤᵤ]_β₂β₃⎥
|
2019-04-05 18:39:47 +02:00
|
|
|
|
⎢ 0 ⎥⊗⎢ 1_α₂ ⎥⊗⎢ 0 ⎥
|
|
|
|
|
⎝ 0 ⎠ ⎝ 0 ⎠ ⎝ 0 ⎠
|
|
|
|
|
where 1_α₂ is a column of zeros having the only 1 at α₂ index.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
This file develops the abstraction for this Kronecker product column
|
|
|
|
|
without multiplication of the zeros at the top. Basically, it will be
|
|
|
|
|
a column which is a Kronecker product of the columns without the
|
|
|
|
|
zeros:
|
2019-04-05 18:39:47 +02:00
|
|
|
|
|
|
|
|
|
⎛[v_y]_α₂⎞
|
|
|
|
|
⎛[v_yu]_α₁β₁⎞⊗ ⎢[w_y]_α₂⎥⊗⎛[vᵤᵤ]_β₂β₃⎞
|
|
|
|
|
⎝[w_yu]_α₁β₁⎠ ⎝ 1 ⎠ ⎝[wᵤᵤ]_β₂β₃⎠
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-04-05 18:39:47 +02:00
|
|
|
|
The class will have a tensor infrastructure introducing ‘index’ which
|
|
|
|
|
iterates over all items in the column with γ₁γ₂γ₃
|
|
|
|
|
as coordinates in [f_z³]. The data of such a tensor is
|
2019-01-08 16:09:25 +01:00
|
|
|
|
not suitable for any matrix operation and will have to be accessed
|
2019-04-05 18:39:47 +02:00
|
|
|
|
only through the ‘index’. Note that this does not matter, since
|
|
|
|
|
[f_zˡ] are sparse. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
#ifndef PYRAMID_PROD2_H
|
|
|
|
|
#define PYRAMID_PROD2_H
|
|
|
|
|
|
|
|
|
|
#include "permutation.hh"
|
|
|
|
|
#include "rfs_tensor.hh"
|
|
|
|
|
#include "stack_container.hh"
|
2023-11-29 19:00:21 +01:00
|
|
|
|
#include "tensor.hh"
|
|
|
|
|
#include "tl_exception.hh"
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
|
#include "Vector.hh"
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-02-26 18:57:36 +01:00
|
|
|
|
#include <vector>
|
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
/* First we declare a helper class for the tensor. Its purpose is to
|
|
|
|
|
gather the columns which are going to be Kronecker multiplied. The
|
2019-04-05 18:39:47 +02:00
|
|
|
|
input of this helper class is StackProduct<FGSTensor> and coordinate
|
|
|
|
|
‘c’ of the column.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-04-05 18:39:47 +02:00
|
|
|
|
It maintains ‘unit_flag’ array which says for what columns we must
|
|
|
|
|
stack 1 below v and w. In this case, the value of ‘unit_flag’ is
|
|
|
|
|
an index of the 1, otherwise the value of ‘unit_flag’ is -1.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-04-05 18:39:47 +02:00
|
|
|
|
Also we have storage for the stacked columns ‘cols’. The object is
|
2019-01-08 16:09:25 +01:00
|
|
|
|
responsible for memory management associated to this storage. That is
|
|
|
|
|
why we do not allow any copy constructor, since we need to be sure
|
|
|
|
|
that no accidental copies take place. We declare the copy constructor
|
|
|
|
|
as private and not implement it. */
|
|
|
|
|
|
|
|
|
|
class IrregTensor;
|
|
|
|
|
class IrregTensorHeader
|
|
|
|
|
{
|
|
|
|
|
friend class IrregTensor;
|
|
|
|
|
int nv;
|
|
|
|
|
IntSequence unit_flag;
|
2019-02-26 18:57:36 +01:00
|
|
|
|
std::vector<std::unique_ptr<Vector>> cols;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
IntSequence end_seq;
|
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
|
|
|
|
IrregTensorHeader(const StackProduct<FGSTensor>& sp, const IntSequence& c);
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2019-01-08 16:09:25 +01:00
|
|
|
|
dimen() const
|
|
|
|
|
{
|
|
|
|
|
return unit_flag.size();
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void increment(IntSequence& v) const;
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int calcMaxOffset() const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
};
|
|
|
|
|
|
2019-04-05 18:39:47 +02:00
|
|
|
|
/* Here we declare the irregular tensor. There is no special logic here. We
|
|
|
|
|
inherit from Tensor and we must implement three methods, increment(),
|
|
|
|
|
decrement() and getOffset(). The last two are not implemented now, since
|
|
|
|
|
they are not needed, and they raise an exception. The first just calls
|
|
|
|
|
increment() of the header. Also we declare a method addTo() which adds this
|
|
|
|
|
unfolded irregular single column tensor to folded (regular) single column
|
|
|
|
|
tensor.
|
|
|
|
|
|
|
|
|
|
The header IrregTensorHeader lives with an object by a reference. This is
|
|
|
|
|
dangerous. However, we will use this class only in a simple loop and both
|
|
|
|
|
IrregTensor and IrregTensorHeader will be destructed at the end of a block.
|
|
|
|
|
Since the super class Tensor must be initialized before any member, we could
|
|
|
|
|
do either a save copy of IrregTensorHeader, or relatively dangerous the
|
|
|
|
|
reference member. For the reason above we chose the latter. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
class IrregTensor : public Tensor
|
|
|
|
|
{
|
2023-11-29 19:00:21 +01:00
|
|
|
|
const IrregTensorHeader& header;
|
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2023-11-29 19:00:21 +01:00
|
|
|
|
IrregTensor(const IrregTensorHeader& h);
|
|
|
|
|
void addTo(FRSingleTensor& out) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
increment(IntSequence& v) const override
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
header.increment(v);
|
|
|
|
|
}
|
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
decrement([[maybe_unused]] IntSequence& v) const override
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
TL_RAISE("Not implemented error in IrregTensor::decrement");
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2023-11-29 19:00:21 +01:00
|
|
|
|
getOffset([[maybe_unused]] const IntSequence& v) const override
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
2019-02-20 18:07:07 +01:00
|
|
|
|
TL_RAISE("Not implemented error in IrregTensor::getOffset");
|
2019-01-08 16:09:25 +01:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|