2019-06-19 14:34:30 +02:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2004 Ondra Kamenik
|
|
|
|
|
* Copyright © 2019 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
#include "rfs_tensor.hh"
|
|
|
|
|
#include "kron_prod.hh"
|
|
|
|
|
#include "tl_exception.hh"
|
|
|
|
|
|
2019-04-16 15:04:19 +02:00
|
|
|
|
/* The conversion from unfolded to folded sums up all data from unfolded
|
|
|
|
|
corresponding to one folded index. So we go through all the rows in the
|
|
|
|
|
unfolded tensor ‘ut’, make an index of the folded tensor by sorting the
|
|
|
|
|
coordinates, and add the row. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
FRTensor::FRTensor(const URTensor &ut)
|
2019-02-12 17:30:10 +01:00
|
|
|
|
: FTensor(indor::along_row, IntSequence(ut.dimen(), ut.nvar()),
|
2019-01-08 16:09:25 +01:00
|
|
|
|
FFSTensor::calcMaxOffset(ut.nvar(), ut.dimen()), ut.ncols(),
|
|
|
|
|
ut.dimen()),
|
|
|
|
|
nv(ut.nvar())
|
|
|
|
|
{
|
|
|
|
|
zeros();
|
|
|
|
|
for (index in = ut.begin(); in != ut.end(); ++in)
|
|
|
|
|
{
|
|
|
|
|
IntSequence vtmp(in.getCoor());
|
|
|
|
|
vtmp.sort();
|
2019-02-12 17:30:10 +01:00
|
|
|
|
index tar(*this, vtmp);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
addRow(ut, *in, *tar);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 14:25:32 +01:00
|
|
|
|
std::unique_ptr<UTensor>
|
2019-01-08 16:09:25 +01:00
|
|
|
|
FRTensor::unfold() const
|
|
|
|
|
{
|
2019-02-20 14:25:32 +01:00
|
|
|
|
return std::make_unique<URTensor>(*this);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 15:04:19 +02:00
|
|
|
|
/* Incrementing is easy. The same as for FFSTensor. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FRTensor::increment(IntSequence &v) const
|
|
|
|
|
{
|
|
|
|
|
TL_RAISE_IF(v.size() != dimen(),
|
|
|
|
|
"Wrong input/output vector size in FRTensor::increment");
|
|
|
|
|
|
|
|
|
|
UTensor::increment(v, nv);
|
|
|
|
|
v.monotone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FRTensor::decrement(IntSequence &v) const
|
|
|
|
|
{
|
|
|
|
|
TL_RAISE_IF(v.size() != dimen(),
|
|
|
|
|
"Wrong input/output vector size in FRTensor::decrement");
|
|
|
|
|
|
|
|
|
|
FTensor::decrement(v, nv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Here we convert folded full symmetry tensor to unfolded. We copy all
|
|
|
|
|
columns of folded tensor to unfolded and leave other columns
|
|
|
|
|
(duplicates) zero. In this way, if the unfolded tensor is folded back,
|
|
|
|
|
we should get the same data. */
|
|
|
|
|
URTensor::URTensor(const FRTensor &ft)
|
2019-02-12 17:30:10 +01:00
|
|
|
|
: UTensor(indor::along_row, IntSequence(ft.dimen(), ft.nvar()),
|
2019-01-08 16:09:25 +01:00
|
|
|
|
UFSTensor::calcMaxOffset(ft.nvar(), ft.dimen()), ft.ncols(),
|
|
|
|
|
ft.dimen()),
|
|
|
|
|
nv(ft.nvar())
|
|
|
|
|
{
|
|
|
|
|
zeros();
|
|
|
|
|
for (index src = ft.begin(); src != ft.end(); ++src)
|
|
|
|
|
{
|
2019-02-12 17:30:10 +01:00
|
|
|
|
index in(*this, src.getCoor());
|
2019-01-08 16:09:25 +01:00
|
|
|
|
copyRow(ft, *src, *in);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 14:25:32 +01:00
|
|
|
|
std::unique_ptr<FTensor>
|
2019-01-08 16:09:25 +01:00
|
|
|
|
URTensor::fold() const
|
|
|
|
|
{
|
2019-02-20 14:25:32 +01:00
|
|
|
|
return std::make_unique<FRTensor>(*this);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
URTensor::increment(IntSequence &v) const
|
|
|
|
|
{
|
|
|
|
|
TL_RAISE_IF(v.size() != dimen(),
|
|
|
|
|
"Wrong input/output vector size in URTensor::increment");
|
|
|
|
|
|
|
|
|
|
UTensor::increment(v, nv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
URTensor::decrement(IntSequence &v) const
|
|
|
|
|
{
|
|
|
|
|
TL_RAISE_IF(v.size() != dimen(),
|
|
|
|
|
"Wrong input/output vector size in URTensor::decrement");
|
|
|
|
|
|
|
|
|
|
UTensor::decrement(v, nv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
URTensor::getOffset(const IntSequence &v) const
|
|
|
|
|
{
|
|
|
|
|
TL_RAISE_IF(v.size() != dimen(),
|
|
|
|
|
"Wrong input vector size in URTensor::getOffset");
|
|
|
|
|
|
|
|
|
|
return UTensor::getOffset(v, nv);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 15:04:19 +02:00
|
|
|
|
/* Here we construct v₁⊗v₂⊗…⊗vₙ, where v₁,v₂,…,vₙ are stored in a
|
|
|
|
|
std::vector<ConstVector>. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-02-06 15:50:01 +01:00
|
|
|
|
URSingleTensor::URSingleTensor(const std::vector<ConstVector> &cols)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
: URTensor(1, cols[0].length(), cols.size())
|
|
|
|
|
{
|
|
|
|
|
if (dimen() == 1)
|
|
|
|
|
{
|
|
|
|
|
getData() = cols[0];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-26 18:57:36 +01:00
|
|
|
|
auto last = std::make_unique<Vector>(cols[cols.size()-1]);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
for (int i = cols.size()-2; i > 0; i--)
|
|
|
|
|
{
|
2019-02-26 18:57:36 +01:00
|
|
|
|
auto newlast = std::make_unique<Vector>(power(nvar(), cols.size()-i));
|
2019-01-08 16:09:25 +01:00
|
|
|
|
KronProd::kronMult(cols[i], ConstVector(*last), *newlast);
|
2019-02-26 18:57:36 +01:00
|
|
|
|
last = std::move(newlast);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
}
|
|
|
|
|
KronProd::kronMult(cols[0], ConstVector(*last), getData());
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 15:04:19 +02:00
|
|
|
|
/* Here we construct v⊗…⊗v, where ‘d’ gives the number of copies of v. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
URSingleTensor::URSingleTensor(const ConstVector &v, int d)
|
|
|
|
|
: URTensor(1, v.length(), d)
|
|
|
|
|
{
|
|
|
|
|
if (d == 1)
|
|
|
|
|
{
|
|
|
|
|
getData() = v;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-26 18:57:36 +01:00
|
|
|
|
auto last = std::make_unique<Vector>(v);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
for (int i = d-2; i > 0; i--)
|
|
|
|
|
{
|
2019-02-26 18:57:36 +01:00
|
|
|
|
auto newlast = std::make_unique<Vector>(last->length()*v.length());
|
2019-01-08 16:09:25 +01:00
|
|
|
|
KronProd::kronMult(v, ConstVector(*last), *newlast);
|
2019-02-26 18:57:36 +01:00
|
|
|
|
last = std::move(newlast);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
}
|
|
|
|
|
KronProd::kronMult(v, ConstVector(*last), getData());
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 14:25:32 +01:00
|
|
|
|
std::unique_ptr<FTensor>
|
2019-01-08 16:09:25 +01:00
|
|
|
|
URSingleTensor::fold() const
|
|
|
|
|
{
|
2019-02-20 14:25:32 +01:00
|
|
|
|
return std::make_unique<FRSingleTensor>(*this);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 15:04:19 +02:00
|
|
|
|
/* The conversion from unfolded URSingleTensor to folded FRSingleTensor is
|
|
|
|
|
exactly the same as the conversion from URTensor to FRTensor, except that we
|
|
|
|
|
do not copy rows but elements. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
FRSingleTensor::FRSingleTensor(const URSingleTensor &ut)
|
|
|
|
|
: FRTensor(1, ut.nvar(), ut.dimen())
|
|
|
|
|
{
|
|
|
|
|
zeros();
|
|
|
|
|
for (index in = ut.begin(); in != ut.end(); ++in)
|
|
|
|
|
{
|
|
|
|
|
IntSequence vtmp(in.getCoor());
|
|
|
|
|
vtmp.sort();
|
2019-02-12 17:30:10 +01:00
|
|
|
|
index tar(*this, vtmp);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
get(*tar, 0) += ut.get(*in, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|