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