File: t_container.hweb

package info (click to toggle)
dynare 4.5.7-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 49,408 kB
  • sloc: cpp: 84,998; ansic: 29,058; pascal: 13,843; sh: 4,833; objc: 4,236; yacc: 3,622; makefile: 2,278; lex: 1,541; python: 236; lisp: 69; xml: 8
file content (380 lines) | stat: -rw-r--r-- 11,320 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
@q $Id: t_container.hweb 2353 2009-09-03 19:22:36Z michel $ @>
@q Copyright 2004, Ondra Kamenik @>

@*2 Tensor containers. Start of {\tt t\_container.h} file.

One of primary purposes of the tensor library is to perform one step
of the Faa Di Bruno formula:
$$\left[B_{s^k}\right]_{\alpha_1\ldots\alpha_k}=
[h_{y^l}]_{\gamma_1\ldots\gamma_l}\sum_{c\in M_{l,k}}
\prod_{m=1}^l\left[g_{s^{\vert c_m\vert}}\right]^{\gamma_m}_{c_m(\alpha)}
$$
where $h_{y^l}$ and $g_{s^i}$ are tensors, $M_{l,k}$ is a set of all
equivalences with $l$ classes of $k$ element set, $c_m$ is $m$-the
class of equivalence $c$, and $\vert c_m\vert$ is its
cardinality. Further, $c_m(\alpha)$ is a sequence of $\alpha$s picked
by equivalence class $c_m$.

In order to accomplish this operation, we basically need some storage
of all tensors of the form $\left[g_{s^i}\right]$. Note that $s$ can
be compound, for instance $s=[y,u]$. Then we need storage for
$\left[g_{y^3}\right]$, $\left[g_{y^2u}\right]$,
$\left[g_{yu^5}\right]$, etc.
 
We need an object holding all tensors of the same type. Here type
means an information, that coordinates of the tensors can be of type
$y$, or $u$. We will group only tensors, whose symmetry is described
by |Symmetry| class. These are only $y^2u^3$, not $yuyu^2$. So, we are
going to define a class which will hold tensors whose symmetries are
of type |Symmetry| and have the same symmetry length (number of
different coordinate types). Also, for each symmetry there will be at
most one tensor.

The class has two purposes: The first is to provide storage (insert
and retrieve). The second is to perform the above step of Faa Di Bruno. This is
going through all equivalences with $l$ classes, perform the tensor
product and add to the result.
  
We define a template class |TensorContainer|. From different
instantiations of the template class we will inherit to create concrete
classes, for example container of unfolded general symmetric
tensors. The one step of the Faa Di Bruno (we call it |multAndAdd|) is
implemented in the concrete subclasses, because the implementation
depends on storage. Note even, that |multAndAdd| has not a template
common declaration. This is because sparse tensor $h$ is multiplied by
folded tensors $g$ yielding folded tensor $B$, but unfolded tensor $h$
is multiplied by unfolded tensors $g$ yielding unfolded tensor $B$.

@c
#ifndef T_CONTAINER_H
#define T_CONTAINER_H

#include "symmetry.h"
#include "gs_tensor.h"
#include "tl_exception.h"
#include "tl_static.h"
#include "sparse_tensor.h"
#include "equivalence.h"
#include "rfs_tensor.h"
#include "Vector.h"

#include <map>
#include <string>
#include <sstream>

#include <matio.h>

@<|ltsym| predicate@>;
@<|TensorContainer| class definition@>;
@<|UGSContainer| class declaration@>;
@<|FGSContainer| class declaration@>;

#endif

@ We need a predicate on strict weak ordering of symmetries.
@<|ltsym| predicate@>=
struct ltsym {
	bool operator()(const Symmetry& s1, const Symmetry& s2) const
	{@+ return s1 < s2;@+}
};

@ Here we define the template class for tensor container. We implement
it as |stl::map|. It is a unique container, no two tensors with same
symmetries can coexist. Keys of the map are symmetries, values are
pointers to tensor. The class is responsible for deallocating all
tensors. Creation of the tensors is done outside.

The class has integer |n| as its member. It is a number of different
coordinate types of all contained tensors. Besides intuitive insert
and retrieve interface, we define a method |fetchTensors|, which for a
given symmetry and given equivalence calculates symmetries implied by
the symmetry and all equivalence classes, and fetches corresponding
tensors in a vector.

Also, each instance of the container has a reference to
|EquivalenceBundle| which allows an access to equivalences.

@s _const_ptr int;
@s _ptr int;
@s _Map int;

@<|TensorContainer| class definition@>=
template<class _Ttype> class TensorContainer {
protected:@;
	typedef const _Ttype* _const_ptr;
	typedef _Ttype* _ptr;
	typedef map<Symmetry, _ptr, ltsym> _Map;@/
	typedef typename _Map::value_type _mvtype;@/
public:@;
	typedef typename _Map::iterator iterator;@/
	typedef typename _Map::const_iterator const_iterator;@/
private:@;
	int n;
	_Map m;
protected:@;
	const EquivalenceBundle& ebundle;
public:@;
	TensorContainer(int nn)
		: n(nn), ebundle(*(tls.ebundle)) @+ {}
	@<|TensorContainer| copy constructor@>;
	@<|TensorContainer| subtensor constructor@>;
	@<|TensorContainer:get| code@>;
	@<|TensorContainer::check| code@>;
	@<|TensorContainer::insert| code@>;
	@<|TensorContainer::remove| code@>;
	@<|TensorContainer::clear| code@>;
	@<|TensorContainer::fetchTensors| code@>;
	@<|TensorContainer::getMaxDim| code@>;
	@<|TensorContainer::print| code@>;
	@<|TensorContainer::writeMat| code@>;
	@<|TensorContainer::writeMMap| code@>;

	virtual ~TensorContainer()
		{@+ clear();@+}

	@<|TensorContainer| inline methods@>;
};

@ 
@<|TensorContainer| inline methods@>=
	int num() const
		{@+ return n;@+}
	const EquivalenceBundle& getEqBundle() const
		{@+ return ebundle;@+}

	const_iterator begin() const
		{@+ return m.begin();@+}
	const_iterator end() const
		{@+ return m.end();@+}
	iterator begin()
		{@+ return m.begin();@+}
	iterator end()
		{@+ return m.end();@+}

@ This is just a copy constructor. This makes a hard copy of all tensors.
@<|TensorContainer| copy constructor@>=
TensorContainer(const TensorContainer<_Ttype>& c)
	: n(c.n), m(), ebundle(c.ebundle)
{
	for (const_iterator it = c.m.begin(); it != c.m.end(); ++it) {
		_Ttype* ten = new _Ttype(*((*it).second));
		insert(ten);
	}
}

@ This constructor constructs a new tensor container, whose tensors
are in-place subtensors of the given container.

@<|TensorContainer| subtensor constructor@>=
TensorContainer(int first_row, int num, TensorContainer<_Ttype>& c)
	: n(c.n), ebundle(*(tls.ebundle))
{
	for (iterator it = c.m.begin(); it != c.m.end(); ++it) {
		_Ttype* t = new _Ttype(first_row, num, *((*it).second));
		insert(t);
	}
}


@ 
@<|TensorContainer:get| code@>=
_const_ptr get(const Symmetry& s) const
{
	TL_RAISE_IF(s.num() != num(),
				"Incompatible symmetry lookup in TensorContainer::get");
	const_iterator it = m.find(s);
	if (it == m.end()) {
		TL_RAISE("Symmetry not found in TensorContainer::get");
		return NULL;
	} else {
		return (*it).second;
	}
}
@#

_ptr get(const Symmetry& s)
{
	TL_RAISE_IF(s.num() != num(),
				"Incompatible symmetry lookup in TensorContainer::get");
	iterator it = m.find(s);
	if (it == m.end()) {
		TL_RAISE("Symmetry not found in TensorContainer::get");
		return NULL;
	} else {
		return (*it).second;
	}
}

@ 
@<|TensorContainer::check| code@>=
bool check(const Symmetry& s) const
{
	TL_RAISE_IF(s.num() != num(),
				"Incompatible symmetry lookup in TensorContainer::check");
	const_iterator it = m.find(s);
	return it != m.end();
}

@ 
@<|TensorContainer::insert| code@>=
void insert(_ptr t)
{
	TL_RAISE_IF(t->getSym().num() != num(),
				"Incompatible symmetry insertion in TensorContainer::insert");
	TL_RAISE_IF(check(t->getSym()),
				"Tensor already in container in TensorContainer::insert");
	m.insert(_mvtype(t->getSym(),t));
	if (! t->isFinite()) {
		throw TLException(__FILE__, __LINE__,  "NaN or Inf asserted in TensorContainer::insert");
	}
}

@ 
@<|TensorContainer::remove| code@>=
void remove(const Symmetry& s)
{
	iterator it = m.find(s);
	if (it != m.end()) {
		_ptr t = (*it).second;
		m.erase(it);
		delete t;
	}
}


@ 
@<|TensorContainer::clear| code@>=
void clear()
{
	while (! m.empty()) {
		delete (*(m.begin())).second;
		m.erase(m.begin());
	}
}

@ 
@<|TensorContainer::getMaxDim| code@>=
int getMaxDim() const
{
	int res = -1;
	for (const_iterator run = m.begin(); run != m.end(); ++run) {
		int dim = (*run).first.dimen();
		if (dim > res)
			res = dim;
	}
	return res;
}


@ Debug print.
@<|TensorContainer::print| code@>=
void print() const
{
	printf("Tensor container: nvars=%d, tensors=%D\n", n, m.size());
	for (const_iterator it = m.begin(); it != m.end(); ++it) {
		printf("Symmetry: ");
		(*it).first.print();
		((*it).second)->print();
	}
}

@ Output to the MAT file.
@<|TensorContainer::writeMat| code@>=
void writeMat(mat_t* fd, const char* prefix) const
{
	for (const_iterator it = begin(); it != end(); ++it) {
		char lname[100];
		sprintf(lname, "%s_g", prefix);
		const Symmetry& sym = (*it).first;
		for (int i = 0; i < sym.num(); i++) {
			char tmp[10];
			sprintf(tmp, "_%d", sym[i]);
			strcat(lname, tmp);
		}
		ConstTwoDMatrix m(*((*it).second));
		m.writeMat(fd, lname);
	}
}

@ Output to the Memory Map.
@<|TensorContainer::writeMMap| code@>=
void writeMMap(map<string,ConstTwoDMatrix> &mm, const string &prefix) const
{
  ostringstream lname;
  for (const_iterator it = begin(); it != end(); ++it) {
    lname.str(prefix);
    lname << "_g";
    const Symmetry& sym = (*it).first;
    for (int i = 0; i < sym.num(); i++)
      lname << "_" << sym[i];
    mm.insert(make_pair(lname.str(), ConstTwoDMatrix(*((*it).second))));
  }
}

@ Here we fetch all tensors given by symmetry and equivalence. We go
through all equivalence classes, calculate implied symmetry, and
fetch its tensor storing it in the same order to the vector.

@<|TensorContainer::fetchTensors| code@>=
vector<_const_ptr>
fetchTensors(const Symmetry& rsym, const Equivalence& e) const
{
	vector<_const_ptr> res(e.numClasses());
	int i = 0;
	for (Equivalence::const_seqit it = e.begin();
		 it != e.end(); ++it, i++) {
		Symmetry s(rsym, *it);
		res[i] = get(s);
	}
	return res;
}

@ Here is a container storing |UGSTensor|s. We declare |multAndAdd| method.

@<|UGSContainer| class declaration@>=
class FGSContainer;
class UGSContainer : public TensorContainer<UGSTensor> {
public:@;
	UGSContainer(int nn)
		: TensorContainer<UGSTensor>(nn)@+ {}
	UGSContainer(const UGSContainer& uc)
		: TensorContainer<UGSTensor>(uc)@+ {}
	UGSContainer(const FGSContainer& c);
	void multAndAdd(const UGSTensor& t, UGSTensor& out) const;
};


@ Here is a container storing |FGSTensor|s. We declare two versions of
|multAndAdd| method. The first works for folded $B$ and folded $h$
tensors, the second works for folded $B$ and unfolded $h$. There is no
point to do it for unfolded $B$ since the algorithm go through all the
indices of $B$ and calculates corresponding columns. So, if $B$ is
needed unfolded, it is more effective to calculate its folded version
and then unfold by conversion.

The static member |num_one_time| is a number of columns formed from
product of $g$ tensors at one time. This is subject to change, probably
we will have to do some tuning and decide about this number based on
symmetries, and dimensions in the runtime.

@s FGSContainer int
@<|FGSContainer| class declaration@>=
class FGSContainer : public TensorContainer<FGSTensor> {
	static const int num_one_time;
public:@;
	FGSContainer(int nn)
		: TensorContainer<FGSTensor>(nn)@+ {}
	FGSContainer(const FGSContainer& fc)
		: TensorContainer<FGSTensor>(fc)@+ {}
	FGSContainer(const UGSContainer& c);
	void multAndAdd(const FGSTensor& t, FGSTensor& out) const;
	void multAndAdd(const UGSTensor& t, FGSTensor& out) const;
private:@;
	static Tensor::index
	getIndices(int num, vector<IntSequence>& out,
			   const Tensor::index& start,
			   const Tensor::index& end);
};


@ End of {\tt t\_container.h} file.