File indexing completed on 2025-09-16 09:08:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef ROOT_Minuit2_MnMatrix
0011 #define ROOT_Minuit2_MnMatrix
0012
0013 #include <Minuit2/MnMatrixfwd.h> // For typedefs
0014
0015 #include <ROOT/RSpan.hxx>
0016
0017 #include <cassert>
0018 #include <cstdlib>
0019 #include <cstring>
0020 #include <new>
0021 #include <ostream>
0022
0023
0024
0025
0026
0027
0028 #ifdef MN_USE_STACK_ALLOC
0029 #define _MN_NO_THREAD_SAVE_
0030 #endif
0031
0032 namespace ROOT {
0033
0034 namespace Minuit2 {
0035
0036 namespace MnMatrix {
0037
0038
0039
0040
0041 int SetMaxNP(int value);
0042
0043
0044 int MaxNP();
0045
0046 }
0047
0048
0049
0050 class StackOverflow {};
0051 class StackError {};
0052
0053
0054
0055
0056
0057
0058
0059
0060 class StackAllocator {
0061
0062 public:
0063
0064 enum {
0065 default_size = 524288
0066 };
0067
0068 StackAllocator() : fStack(nullptr)
0069 {
0070 #ifdef _MN_NO_THREAD_SAVE_
0071
0072 fStack = new unsigned char[default_size];
0073 #endif
0074 fStackOffset = 0;
0075 fBlockCount = 0;
0076 }
0077
0078 ~StackAllocator()
0079 {
0080 #ifdef _MN_NO_THREAD_SAVE_
0081
0082 if (fStack)
0083 delete[] fStack;
0084 #endif
0085 }
0086
0087 void *Allocate(size_t nBytes)
0088 {
0089 #ifdef _MN_NO_THREAD_SAVE_
0090 if (fStack == 0)
0091 fStack = new unsigned char[default_size];
0092 int nAlloc = AlignedSize(nBytes);
0093 CheckOverflow(nAlloc);
0094
0095
0096
0097
0098 WriteInt(fStackOffset, fStackOffset + nAlloc);
0099
0100 WriteInt(fStackOffset + nAlloc - sizeof(int), fStackOffset);
0101
0102 void *result = fStack + fStackOffset + sizeof(int);
0103 fStackOffset += nAlloc;
0104 fBlockCount++;
0105
0106 #ifdef DEBUG_ALLOCATOR
0107 CheckConsistency();
0108 #endif
0109
0110 #else
0111 void *result = malloc(nBytes);
0112 if (!result)
0113 throw std::bad_alloc();
0114 #endif
0115
0116 return result;
0117 }
0118
0119 void Deallocate(void *p)
0120 {
0121 #ifdef _MN_NO_THREAD_SAVE_
0122
0123 int delBlock = ToInt(p);
0124 int nextBlock = ReadInt(delBlock);
0125 int previousBlock = ReadInt(nextBlock - sizeof(int));
0126 if (nextBlock == fStackOffset) {
0127
0128 fStackOffset = previousBlock;
0129 } else {
0130
0131 int nextNextBlock = ReadInt(nextBlock);
0132 WriteInt(nextNextBlock - sizeof(int), previousBlock);
0133
0134 WriteInt(previousBlock, nextNextBlock);
0135 }
0136 fBlockCount--;
0137
0138 #ifdef DEBUG_ALLOCATOR
0139 CheckConsistency();
0140 #endif
0141 #else
0142 free(p);
0143 #endif
0144
0145
0146 }
0147
0148 int ReadInt(int offset)
0149 {
0150 int *ip = (int *)(fStack + offset);
0151
0152
0153
0154 return *ip;
0155 }
0156
0157 void WriteInt(int offset, int Value)
0158 {
0159
0160
0161
0162 int *ip = reinterpret_cast<int *>(fStack + offset);
0163 *ip = Value;
0164 }
0165
0166 int ToInt(void *p)
0167 {
0168 unsigned char *pc = static_cast<unsigned char *>(p);
0169
0170
0171
0172 int userBlock = pc - fStack;
0173 return userBlock - sizeof(int);
0174 }
0175
0176 int AlignedSize(int nBytes)
0177 {
0178 const int fAlignment = 4;
0179 int needed = nBytes % fAlignment == 0 ? nBytes : (nBytes / fAlignment + 1) * fAlignment;
0180 return needed + 2 * sizeof(int);
0181 }
0182
0183 void CheckOverflow(int n)
0184 {
0185 if (fStackOffset + n >= default_size) {
0186
0187 throw StackOverflow();
0188 }
0189 }
0190
0191 bool CheckConsistency()
0192 {
0193
0194
0195
0196
0197 int beg = 0;
0198 int end = fStackOffset;
0199 int nblocks = 0;
0200 while (beg < fStackOffset) {
0201 end = ReadInt(beg);
0202
0203
0204
0205
0206 int beg2 = ReadInt(end - sizeof(int));
0207 if (beg != beg2) {
0208
0209 return false;
0210 }
0211 nblocks++;
0212 beg = end;
0213 }
0214 if (end != fStackOffset) {
0215
0216 return false;
0217 }
0218 if (nblocks != fBlockCount) {
0219
0220 return false;
0221 }
0222
0223 return true;
0224 }
0225
0226 private:
0227 unsigned char *fStack;
0228
0229 int fStackOffset;
0230 int fBlockCount;
0231 };
0232
0233 class StackAllocatorHolder {
0234
0235
0236
0237
0238 public:
0239 static StackAllocator &Get()
0240 {
0241 static StackAllocator gStackAllocator;
0242 return gStackAllocator;
0243 }
0244 };
0245
0246 class sym {};
0247 class vec {};
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257 class DeleteAssignment {
0258 public:
0259 DeleteAssignment() = default;
0260 ~DeleteAssignment() = default;
0261 DeleteAssignment(const DeleteAssignment &) = default;
0262 DeleteAssignment(DeleteAssignment &&) = default;
0263 DeleteAssignment &operator=(const DeleteAssignment &) = delete;
0264 DeleteAssignment &operator=(DeleteAssignment &&) = delete;
0265 };
0266
0267 template <class Type, class M, class T = double>
0268 class ABObj : public DeleteAssignment {
0269
0270 public:
0271 ABObj(const M &obj, T factor = 1.) : fObject(obj), fFactor(factor) {}
0272
0273 const M &Obj() const { return fObject; }
0274
0275 T f() const { return fFactor; }
0276
0277 private:
0278 M fObject;
0279 T fFactor;
0280 };
0281
0282
0283 template <class mt, class M, class T>
0284 ABObj<mt, M, T> operator*(T f, const M &obj)
0285 {
0286 return {obj, f};
0287 }
0288
0289
0290 template <class mt, class M, class T>
0291 ABObj<mt, M, T> operator/(const M &obj, T f)
0292 {
0293 return {obj, T(1.) / f};
0294 }
0295
0296
0297 template <class mt, class M, class T>
0298 ABObj<mt, M, T> operator-(const M &obj)
0299 {
0300 return {obj, -1.};
0301 }
0302
0303
0304 template <class mt, class M, class T>
0305 ABObj<mt, M, T> operator*(T f, const ABObj<mt, M, T> &obj)
0306 {
0307 return {obj.Obj(), obj.f() * f};
0308 }
0309
0310
0311 template <class mt, class M, class T>
0312 ABObj<mt, M, T> operator/(const ABObj<mt, M, T> &obj, T f)
0313 {
0314 return {obj.Obj(), obj.f() / f};
0315 }
0316
0317
0318 template <class mt, class M, class T>
0319 ABObj<mt, M, T> operator-(const ABObj<mt, M, T> &obj)
0320 {
0321 return {obj.Obj(), T(-1.) * obj.f()};
0322 }
0323
0324 template <class M1, class M2>
0325 class ABSum : public DeleteAssignment {
0326 public:
0327 ABSum(const M1 &a, const M2 &b) : fA(a), fB(b) {}
0328
0329 const M1 &A() const { return fA; }
0330 const M2 &B() const { return fB; }
0331
0332 private:
0333 M1 fA;
0334 M2 fB;
0335 };
0336
0337
0338 template <class atype, class A, class B, class T>
0339 ABObj<atype, ABSum<ABObj<atype, A, T>, ABObj<atype, B, T>>, T>
0340 operator+(const ABObj<atype, A, T> &a, const ABObj<atype, B, T> &b)
0341 {
0342
0343 return {ABSum<ABObj<atype, A, T>, ABObj<atype, B, T>>(a, b)};
0344 }
0345
0346
0347 template <class atype, class A, class B, class T>
0348 ABObj<atype, ABSum<ABObj<atype, A, T>, ABObj<atype, B, T>>, T>
0349 operator-(const ABObj<atype, A, T> &a, const ABObj<atype, B, T> &b)
0350 {
0351
0352 return {ABSum<ABObj<atype, A, T>, ABObj<atype, B, T>>(a, ABObj<atype, B, T>(b.Obj(), T(-1.) * b.f()))};
0353 }
0354
0355 template <class M1, class M2>
0356 class ABProd : public DeleteAssignment {
0357 public:
0358 ABProd(const M1 &a, const M2 &b) : fA(a), fB(b) {}
0359
0360 const M1 &A() const { return fA; }
0361 const M2 &B() const { return fB; }
0362
0363 private:
0364 M1 fA;
0365 M2 fB;
0366 };
0367
0368
0369 template <class A, class B, class T>
0370 ABObj<vec, ABProd<ABObj<sym, A, T>, ABObj<vec, B, T>>, T>
0371 operator*(const ABObj<sym, A, T> &a, const ABObj<vec, B, T> &b)
0372 {
0373
0374 return {ABProd<ABObj<sym, A, T>, ABObj<vec, B, T>>(a, b)};
0375 }
0376
0377 template <class M, class T>
0378 class VectorOuterProduct {
0379
0380 public:
0381 VectorOuterProduct(const M &obj) : fObject(obj) {}
0382
0383 const M &Obj() const { return fObject; }
0384
0385 private:
0386 M fObject;
0387 };
0388
0389 template <class M, class T>
0390 ABObj<sym, VectorOuterProduct<ABObj<vec, M, T>, T>, T> Outer_product(const ABObj<vec, M, T> &obj)
0391 {
0392 return {VectorOuterProduct<ABObj<vec, M, T>, T>(obj)};
0393 }
0394
0395 template <class mtype, class M, class T>
0396 class MatrixInverse {
0397
0398 public:
0399 MatrixInverse(const M &obj) : fObject(obj) {}
0400
0401 const M &Obj() const { return fObject; }
0402
0403 private:
0404 M fObject;
0405 };
0406
0407
0408 template <class M, class T>
0409 class MatrixInverse<vec, M, T> {
0410 MatrixInverse() = delete;
0411 MatrixInverse(const MatrixInverse &) = delete;
0412 MatrixInverse(MatrixInverse &&) = delete;
0413 };
0414
0415 template <class mt, class M, class T>
0416 inline ABObj<mt, MatrixInverse<mt, ABObj<mt, M, T>, T>, T> Inverse(const ABObj<mt, M, T> &obj)
0417 {
0418 return {MatrixInverse<mt, ABObj<mt, M, T>, T>(obj)};
0419 }
0420
0421 void Mndaxpy(unsigned int, double, const double *, double *);
0422 void Mndscal(unsigned int, double, double *);
0423
0424 class LASymMatrix;
0425 class LAVector;
0426
0427 int Invert(LASymMatrix &);
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438 class LASymMatrix {
0439
0440 public:
0441 typedef sym Type;
0442
0443 LASymMatrix(unsigned int n)
0444 : fSize(n * (n + 1) / 2),
0445 fNRow(n),
0446 fData((n > 0) ? (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * n * (n + 1) / 2) : nullptr)
0447 {
0448
0449 if (fData)
0450 std::memset(fData, 0, fSize * sizeof(double));
0451 }
0452
0453 ~LASymMatrix()
0454 {
0455 if (fData)
0456 StackAllocatorHolder::Get().Deallocate(fData);
0457 }
0458
0459 LASymMatrix(const LASymMatrix &v)
0460 : fSize(v.size()),
0461 fNRow(v.Nrow()),
0462 fData((double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * v.size()))
0463 {
0464 std::memcpy(fData, v.Data(), fSize * sizeof(double));
0465 }
0466
0467 LASymMatrix(LASymMatrix &&v)
0468 : fSize(v.size()),
0469 fNRow(v.Nrow()),
0470 fData(v.fData)
0471 {
0472 v.fData = nullptr;
0473 }
0474
0475
0476 LASymMatrix &operator=(const LASymMatrix &v)
0477 {
0478 if (fSize < v.size()) {
0479 if (fData)
0480 StackAllocatorHolder::Get().Deallocate(fData);
0481 fSize = v.size();
0482 fNRow = v.Nrow();
0483 fData = (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * fSize);
0484 } else if (fSize > v.size()) {
0485 throw std::runtime_error("Can't assign smaller LASymMatrix to larger LASymMatrix");
0486 }
0487 std::memcpy(fData, v.Data(), fSize * sizeof(double));
0488 return *this;
0489 }
0490
0491 LASymMatrix &operator=(LASymMatrix &&v)
0492 {
0493 fSize = v.size();
0494 fNRow = v.Nrow();
0495 fData = v.Data();
0496 v.fData = nullptr;
0497 return *this;
0498 }
0499
0500 template <class T>
0501 LASymMatrix(const ABObj<sym, LASymMatrix, T> &v)
0502 : fSize(v.Obj().size()),
0503 fNRow(v.Obj().Nrow()),
0504 fData((double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * v.Obj().size()))
0505 {
0506
0507
0508 std::memcpy(fData, v.Obj().Data(), fSize * sizeof(double));
0509 Mndscal(fSize, double(v.f()), fData);
0510
0511 }
0512
0513 template <class A, class B, class T>
0514 LASymMatrix(const ABObj<sym, ABSum<ABObj<sym, A, T>, ABObj<sym, B, T>>, T> &sum)
0515 {
0516
0517
0518 (*this) = sum.Obj().A();
0519 (*this) += sum.Obj().B();
0520
0521 }
0522
0523 template <class A, class T>
0524 LASymMatrix(const ABObj<sym, ABSum<ABObj<sym, LASymMatrix, T>, ABObj<sym, A, T>>, T> &sum)
0525 {
0526
0527
0528
0529
0530
0531 (*this) = sum.Obj().B();
0532
0533 (*this) += sum.Obj().A();
0534
0535
0536 }
0537
0538 template <class A, class T>
0539 LASymMatrix(const ABObj<sym, ABObj<sym, A, T>, T> &something)
0540 {
0541
0542
0543 (*this) = something.Obj();
0544 (*this) *= something.f();
0545
0546
0547 }
0548
0549 template <class T>
0550 LASymMatrix(const ABObj<sym, MatrixInverse<sym, ABObj<sym, LASymMatrix, T>, T>, T> &inv)
0551 : fSize(inv.Obj().Obj().Obj().size()),
0552 fNRow(inv.Obj().Obj().Obj().Nrow()),
0553 fData((double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * inv.Obj().Obj().Obj().size()))
0554 {
0555 std::memcpy(fData, inv.Obj().Obj().Obj().Data(), fSize * sizeof(double));
0556 Mndscal(fSize, double(inv.Obj().Obj().f()), fData);
0557 Invert(*this);
0558 Mndscal(fSize, double(inv.f()), fData);
0559 }
0560
0561 template <class A, class T>
0562 LASymMatrix(
0563 const ABObj<sym, ABSum<ABObj<sym, MatrixInverse<sym, ABObj<sym, LASymMatrix, T>, T>, T>, ABObj<sym, A, T>>, T>
0564 &sum)
0565 {
0566
0567
0568
0569
0570 (*this) = sum.Obj().B();
0571 (*this) += sum.Obj().A();
0572
0573
0574 }
0575
0576 LASymMatrix(const ABObj<sym, VectorOuterProduct<ABObj<vec, LAVector, double>, double>, double> &);
0577
0578 template <class A, class T>
0579 LASymMatrix(
0580 const ABObj<sym, ABSum<ABObj<sym, VectorOuterProduct<ABObj<vec, LAVector, T>, T>, T>, ABObj<sym, A, T>>, T> &sum)
0581 {
0582
0583
0584
0585
0586 (*this) = sum.Obj().B();
0587 (*this) += sum.Obj().A();
0588
0589
0590 }
0591
0592 LASymMatrix &operator+=(const LASymMatrix &m)
0593 {
0594
0595 assert(fSize == m.size());
0596 Mndaxpy(fSize, 1., m.Data(), fData);
0597 return *this;
0598 }
0599
0600 LASymMatrix &operator-=(const LASymMatrix &m)
0601 {
0602
0603 assert(fSize == m.size());
0604 Mndaxpy(fSize, -1., m.Data(), fData);
0605 return *this;
0606 }
0607
0608 template <class T>
0609 LASymMatrix &operator+=(const ABObj<sym, LASymMatrix, T> &m)
0610 {
0611
0612 assert(fSize == m.Obj().size());
0613 if (m.Obj().Data() == fData) {
0614 Mndscal(fSize, 1. + double(m.f()), fData);
0615 } else {
0616 Mndaxpy(fSize, double(m.f()), m.Obj().Data(), fData);
0617 }
0618
0619 return *this;
0620 }
0621
0622 template <class A, class T>
0623 LASymMatrix &operator+=(const ABObj<sym, A, T> &m)
0624 {
0625
0626 (*this) += LASymMatrix(m);
0627 return *this;
0628 }
0629
0630 template <class T>
0631 LASymMatrix &operator+=(const ABObj<sym, MatrixInverse<sym, ABObj<sym, LASymMatrix, T>, T>, T> &m)
0632 {
0633
0634
0635 assert(fNRow > 0);
0636 LASymMatrix tmp(m.Obj().Obj());
0637 Invert(tmp);
0638 tmp *= double(m.f());
0639 (*this) += tmp;
0640 return *this;
0641 }
0642
0643 template <class T>
0644 LASymMatrix &operator+=(const ABObj<sym, VectorOuterProduct<ABObj<vec, LAVector, T>, T>, T> &m)
0645 {
0646
0647
0648 assert(fNRow > 0);
0649 Outer_prod(*this, m.Obj().Obj().Obj(), m.f() * m.Obj().Obj().f() * m.Obj().Obj().f());
0650 return *this;
0651 }
0652
0653 LASymMatrix &operator*=(double scal)
0654 {
0655 Mndscal(fSize, scal, fData);
0656 return *this;
0657 }
0658
0659 double operator()(unsigned int row, unsigned int col) const
0660 {
0661 assert(row < fNRow && col < fNRow);
0662 if (row > col)
0663 return fData[col + row * (row + 1) / 2];
0664 else
0665 return fData[row + col * (col + 1) / 2];
0666 }
0667
0668 double &operator()(unsigned int row, unsigned int col)
0669 {
0670 assert(row < fNRow && col < fNRow);
0671 if (row > col)
0672 return fData[col + row * (row + 1) / 2];
0673 else
0674 return fData[row + col * (col + 1) / 2];
0675 }
0676
0677 const double *Data() const { return fData; }
0678
0679 double *Data() { return fData; }
0680
0681 unsigned int size() const { return fSize; }
0682
0683 unsigned int Nrow() const { return fNRow; }
0684
0685 unsigned int Ncol() const { return Nrow(); }
0686
0687 private:
0688 unsigned int fSize = 0;
0689 unsigned int fNRow = 0;
0690 double *fData = nullptr;
0691
0692 public:
0693 template <class T>
0694 LASymMatrix &operator=(const ABObj<sym, LASymMatrix, T> &v)
0695 {
0696
0697 if (fSize == 0 && !fData) {
0698 fSize = v.Obj().size();
0699 fNRow = v.Obj().Nrow();
0700 fData = (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * fSize);
0701 } else {
0702 assert(fSize == v.Obj().size());
0703 }
0704
0705 std::memcpy(fData, v.Obj().Data(), fSize * sizeof(double));
0706 (*this) *= v.f();
0707 return *this;
0708 }
0709
0710 template <class A, class T>
0711 LASymMatrix &operator=(const ABObj<sym, ABObj<sym, A, T>, T> &something)
0712 {
0713
0714
0715 if (fSize == 0 && fData == nullptr) {
0716 (*this) = something.Obj();
0717 (*this) *= something.f();
0718 } else {
0719 LASymMatrix tmp(something.Obj());
0720 tmp *= something.f();
0721 assert(fSize == tmp.size());
0722 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
0723 }
0724
0725
0726 return *this;
0727 }
0728
0729 template <class A, class B, class T>
0730 LASymMatrix &operator=(const ABObj<sym, ABSum<ABObj<sym, A, T>, ABObj<sym, B, T>>, T> &sum)
0731 {
0732
0733
0734
0735 if (fSize == 0 && fData == nullptr) {
0736 (*this) = sum.Obj().A();
0737 (*this) += sum.Obj().B();
0738 (*this) *= sum.f();
0739 } else {
0740 LASymMatrix tmp(sum.Obj().A());
0741 tmp += sum.Obj().B();
0742 tmp *= sum.f();
0743 assert(fSize == tmp.size());
0744 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
0745 }
0746 return *this;
0747 }
0748
0749 template <class A, class T>
0750 LASymMatrix &operator=(const ABObj<sym, ABSum<ABObj<sym, LASymMatrix, T>, ABObj<sym, A, T>>, T> &sum)
0751 {
0752
0753
0754
0755 if (fSize == 0 && fData == nullptr) {
0756
0757 (*this) = sum.Obj().B();
0758 (*this) += sum.Obj().A();
0759 (*this) *= sum.f();
0760 } else {
0761
0762 LASymMatrix tmp(sum.Obj().B());
0763 tmp += sum.Obj().A();
0764 tmp *= sum.f();
0765 assert(fSize == tmp.size());
0766 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
0767 }
0768
0769 return *this;
0770 }
0771
0772 template <class T>
0773 LASymMatrix &operator=(const ABObj<sym, MatrixInverse<sym, ABObj<sym, LASymMatrix, T>, T>, T> &inv)
0774 {
0775 if (fSize == 0 && fData == nullptr) {
0776 fSize = inv.Obj().Obj().Obj().size();
0777 fNRow = inv.Obj().Obj().Obj().Nrow();
0778 fData = (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * fSize);
0779 std::memcpy(fData, inv.Obj().Obj().Obj().Data(), fSize * sizeof(double));
0780 (*this) *= inv.Obj().Obj().f();
0781 Invert(*this);
0782 (*this) *= inv.f();
0783 } else {
0784 LASymMatrix tmp(inv.Obj().Obj());
0785 Invert(tmp);
0786 tmp *= double(inv.f());
0787 assert(fSize == tmp.size());
0788 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
0789 }
0790 return *this;
0791 }
0792
0793 LASymMatrix &operator=(const ABObj<sym, VectorOuterProduct<ABObj<vec, LAVector, double>, double>, double> &);
0794 };
0795
0796 inline ABObj<sym, ABSum<ABObj<sym, LASymMatrix>, ABObj<sym, LASymMatrix>>>
0797 operator+(const ABObj<sym, LASymMatrix> &a, const ABObj<sym, LASymMatrix> &b)
0798 {
0799 return {ABSum<ABObj<sym, LASymMatrix>, ABObj<sym, LASymMatrix>>(a, b)};
0800 }
0801
0802 inline ABObj<sym, ABSum<ABObj<sym, LASymMatrix>, ABObj<sym, LASymMatrix>>>
0803 operator-(const ABObj<sym, LASymMatrix> &a, const ABObj<sym, LASymMatrix> &b)
0804 {
0805 return {ABSum<ABObj<sym, LASymMatrix>, ABObj<sym, LASymMatrix>>(a, ABObj<sym, LASymMatrix>(b.Obj(), -1. * b.f()))};
0806 }
0807
0808 inline ABObj<sym, LASymMatrix> operator*(double f, const LASymMatrix &obj)
0809 {
0810 return {obj, f};
0811 }
0812
0813 inline ABObj<sym, LASymMatrix> operator/(const LASymMatrix &obj, double f)
0814 {
0815 return {obj, 1. / f};
0816 }
0817
0818 inline ABObj<sym, LASymMatrix> operator-(const LASymMatrix &obj)
0819 {
0820 return {obj, -1.};
0821 }
0822
0823 void Mndaxpy(unsigned int, double, const double *, double *);
0824 void Mndscal(unsigned int, double, double *);
0825 void Mndspmv(unsigned int, double, const double *, const double *, double, double *);
0826
0827 class LAVector {
0828
0829 public:
0830 typedef vec Type;
0831
0832 LAVector(unsigned int n)
0833 : fSize(n), fData((n > 0) ? (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * n) : nullptr)
0834 {
0835 if (fData)
0836 std::memset(fData, 0, size() * sizeof(double));
0837 }
0838
0839 ~LAVector()
0840 {
0841 if (fData)
0842 StackAllocatorHolder::Get().Deallocate(fData);
0843 }
0844
0845 LAVector(LAVector &&v)
0846 : fSize(v.size()), fData(v.Data())
0847 {
0848 v.fData = nullptr;
0849 }
0850
0851 LAVector(const LAVector &v) : LAVector{std::span<const double>{v.Data(), v.size()}} {}
0852
0853 explicit LAVector(std::span<const double> v)
0854 : fSize(v.size()), fData((double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * v.size()))
0855 {
0856 std::memcpy(fData, v.data(), fSize * sizeof(double));
0857 }
0858
0859 LAVector &operator=(const LAVector &v)
0860 {
0861
0862 if (v.size() > fSize) {
0863 if (fData)
0864 StackAllocatorHolder::Get().Deallocate(fData);
0865 fSize = v.size();
0866 fData = (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * fSize);
0867 } else if (fSize > v.size()) {
0868 throw std::runtime_error("Can't assign smaller LAVector to larger LAVector");
0869 }
0870 std::memcpy(fData, v.Data(), fSize * sizeof(double));
0871 return *this;
0872 }
0873
0874 LAVector &operator=(LAVector &&v)
0875 {
0876 fSize = v.fSize;
0877 fData = v.fData;
0878 v.fData = nullptr;
0879 return *this;
0880 }
0881
0882 template <class T>
0883 LAVector(const ABObj<vec, LAVector, T> &v)
0884 : fSize(v.Obj().size()), fData((double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * v.Obj().size()))
0885 {
0886
0887
0888 std::memcpy(fData, v.Obj().Data(), fSize * sizeof(T));
0889 (*this) *= T(v.f());
0890
0891 }
0892
0893 template <class A, class B, class T>
0894 LAVector(const ABObj<vec, ABSum<ABObj<vec, A, T>, ABObj<vec, B, T>>, T> &sum)
0895 {
0896
0897
0898 (*this) = sum.Obj().A();
0899 (*this) += sum.Obj().B();
0900 (*this) *= double(sum.f());
0901 }
0902
0903 template <class A, class T>
0904 LAVector(const ABObj<vec, ABSum<ABObj<vec, LAVector, T>, ABObj<vec, A, T>>, T> &sum)
0905 {
0906
0907
0908
0909
0910
0911 (*this) = sum.Obj().B();
0912
0913 (*this) += sum.Obj().A();
0914 (*this) *= double(sum.f());
0915
0916 }
0917
0918 template <class A, class T>
0919 LAVector(const ABObj<vec, ABObj<vec, A, T>, T> &something)
0920 {
0921
0922 (*this) = something.Obj();
0923 (*this) *= something.f();
0924 }
0925
0926
0927 template <class T>
0928 LAVector(const ABObj<vec, ABProd<ABObj<sym, LASymMatrix, T>, ABObj<vec, LAVector, T>>, T> &prod)
0929 : fSize(prod.Obj().B().Obj().size()),
0930 fData((double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * prod.Obj().B().Obj().size()))
0931 {
0932
0933
0934
0935 Mndspmv(fSize, prod.f() * prod.Obj().A().f() * prod.Obj().B().f(), prod.Obj().A().Obj().Data(),
0936 prod.Obj().B().Obj().Data(), 0., fData);
0937 }
0938
0939
0940 template <class T>
0941 LAVector(const ABObj<
0942 vec,
0943 ABSum<ABObj<vec, ABProd<ABObj<sym, LASymMatrix, T>, ABObj<vec, LAVector, T>>, T>, ABObj<vec, LAVector, T>>,
0944 T> &prod)
0945 {
0946 (*this) = prod.Obj().B();
0947 (*this) += prod.Obj().A();
0948 (*this) *= double(prod.f());
0949 }
0950
0951
0952 LAVector &operator+=(const LAVector &m)
0953 {
0954
0955 assert(fSize == m.size());
0956 Mndaxpy(fSize, 1., m.Data(), fData);
0957 return *this;
0958 }
0959
0960 LAVector &operator-=(const LAVector &m)
0961 {
0962
0963 assert(fSize == m.size());
0964 Mndaxpy(fSize, -1., m.Data(), fData);
0965 return *this;
0966 }
0967
0968 template <class T>
0969 LAVector &operator+=(const ABObj<vec, LAVector, T> &m)
0970 {
0971
0972 assert(fSize == m.Obj().size());
0973 if (m.Obj().Data() == fData) {
0974 Mndscal(fSize, 1. + double(m.f()), fData);
0975 } else {
0976 Mndaxpy(fSize, double(m.f()), m.Obj().Data(), fData);
0977 }
0978
0979 return *this;
0980 }
0981
0982 template <class A, class T>
0983 LAVector &operator+=(const ABObj<vec, A, T> &m)
0984 {
0985
0986 (*this) += LAVector(m);
0987 return *this;
0988 }
0989
0990 template <class T>
0991 LAVector &operator+=(const ABObj<vec, ABProd<ABObj<sym, LASymMatrix, T>, ABObj<vec, LAVector, T>>, T> &prod)
0992 {
0993 Mndspmv(fSize, prod.f() * prod.Obj().A().f() * prod.Obj().B().f(), prod.Obj().A().Obj().Data(),
0994 prod.Obj().B().Data(), 1., fData);
0995 return *this;
0996 }
0997
0998 LAVector &operator*=(double scal)
0999 {
1000 Mndscal(fSize, scal, fData);
1001 return *this;
1002 }
1003
1004 double operator()(unsigned int i) const
1005 {
1006 assert(i < fSize);
1007 return fData[i];
1008 }
1009
1010 double &operator()(unsigned int i)
1011 {
1012 assert(i < fSize);
1013 return fData[i];
1014 }
1015
1016 double operator[](unsigned int i) const
1017 {
1018 assert(i < fSize);
1019 return fData[i];
1020 }
1021
1022 double &operator[](unsigned int i)
1023 {
1024 assert(i < fSize);
1025 return fData[i];
1026 }
1027
1028 const double *Data() const { return fData; }
1029
1030 double *Data() { return fData; }
1031
1032 unsigned int size() const { return fSize; }
1033
1034 private:
1035 unsigned int fSize = 0;
1036 double *fData = nullptr;
1037
1038 public:
1039 template <class T>
1040 LAVector &operator=(const ABObj<vec, LAVector, T> &v)
1041 {
1042
1043 if (fSize == 0 && !fData) {
1044 fSize = v.Obj().size();
1045 fData = (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * fSize);
1046 } else {
1047 assert(fSize == v.Obj().size());
1048 }
1049 std::memcpy(fData, v.Obj().Data(), fSize * sizeof(double));
1050 (*this) *= T(v.f());
1051 return *this;
1052 }
1053
1054 template <class A, class T>
1055 LAVector &operator=(const ABObj<vec, ABObj<vec, A, T>, T> &something)
1056 {
1057
1058
1059 if (fSize == 0 && !fData) {
1060 (*this) = something.Obj();
1061 } else {
1062 LAVector tmp(something.Obj());
1063 assert(fSize == tmp.size());
1064 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
1065 }
1066 (*this) *= something.f();
1067 return *this;
1068 }
1069
1070 template <class A, class B, class T>
1071 LAVector &operator=(const ABObj<vec, ABSum<ABObj<vec, A, T>, ABObj<vec, B, T>>, T> &sum)
1072 {
1073 if (fSize == 0 && !fData) {
1074 (*this) = sum.Obj().A();
1075 (*this) += sum.Obj().B();
1076 } else {
1077 LAVector tmp(sum.Obj().A());
1078 tmp += sum.Obj().B();
1079 assert(fSize == tmp.size());
1080 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
1081 }
1082 (*this) *= sum.f();
1083 return *this;
1084 }
1085
1086 template <class A, class T>
1087 LAVector &operator=(const ABObj<vec, ABSum<ABObj<vec, LAVector, T>, ABObj<vec, A, T>>, T> &sum)
1088 {
1089 if (fSize == 0 && !fData) {
1090 (*this) = sum.Obj().B();
1091 (*this) += sum.Obj().A();
1092 } else {
1093 LAVector tmp(sum.Obj().A());
1094 tmp += sum.Obj().B();
1095 assert(fSize == tmp.size());
1096 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
1097 }
1098 (*this) *= sum.f();
1099 return *this;
1100 }
1101
1102
1103 template <class T>
1104 LAVector &operator=(const ABObj<vec, ABProd<ABObj<sym, LASymMatrix, T>, ABObj<vec, LAVector, T>>, T> &prod)
1105 {
1106 if (fSize == 0 && !fData) {
1107 fSize = prod.Obj().B().Obj().size();
1108 fData = (double *)StackAllocatorHolder::Get().Allocate(sizeof(double) * fSize);
1109 Mndspmv(fSize, double(prod.f() * prod.Obj().A().f() * prod.Obj().B().f()), prod.Obj().A().Obj().Data(),
1110 prod.Obj().B().Obj().Data(), 0., fData);
1111 } else {
1112 LAVector tmp(prod.Obj().B());
1113 assert(fSize == tmp.size());
1114 Mndspmv(fSize, double(prod.f() * prod.Obj().A().f()), prod.Obj().A().Obj().Data(), tmp.Data(), 0., fData);
1115 }
1116 return *this;
1117 }
1118
1119
1120 template <class T>
1121 LAVector &
1122 operator=(const ABObj<
1123 vec,
1124 ABSum<ABObj<vec, ABProd<ABObj<sym, LASymMatrix, T>, ABObj<vec, LAVector, T>>, T>, ABObj<vec, LAVector, T>>,
1125 T> &prod)
1126 {
1127 if (fSize == 0 && !fData) {
1128 (*this) = prod.Obj().B();
1129 (*this) += prod.Obj().A();
1130 } else {
1131
1132 LAVector tmp(prod.Obj().B());
1133 tmp += prod.Obj().A();
1134 assert(fSize == tmp.size());
1135 std::memcpy(fData, tmp.Data(), fSize * sizeof(double));
1136 }
1137 (*this) *= prod.f();
1138 return *this;
1139 }
1140 };
1141
1142 inline ABObj<vec, ABSum<ABObj<vec, LAVector>, ABObj<vec, LAVector>>>
1143 operator+(const ABObj<vec, LAVector> &a, const ABObj<vec, LAVector> &b)
1144 {
1145 return {ABSum<ABObj<vec, LAVector>, ABObj<vec, LAVector>>(a, b)};
1146 }
1147
1148 template <class V>
1149 ABObj<vec, ABSum<ABObj<vec, LAVector>, ABObj<vec, V>>> operator+(const ABObj<vec, LAVector> &a, const ABObj<vec, V> &b)
1150 {
1151 return {ABSum<ABObj<vec, LAVector>, ABObj<vec, V>>(a, b)};
1152 }
1153
1154 inline ABObj<vec, ABSum<ABObj<vec, LAVector>, ABObj<vec, LAVector>>>
1155 operator-(const ABObj<vec, LAVector> &a, const ABObj<vec, LAVector> &b)
1156 {
1157 return {ABSum<ABObj<vec, LAVector>, ABObj<vec, LAVector>>(a, ABObj<vec, LAVector>(b.Obj(), -1. * b.f()))};
1158 }
1159
1160 inline ABObj<vec, LAVector> operator*(double f, const LAVector &obj)
1161 {
1162 return {obj, f};
1163 }
1164 inline ABObj<vec, LAVector> operator/(const LAVector &obj, double f)
1165 {
1166 return {obj, 1. / f};
1167 }
1168 inline ABObj<vec, LAVector> operator-(const LAVector &obj)
1169 {
1170 return {obj, -1.};
1171 }
1172
1173
1174 inline ABObj<vec, ABProd<ABObj<sym, LASymMatrix>, ABObj<vec, LAVector>>>
1175 operator*(const ABObj<sym, LASymMatrix> &a, const ABObj<vec, LAVector> &b)
1176 {
1177 return {ABProd<ABObj<sym, LASymMatrix>, ABObj<vec, LAVector>>(a, b)};
1178 }
1179
1180
1181
1182
1183 inline ABObj<sym, MatrixInverse<sym, ABObj<sym, LASymMatrix>, double>> Inverse(const ABObj<sym, LASymMatrix> &obj)
1184 {
1185 return {MatrixInverse<sym, ABObj<sym, LASymMatrix>, double>{obj}};
1186 }
1187
1188 int Invert(LASymMatrix &);
1189
1190 int Invert_undef_sym(LASymMatrix &);
1191
1192
1193
1194
1195 inline ABObj<sym, VectorOuterProduct<ABObj<vec, LAVector>, double>> Outer_product(const ABObj<vec, LAVector> &obj)
1196 {
1197 return {VectorOuterProduct<ABObj<vec, LAVector>, double>{obj}};
1198 }
1199
1200 void Outer_prod(LASymMatrix &, const LAVector &, double f = 1.);
1201
1202 double inner_product(const LAVector &, const LAVector &);
1203 double similarity(const LAVector &, const LASymMatrix &);
1204 double sum_of_elements(const LASymMatrix &);
1205 LAVector eigenvalues(const LASymMatrix &);
1206
1207 std::ostream &operator<<(std::ostream &, const LAVector &);
1208
1209 std::ostream &operator<<(std::ostream &, const LASymMatrix &);
1210
1211 }
1212
1213 }
1214
1215 #endif