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
|
|
|
|
|
|
|
|
|
// Equivalences.
|
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
/* Here we define an equivalence of a set of integers {0, 1, …, k-1}.
|
|
|
|
|
The purpose is clear, in the tensor library we often iterate
|
2019-01-08 16:09:25 +01:00
|
|
|
|
through all equivalences and sum matrices. We need an abstraction for
|
|
|
|
|
an equivalence class, equivalence and a set of all equivalences.
|
|
|
|
|
|
|
|
|
|
The equivalence class (which is basically a set of integers) is here
|
|
|
|
|
implemented as ordered integer sequence. The ordered sequence is not
|
2019-03-27 19:22:35 +01:00
|
|
|
|
implemented via IntSequence, but via vector<int> since we need
|
2019-01-08 16:09:25 +01:00
|
|
|
|
insertions. The equivalence is implemented as an ordered list of
|
|
|
|
|
equivalence classes, and equivalence set is a list of equivalences.
|
|
|
|
|
|
|
|
|
|
The ordering of the equivalence classes within an equivalence is very
|
2019-03-27 19:22:35 +01:00
|
|
|
|
important. For instance, if we iterate through equivalences for k=5
|
|
|
|
|
and pickup some equivalence class, say { {0,4}, {1,2}, {3} }, we
|
2019-01-08 16:09:25 +01:00
|
|
|
|
then evaluate something like:
|
2019-03-27 19:22:35 +01:00
|
|
|
|
|
|
|
|
|
[B_y²u³]_α₁α₂β₁β₂β₃ = … + [f_z³]_γ₁γ₂γ₃ [z_yu]^γ₁_α₁β₃ [z_yu]^γ₂_α₂β₁ [zᵤ]^γ₃_β₂ + …
|
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
|
If the tensors are unfolded, we can evaluate this expression as
|
2019-03-27 19:22:35 +01:00
|
|
|
|
f_z³·(z_yu ⊗ z_yu ⊗ zᵤ)·P, where P is a suitable permutation of columns of
|
|
|
|
|
the expressions, which permutes them so that the index
|
|
|
|
|
(α₁,β₃,α₂,β₁,β₂) would go to (α₁,α₂,β₁,β₂,β₃).
|
|
|
|
|
|
|
|
|
|
The permutation P can be very ineffective (copying great amount of
|
2019-01-08 16:09:25 +01:00
|
|
|
|
small chunks of data) if the equivalence class ordering is chosen
|
|
|
|
|
badly. However, we do not provide any heuristic minimizing a total
|
|
|
|
|
time spent in all permutations. We choose an ordering which orders the
|
|
|
|
|
classes according to their averages, and according to the smallest
|
|
|
|
|
equivalence class element if the averages are the same. */
|
|
|
|
|
|
|
|
|
|
#ifndef EQUIVALENCE_H
|
|
|
|
|
#define EQUIVALENCE_H
|
|
|
|
|
|
|
|
|
|
#include "int_sequence.hh"
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <list>
|
2019-02-12 17:30:10 +01:00
|
|
|
|
#include <string>
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
/* Here is the abstraction for an equivalence class. We implement it as
|
2019-03-27 19:22:35 +01:00
|
|
|
|
vector<int>. We have a constructor for empty class, copy
|
2019-01-08 16:09:25 +01:00
|
|
|
|
constructor. What is important here is the ordering operator
|
2019-03-27 19:22:35 +01:00
|
|
|
|
operator<() and methods for addition of an integer, and addition of
|
|
|
|
|
another sequence. Also we provide method has() which returns true if a
|
2019-01-08 16:09:25 +01:00
|
|
|
|
given integer is contained. */
|
|
|
|
|
|
|
|
|
|
class OrdSequence
|
|
|
|
|
{
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::vector<int> data;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
|
|
|
|
OrdSequence() : data()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
bool operator==(const OrdSequence &s) const;
|
|
|
|
|
int operator[](int i) const;
|
|
|
|
|
bool operator<(const OrdSequence &s) const;
|
2019-02-06 15:50:01 +01:00
|
|
|
|
const std::vector<int> &
|
2019-01-08 16:09:25 +01:00
|
|
|
|
getData() const
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
int
|
|
|
|
|
length() const
|
|
|
|
|
{
|
|
|
|
|
return data.size();
|
|
|
|
|
}
|
|
|
|
|
void add(int i);
|
|
|
|
|
void add(const OrdSequence &s);
|
|
|
|
|
bool has(int i) const;
|
2019-02-12 17:30:10 +01:00
|
|
|
|
void print(const std::string &prefix) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
private:
|
|
|
|
|
double average() const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Here is the abstraction for the equivalence. It is a list of
|
2019-03-27 19:22:35 +01:00
|
|
|
|
equivalence classes. Also we remember n, which is a size of
|
|
|
|
|
underlying set {0, 1, …, n-1}.
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
Method trace() “prints” the equivalence into the integer sequence. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
class Permutation;
|
|
|
|
|
class Equivalence
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
int n;
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::list<OrdSequence> classes;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2019-02-06 15:50:01 +01:00
|
|
|
|
using const_seqit = std::list<OrdSequence>::const_iterator;
|
|
|
|
|
using seqit = std::list<OrdSequence>::iterator;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
// Constructs { {0}, {1}, …, {n-1} }
|
2019-02-27 19:07:01 +01:00
|
|
|
|
explicit Equivalence(int num);
|
2019-03-27 19:22:35 +01:00
|
|
|
|
// Constructs { {0,1,…,n-1 } }
|
2019-02-12 17:30:10 +01:00
|
|
|
|
Equivalence(int num, const std::string &dummy);
|
2019-03-27 19:22:35 +01:00
|
|
|
|
// Copy constructor plus gluing i1 and i2 in one class
|
2019-01-08 16:09:25 +01:00
|
|
|
|
Equivalence(const Equivalence &e, int i1, int i2);
|
|
|
|
|
|
|
|
|
|
bool operator==(const Equivalence &e) const;
|
|
|
|
|
bool
|
|
|
|
|
operator!=(const Equivalence &e) const
|
|
|
|
|
{
|
|
|
|
|
return !operator==(e);
|
|
|
|
|
}
|
|
|
|
|
int
|
|
|
|
|
getN() const
|
|
|
|
|
{
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
int
|
|
|
|
|
numClasses() const
|
|
|
|
|
{
|
|
|
|
|
return classes.size();
|
|
|
|
|
}
|
|
|
|
|
void trace(IntSequence &out, int n) const;
|
|
|
|
|
void
|
|
|
|
|
trace(IntSequence &out) const
|
|
|
|
|
{
|
|
|
|
|
trace(out, numClasses());
|
|
|
|
|
}
|
|
|
|
|
void trace(IntSequence &out, const Permutation &per) const;
|
2019-02-12 17:30:10 +01:00
|
|
|
|
void print(const std::string &prefix) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
seqit
|
|
|
|
|
begin()
|
|
|
|
|
{
|
|
|
|
|
return classes.begin();
|
|
|
|
|
}
|
|
|
|
|
const_seqit
|
|
|
|
|
begin() const
|
|
|
|
|
{
|
|
|
|
|
return classes.begin();
|
|
|
|
|
}
|
|
|
|
|
seqit
|
|
|
|
|
end()
|
|
|
|
|
{
|
|
|
|
|
return classes.end();
|
|
|
|
|
}
|
|
|
|
|
const_seqit
|
|
|
|
|
end() const
|
|
|
|
|
{
|
|
|
|
|
return classes.end();
|
|
|
|
|
}
|
|
|
|
|
const_seqit find(int i) const;
|
|
|
|
|
seqit find(int i);
|
|
|
|
|
protected:
|
|
|
|
|
/* Here we have find methods. We can find an equivalence class having a
|
|
|
|
|
given number or we can find an equivalence class of a given index within
|
|
|
|
|
the ordering.
|
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
We have also an insert() method which inserts a given class
|
2019-01-08 16:09:25 +01:00
|
|
|
|
according to the class ordering. */
|
|
|
|
|
const_seqit findHaving(int i) const;
|
|
|
|
|
seqit findHaving(int i);
|
|
|
|
|
void insert(const OrdSequence &s);
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
/* The EquivalenceSet is a list of equivalences. The unique
|
|
|
|
|
constructor constructs a set of all equivalences over an n-elements
|
2019-01-08 16:09:25 +01:00
|
|
|
|
set. The equivalences are sorted in the list so that equivalences with
|
|
|
|
|
fewer number of classes are in the end.
|
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
The two methods has() and addParents() are useful in the constructor. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
class EquivalenceSet
|
|
|
|
|
{
|
|
|
|
|
int n;
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::list<Equivalence> equis;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2019-02-27 19:07:01 +01:00
|
|
|
|
explicit EquivalenceSet(int num);
|
2019-02-12 17:30:10 +01:00
|
|
|
|
void print(const std::string &prefix) const;
|
2019-02-27 19:07:01 +01:00
|
|
|
|
auto
|
2019-01-08 16:09:25 +01:00
|
|
|
|
begin() const
|
|
|
|
|
{
|
|
|
|
|
return equis.begin();
|
|
|
|
|
}
|
2019-02-27 19:07:01 +01:00
|
|
|
|
auto
|
2019-01-08 16:09:25 +01:00
|
|
|
|
end() const
|
|
|
|
|
{
|
|
|
|
|
return equis.end();
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
bool has(const Equivalence &e) const;
|
2019-02-06 15:50:01 +01:00
|
|
|
|
void addParents(const Equivalence &e, std::list<Equivalence> &added);
|
2019-01-08 16:09:25 +01:00
|
|
|
|
};
|
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
/* The equivalence bundle class only encapsulates EquivalenceSet·s
|
2019-01-08 16:09:25 +01:00
|
|
|
|
from 1 up to a given number. It is able to retrieve the equivalence set
|
2019-03-27 19:22:35 +01:00
|
|
|
|
over n-element set for a given n, and also it can generate some more
|
2019-01-08 16:09:25 +01:00
|
|
|
|
sets on request.
|
|
|
|
|
|
2019-03-27 19:22:35 +01:00
|
|
|
|
It is fully responsible for storage needed for EquivalenceSet·s. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
|
|
class EquivalenceBundle
|
|
|
|
|
{
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::vector<EquivalenceSet> bundle;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
public:
|
2019-02-27 19:07:01 +01:00
|
|
|
|
explicit EquivalenceBundle(int nmax);
|
2019-02-12 17:30:10 +01:00
|
|
|
|
const EquivalenceSet &get(int n) const;
|
2019-01-08 16:09:25 +01:00
|
|
|
|
void generateUpTo(int nmax);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|