2019-01-08 16:09:25 +01:00
|
|
|
// Copyright 2004, Ondra Kamenik
|
|
|
|
|
|
|
|
#include "t_container.hh"
|
|
|
|
#include "kron_prod.hh"
|
|
|
|
#include "ps_tensor.hh"
|
|
|
|
#include "pyramid_prod.hh"
|
|
|
|
|
|
|
|
const int FGSContainer::num_one_time = 10;
|
|
|
|
|
|
|
|
// |UGSContainer| conversion from |FGSContainer|
|
|
|
|
UGSContainer::UGSContainer(const FGSContainer &c)
|
|
|
|
: TensorContainer<UGSTensor>(c.num())
|
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & it : c)
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
2019-01-09 15:51:19 +01:00
|
|
|
auto *unfolded = new UGSTensor(*(it.second));
|
2019-01-08 16:09:25 +01:00
|
|
|
insert(unfolded);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We set |l| to dimension of |t|, this is a tensor which multiplies
|
|
|
|
tensors from the container from the left. Also we set |k| to a
|
|
|
|
dimension of the resulting tensor. We go through all equivalences on
|
|
|
|
|k| element set and pickup only those which have $l$ classes.
|
|
|
|
|
|
|
|
In each loop, we fetch all necessary tensors for the product to the
|
|
|
|
vector |ts|. Then we form Kronecker product |KronProdAll| and feed it
|
|
|
|
with tensors from |ts|. Then we form unfolded permuted symmetry tensor
|
|
|
|
|UPSTensor| as matrix product of |t| and Kronecker product |kp|. Then
|
|
|
|
we add the permuted data to |out|. This is done by |UPSTensor| method
|
|
|
|
|addTo|. */
|
|
|
|
|
|
|
|
void
|
|
|
|
UGSContainer::multAndAdd(const UGSTensor &t, UGSTensor &out) const
|
|
|
|
{
|
|
|
|
int l = t.dimen();
|
|
|
|
int k = out.dimen();
|
|
|
|
const EquivalenceSet &eset = ebundle.get(k);
|
|
|
|
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & it : eset)
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
if (it.numClasses() == l)
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
|
|
|
vector<const UGSTensor *> ts
|
2019-01-09 15:44:26 +01:00
|
|
|
= fetchTensors(out.getSym(), it);
|
2019-01-08 16:09:25 +01:00
|
|
|
KronProdAllOptim kp(l);
|
|
|
|
for (int i = 0; i < l; i++)
|
|
|
|
kp.setMat(i, *(ts[i]));
|
|
|
|
kp.optimizeOrder();
|
2019-01-09 15:44:26 +01:00
|
|
|
UPSTensor ups(out.getDims(), it, t, kp);
|
2019-01-08 16:09:25 +01:00
|
|
|
ups.addTo(out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// |FGSContainer| conversion from |UGSContainer|
|
|
|
|
FGSContainer::FGSContainer(const UGSContainer &c)
|
|
|
|
: TensorContainer<FGSTensor>(c.num())
|
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & it : c)
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
2019-01-09 15:51:19 +01:00
|
|
|
auto *folded = new FGSTensor(*(it.second));
|
2019-01-08 16:09:25 +01:00
|
|
|
insert(folded);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// |FGSContainer::multAndAdd| folded code
|
|
|
|
/* Here we perform one step of the Faa Di Bruno operation. We call the
|
|
|
|
|multAndAdd| for unfolded tensor. */
|
|
|
|
void
|
|
|
|
FGSContainer::multAndAdd(const FGSTensor &t, FGSTensor &out) const
|
|
|
|
{
|
|
|
|
UGSTensor ut(t);
|
|
|
|
multAndAdd(ut, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
// |FGSContainer::multAndAdd| unfolded code
|
|
|
|
/* This is the same as |@<|UGSContainer::multAndAdd| code@>|
|
|
|
|
but we do not construct |UPSTensor| from the Kronecker
|
|
|
|
product, but |FPSTensor|. */
|
|
|
|
void
|
|
|
|
FGSContainer::multAndAdd(const UGSTensor &t, FGSTensor &out) const
|
|
|
|
{
|
|
|
|
int l = t.dimen();
|
|
|
|
int k = out.dimen();
|
|
|
|
const EquivalenceSet &eset = ebundle.get(k);
|
|
|
|
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & it : eset)
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
if (it.numClasses() == l)
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
|
|
|
vector<const FGSTensor *> ts
|
2019-01-09 15:44:26 +01:00
|
|
|
= fetchTensors(out.getSym(), it);
|
2019-01-08 16:09:25 +01:00
|
|
|
KronProdAllOptim kp(l);
|
|
|
|
for (int i = 0; i < l; i++)
|
|
|
|
kp.setMat(i, *(ts[i]));
|
|
|
|
kp.optimizeOrder();
|
2019-01-09 15:44:26 +01:00
|
|
|
FPSTensor fps(out.getDims(), it, t, kp);
|
2019-01-08 16:09:25 +01:00
|
|
|
fps.addTo(out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This fills a given vector with integer sequences corresponding to
|
|
|
|
first |num| indices from interval |start| (including) to |end|
|
|
|
|
(excluding). If there are not |num| of such indices, the shorter vector
|
|
|
|
is returned. */
|
|
|
|
Tensor::index
|
|
|
|
FGSContainer::getIndices(int num, vector<IntSequence> &out,
|
|
|
|
const Tensor::index &start,
|
|
|
|
const Tensor::index &end)
|
|
|
|
{
|
|
|
|
out.clear();
|
|
|
|
int i = 0;
|
|
|
|
Tensor::index run = start;
|
|
|
|
while (i < num && run != end)
|
|
|
|
{
|
|
|
|
out.push_back(run.getCoor());
|
|
|
|
i++;
|
|
|
|
++run;
|
|
|
|
}
|
|
|
|
return run;
|
|
|
|
}
|