2019-06-19 14:34:30 +02:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2004 Ondra Kamenik
|
2024-01-09 13:04:33 +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
|
|
|
|
|
|
|
|
|
// Even more general symmetry tensor.
|
|
|
|
|
|
2019-04-01 18:41:31 +02:00
|
|
|
|
/* Here we define an abstraction for a tensor, which has a general symmetry,
|
|
|
|
|
but the symmetry is not of what is modelled by Symmetry. This kind of tensor
|
|
|
|
|
comes to existence when we evaluate something like:
|
|
|
|
|
|
|
|
|
|
[B_y²u³]_α₁α₂β₁β₂β₃ = … + [g_y³]_γ₁γ₂γ₃ [g_yu]^γ₁_α₁β₃ [g_yu]^γ₂_α₂β₁
|
|
|
|
|
[g_u]^γ₃_β₂ + …
|
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
If the tensors are unfolded, we obtain a tensor
|
2019-04-01 18:41:31 +02:00
|
|
|
|
|
|
|
|
|
g_y³·(g_yu ⊗ g_yu ⊗ g_u)
|
|
|
|
|
|
|
|
|
|
Obviously, this tensor can have a symmetry not compatible with ordering
|
|
|
|
|
α₁α₂β₁β₂β₃, (in other words, not compatible with symmetry y²u³). In fact,
|
|
|
|
|
the indices are permuted.
|
|
|
|
|
|
|
|
|
|
This kind of tensor must be added to [B_y²u³]. Its dimensions are the same
|
|
|
|
|
as of [B_y²u³], but some coordinates are permuted. The addition is the only
|
|
|
|
|
action we need to do with the tensor.
|
|
|
|
|
|
|
|
|
|
Another application where this permuted symmetry tensor appears is a slice
|
|
|
|
|
of a fully symmetric tensor. If the symmetric dimension of the tensor is
|
|
|
|
|
partitioned to continuous parts, and we are interested only in data with a
|
|
|
|
|
given symmetry (permuted) of the partitions, then we have the permuted
|
|
|
|
|
symmetry tensor. For instance, if x is partitioned x=(a,b,c,d), and having
|
|
|
|
|
tensor [f_x³], one can define a slice (subtensor) [f_aca]. The data of this
|
|
|
|
|
tensor are permuted of [f_a²c].
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
Here we also define the folded version of permuted symmetry tensor. It
|
|
|
|
|
has permuted symmetry and is partially folded. One can imagine it as a
|
|
|
|
|
product of a few dimensions, each of them is folded and having a few
|
|
|
|
|
variables. The underlying variables are permuted. The product of such
|
2019-04-01 18:41:31 +02:00
|
|
|
|
dimensions is described by PerTensorDimens2. The tensor holding the
|
|
|
|
|
underlying data is FPSTensor. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2023-12-13 16:50:28 +01:00
|
|
|
|
#ifndef PS_TENSOR_HH
|
|
|
|
|
#define PS_TENSOR_HH
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
#include "equivalence.hh"
|
2023-11-29 19:00:21 +01:00
|
|
|
|
#include "gs_tensor.hh"
|
2019-01-08 16:09:25 +01:00
|
|
|
|
#include "kron_prod.hh"
|
2023-11-29 19:00:21 +01:00
|
|
|
|
#include "permutation.hh"
|
2019-01-08 16:09:25 +01:00
|
|
|
|
#include "sparse_tensor.hh"
|
2023-11-29 19:00:21 +01:00
|
|
|
|
#include "tensor.hh"
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-04-01 18:41:31 +02:00
|
|
|
|
/* Here we declare a class describing dimensions of permuted symmetry tensor.
|
|
|
|
|
It inherits from TensorDimens and adds a permutation which permutes ‘nvmax’.
|
|
|
|
|
It has two constructors, each corresponds to a context where the tensor
|
|
|
|
|
appears.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
The first constructor calculates the permutation from a given equivalence.
|
|
|
|
|
|
2019-04-01 18:41:31 +02:00
|
|
|
|
The second constructor corresponds to dimensions of a slice. Let us take
|
|
|
|
|
[f_aca] as an example. First it calculates TensorDimens of [f_a²c], then it
|
|
|
|
|
calculates a permutation corresponding to ordering of “aca” to “a²c”, and
|
|
|
|
|
applies this permutation on the dimensions as the first constructor. The
|
|
|
|
|
constructor takes only stack sizes (lengths of a, b, c, and d), and
|
|
|
|
|
coordinates of picked partitions.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-04-01 18:41:31 +02:00
|
|
|
|
Note that inherited methods calcUnfoldColumns() and calcFoldColumns() work,
|
|
|
|
|
since number of columns is independent on the permutation, and
|
|
|
|
|
calcFoldColumns() does not use changed ‘nvmax’, it uses ‘nvs’, so it is
|
|
|
|
|
OK. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
class PerTensorDimens : public TensorDimens
|
|
|
|
|
{
|
2019-02-27 19:07:01 +01:00
|
|
|
|
private:
|
2019-12-20 14:36:20 +01:00
|
|
|
|
static IntSequence
|
|
|
|
|
sortIntSequence(IntSequence s)
|
2019-02-27 19:07:01 +01:00
|
|
|
|
{
|
|
|
|
|
s.sort();
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
protected:
|
|
|
|
|
Permutation per;
|
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
|
|
|
|
PerTensorDimens(Symmetry s, IntSequence nvars, const Equivalence& e) :
|
|
|
|
|
TensorDimens(std::move(s), std::move(nvars)), per(e)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
per.apply(nvmax);
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
PerTensorDimens(TensorDimens td, const Equivalence& e) : TensorDimens(std::move(td)), per(e)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
per.apply(nvmax);
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
PerTensorDimens(TensorDimens td, Permutation p) : TensorDimens(std::move(td)), per(std::move(p))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
per.apply(nvmax);
|
|
|
|
|
}
|
2023-12-12 18:20:11 +01:00
|
|
|
|
PerTensorDimens(const IntSequence& ss, const IntSequence& coor) :
|
|
|
|
|
TensorDimens(ss, sortIntSequence(coor)), per(coor)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
per.apply(nvmax);
|
|
|
|
|
}
|
2024-01-09 13:04:33 +01:00
|
|
|
|
[[nodiscard]] bool
|
2023-11-29 19:00:21 +01:00
|
|
|
|
operator==(const PerTensorDimens& td) const
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
return TensorDimens::operator==(td) && per == td.per;
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2019-01-08 16:09:25 +01:00
|
|
|
|
tailIdentity() const
|
|
|
|
|
{
|
|
|
|
|
return per.tailIdentity();
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] const Permutation&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getPer() const
|
|
|
|
|
{
|
|
|
|
|
return per;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Here we declare the permuted symmetry unfolded tensor. It has
|
2019-04-01 18:41:31 +02:00
|
|
|
|
PerTensorDimens as a member. It inherits from UTensor which requires to
|
|
|
|
|
implement fold() method. There is no folded counterpart, so in our
|
|
|
|
|
implementation we raise unconditional exception, and return some dummy
|
|
|
|
|
object (just to make it compilable without warnings).
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
The class has two sorts of constructors corresponding to a context where it
|
2019-04-01 18:41:31 +02:00
|
|
|
|
appears. The first constructs object from a given matrix, and Kronecker
|
|
|
|
|
product. Within the constructor, all the calculations are performed. Also we
|
|
|
|
|
need to define dimensions, these are the same of the resulting matrix (in
|
|
|
|
|
our example [B_y²u³]) but permuted. The permutation is done in
|
|
|
|
|
PerTensorDimens constructor.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
The second type of constructor is slicing. It makes a slice from
|
2019-04-01 18:41:31 +02:00
|
|
|
|
FSSparseTensor. The slice is given by stack sizes, and coordinates of
|
2019-01-08 16:09:25 +01:00
|
|
|
|
picked stacks.
|
|
|
|
|
|
|
|
|
|
There are two algorithms for filling a slice of a sparse tensor. The
|
2019-04-01 18:41:31 +02:00
|
|
|
|
first fillFromSparseOne() works well for more dense tensors, the
|
|
|
|
|
second fillFromSparseTwo() is better for very sparse tensors. We
|
2019-01-08 16:09:25 +01:00
|
|
|
|
provide a static method, which decides what of the two algorithms is
|
|
|
|
|
better. */
|
|
|
|
|
|
|
|
|
|
class UPSTensor : public UTensor
|
|
|
|
|
{
|
|
|
|
|
const PerTensorDimens tdims;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2019-04-01 18:41:31 +02:00
|
|
|
|
// UPSTensor constructors from Kronecker product
|
|
|
|
|
/* Here we have four constructors making an UPSTensor from a product
|
|
|
|
|
of matrix and Kronecker product. */
|
|
|
|
|
|
|
|
|
|
/* Constructs the tensor from equivalence classes of the given equivalence in
|
|
|
|
|
an order given by the equivalence */
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UPSTensor(TensorDimens td, const Equivalence& e, const ConstTwoDMatrix& a,
|
|
|
|
|
const KronProdAll& kp) :
|
|
|
|
|
UTensor(indor::along_col, PerTensorDimens(td, e).getNVX(), a.nrows(), kp.ncols(), td.dimen()),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
tdims(std::move(td), e)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
2019-04-01 18:41:31 +02:00
|
|
|
|
|
|
|
|
|
/* Same as the previous one but with optimized KronProdAllOptim, which has a
|
|
|
|
|
different order of matrices than given by the classes in the equivalence.
|
|
|
|
|
This permutation is projected to the permutation of the UPSTensor. */
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UPSTensor(TensorDimens td, const Equivalence& e, const ConstTwoDMatrix& a,
|
|
|
|
|
const KronProdAllOptim& kp) :
|
|
|
|
|
UTensor(indor::along_col, PerTensorDimens(td, Permutation(e, kp.getPer())).getNVX(),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
a.nrows(), kp.ncols(), td.dimen()),
|
|
|
|
|
tdims(std::move(td), Permutation(e, kp.getPer()))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
2019-04-01 18:41:31 +02:00
|
|
|
|
|
|
|
|
|
/* Same as the first constructor, but the classes of the equivalence are
|
|
|
|
|
permuted by the given permutation. */
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UPSTensor(TensorDimens td, const Equivalence& e, const Permutation& p, const ConstTwoDMatrix& a,
|
|
|
|
|
const KronProdAll& kp) :
|
|
|
|
|
UTensor(indor::along_col, PerTensorDimens(td, Permutation(e, p)).getNVX(), a.nrows(),
|
|
|
|
|
kp.ncols(), td.dimen()),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
tdims(std::move(td), Permutation(e, p))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
2019-04-01 18:41:31 +02:00
|
|
|
|
|
|
|
|
|
/* Most general constructor. It allows for a permutation of equivalence
|
|
|
|
|
classes, and for optimized KronProdAllOptim, which permutes the permuted
|
|
|
|
|
equivalence classes. */
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UPSTensor(TensorDimens td, const Equivalence& e, const Permutation& p, const ConstTwoDMatrix& a,
|
|
|
|
|
const KronProdAllOptim& kp) :
|
|
|
|
|
UTensor(indor::along_col,
|
|
|
|
|
PerTensorDimens(td, Permutation(e, Permutation(p, kp.getPer()))).getNVX(), a.nrows(),
|
|
|
|
|
kp.ncols(), td.dimen()),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
tdims(std::move(td), Permutation(e, Permutation(p, kp.getPer())))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
2019-04-01 18:41:31 +02:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
UPSTensor(const FSSparseTensor& t, const IntSequence& ss, const IntSequence& coor,
|
|
|
|
|
PerTensorDimens ptd);
|
|
|
|
|
UPSTensor(const UPSTensor&) = default;
|
|
|
|
|
UPSTensor(UPSTensor&&) = 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;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int getOffset(const IntSequence& v) const override;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void addTo(FGSTensor& out) const;
|
|
|
|
|
void addTo(UGSTensor& out) const;
|
|
|
|
|
|
|
|
|
|
enum class fill_method
|
|
|
|
|
{
|
|
|
|
|
first,
|
|
|
|
|
second
|
|
|
|
|
};
|
|
|
|
|
static fill_method decideFillMethod(const FSSparseTensor& t);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
private:
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int tailIdentitySize() const;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void fillFromSparseOne(const FSSparseTensor& t, const IntSequence& ss, const IntSequence& coor);
|
|
|
|
|
void fillFromSparseTwo(const FSSparseTensor& t, const IntSequence& ss, const IntSequence& coor);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
};
|
|
|
|
|
|
2019-04-01 18:41:31 +02:00
|
|
|
|
/* Here we define an abstraction for the tensor dimension with the symmetry
|
|
|
|
|
like xuv|uv|xu|y|y|x|x|y. These symmetries come as induces symmetries of
|
|
|
|
|
equivalence and some outer symmetry. Thus the underlying variables are
|
|
|
|
|
permuted. One can imagine the dimensions as an unfolded product of
|
|
|
|
|
dimensions which consist of folded products of variables.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-04-01 18:41:31 +02:00
|
|
|
|
We inherit from PerTensorDimens since we need the permutation implied by the
|
|
|
|
|
equivalence. The new member are the induced symmetries (symmetries of each
|
|
|
|
|
folded dimensions) and ‘ds’ which are sizes of the dimensions. The number of
|
|
|
|
|
folded dimensions is return by ‘numSyms’.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
The object is constructed from outer tensor dimensions and from
|
|
|
|
|
equivalence with optionally permuted classes. */
|
|
|
|
|
|
|
|
|
|
class PerTensorDimens2 : public PerTensorDimens
|
|
|
|
|
{
|
|
|
|
|
InducedSymmetries syms;
|
|
|
|
|
IntSequence ds;
|
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
|
|
|
|
PerTensorDimens2(const TensorDimens& td, const Equivalence& e, const Permutation& p) :
|
|
|
|
|
PerTensorDimens(td, Permutation(e, p)), syms(e, p, td.getSym()), ds(syms.size())
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
setDimensionSizes();
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
PerTensorDimens2(const TensorDimens& td, const Equivalence& e) :
|
|
|
|
|
PerTensorDimens(td, e), syms(e, td.getSym()), ds(syms.size())
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
setDimensionSizes();
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2019-01-08 16:09:25 +01:00
|
|
|
|
numSyms() const
|
|
|
|
|
{
|
2019-04-23 12:58:38 +02:00
|
|
|
|
return static_cast<int>(syms.size());
|
2019-01-08 16:09:25 +01:00
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] const Symmetry&
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getSym(int i) const
|
|
|
|
|
{
|
|
|
|
|
return syms[i];
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int
|
2019-01-08 16:09:25 +01:00
|
|
|
|
calcMaxOffset() const
|
|
|
|
|
{
|
|
|
|
|
return ds.mult();
|
|
|
|
|
}
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int calcOffset(const IntSequence& coor) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
void print() const;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
protected:
|
|
|
|
|
void setDimensionSizes();
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-01 18:41:31 +02:00
|
|
|
|
/* Here we define an abstraction of the permuted symmetry folded tensor. It is
|
|
|
|
|
needed in context of the Faà Di Bruno formula for folded stack container
|
|
|
|
|
multiplied with container of dense folded tensors, or multiplied by one full
|
|
|
|
|
symmetry sparse tensor.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
For example, if we perform the Faà Di Bruno for $F=f(z)$, where
|
2019-04-01 18:41:31 +02:00
|
|
|
|
⎛g(x,y,u,v)⎞
|
|
|
|
|
⎢ h(x,y,u) ⎥
|
|
|
|
|
z=⎢ x ⎥
|
|
|
|
|
⎝ y ⎠
|
|
|
|
|
we get for one concrete equivalence:
|
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
[F_x⁴y³u³v²] = … + [f_g²h²x²y]·([g]_xv ⊗ [g]_u²v ⊗ [h]_xu ⊗ [h]_y² ⊗
|
2019-04-01 18:41:31 +02:00
|
|
|
|
[I]_x ⊗ [I]_x ⊗ [I]_y)
|
|
|
|
|
+ …
|
|
|
|
|
|
|
|
|
|
The class FPSTensor represents the tensor on the right. Its dimension
|
|
|
|
|
corresponds to a product of 7 dimensions with the following symmetries:
|
|
|
|
|
xv|u²v|xu|y²|x|x|y. Such a dimension is described by PerTensorDimens2.
|
|
|
|
|
|
|
|
|
|
The tensor is constructed in a context of stack container multiplication,
|
|
|
|
|
so, it is constructed from dimensions ‘td’ (dimensions of the output
|
|
|
|
|
tensor), stack product ‘sp’ (implied symmetries picking tensors from a stack
|
|
|
|
|
container, here it is z), then a sorted integer sequence of the picked
|
|
|
|
|
stacks of the stack product (it is always sorted, here it is
|
|
|
|
|
(0,0,1,1,2,2,3)), then the tensor [f_g²h²x²y] (its symmetry must be the same
|
|
|
|
|
as symmetry given by the ‘istacks’), and finally from the equivalence with
|
|
|
|
|
permuted classes.
|
|
|
|
|
|
|
|
|
|
We implement increment() and getOffset() methods, decrement() and unfold()
|
|
|
|
|
raise an exception. Also, we implement addTo() method, which adds the tensor
|
|
|
|
|
data (partially unfolded) to folded general symmetry tensor. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
template<typename _Ttype>
|
|
|
|
|
class StackProduct;
|
|
|
|
|
|
|
|
|
|
class FPSTensor : public FTensor
|
|
|
|
|
{
|
|
|
|
|
const PerTensorDimens2 tdims;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2019-04-01 18:41:31 +02:00
|
|
|
|
/* As for UPSTensor, we provide four constructors allowing for
|
2019-01-08 16:09:25 +01:00
|
|
|
|
combinations of permuting equivalence classes, and optimization of
|
2019-04-01 18:41:31 +02:00
|
|
|
|
KronProdAllOptim. These constructors multiply with dense general
|
2019-01-08 16:09:25 +01:00
|
|
|
|
symmetry tensor (coming from the dense container, or as a dense slice
|
|
|
|
|
of the full symmetry sparse tensor). In addition to these 4
|
|
|
|
|
constructors, we have one constructor multiplying with general
|
|
|
|
|
symmetry sparse tensor (coming as a sparse slice of the full symmetry
|
|
|
|
|
sparse tensor). */
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FPSTensor(const TensorDimens& td, const Equivalence& e, const ConstTwoDMatrix& a,
|
|
|
|
|
const KronProdAll& kp) :
|
|
|
|
|
FTensor(indor::along_col, PerTensorDimens(td, e).getNVX(), a.nrows(), kp.ncols(), td.dimen()),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
tdims(td, e)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FPSTensor(const TensorDimens& td, const Equivalence& e, const ConstTwoDMatrix& a,
|
|
|
|
|
const KronProdAllOptim& kp) :
|
|
|
|
|
FTensor(indor::along_col, PerTensorDimens(td, Permutation(e, kp.getPer())).getNVX(),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
a.nrows(), kp.ncols(), td.dimen()),
|
|
|
|
|
tdims(td, e, kp.getPer())
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FPSTensor(const TensorDimens& td, const Equivalence& e, const Permutation& p,
|
|
|
|
|
const ConstTwoDMatrix& a, const KronProdAll& kp) :
|
|
|
|
|
FTensor(indor::along_col, PerTensorDimens(td, Permutation(e, p)).getNVX(), a.nrows(),
|
|
|
|
|
kp.ncols(), td.dimen()),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
tdims(td, e, p)
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FPSTensor(const TensorDimens& td, const Equivalence& e, const Permutation& p,
|
|
|
|
|
const ConstTwoDMatrix& a, const KronProdAllOptim& kp) :
|
|
|
|
|
FTensor(indor::along_col,
|
|
|
|
|
PerTensorDimens(td, Permutation(e, Permutation(p, kp.getPer()))).getNVX(), a.nrows(),
|
|
|
|
|
kp.ncols(), td.dimen()),
|
2019-02-27 19:07:01 +01:00
|
|
|
|
tdims(td, e, Permutation(p, kp.getPer()))
|
2019-01-08 16:09:25 +01:00
|
|
|
|
{
|
|
|
|
|
kp.mult(a, *this);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FPSTensor(const TensorDimens& td, const Equivalence& e, const Permutation& p,
|
|
|
|
|
const GSSparseTensor& t, const KronProdAll& kp);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
FPSTensor(const FPSTensor&) = default;
|
|
|
|
|
FPSTensor(FPSTensor&&) = 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<UTensor> unfold() const override;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2023-12-05 15:44:23 +01:00
|
|
|
|
[[nodiscard]] int getOffset(const IntSequence& v) const override;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
void addTo(FGSTensor& out) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|