Dynare++: refactor iterator over symmetries

Simplify the logic of iteration. Adapt the range-based for loop syntax.
time-shift
Sébastien Villemot 2019-02-12 12:15:56 +01:00
parent e9688560f6
commit 44d47ee560
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
9 changed files with 144 additions and 186 deletions

View File

@ -112,12 +112,11 @@ SmolyakQuadrature::SmolyakQuadrature(int d, int l, const OneDQuadrature &uq)
// todo: check |l>1|, |l>=d| // todo: check |l>1|, |l>=d|
// todo: check |l>=uquad.miLevel()|, |l<=uquad.maxLevel()| // todo: check |l>=uquad.miLevel()|, |l<=uquad.maxLevel()|
int cum = 0; int cum = 0;
SymmetrySet ss(l-1, d+1); for (auto &si : SymmetrySet(l-1, d+1))
for (symiterator si(ss); !si.isEnd(); ++si)
{ {
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); lev.add(1);
levels.push_back(lev); levels.push_back(lev);
IntSequence levpts(d); IntSequence levpts(d);
@ -171,12 +170,11 @@ int
SmolyakQuadrature::calcNumEvaluations(int lev) const SmolyakQuadrature::calcNumEvaluations(int lev) const
{ {
int cum = 0; int cum = 0;
SymmetrySet ss(lev-1, dim+1); for (auto &si : SymmetrySet(lev-1, dim+1))
for (symiterator si(ss); !si.isEnd(); ++si)
{ {
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); lev.add(1);
IntSequence levpts(dim); IntSequence levpts(dim);
for (int i = 0; i < dim; i++) for (int i = 0; i < dim; i++)

View File

@ -342,30 +342,27 @@ KOrder::switchToFolded()
int maxdim = g<unfold>().getMaxDim(); int maxdim = g<unfold>().getMaxDim();
for (int dim = 1; dim <= maxdim; dim++) 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)));
{ insertDerivative<fold>(ft);
auto *ft = new FGSTensor(*(g<unfold>().get(*si))); if (dim > 1)
insertDerivative<fold>(ft); {
if (dim > 1) gss<unfold>().remove(si);
{ gs<unfold>().remove(si);
gss<unfold>().remove(*si); g<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)));
{ G<fold>().insert(ft);
auto *ft = new FGSTensor(*(G<unfold>().get(*si))); if (dim > 1)
G<fold>().insert(ft); {
if (dim > 1) G<fold>().remove(si);
{ }
G<fold>().remove(*si); }
} }
}
}
}
} }

View File

@ -871,12 +871,11 @@ KOrder::check(int dim) const
} }
// check for $F_{y^iu^ju'^k}+D_{ijk}+E_{ijk}=0$ // check for $F_{y^iu^ju'^k}+D_{ijk}+E_{ijk}=0$
SymmetrySet ss(dim, 3); for (auto &si : SymmetrySet(dim, 3))
for (symiterator si(ss); !si.isEnd(); ++si)
{ {
int i = (*si)[0]; int i = si[0];
int j = (*si)[1]; int j = si[1];
int k = (*si)[2]; int k = si[2];
if (i+j > 0 && k > 0) if (i+j > 0 && k > 0)
{ {
Symmetry sym{i, j, 0, k}; Symmetry sym{i, j, 0, k};

View File

@ -516,18 +516,17 @@ KOrderStoch::performStep(int order)
int maxd = g<t>().getMaxDim(); int maxd = g<t>().getMaxDim();
KORD_RAISE_IF(order-1 != maxd && (order != 1 || maxd != -1), KORD_RAISE_IF(order-1 != maxd && (order != 1 || maxd != -1),
"Wrong order for KOrderStoch::performStep"); "Wrong order for KOrderStoch::performStep");
SymmetrySet ss(order, 4); for (auto &si : SymmetrySet(order, 4))
for (symiterator si(ss); !si.isEnd(); ++si)
{ {
if ((*si)[2] == 0) if (si[2] == 0)
{ {
JournalRecordPair pa(journal); 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); G<t>().insert(G_sym);
_Ttensor *g_sym = faaDiBrunoZ<t>(*si); _Ttensor *g_sym = faaDiBrunoZ<t>(si);
g_sym->mult(-1.0); g_sym->mult(-1.0);
matA.multInv(*g_sym); matA.multInv(*g_sym);
g<t>().insert(g_sym); g<t>().insert(g_sym);

View File

@ -42,10 +42,10 @@ FoldedStackContainer::multAndAdd(int dim, const FGSContainer &c, FGSTensor &out)
"Wrong symmetry length of container for FoldedStackContainer::multAndAdd"); "Wrong symmetry length of container for FoldedStackContainer::multAndAdd");
sthread::detach_thread_group gr; sthread::detach_thread_group gr;
SymmetrySet ss(dim, c.num());
for (symiterator si(ss); !si.isEnd(); ++si) for (auto &si : SymmetrySet(dim, c.num()))
if (c.check(*si)) if (c.check(si))
gr.insert(std::make_unique<WorkerFoldMAADense>(*this, *si, c, out)); gr.insert(std::make_unique<WorkerFoldMAADense>(*this, si, c, out));
gr.run(); gr.run();
} }
@ -395,10 +395,9 @@ UnfoldedStackContainer::multAndAdd(int dim, const UGSContainer &c,
"Wrong symmetry length of container for UnfoldedStackContainer::multAndAdd"); "Wrong symmetry length of container for UnfoldedStackContainer::multAndAdd");
sthread::detach_thread_group gr; sthread::detach_thread_group gr;
SymmetrySet ss(dim, c.num()); for (auto &si : SymmetrySet(dim, c.num()))
for (symiterator si(ss); !si.isEnd(); ++si) if (c.check(si))
if (c.check(*si)) gr.insert(std::make_unique<WorkerUnfoldMAADense>(*this, si, c, out));
gr.insert(std::make_unique<WorkerUnfoldMAADense>(*this, *si, c, out));
gr.run(); gr.run();
} }

View File

@ -51,53 +51,42 @@ Symmetry::isFull() const
return count <= 1; return count <= 1;
} }
/* Here we construct the beginning of the |symiterator|. The first /* Construct a symiterator of given dimension, starting from the given
symmetry index is 0. If length is 2, the second index is the symmetry. */
dimension, otherwise we create the subordinal symmetry set and its
beginning as subordinal |symiterator|. */
symiterator::symiterator(SymmetrySet &ss) symiterator::symiterator(int dim_arg, Symmetry run_arg)
: s(ss), end_flag(false) : 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 /* 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 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 index, otherwise we increase the subordinal symmetry. If we got to the
end, we recreate the subordinal symmetry set and set the subordinal 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 iterator to the beginning. */
end. This is recognized if the lowest index exceeded the dimension. */
symiterator & symiterator &
symiterator::operator++() 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) run[0]++;
run[1]--;
}
else
{
symiterator subit{dim-run[0], Symmetry(run, run.size()-1)};
++subit;
if (run[1] == dim-run[0]+1)
{ {
s.sym()[0]++; run[0]++;
s.sym()[1]--; 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];
} }
else
{
++(*subit);
if (subit->isEnd())
{
s.sym()[0]++;
subs = std::make_unique<SymmetrySet>(s, s.dimen()-s.sym()[0]);
subit = std::make_unique<symiterator>(*subs);
}
}
if (s.sym()[0] == s.dimen()+1)
end_flag = true;
} }
return *this; return *this;
} }

View File

@ -105,95 +105,77 @@ public:
bool isFull() const; bool isFull() const;
}; };
/* The class |SymmetrySet| defines a set of symmetries of the given /* This is an iterator that iterates over all symmetries of given length and
length having given dimension. It does not store all the symmetries, dimension (see the SymmetrySet class for details).
rather it provides a storage for one symmetry, which is changed as an
adjoint iterator moves.
The iterator class is |symiterator|. It is implemented The beginning iterator is (0, , 0, dim).
recursively. The iterator object, when created, creates subordinal Increasing it gives (0, , 1, dim-1)
iterator, which iterates over a symmetry set whose length is one less, The just-before-end iterator is (dim, 0, , 0)
and dimension is the former dimension. When the subordinal iterator The past-the-end iterator is (dim+1, 0, , 0)
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 typical usage of the abstractions for |SymmetrySet| and The constructor creates the iterator which starts from the given symmetry
|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
symmetry (beginning). */ symmetry (beginning). */
class symiterator class symiterator
{ {
SymmetrySet &s; const int dim;
std::unique_ptr<symiterator> subit; Symmetry run;
std::unique_ptr<SymmetrySet> subs;
bool end_flag;
public: public:
symiterator(SymmetrySet &ss); symiterator(int dim_arg, Symmetry run_arg);
~symiterator() = default; ~symiterator() = default;
symiterator &operator++(); symiterator &operator++();
bool
isEnd() const
{
return end_flag;
}
const Symmetry & const Symmetry &
operator*() const 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 };
} }
}; };

View File

@ -471,13 +471,12 @@ SparseDerivGenerator::SparseDerivGenerator(
for (int dim = 1; dim <= maxdimen; dim++) for (int dim = 1; dim <= maxdimen; dim++)
{ {
SymmetrySet ss(dim, 4); for (auto &si : SymmetrySet(dim, 4))
for (symiterator si(ss); !si.isEnd(); ++si)
{ {
bigg->insert(bigg_m.deriv(*si)); bigg->insert(bigg_m.deriv(si));
rcont->insert(r.deriv(*si)); rcont->insert(r.deriv(si));
if ((*si)[2] == 0) if (si[2] == 0)
g->insert(g_m.deriv(*si)); g->insert(g_m.deriv(si));
} }
ts[dim-1] = f.deriv(dim); ts[dim-1] = f.deriv(dim);

View File

@ -362,21 +362,19 @@ TestRunnable::fold_zcont(int nf, int ny, int nu, int nup, int nbigg,
for (int d = 2; d <= dim; d++) for (int d = 2; d <= dim; d++)
{ {
SymmetrySet ss(d, 4); for (auto &si : SymmetrySet(d, 4))
for (symiterator si(ss); !si.isEnd(); ++si)
{ {
printf("\tSymmetry: "); (*si).print(); printf("\tSymmetry: ");
FGSTensor res(nf, TensorDimens(*si, nvs)); si.print();
FGSTensor res(nf, TensorDimens(si, nvs));
res.getData().zeros(); res.getData().zeros();
clock_t stime = clock(); 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);
zc.multAndAdd(*(dg.ts[l-1]), res);
}
stime = clock() - stime; stime = clock() - stime;
printf("\t\ttime for symmetry: %8.4g\n", printf("\t\ttime for symmetry: %8.4g\n",
((double) stime)/CLOCKS_PER_SEC); ((double) stime)/CLOCKS_PER_SEC);
const FGSTensor *mres = dg.rcont->get(*si); const FGSTensor *mres = dg.rcont->get(si);
res.add(-1.0, *mres); res.add(-1.0, *mres);
double normtmp = res.getData().getMax(); double normtmp = res.getData().getMax();
printf("\t\terror normMax: %10.6g\n", normtmp); 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++) for (int d = 2; d <= dim; d++)
{ {
SymmetrySet ss(d, 4); for (auto &si : SymmetrySet(d, 4))
for (symiterator si(ss); !si.isEnd(); ++si)
{ {
printf("\tSymmetry: "); (*si).print(); printf("\tSymmetry: ");
UGSTensor res(nf, TensorDimens(*si, nvs)); si.print();
UGSTensor res(nf, TensorDimens(si, nvs));
res.getData().zeros(); res.getData().zeros();
clock_t stime = clock(); 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);
zc.multAndAdd(*(dg.ts[l-1]), res);
}
stime = clock() - stime; stime = clock() - stime;
printf("\t\ttime for symmetry: %8.4g\n", printf("\t\ttime for symmetry: %8.4g\n",
((double) stime)/CLOCKS_PER_SEC); ((double) stime)/CLOCKS_PER_SEC);
FGSTensor fold_res(res); FGSTensor fold_res(res);
const FGSTensor *mres = dg.rcont->get(*si); const FGSTensor *mres = dg.rcont->get(si);
fold_res.add(-1.0, *mres); fold_res.add(-1.0, *mres);
double normtmp = fold_res.getData().getMax(); double normtmp = fold_res.getData().getMax();
printf("\t\terror normMax: %10.6g\n", normtmp); printf("\t\terror normMax: %10.6g\n", normtmp);