@q $Id: equivalence.hweb 148 2005-04-19 15:12:26Z kamenik $ @>
@q Copyright 2004, Ondra Kamenik @>

@*2 Equivalences. Start of {\tt equivalence.h} file

Here we define an equivalence of a set of integers $\{0, 1, \ldots,
k-1\}$. The purpose is clear, in the tensor library we often iterate
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
implemented via |IntSequence|, but via |vector<int>| since we need
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
important. For instance, if we iterate through equivalences for $k=5$
and pickup some equivalence class, say $\{\{0,4\},\{1,2\},\{3\}\}$, we
then evaluate something like:
$$\left[B_{y^2u^3}\right]_{\alpha_1\alpha_2\beta_1\beta_2\beta_3}=
\cdots+\left[g_{y^3}\right]_{\gamma_1\gamma_2\gamma_3}
\left[g_{yu}\right]^{\gamma_1}_{\alpha_1\beta_3}
\left[g_{yu}\right]^{\gamma_2}_{\alpha_2\beta_1}
\left[g_u\right]^{\gamma_3}_{\beta_2}+\cdots
$$ 
If the tensors are unfolded, we can evaluate this expression as
$$g_{y^3}\cdot\left(g_{yu}\otimes g_{yu}\otimes g_{u}\right)\cdot P,$$
where $P$ is a suitable permutation of columns of the expressions,
which permutes them so that the index
$(\alpha_1,\beta_3,\alpha_2,\beta_1,\beta_2)$ would go to
$(\alpha_1,\alpha_2,\beta_1,\beta_2,\beta_3)$.
The permutation $P$ can be very ineffective (copying great amount of
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.



@s OrdSequence int
@s Equivalence int
@s EquivalenceSet int

@c
#ifndef EQUIVALENCE_H
#define EQUIVALENCE_H

#include "int_sequence.h"

#include <vector>
#include <list>

using namespace std;

@<|OrdSequence| class declaration@>;
@<|Equivalence| class declaration@>;
@<|EquivalenceSet| class declaration@>;
@<|EquivalenceBundle| class declaration@>;

#endif


@ Here is the abstraction for an equivalence class. We implement it as
|vector<int>|. We have a constructor for empty class, copy
constructor. What is important here is the ordering operator
|operator<| and methods for addition of an integer, and addition of
another sequence. Also we provide method |has| which returns true if a
given integer is contained.

@<|OrdSequence| class declaration@>=
class OrdSequence {
	vector<int> data;
public:@/
	OrdSequence() : data()@+ {}
	OrdSequence(const OrdSequence& s) : data(s.data)@+ {}
	const OrdSequence& operator=(const OrdSequence& s)
		{@+ data = s.data;@+ return *this;@+}
	bool operator==(const OrdSequence& s) const;
	int operator[](int i) const;
	bool operator<(const OrdSequence& s) const;
	const vector<int>& getData() const
		{@+ return data;@+}
	int length() const {@+ return data.size();@+}
	void add(int i);
	void add(const OrdSequence& s);
	bool has(int i) const;
	void print(const char* prefix) const;
private:@/
	double average() const;
};


@ Here is the abstraction for the equivalence. It is a list of
equivalence classes. Also we remember |n|, which is a size of
underlying set $\{0, 1, \ldots, n-1\}$.

Method |trace| ``prints'' the equivalence into the integer sequence.

@<|Equivalence| class declaration@>=
class Permutation;
class Equivalence {
private:
	int n;
	list<OrdSequence> classes;
public:@;
	typedef list<OrdSequence>::const_iterator const_seqit;
	typedef list<OrdSequence>::iterator seqit;

	@<|Equivalence| constructors@>;
	const Equivalence& operator=(const Equivalence& e);
	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;
	void print(const char* prefix) const;
	@<|Equivalence| begin and end methods@>;
	const_seqit find(int i) const;
	seqit find(int i);
protected:@;
	@<|Equivalence| protected methods@>;
};

@ The |EquivalenceSet| is a list of equivalences. The unique
constructor constructs a set of all equivalences over $n$-element
set. The equivalences are sorted in the list so that equivalences with
fewer number of classes are in the end.

The two methods |has| and |addParents| are useful in the constructor.

@<|EquivalenceSet| class declaration@>=
class EquivalenceSet {
	int n;
	list<Equivalence> equis;
public:@;
	typedef list<Equivalence>::const_iterator const_iterator; 
	EquivalenceSet(int num);
	void print(const char* prefix) const;
	const_iterator begin() const
		{@+ return equis.begin();@+}
	const_iterator end() const
		{@+ return equis.end();@+}
private:@;
	bool has(const Equivalence& e) const;
	void addParents(const Equivalence& e, list<Equivalence>& added);
};

@ The equivalence bundle class only encapsulates |EquivalenceSet|s
from 1 up to a given number. It is able to retrieve the equivalence set
over $n$-element set for a given $n$, and also it can generate some more
sets on request.

It is fully responsible for storage needed for |EquivalenceSet|s.

@<|EquivalenceBundle| class declaration@>=
class EquivalenceBundle {
	vector<EquivalenceSet*> bundle;
public:@;
	EquivalenceBundle(int nmax);
	~EquivalenceBundle();
	const EquivalenceSet& get(int n) const;
	void generateUpTo(int nmax);
};

@ The first constructor constructs $\{\{0\},\{1\},\ldots,\{n-1\}\}$.

The second constructor constructs $\{\{0,1,\ldots,n-1\}\}$.

The third is the copy constructor. And the fourth is the copy
constructor plus gluing |i1| and |i2| in one class.

@<|Equivalence| constructors@>=
	Equivalence(int num);
	Equivalence(int num, const char* dummy);
	Equivalence(const Equivalence& e);
	Equivalence(const Equivalence& e, int i1, int i2);

@ 
@<|Equivalence| begin and end methods@>=
	seqit begin() {@+ return classes.begin();@+}
	const_seqit begin() const {@+ return classes.begin();@+}
	seqit end() {@+ return classes.end();@+}
	const_seqit end() const {@+ return classes.end();@+}

@ 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.

We have also an |insert| method which inserts a given class
according to the class ordering.

@<|Equivalence| protected methods@>=
	const_seqit findHaving(int i) const;
	seqit findHaving(int i);
	void insert(const OrdSequence& s);

@ End of {\tt equivalence.h} file.