Dynare++: refactor iterator over symmetries
Simplify the logic of iteration. Adapt the range-based for loop syntax.time-shift
parent
e9688560f6
commit
44d47ee560
|
@ -112,12 +112,11 @@ SmolyakQuadrature::SmolyakQuadrature(int d, int l, const OneDQuadrature &uq)
|
|||
// todo: check |l>1|, |l>=d|
|
||||
// todo: check |l>=uquad.miLevel()|, |l<=uquad.maxLevel()|
|
||||
int cum = 0;
|
||||
SymmetrySet ss(l-1, d+1);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
for (auto &si : SymmetrySet(l-1, d+1))
|
||||
{
|
||||
if ((*si)[d] <= d-1)
|
||||
if (si[d] <= d-1)
|
||||
{
|
||||
IntSequence lev((const IntSequence &)*si, 0, d);
|
||||
IntSequence lev((const IntSequence &) si, 0, d);
|
||||
lev.add(1);
|
||||
levels.push_back(lev);
|
||||
IntSequence levpts(d);
|
||||
|
@ -171,12 +170,11 @@ int
|
|||
SmolyakQuadrature::calcNumEvaluations(int lev) const
|
||||
{
|
||||
int cum = 0;
|
||||
SymmetrySet ss(lev-1, dim+1);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
for (auto &si : SymmetrySet(lev-1, dim+1))
|
||||
{
|
||||
if ((*si)[dim] <= dim-1)
|
||||
if (si[dim] <= dim-1)
|
||||
{
|
||||
IntSequence lev((const IntSequence &)*si, 0, dim);
|
||||
IntSequence lev((const IntSequence &) si, 0, dim);
|
||||
lev.add(1);
|
||||
IntSequence levpts(dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
|
|
|
@ -342,29 +342,26 @@ KOrder::switchToFolded()
|
|||
|
||||
int maxdim = g<unfold>().getMaxDim();
|
||||
for (int dim = 1; dim <= maxdim; dim++)
|
||||
for (auto &si : SymmetrySet(dim, 4))
|
||||
{
|
||||
SymmetrySet ss(dim, 4);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
if (si[2] == 0 && g<unfold>().check(si))
|
||||
{
|
||||
if ((*si)[2] == 0 && g<unfold>().check(*si))
|
||||
{
|
||||
auto *ft = new FGSTensor(*(g<unfold>().get(*si)));
|
||||
auto *ft = new FGSTensor(*(g<unfold>().get(si)));
|
||||
insertDerivative<fold>(ft);
|
||||
if (dim > 1)
|
||||
{
|
||||
gss<unfold>().remove(*si);
|
||||
gs<unfold>().remove(*si);
|
||||
g<unfold>().remove(*si);
|
||||
gss<unfold>().remove(si);
|
||||
gs<unfold>().remove(si);
|
||||
g<unfold>().remove(si);
|
||||
}
|
||||
}
|
||||
if (G<unfold>().check(*si))
|
||||
if (G<unfold>().check(si))
|
||||
{
|
||||
auto *ft = new FGSTensor(*(G<unfold>().get(*si)));
|
||||
auto *ft = new FGSTensor(*(G<unfold>().get(si)));
|
||||
G<fold>().insert(ft);
|
||||
if (dim > 1)
|
||||
{
|
||||
G<fold>().remove(*si);
|
||||
}
|
||||
G<fold>().remove(si);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -871,12 +871,11 @@ KOrder::check(int dim) const
|
|||
}
|
||||
|
||||
// check for $F_{y^iu^ju'^k}+D_{ijk}+E_{ijk}=0$
|
||||
SymmetrySet ss(dim, 3);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
for (auto &si : SymmetrySet(dim, 3))
|
||||
{
|
||||
int i = (*si)[0];
|
||||
int j = (*si)[1];
|
||||
int k = (*si)[2];
|
||||
int i = si[0];
|
||||
int j = si[1];
|
||||
int k = si[2];
|
||||
if (i+j > 0 && k > 0)
|
||||
{
|
||||
Symmetry sym{i, j, 0, k};
|
||||
|
|
|
@ -516,18 +516,17 @@ KOrderStoch::performStep(int order)
|
|||
int maxd = g<t>().getMaxDim();
|
||||
KORD_RAISE_IF(order-1 != maxd && (order != 1 || maxd != -1),
|
||||
"Wrong order for KOrderStoch::performStep");
|
||||
SymmetrySet ss(order, 4);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
for (auto &si : SymmetrySet(order, 4))
|
||||
{
|
||||
if ((*si)[2] == 0)
|
||||
if (si[2] == 0)
|
||||
{
|
||||
JournalRecordPair pa(journal);
|
||||
pa << "Recovering symmetry " << *si << endrec;
|
||||
pa << "Recovering symmetry " << si << endrec;
|
||||
|
||||
_Ttensor *G_sym = faaDiBrunoG<t>(*si);
|
||||
_Ttensor *G_sym = faaDiBrunoG<t>(si);
|
||||
G<t>().insert(G_sym);
|
||||
|
||||
_Ttensor *g_sym = faaDiBrunoZ<t>(*si);
|
||||
_Ttensor *g_sym = faaDiBrunoZ<t>(si);
|
||||
g_sym->mult(-1.0);
|
||||
matA.multInv(*g_sym);
|
||||
g<t>().insert(g_sym);
|
||||
|
|
|
@ -42,10 +42,10 @@ FoldedStackContainer::multAndAdd(int dim, const FGSContainer &c, FGSTensor &out)
|
|||
"Wrong symmetry length of container for FoldedStackContainer::multAndAdd");
|
||||
|
||||
sthread::detach_thread_group gr;
|
||||
SymmetrySet ss(dim, c.num());
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
if (c.check(*si))
|
||||
gr.insert(std::make_unique<WorkerFoldMAADense>(*this, *si, c, out));
|
||||
|
||||
for (auto &si : SymmetrySet(dim, c.num()))
|
||||
if (c.check(si))
|
||||
gr.insert(std::make_unique<WorkerFoldMAADense>(*this, si, c, out));
|
||||
|
||||
gr.run();
|
||||
}
|
||||
|
@ -395,10 +395,9 @@ UnfoldedStackContainer::multAndAdd(int dim, const UGSContainer &c,
|
|||
"Wrong symmetry length of container for UnfoldedStackContainer::multAndAdd");
|
||||
|
||||
sthread::detach_thread_group gr;
|
||||
SymmetrySet ss(dim, c.num());
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
if (c.check(*si))
|
||||
gr.insert(std::make_unique<WorkerUnfoldMAADense>(*this, *si, c, out));
|
||||
for (auto &si : SymmetrySet(dim, c.num()))
|
||||
if (c.check(si))
|
||||
gr.insert(std::make_unique<WorkerUnfoldMAADense>(*this, si, c, out));
|
||||
|
||||
gr.run();
|
||||
}
|
||||
|
|
|
@ -51,54 +51,43 @@ Symmetry::isFull() const
|
|||
return count <= 1;
|
||||
}
|
||||
|
||||
/* Here we construct the beginning of the |symiterator|. The first
|
||||
symmetry index is 0. If length is 2, the second index is the
|
||||
dimension, otherwise we create the subordinal symmetry set and its
|
||||
beginning as subordinal |symiterator|. */
|
||||
/* Construct a symiterator of given dimension, starting from the given
|
||||
symmetry. */
|
||||
|
||||
symiterator::symiterator(SymmetrySet &ss)
|
||||
: s(ss), end_flag(false)
|
||||
symiterator::symiterator(int dim_arg, Symmetry run_arg)
|
||||
: dim{dim_arg}, run(std::move(run_arg))
|
||||
{
|
||||
s.sym()[0] = 0;
|
||||
if (s.size() == 2)
|
||||
s.sym()[1] = s.dimen();
|
||||
else
|
||||
{
|
||||
subs = std::make_unique<SymmetrySet>(s, s.dimen());
|
||||
subit = std::make_unique<symiterator>(*subs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Here we move to the next symmetry. We do so only, if we are not at
|
||||
the end. If length is 2, we increase lower index and decrease upper
|
||||
index, otherwise we increase the subordinal symmetry. If we got to the
|
||||
end, we recreate the subordinal symmetry set and set the subordinal
|
||||
iterator to the beginning. At the end we test, if we are not at the
|
||||
end. This is recognized if the lowest index exceeded the dimension. */
|
||||
iterator to the beginning. */
|
||||
|
||||
symiterator &
|
||||
symiterator::operator++()
|
||||
{
|
||||
if (!end_flag)
|
||||
if (run[0] == dim)
|
||||
run[0]++; // Jump to the past-the-end iterator
|
||||
else if (run.size() == 2)
|
||||
{
|
||||
if (s.size() == 2)
|
||||
{
|
||||
s.sym()[0]++;
|
||||
s.sym()[1]--;
|
||||
run[0]++;
|
||||
run[1]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
++(*subit);
|
||||
if (subit->isEnd())
|
||||
symiterator subit{dim-run[0], Symmetry(run, run.size()-1)};
|
||||
++subit;
|
||||
if (run[1] == dim-run[0]+1)
|
||||
{
|
||||
s.sym()[0]++;
|
||||
subs = std::make_unique<SymmetrySet>(s, s.dimen()-s.sym()[0]);
|
||||
subit = std::make_unique<symiterator>(*subs);
|
||||
run[0]++;
|
||||
run[1] = 0;
|
||||
/* subit is equal to the past-the-end iterator, so the range
|
||||
2..(size()-1) is already set to 0 */
|
||||
run[run.size()-1] = dim-run[0];
|
||||
}
|
||||
}
|
||||
if (s.sym()[0] == s.dimen()+1)
|
||||
end_flag = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,95 +105,77 @@ public:
|
|||
bool isFull() const;
|
||||
};
|
||||
|
||||
/* The class |SymmetrySet| defines a set of symmetries of the given
|
||||
length having given dimension. It does not store all the symmetries,
|
||||
rather it provides a storage for one symmetry, which is changed as an
|
||||
adjoint iterator moves.
|
||||
/* This is an iterator that iterates over all symmetries of given length and
|
||||
dimension (see the SymmetrySet class for details).
|
||||
|
||||
The iterator class is |symiterator|. It is implemented
|
||||
recursively. The iterator object, when created, creates subordinal
|
||||
iterator, which iterates over a symmetry set whose length is one less,
|
||||
and dimension is the former dimension. When the subordinal iterator
|
||||
goes to its end, the superordinal iterator increases left most index in
|
||||
the symmetry, resets the subordinal symmetry set with different
|
||||
dimension, and iterates through the subordinal symmetry set until its
|
||||
end, and so on. That's why we provide also |SymmetrySet| constructor
|
||||
for construction of a subordinal symmetry set.
|
||||
The beginning iterator is (0, …, 0, dim).
|
||||
Increasing it gives (0, … , 1, dim-1)
|
||||
The just-before-end iterator is (dim, 0, …, 0)
|
||||
The past-the-end iterator is (dim+1, 0, …, 0)
|
||||
|
||||
The typical usage of the abstractions for |SymmetrySet| and
|
||||
|symiterator| is as follows:
|
||||
|
||||
\kern0.3cm
|
||||
\centerline{|for (symiterator si(SymmetrySet(6, 4)); !si.isEnd(); ++si) {body}|}
|
||||
\kern0.3cm
|
||||
|
||||
\noindent It goes through all symmetries of size 4 having dimension
|
||||
6. One can use |*si| as the symmetry in the body. */
|
||||
|
||||
class SymmetrySet
|
||||
{
|
||||
Symmetry run;
|
||||
int dim;
|
||||
public:
|
||||
SymmetrySet(int d, int length)
|
||||
: run(length), dim(d)
|
||||
{
|
||||
}
|
||||
SymmetrySet(SymmetrySet &s, int d)
|
||||
: run(s.run, s.size()-1), dim(d)
|
||||
{
|
||||
}
|
||||
int
|
||||
dimen() const
|
||||
{
|
||||
return dim;
|
||||
}
|
||||
const Symmetry &
|
||||
sym() const
|
||||
{
|
||||
return run;
|
||||
}
|
||||
Symmetry &
|
||||
sym()
|
||||
{
|
||||
return run;
|
||||
}
|
||||
int
|
||||
size() const
|
||||
{
|
||||
return run.size();
|
||||
}
|
||||
};
|
||||
|
||||
/* The logic of |symiterator| was described in |@<|SymmetrySet| class
|
||||
declaration@>|. Here we only comment that: the class has a reference
|
||||
to the |SymmetrySet| only to know dimension and for access of its
|
||||
symmetry storage. Further we have pointers to subordinal |symiterator|
|
||||
and its |SymmetrySet|. These are pointers, since the recursion ends at
|
||||
length equal to 2, in which case these pointers are uninitialized.
|
||||
|
||||
The constructor creates the iterator which initializes to the first
|
||||
The constructor creates the iterator which starts from the given symmetry
|
||||
symmetry (beginning). */
|
||||
|
||||
class symiterator
|
||||
{
|
||||
SymmetrySet &s;
|
||||
std::unique_ptr<symiterator> subit;
|
||||
std::unique_ptr<SymmetrySet> subs;
|
||||
bool end_flag;
|
||||
const int dim;
|
||||
Symmetry run;
|
||||
public:
|
||||
symiterator(SymmetrySet &ss);
|
||||
symiterator(int dim_arg, Symmetry run_arg);
|
||||
~symiterator() = default;
|
||||
symiterator &operator++();
|
||||
bool
|
||||
isEnd() const
|
||||
{
|
||||
return end_flag;
|
||||
}
|
||||
const Symmetry &
|
||||
operator*() const
|
||||
{
|
||||
return s.sym();
|
||||
return run;
|
||||
}
|
||||
bool
|
||||
operator=(const symiterator &it)
|
||||
{
|
||||
return dim == it.dim && run == it.run;
|
||||
}
|
||||
bool
|
||||
operator!=(const symiterator &it)
|
||||
{
|
||||
return !operator=(it);
|
||||
}
|
||||
};
|
||||
|
||||
/* The class |SymmetrySet| defines a set of symmetries of the given length
|
||||
having given dimension (i.e. it represents all the lists of integers of
|
||||
length "len" and of sum equal to "dim"). It does not store all the
|
||||
symmetries, it is just a convenience class for iteration.
|
||||
|
||||
The typical usage of the abstractions for |SymmetrySet| and
|
||||
|symiterator| is as follows:
|
||||
|
||||
for (auto &si : SymmetrySet(6, 4))
|
||||
|
||||
It goes through all symmetries of lenght 4 having dimension 6. One can use
|
||||
"si" as the symmetry in the body. */
|
||||
|
||||
class SymmetrySet
|
||||
{
|
||||
public:
|
||||
const int len;
|
||||
const int dim;
|
||||
SymmetrySet(int dim_arg, int len_arg)
|
||||
: len(len_arg), dim(dim_arg)
|
||||
{
|
||||
}
|
||||
symiterator
|
||||
begin() const
|
||||
{
|
||||
Symmetry run(len);
|
||||
run[len-1] = dim;
|
||||
return { dim, run };
|
||||
}
|
||||
symiterator
|
||||
end() const
|
||||
{
|
||||
Symmetry run(len);
|
||||
run[0] = dim+1;
|
||||
return { dim, run };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -471,13 +471,12 @@ SparseDerivGenerator::SparseDerivGenerator(
|
|||
|
||||
for (int dim = 1; dim <= maxdimen; dim++)
|
||||
{
|
||||
SymmetrySet ss(dim, 4);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
for (auto &si : SymmetrySet(dim, 4))
|
||||
{
|
||||
bigg->insert(bigg_m.deriv(*si));
|
||||
rcont->insert(r.deriv(*si));
|
||||
if ((*si)[2] == 0)
|
||||
g->insert(g_m.deriv(*si));
|
||||
bigg->insert(bigg_m.deriv(si));
|
||||
rcont->insert(r.deriv(si));
|
||||
if (si[2] == 0)
|
||||
g->insert(g_m.deriv(si));
|
||||
}
|
||||
|
||||
ts[dim-1] = f.deriv(dim);
|
||||
|
|
|
@ -362,21 +362,19 @@ TestRunnable::fold_zcont(int nf, int ny, int nu, int nup, int nbigg,
|
|||
|
||||
for (int d = 2; d <= dim; d++)
|
||||
{
|
||||
SymmetrySet ss(d, 4);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
for (auto &si : SymmetrySet(d, 4))
|
||||
{
|
||||
printf("\tSymmetry: "); (*si).print();
|
||||
FGSTensor res(nf, TensorDimens(*si, nvs));
|
||||
printf("\tSymmetry: ");
|
||||
si.print();
|
||||
FGSTensor res(nf, TensorDimens(si, nvs));
|
||||
res.getData().zeros();
|
||||
clock_t stime = clock();
|
||||
for (int l = 1; l <= (*si).dimen(); l++)
|
||||
{
|
||||
for (int l = 1; l <= si.dimen(); l++)
|
||||
zc.multAndAdd(*(dg.ts[l-1]), res);
|
||||
}
|
||||
stime = clock() - stime;
|
||||
printf("\t\ttime for symmetry: %8.4g\n",
|
||||
((double) stime)/CLOCKS_PER_SEC);
|
||||
const FGSTensor *mres = dg.rcont->get(*si);
|
||||
const FGSTensor *mres = dg.rcont->get(si);
|
||||
res.add(-1.0, *mres);
|
||||
double normtmp = res.getData().getMax();
|
||||
printf("\t\terror normMax: %10.6g\n", normtmp);
|
||||
|
@ -419,22 +417,20 @@ TestRunnable::unfold_zcont(int nf, int ny, int nu, int nup, int nbigg,
|
|||
|
||||
for (int d = 2; d <= dim; d++)
|
||||
{
|
||||
SymmetrySet ss(d, 4);
|
||||
for (symiterator si(ss); !si.isEnd(); ++si)
|
||||
for (auto &si : SymmetrySet(d, 4))
|
||||
{
|
||||
printf("\tSymmetry: "); (*si).print();
|
||||
UGSTensor res(nf, TensorDimens(*si, nvs));
|
||||
printf("\tSymmetry: ");
|
||||
si.print();
|
||||
UGSTensor res(nf, TensorDimens(si, nvs));
|
||||
res.getData().zeros();
|
||||
clock_t stime = clock();
|
||||
for (int l = 1; l <= (*si).dimen(); l++)
|
||||
{
|
||||
for (int l = 1; l <= si.dimen(); l++)
|
||||
zc.multAndAdd(*(dg.ts[l-1]), res);
|
||||
}
|
||||
stime = clock() - stime;
|
||||
printf("\t\ttime for symmetry: %8.4g\n",
|
||||
((double) stime)/CLOCKS_PER_SEC);
|
||||
FGSTensor fold_res(res);
|
||||
const FGSTensor *mres = dg.rcont->get(*si);
|
||||
const FGSTensor *mres = dg.rcont->get(si);
|
||||
fold_res.add(-1.0, *mres);
|
||||
double normtmp = fold_res.getData().getMax();
|
||||
printf("\t\terror normMax: %10.6g\n", normtmp);
|
||||
|
|
Loading…
Reference in New Issue