1 /* 2 * Copyright © 2004 Ondra Kamenik 3 * Copyright © 2019 Dynare Team 4 * 5 * This file is part of Dynare. 6 * 7 * Dynare is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * Dynare is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with Dynare. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 // Stack of containers. 22 23 /* Here we develop abstractions for stacked containers of tensors. For 24 instance, in perturbation methods for DSGE models, we need the function: 25 26 ⎛ G(y*,u,u′,σ) ⎞ 27 z(y*,u,u′,σ) = ⎢ g(y*,u,σ) ⎥ 28 ⎢ y* ⎥ 29 ⎝ u ⎠ 30 31 and we need to calculate one step of Faà Di Bruno formula: 32 33 ₗ 34 [B_sᵏ]_α₁…αₗ = [f_zˡ]_β₁…βₗ ∑ ∏ [z_{s^|cₘ|}]_cₘ(α)^βₘ 35 c∈ℳₗ,ₖ ᵐ⁼¹ 36 37 where we have containers for derivatives of G and g. 38 39 The main purpose of this file is to define abstractions for stack of 40 containers and possibly raw variables, and code multAndAdd() method 41 calculating (one step of) the Faà Di Bruno formula for folded and 42 unfolded tensors. Note also, that tensors [f_zˡ] are sparse. 43 44 The abstractions are built as follows. At the top, there is an 45 interface describing stack of columns. It contains pure virtual 46 methods needed for manipulating the container stack. For technical 47 reasons it is a template. Both versions (folded, and unfolded) provide 48 all interface necessary for implementation of multAndAdd(). The second 49 way of inheritance is first general implementation of the interface 50 StackContainer, and then specific (ZContainer for our specific z). 51 The only method which is virtual also after StackContainer is 52 getType(), which is implemented in the specialization and determines 53 behaviour of the stack. The complete classes are obtained by 54 inheriting from the both branches, as it is drawn below: 55 56 57 StackContainerInterface<FGSTensor> 58 ↙ ↘ 59 StackContainer<FGSTensor> FoldedStackContainer 60 ↓ 61 ZContainer<FGSTensor> ↙ 62 ↘ 63 FoldedZContainer 64 65 66 StackContainerInterface<UGSTensor> 67 ↙ ↘ 68 StackContainer<UGSTensor> UnfoldedStackContainer 69 ↓ 70 ZContainer<UGSTensor> ↙ 71 ↘ 72 UnfoldedZContainer 73 74 75 We have also two supporting classes StackProduct and KronProdStack 76 and a number of worker classes used as threads. */ 77 78 #ifndef STACK_CONTAINER_H 79 #define STACK_CONTAINER_H 80 81 #include "int_sequence.hh" 82 #include "equivalence.hh" 83 #include "tl_static.hh" 84 #include "t_container.hh" 85 #include "kron_prod.hh" 86 #include "permutation.hh" 87 #include "sthread.hh" 88 89 /* Here is the general interface to stack container. The subclasses 90 maintain IntSequence of stack sizes, i.e. size of G, g, y, and 91 u. Then a convenience IntSequence of stack offsets. Then vector of 92 pointers to containers, in our example G, and g. 93 94 A non-virtual subclass must implement getType() which determines 95 dependency of stack items on symmetries. There are three possible types 96 for a symmetry. Either the stack item derivative wrt. the symmetry is 97 a matrix, or a unit matrix, or zero. 98 99 Method isZero() returns true if the derivative of a given stack item 100 wrt. to given symmetry is zero as defined by getType() or the 101 derivative is not present in the container. In this way, we can 102 implement the formula conditional some of the tensors are zero, which 103 is not true (they are only missing). 104 105 Method createPackedColumn() returns a vector of stack derivatives with 106 respect to the given symmetry and of the given column, where all zeros 107 from zero types, or unit matrices are deleted. See kron_prod.hh for an 108 explanation. */ 109 110 template<class _Ttype> 111 class StackContainerInterface 112 { 113 public: 114 using _Ctype = TensorContainer<_Ttype>; 115 enum class itype { matrix, unit, zero }; 116 public: 117 StackContainerInterface() = default; 118 virtual ~StackContainerInterface() = default; 119 virtual const IntSequence &getStackSizes() const = 0; 120 virtual IntSequence &getStackSizes() = 0; 121 virtual const IntSequence &getStackOffsets() const = 0; 122 virtual IntSequence &getStackOffsets() = 0; 123 virtual int numConts() const = 0; 124 virtual const _Ctype &getCont(int i) const = 0; 125 virtual itype getType(int i, const Symmetry &s) const = 0; 126 virtual int numStacks() const = 0; 127 virtual bool isZero(int i, const Symmetry &s) const = 0; 128 virtual const _Ttype &getMatrix(int i, const Symmetry &s) const = 0; 129 virtual int getLengthOfMatrixStacks(const Symmetry &s) const = 0; 130 virtual int getUnitPos(const Symmetry &s) const = 0; 131 virtual std::unique_ptr<Vector> createPackedColumn(const Symmetry &s, 132 const IntSequence &coor, 133 int &iu) const = 0; 134 int getAllSize() const135 getAllSize() const 136 { 137 return getStackOffsets()[numStacks()-1] 138 + getStackSizes()[numStacks()-1]; 139 } 140 }; 141 142 /* Here is StackContainer, which implements almost all interface 143 StackContainerInterface but one method getType() which is left for 144 implementation to specializations. 145 146 It does not own its tensors. */ 147 148 template<class _Ttype> 149 class StackContainer : virtual public StackContainerInterface<_Ttype> 150 { 151 public: 152 using _Stype = StackContainerInterface<_Ttype>; 153 using _Ctype = typename StackContainerInterface<_Ttype>::_Ctype; 154 using itype = typename StackContainerInterface<_Ttype>::itype; 155 protected: 156 int num_conts; 157 IntSequence stack_sizes; 158 IntSequence stack_offsets; 159 std::vector<const _Ctype *> conts; 160 public: StackContainer(int ns,int nc)161 StackContainer(int ns, int nc) 162 : stack_sizes(ns, 0), stack_offsets(ns, 0), 163 conts(nc) 164 { 165 } 166 const IntSequence & getStackSizes() const167 getStackSizes() const override 168 { 169 return stack_sizes; 170 } 171 IntSequence & getStackSizes()172 getStackSizes() override 173 { 174 return stack_sizes; 175 } 176 const IntSequence & getStackOffsets() const177 getStackOffsets() const override 178 { 179 return stack_offsets; 180 } 181 IntSequence & getStackOffsets()182 getStackOffsets() override 183 { 184 return stack_offsets; 185 } 186 int numConts() const187 numConts() const override 188 { 189 return conts.size(); 190 } 191 const _Ctype & getCont(int i) const192 getCont(int i) const override 193 { 194 return *(conts[i]); 195 } 196 itype getType(int i, const Symmetry &s) const override = 0; 197 int numStacks() const198 numStacks() const override 199 { 200 return stack_sizes.size(); 201 } 202 bool isZero(int i,const Symmetry & s) const203 isZero(int i, const Symmetry &s) const override 204 { 205 TL_RAISE_IF(i < 0 || i >= numStacks(), 206 "Wrong index to stack in StackContainer::isZero."); 207 return (getType(i, s) == itype::zero 208 || (getType(i, s) == itype::matrix && !conts[i]->check(s))); 209 } 210 211 const _Ttype & getMatrix(int i,const Symmetry & s) const212 getMatrix(int i, const Symmetry &s) const override 213 { 214 TL_RAISE_IF(isZero(i, s) || getType(i, s) == itype::unit, 215 "Matrix is not returned in StackContainer::getMatrix"); 216 return conts[i]->get(s); 217 } 218 219 int getLengthOfMatrixStacks(const Symmetry & s) const220 getLengthOfMatrixStacks(const Symmetry &s) const override 221 { 222 int res = 0; 223 int i = 0; 224 while (i < numStacks() && getType(i, s) == itype::matrix) 225 res += stack_sizes[i++]; 226 return res; 227 } 228 229 int getUnitPos(const Symmetry & s) const230 getUnitPos(const Symmetry &s) const override 231 { 232 if (s.dimen() != 1) 233 return -1; 234 int i = numStacks()-1; 235 while (i >= 0 && getType(i, s) != itype::unit) 236 i--; 237 return i; 238 } 239 240 std::unique_ptr<Vector> createPackedColumn(const Symmetry & s,const IntSequence & coor,int & iu) const241 createPackedColumn(const Symmetry &s, 242 const IntSequence &coor, int &iu) const override 243 { 244 TL_RAISE_IF(s.dimen() != coor.size(), 245 "Incompatible coordinates for symmetry in StackContainer::createPackedColumn"); 246 247 int len = getLengthOfMatrixStacks(s); 248 iu = -1; 249 int i = 0; 250 if (-1 != (i = getUnitPos(s))) 251 { 252 iu = stack_offsets[i] + coor[0]; 253 len++; 254 } 255 256 auto res = std::make_unique<Vector>(len); 257 i = 0; 258 while (i < numStacks() && getType(i, s) == itype::matrix) 259 { 260 const _Ttype &t = getMatrix(i, s); 261 Tensor::index ind(t, coor); 262 Vector subres(*res, stack_offsets[i], stack_sizes[i]); 263 subres = ConstGeneralMatrix(t).getCol(*ind); 264 i++; 265 } 266 if (iu != -1) 267 (*res)[len-1] = 1; 268 269 return res; 270 } 271 272 protected: 273 void calculateOffsets()274 calculateOffsets() 275 { 276 stack_offsets[0] = 0; 277 for (int i = 1; i < stack_offsets.size(); i++) 278 stack_offsets[i] = stack_offsets[i-1] + stack_sizes[i-1]; 279 } 280 }; 281 282 class WorkerFoldMAADense; 283 class WorkerFoldMAASparse1; 284 class WorkerFoldMAASparse2; 285 class WorkerFoldMAASparse4; 286 class FoldedStackContainer : virtual public StackContainerInterface<FGSTensor> 287 { 288 friend class WorkerFoldMAADense; 289 friend class WorkerFoldMAASparse1; 290 friend class WorkerFoldMAASparse2; 291 friend class WorkerFoldMAASparse4; 292 public: 293 static constexpr double fill_threshold = 0.00005; 294 void multAndAdd(int dim,const TensorContainer<FSSparseTensor> & c,FGSTensor & out) const295 multAndAdd(int dim, const TensorContainer<FSSparseTensor> &c, 296 FGSTensor &out) const 297 { 298 if (c.check(Symmetry{dim})) 299 multAndAdd(c.get(Symmetry{dim}), out); 300 } 301 void multAndAdd(const FSSparseTensor &t, FGSTensor &out) const; 302 void multAndAdd(int dim, const FGSContainer &c, FGSTensor &out) const; 303 protected: 304 void multAndAddSparse1(const FSSparseTensor &t, FGSTensor &out) const; 305 void multAndAddSparse2(const FSSparseTensor &t, FGSTensor &out) const; 306 void multAndAddSparse3(const FSSparseTensor &t, FGSTensor &out) const; 307 void multAndAddSparse4(const FSSparseTensor &t, FGSTensor &out) const; 308 void multAndAddStacks(const IntSequence &fi, const FGSTensor &g, 309 FGSTensor &out, std::mutex &mut) const; 310 void multAndAddStacks(const IntSequence &fi, const GSSparseTensor &g, 311 FGSTensor &out, std::mutex &mut) const; 312 }; 313 314 class WorkerUnfoldMAADense; 315 class WorkerUnfoldMAASparse1; 316 class WorkerUnfoldMAASparse2; 317 class UnfoldedStackContainer : virtual public StackContainerInterface<UGSTensor> 318 { 319 friend class WorkerUnfoldMAADense; 320 friend class WorkerUnfoldMAASparse1; 321 friend class WorkerUnfoldMAASparse2; 322 public: 323 static constexpr double fill_threshold = 0.00005; 324 void multAndAdd(int dim,const TensorContainer<FSSparseTensor> & c,UGSTensor & out) const325 multAndAdd(int dim, const TensorContainer<FSSparseTensor> &c, 326 UGSTensor &out) const 327 { 328 if (c.check(Symmetry{dim})) 329 multAndAdd(c.get(Symmetry{dim}), out); 330 } 331 void multAndAdd(const FSSparseTensor &t, UGSTensor &out) const; 332 void multAndAdd(int dim, const UGSContainer &c, UGSTensor &out) const; 333 protected: 334 void multAndAddSparse1(const FSSparseTensor &t, UGSTensor &out) const; 335 void multAndAddSparse2(const FSSparseTensor &t, UGSTensor &out) const; 336 void multAndAddStacks(const IntSequence &fi, const UGSTensor &g, 337 UGSTensor &out, std::mutex &mut) const; 338 }; 339 340 /* Here is the specialization of the StackContainer. We implement 341 here the z needed in DSGE context. We implement getType() and define 342 a constructor feeding the data and sizes. 343 344 Note that it has two containers, the first is dependent on four variables 345 G(y*,u,u′,σ), and the second dependent on three variables g(y*,u,σ). So that 346 we would be able to stack them, we make the second container g be dependent 347 on four variables, the third being u′ a dummy and always returning zero if 348 dimension of u′ is positive. */ 349 350 template<class _Ttype> 351 class ZContainer : public StackContainer<_Ttype> 352 { 353 public: 354 using _Tparent = StackContainer<_Ttype>; 355 using _Stype = StackContainerInterface<_Ttype>; 356 using _Ctype = typename _Tparent::_Ctype; 357 using itype = typename _Tparent::itype; ZContainer(const _Ctype * gss,int ngss,const _Ctype * g,int ng,int ny,int nu)358 ZContainer(const _Ctype *gss, int ngss, const _Ctype *g, int ng, 359 int ny, int nu) 360 : _Tparent(4, 2) 361 { 362 _Tparent::stack_sizes = { ngss, ng, ny, nu }; 363 _Tparent::conts[0] = gss; 364 _Tparent::conts[1] = g; 365 _Tparent::calculateOffsets(); 366 } 367 368 /* Here we say, what happens if we derive z. recall the top of the 369 file, how z looks, and code is clear. */ 370 371 itype getType(int i,const Symmetry & s) const372 getType(int i, const Symmetry &s) const override 373 { 374 if (i == 0) 375 return itype::matrix; 376 if (i == 1) 377 if (s[2] > 0) 378 return itype::zero; 379 else 380 return itype::matrix; 381 if (i == 2) 382 if (s == Symmetry{1, 0, 0, 0}) 383 return itype::unit; 384 else 385 return itype::zero; 386 if (i == 3) 387 if (s == Symmetry{0, 1, 0, 0}) 388 return itype::unit; 389 else 390 return itype::zero; 391 392 TL_RAISE("Wrong stack index in ZContainer::getType"); 393 } 394 395 }; 396 397 class FoldedZContainer : public ZContainer<FGSTensor>, 398 public FoldedStackContainer 399 { 400 public: 401 using _Ctype = TensorContainer<FGSTensor>; FoldedZContainer(const _Ctype * gss,int ngss,const _Ctype * g,int ng,int ny,int nu)402 FoldedZContainer(const _Ctype *gss, int ngss, const _Ctype *g, int ng, 403 int ny, int nu) 404 : ZContainer<FGSTensor>(gss, ngss, g, ng, ny, nu) 405 { 406 } 407 }; 408 409 class UnfoldedZContainer : public ZContainer<UGSTensor>, 410 public UnfoldedStackContainer 411 { 412 public: 413 using _Ctype = TensorContainer<UGSTensor>; UnfoldedZContainer(const _Ctype * gss,int ngss,const _Ctype * g,int ng,int ny,int nu)414 UnfoldedZContainer(const _Ctype *gss, int ngss, const _Ctype *g, int ng, 415 int ny, int nu) 416 : ZContainer<UGSTensor>(gss, ngss, g, ng, ny, nu) 417 { 418 } 419 }; 420 421 /* Here we have another specialization of container used in context of 422 DSGE. We define a container for 423 424 G(y,u,u′,σ)=g**(g*(y,u,σ),u′,σ) 425 426 For some reason, the symmetry of g** has length 4 although it 427 is really dependent on three variables (To now the reason, consult 428 the ZContainer class declaration). So, it has four stacks, the 429 third one is dummy, and always returns zero. The first stack 430 corresponds to a container of g*. */ 431 432 template<class _Ttype> 433 class GContainer : public StackContainer<_Ttype> 434 { 435 public: 436 using _Tparent = StackContainer<_Ttype>; 437 using _Stype = StackContainerInterface<_Ttype>; 438 using _Ctype = typename StackContainer<_Ttype>::_Ctype; 439 using itype = typename StackContainer<_Ttype>::itype; GContainer(const _Ctype * gs,int ngs,int nu)440 GContainer(const _Ctype *gs, int ngs, int nu) 441 : StackContainer<_Ttype>(4, 1) 442 { 443 _Tparent::stack_sizes = { ngs, nu, nu, 1 }; 444 _Tparent::conts[0] = gs; 445 _Tparent::calculateOffsets(); 446 } 447 448 /* Here we define the dependencies in g**(g*(y,u,σ),u′,σ). Also note, that 449 first derivative of g* w.r.t. σ is always zero, so we also add this 450 information. */ 451 452 itype getType(int i,const Symmetry & s) const453 getType(int i, const Symmetry &s) const override 454 { 455 if (i == 0) 456 if (s[2] > 0 || s == Symmetry{0, 0, 0, 1}) 457 return itype::zero; 458 else 459 return itype::matrix; 460 if (i == 1) 461 if (s == Symmetry{0, 0, 1, 0}) 462 return itype::unit; 463 else 464 return itype::zero; 465 if (i == 2) 466 return itype::zero; 467 if (i == 3) 468 if (s == Symmetry{0, 0, 0, 1}) 469 return itype::unit; 470 else 471 return itype::zero; 472 473 TL_RAISE("Wrong stack index in GContainer::getType"); 474 } 475 476 }; 477 478 class FoldedGContainer : public GContainer<FGSTensor>, 479 public FoldedStackContainer 480 { 481 public: 482 using _Ctype = TensorContainer<FGSTensor>; FoldedGContainer(const _Ctype * gs,int ngs,int nu)483 FoldedGContainer(const _Ctype *gs, int ngs, int nu) 484 : GContainer<FGSTensor>(gs, ngs, nu) 485 { 486 } 487 }; 488 489 class UnfoldedGContainer : public GContainer<UGSTensor>, 490 public UnfoldedStackContainer 491 { 492 public: 493 using _Ctype = TensorContainer<UGSTensor>; UnfoldedGContainer(const _Ctype * gs,int ngs,int nu)494 UnfoldedGContainer(const _Ctype *gs, int ngs, int nu) 495 : GContainer<UGSTensor>(gs, ngs, nu) 496 { 497 } 498 }; 499 500 /* Here we have a support class for product of StackContainers. It 501 only adds a dimension to StackContainer. It selects the symmetries 502 according to equivalence classes passed to the constructor. The 503 equivalence can have permuted classes by some given 504 permutation. Nothing else is interesting. */ 505 506 template<class _Ttype> 507 class StackProduct 508 { 509 public: 510 using _Stype = StackContainerInterface<_Ttype>; 511 using _Ctype = typename _Stype::_Ctype; 512 using itype = typename _Stype::itype; 513 protected: 514 const _Stype &stack_cont; 515 InducedSymmetries syms; 516 Permutation per; 517 public: StackProduct(const _Stype & sc,const Equivalence & e,const Symmetry & os)518 StackProduct(const _Stype &sc, const Equivalence &e, 519 const Symmetry &os) 520 : stack_cont(sc), syms(e, os), per(e) 521 { 522 } StackProduct(const _Stype & sc,const Equivalence & e,const Permutation & p,const Symmetry & os)523 StackProduct(const _Stype &sc, const Equivalence &e, 524 const Permutation &p, const Symmetry &os) 525 : stack_cont(sc), syms(e, p, os), per(e, p) 526 { 527 } 528 int dimen() const529 dimen() const 530 { 531 return syms.size(); 532 } 533 int getAllSize() const534 getAllSize() const 535 { 536 return stack_cont.getAllSize(); 537 } 538 const Symmetry & getProdSym(int ip) const539 getProdSym(int ip) const 540 { 541 return syms[ip]; 542 } 543 bool isZero(const IntSequence & istacks) const544 isZero(const IntSequence &istacks) const 545 { 546 TL_RAISE_IF(istacks.size() != dimen(), 547 "Wrong istacks coordinates for StackProduct::isZero"); 548 549 bool res = false; 550 int i = 0; 551 while (i < dimen() && !(res = stack_cont.isZero(istacks[i], syms[i]))) 552 i++; 553 return res; 554 } 555 556 itype getType(int is,int ip) const557 getType(int is, int ip) const 558 { 559 TL_RAISE_IF(is < 0 || is >= stack_cont.numStacks(), 560 "Wrong index to stack in StackProduct::getType"); 561 TL_RAISE_IF(ip < 0 || ip >= dimen(), 562 "Wrong index to stack container in StackProduct::getType"); 563 return stack_cont.getType(is, syms[ip]); 564 } 565 566 const _Ttype & getMatrix(int is,int ip) const567 getMatrix(int is, int ip) const 568 { 569 return stack_cont.getMatrix(is, syms[ip]); 570 } 571 572 std::vector<std::unique_ptr<Vector>> createPackedColumns(const IntSequence & coor,IntSequence & iu) const573 createPackedColumns(const IntSequence &coor, IntSequence &iu) const 574 { 575 TL_RAISE_IF(iu.size() != dimen(), 576 "Wrong storage length for unit flags in StackProduct::createPackedColumns"); 577 TL_RAISE_IF(coor.size() != per.size(), 578 "Wrong size of index coor in StackProduct::createPackedColumns"); 579 IntSequence perindex(coor.size()); 580 std::vector<std::unique_ptr<Vector>> vs; 581 per.apply(coor, perindex); 582 int off = 0; 583 for (int i = 0; i < dimen(); i++) 584 { 585 IntSequence percoor(perindex, off, syms[i].dimen() + off); 586 vs.push_back(stack_cont.createPackedColumn(syms[i], percoor, iu[i])); 587 off += syms[i].dimen(); 588 } 589 return vs; 590 } 591 592 int getSize(int is) const593 getSize(int is) const 594 { 595 return stack_cont.getStackSizes()[is]; 596 } 597 598 int numMatrices(const IntSequence & istacks) const599 numMatrices(const IntSequence &istacks) const 600 { 601 TL_RAISE_IF(istacks.size() != dimen(), 602 "Wrong size of stack coordinates in StackContainer::numMatrices"); 603 int ret = 0; 604 int ip = 0; 605 while (ip < dimen() && getType(istacks[ip], ip) == _Stype::matrix) 606 { 607 ret++; 608 ip++; 609 } 610 return ret; 611 } 612 }; 613 614 /* Here we only inherit from Kronecker product KronProdAllOptim, only to 615 allow for a constructor constructing from StackProduct. */ 616 617 template<class _Ttype> 618 class KronProdStack : public KronProdAllOptim 619 { 620 public: 621 using _Ptype = StackProduct<_Ttype>; 622 using _Stype = StackContainerInterface<_Ttype>; 623 624 /* Here we construct KronProdAllOptim from StackContainer and given 625 selections of stack items from stack containers in the product. We 626 only decide whether to insert matrix, or unit matrix. 627 628 At this point, we do not call KronProdAllOptim::optimizeOrder(), so 629 the KronProdStack behaves like KronProdAll (i.e. no optimization 630 is done). */ 631 KronProdStack(const _Ptype & sp,const IntSequence & istack)632 KronProdStack(const _Ptype &sp, const IntSequence &istack) 633 : KronProdAllOptim(sp.dimen()) 634 { 635 TL_RAISE_IF(sp.dimen() != istack.size(), 636 "Wrong stack product dimension for KronProdStack constructor"); 637 638 for (int i = 0; i < sp.dimen(); i++) 639 { 640 TL_RAISE_IF(sp.getType(istack[i], i) == _Stype::itype::zero, 641 "Attempt to construct KronProdStack from zero matrix"); 642 if (sp.getType(istack[i], i) == _Stype::itype::unit) 643 setUnit(i, sp.getSize(istack[i])); 644 if (sp.getType(istack[i], i) == _Stype::itype::matrix) 645 { 646 const TwoDMatrix &m = sp.getMatrix(istack[i], i); 647 TL_RAISE_IF(m.nrows() != sp.getSize(istack[i]), 648 "Wrong size of returned matrix in KronProdStack constructor"); 649 setMat(i, m); 650 } 651 } 652 } 653 }; 654 655 class WorkerFoldMAADense : public sthread::detach_thread 656 { 657 const FoldedStackContainer &cont; 658 Symmetry sym; 659 const FGSContainer &dense_cont; 660 FGSTensor &out; 661 public: 662 WorkerFoldMAADense(const FoldedStackContainer &container, 663 Symmetry s, 664 const FGSContainer &dcontainer, 665 FGSTensor &outten); 666 void operator()(std::mutex &mut) override; 667 }; 668 669 class WorkerFoldMAASparse1 : public sthread::detach_thread 670 { 671 const FoldedStackContainer &cont; 672 const FSSparseTensor &t; 673 FGSTensor &out; 674 IntSequence coor; 675 public: 676 WorkerFoldMAASparse1(const FoldedStackContainer &container, 677 const FSSparseTensor &ten, 678 FGSTensor &outten, IntSequence c); 679 void operator()(std::mutex &mut) override; 680 }; 681 682 class WorkerFoldMAASparse2 : public sthread::detach_thread 683 { 684 const FoldedStackContainer &cont; 685 const FSSparseTensor &t; 686 FGSTensor &out; 687 IntSequence coor; 688 public: 689 WorkerFoldMAASparse2(const FoldedStackContainer &container, 690 const FSSparseTensor &ten, 691 FGSTensor &outten, IntSequence c); 692 void operator()(std::mutex &mut) override; 693 }; 694 695 class WorkerFoldMAASparse4 : public sthread::detach_thread 696 { 697 const FoldedStackContainer &cont; 698 const FSSparseTensor &t; 699 FGSTensor &out; 700 IntSequence coor; 701 public: 702 WorkerFoldMAASparse4(const FoldedStackContainer &container, 703 const FSSparseTensor &ten, 704 FGSTensor &outten, IntSequence c); 705 void operator()(std::mutex &mut) override; 706 }; 707 708 class WorkerUnfoldMAADense : public sthread::detach_thread 709 { 710 const UnfoldedStackContainer &cont; 711 Symmetry sym; 712 const UGSContainer &dense_cont; 713 UGSTensor &out; 714 public: 715 WorkerUnfoldMAADense(const UnfoldedStackContainer &container, 716 Symmetry s, 717 const UGSContainer &dcontainer, 718 UGSTensor &outten); 719 void operator()(std::mutex &mut) override; 720 }; 721 722 class WorkerUnfoldMAASparse1 : public sthread::detach_thread 723 { 724 const UnfoldedStackContainer &cont; 725 const FSSparseTensor &t; 726 UGSTensor &out; 727 IntSequence coor; 728 public: 729 WorkerUnfoldMAASparse1(const UnfoldedStackContainer &container, 730 const FSSparseTensor &ten, 731 UGSTensor &outten, IntSequence c); 732 void operator()(std::mutex &mut) override; 733 }; 734 735 class WorkerUnfoldMAASparse2 : public sthread::detach_thread 736 { 737 const UnfoldedStackContainer &cont; 738 const FSSparseTensor &t; 739 UGSTensor &out; 740 IntSequence coor; 741 public: 742 WorkerUnfoldMAASparse2(const UnfoldedStackContainer &container, 743 const FSSparseTensor &ten, 744 UGSTensor &outten, IntSequence c); 745 void operator()(std::mutex &mut) override; 746 }; 747 748 #endif 749