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
|
@q $Id: fs_tensor.cweb 280 2005-06-13 09:40:02Z kamenik $ @>
@q Copyright 2004, Ondra Kamenik @>
@ Start of {\tt fs\_tensor.cpp} file.
@c
#include "fs_tensor.h"
#include "gs_tensor.h"
#include "sparse_tensor.h"
#include "rfs_tensor.h"
#include "tl_exception.h"
@<|FFSTensor| contraction constructor@>;
@<|FFSTensor::calcMaxOffset| code@>;
@<|FFSTensor| conversion from sparse@>;
@<|FFSTensor| conversion from unfolded@>;
@<|FFSTensor::unfold| code@>;
@<|FFSTensor::increment| code@>;
@<|FFSTensor::decrement| code@>;
@<|FFSTensor::getOffset| code@>;
@<|FFSTensor::addSubTensor| code@>;
@<|UFSTensor| contraction constructor@>;
@<|UFSTensor| conversion from folded@>;
@<|UFSTensor::fold| code@>;
@<|UFSTensor| increment and decrement@>;
@<|UFSTensor::getOffset| code@>;
@<|UFSTensor::addSubTensor| code@>;
@<|UFSTensor::unfoldData| code@>;
@ This constructs a fully symmetric tensor as given by the contraction:
$$\left[g_{y^n}\right]_{\alpha_1\ldots\alpha_n}=
\left[t_{y^{n+1}}\right]_{\alpha_1\ldots\alpha_n\beta}[x]^\beta$$
We go through all columns of output tensor $[g]$ and for each column
we cycle through all variables, insert a variable to the column
coordinates obtaining a column of tensor $[t]$. the column is multiplied
by an appropriate item of |x| and added to the column of $[g]$ tensor.
@<|FFSTensor| contraction constructor@>=
FFSTensor::FFSTensor(const FFSTensor& t, const ConstVector& x)
: FTensor(along_col, IntSequence(t.dimen()-1, t.nvar()),
t.nrows(), calcMaxOffset(t.nvar(), t.dimen()-1), t.dimen()-1),
nv(t.nvar())
{
TL_RAISE_IF(t.dimen() < 1,
"Wrong dimension for tensor contraction of FFSTensor");
TL_RAISE_IF(t.nvar() != x.length(),
"Wrong number of variables for tensor contraction of FFSTensor");
zeros();
for (Tensor::index to = begin(); to != end(); ++to) {
for (int i = 0; i < nvar(); i++) {
IntSequence from_ind(i, to.getCoor());
Tensor::index from(&t, from_ind);
addColumn(x[i], t, *from, *to);
}
}
}
@ This returns number of indices for folded tensor with full
symmetry. Let $n$ be a number of variables |nvar| and $d$ the
dimension |dim|. Then the number of indices is $\pmatrix{n+d-1\cr d}$.
@<|FFSTensor::calcMaxOffset| code@>=
int FFSTensor::calcMaxOffset(int nvar, int d)
{
if (nvar == 0 && d == 0)
return 1;
if (nvar == 0 && d > 0)
return 0;
return noverk(nvar + d - 1, d);
}
@ The conversion from sparse tensor is clear. We go through all the
tensor and write to the dense what is found.
@<|FFSTensor| conversion from sparse@>=
FFSTensor::FFSTensor(const FSSparseTensor& t)
: FTensor(along_col, IntSequence(t.dimen(), t.nvar()),
t.nrows(), calcMaxOffset(t.nvar(), t.dimen()), t.dimen()),
nv(t.nvar())
{
zeros();
for (FSSparseTensor::const_iterator it = t.getMap().begin();
it != t.getMap().end(); ++it) {
index ind(this, (*it).first);
get((*it).second.first, *ind) = (*it).second.second;
}
}
@ The conversion from unfolded copies only columns of respective
coordinates. So we go through all the columns in the folded tensor
(this), make an index of the unfolded vector from coordinates, and
copy the column.
@<|FFSTensor| conversion from unfolded@>=
FFSTensor::FFSTensor(const UFSTensor& ut)
: FTensor(along_col, IntSequence(ut.dimen(), ut.nvar()),
ut.nrows(), calcMaxOffset(ut.nvar(), ut.dimen()), ut.dimen()),
nv(ut.nvar())
{
for (index in = begin(); in != end(); ++in) {
index src(&ut, in.getCoor());
copyColumn(ut, *src, *in);
}
}
@ Here just make a new instance and return the reference.
@<|FFSTensor::unfold| code@>=
UTensor& FFSTensor::unfold() const
{
return *(new UFSTensor(*this));
}
@ Incrementing is easy. We have to increment by calling static method
|UTensor::increment| first. In this way, we have coordinates of
unfolded tensor. Then we have to skip to the closest folded index
which corresponds to monotonizeing the integer sequence.
@<|FFSTensor::increment| code@>=
void FFSTensor::increment(IntSequence& v) const
{
TL_RAISE_IF(v.size() != dimen(),
"Wrong input/output vector size in FFSTensor::increment");
UTensor::increment(v, nv);
v.monotone();
}
@ Decrement calls static |FTensor::decrement|.
@<|FFSTensor::decrement| code@>=
void FFSTensor::decrement(IntSequence& v) const
{
TL_RAISE_IF(v.size() != dimen(),
"Wrong input/output vector size in FFSTensor::decrement");
FTensor::decrement(v, nv);
}
@
@<|FFSTensor::getOffset| code@>=
int FFSTensor::getOffset(const IntSequence& v) const
{
TL_RAISE_IF(v.size() != dimen(),
"Wrong input vector size in FFSTensor::getOffset");
return FTensor::getOffset(v, nv);
}
@ Here we add a general symmetry tensor to the (part of) full symmetry
tensor provided that the unique variable of the full symmetry tensor
is a stack of variables from the general symmetry tensor.
We check for the dimensions and number of variables. Then we calculate
a shift of coordinates when going from the general symmetry tensor to
full symmetry (it corresponds to shift of coordinates induces by
stacking the variables). Then we add the appropriate columns by going
through the columns in general symmetry, adding the shift and sorting.
@<|FFSTensor::addSubTensor| code@>=
void FFSTensor::addSubTensor(const FGSTensor& t)
{
TL_RAISE_IF(dimen() != t.getDims().dimen(),
"Wrong dimensions for FFSTensor::addSubTensor");
TL_RAISE_IF(nvar() != t.getDims().getNVS().sum(),
"Wrong nvs for FFSTensor::addSubTensor");
@<set shift for |addSubTensor|@>;
for (Tensor::index ind = t.begin(); ind != t.end(); ++ind) {
IntSequence c(ind.getCoor());
c.add(1, shift);
c.sort();
Tensor::index tar(this, c);
addColumn(t, *ind, *tar);
}
}
@
@<set shift for |addSubTensor|@>=
IntSequence shift_pre(t.getSym().num(), 0);
for (int i = 1; i < t.getSym().num(); i++)
shift_pre[i] = shift_pre[i-1]+t.getDims().getNVS()[i-1];
IntSequence shift(t.getSym(), shift_pre);
@ This is a bit more straightforward than |@<|FFSTensor| contraction constructor@>|.
We do not add column by column but we do it by submatrices due to
regularity of the unfolded tensor.
@<|UFSTensor| contraction constructor@>=
UFSTensor::UFSTensor(const UFSTensor& t, const ConstVector& x)
: UTensor(along_col, IntSequence(t.dimen()-1, t.nvar()),
t.nrows(), calcMaxOffset(t.nvar(), t.dimen()-1), t.dimen()-1),
nv(t.nvar())
{
TL_RAISE_IF(t.dimen() < 1,
"Wrong dimension for tensor contraction of UFSTensor");
TL_RAISE_IF(t.nvar() != x.length(),
"Wrong number of variables for tensor contraction of UFSTensor");
zeros();
for (int i = 0; i < ncols(); i++) {
ConstTwoDMatrix tpart(t, i*nvar(), nvar());
Vector outcol(*this, i);
tpart.multaVec(outcol, x);
}
}
@ Here we convert folded full symmetry tensor to unfolded. We copy all
columns of folded tensor, and then call |unfoldData()|.
@<|UFSTensor| conversion from folded@>=
UFSTensor::UFSTensor(const FFSTensor& ft)
: UTensor(along_col, IntSequence(ft.dimen(), ft.nvar()),
ft.nrows(), calcMaxOffset(ft.nvar(), ft.dimen()), ft.dimen()),
nv(ft.nvar())
{
for (index src = ft.begin(); src != ft.end(); ++src) {
index in(this, src.getCoor());
copyColumn(ft, *src, *in);
}
unfoldData();
}
@ Here we just return a reference to new instance of folded tensor.
@<|UFSTensor::fold| code@>=
FTensor& UFSTensor::fold() const
{
return *(new FFSTensor(*this));
}
@ Here we just call |UTensor| respective static methods.
@<|UFSTensor| increment and decrement@>=
void UFSTensor::increment(IntSequence& v) const
{
TL_RAISE_IF(v.size() != dimen(),
"Wrong input/output vector size in UFSTensor::increment");
UTensor::increment(v, nv);
}
void UFSTensor::decrement(IntSequence& v) const
{
TL_RAISE_IF(v.size() != dimen(),
"Wrong input/output vector size in UFSTensor::decrement");
UTensor::decrement(v, nv);
}
@
@<|UFSTensor::getOffset| code@>=
int UFSTensor::getOffset(const IntSequence& v) const
{
TL_RAISE_IF(v.size() != dimen(),
"Wrong input vector size in UFSTensor::getOffset");
return UTensor::getOffset(v, nv);
}
@ This is very similar to |@<|FFSTensor::addSubTensor| code@>|. The
only difference is the addition. We go through all columns in the full
symmetry tensor and cancel the shift. If the coordinates after the
cancellation are positive, we find the column in the general symmetry
tensor, and add it.
@<|UFSTensor::addSubTensor| code@>=
void UFSTensor::addSubTensor(const UGSTensor& t)
{
TL_RAISE_IF(dimen() != t.getDims().dimen(),
"Wrong dimensions for UFSTensor::addSubTensor");
TL_RAISE_IF(nvar() != t.getDims().getNVS().sum(),
"Wrong nvs for UFSTensor::addSubTensor");
@<set shift for |addSubTensor|@>;
for (Tensor::index tar = begin(); tar != end(); ++tar) {
IntSequence c(tar.getCoor());
c.sort();
c.add(-1, shift);
if (c.isPositive() && c.less(t.getDims().getNVX())) {
Tensor::index from(&t, c);
addColumn(t, *from, *tar);
}
}
}
@ Here we go through all columns, find a column of folded index, and
then copy the column data. Finding the index is done by sorting the
integer sequence.
@<|UFSTensor::unfoldData| code@>=
void UFSTensor::unfoldData()
{
for (index in = begin(); in != end(); ++in) {
IntSequence v(in.getCoor());
v.sort();
index tmp(this, v);
copyColumn(*tmp, *in);
}
}
@ End of {\tt fs\_tensor.cpp} file.
|