Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:08:16

0001 // @(#)root/minuit2:$Id$
0002 // Authors: M. Winkler, F. James, L. Moneta, A. Zsenei   2003-2005
0003 
0004 /**********************************************************************
0005  *                                                                    *
0006  * Copyright (c) 2005 LCG ROOT Math team,  CERN/PH-SFT                *
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 // comment out this line and recompile if you want to gain additional
0024 // performance (the gain is mainly for "simple" functions which are easy
0025 // to calculate and vanishes quickly if going to cost-intensive functions)
0026 // the library is no longer thread save however
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 // Whether to cut the maximum number of parameters shown for vector and matrices
0039 // set maximum number of printed parameters and return previous value
0040 // A negative value will mean all parameters are printed
0041 int SetMaxNP(int value);
0042 
0043 // retrieve maximum number of printed parameters
0044 int MaxNP();
0045 
0046 } // namespace MnMatrix
0047 
0048 /// define stack allocator symbol
0049 
0050 class StackOverflow {};
0051 class StackError {};
0052 
0053 /** StackAllocator controls the memory allocation/deallocation of Minuit. If
0054     _MN_NO_THREAD_SAVE_ is defined, memory is taken from a pre-allocated piece
0055     of heap memory which is then used like a stack, otherwise via standard
0056     malloc/free. Note that defining _MN_NO_THREAD_SAVE_ makes the code thread-
0057     unsave. The gain in performance is mainly for cost-cheap FCN functions.
0058  */
0059 
0060 class StackAllocator {
0061 
0062 public:
0063    //   enum {default_size = 1048576};
0064    enum {
0065       default_size = 524288
0066    };
0067 
0068    StackAllocator() : fStack(nullptr)
0069    {
0070 #ifdef _MN_NO_THREAD_SAVE_
0071       // std::cout<<"StackAllocator Allocate "<<default_size<<std::endl;
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       // std::cout<<"StackAllocator destruct "<<fStackOffset<<std::endl;
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       //       std::cout << "Allocating " << nAlloc << " bytes, requested = " << nBytes << std::endl;
0096 
0097       // write the start position of the next block at the start of the block
0098       WriteInt(fStackOffset, fStackOffset + nAlloc);
0099       // write the start position of the new block at the end of the block
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       // int previousOffset = ReadInt( fStackOffset - sizeof(int));
0123       int delBlock = ToInt(p);
0124       int nextBlock = ReadInt(delBlock);
0125       int previousBlock = ReadInt(nextBlock - sizeof(int));
0126       if (nextBlock == fStackOffset) {
0127          // deallocating last allocated
0128          fStackOffset = previousBlock;
0129       } else {
0130          // overwrite previous adr of next block
0131          int nextNextBlock = ReadInt(nextBlock);
0132          WriteInt(nextNextBlock - sizeof(int), previousBlock);
0133          // overwrite head of deleted block
0134          WriteInt(previousBlock, nextNextBlock);
0135       }
0136       fBlockCount--;
0137 
0138 #ifdef DEBUG_ALLOCATOR
0139       CheckConsistency();
0140 #endif
0141 #else
0142       free(p);
0143 #endif
0144       // std::cout << "Block at " << delBlock
0145       //   << " deallocated, fStackOffset = " << fStackOffset << std::endl;
0146    }
0147 
0148    int ReadInt(int offset)
0149    {
0150       int *ip = (int *)(fStack + offset);
0151 
0152       // std::cout << "read " << *ip << " from offset " << offset << std::endl;
0153 
0154       return *ip;
0155    }
0156 
0157    void WriteInt(int offset, int Value)
0158    {
0159 
0160       // std::cout << "writing " << Value << " to offset " << offset << std::endl;
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       // std::cout << "toInt: p = " << p << " fStack = " << (void*) fStack << std::endl;
0171       // VC 7.1 warning:conversion from __w64 int to int
0172       int userBlock = pc - fStack;
0173       return userBlock - sizeof(int); // correct for starting 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          // std::cout << " no more space on stack allocator" << std::endl;
0187          throw StackOverflow();
0188       }
0189    }
0190 
0191    bool CheckConsistency()
0192    {
0193 
0194       // std::cout << "checking consistency for " << fBlockCount << " blocks"<< std::endl;
0195 
0196       // loop over all blocks
0197       int beg = 0;
0198       int end = fStackOffset;
0199       int nblocks = 0;
0200       while (beg < fStackOffset) {
0201          end = ReadInt(beg);
0202 
0203          // std::cout << "beg = " << beg << " end = " << end
0204          //     << " fStackOffset = " << fStackOffset << std::endl;
0205 
0206          int beg2 = ReadInt(end - sizeof(int));
0207          if (beg != beg2) {
0208             // std::cout << "  beg != beg2 " << std::endl;
0209             return false;
0210          }
0211          nblocks++;
0212          beg = end;
0213       }
0214       if (end != fStackOffset) {
0215          // std::cout << " end != fStackOffset" << std::endl;
0216          return false;
0217       }
0218       if (nblocks != fBlockCount) {
0219          // std::cout << "nblocks != fBlockCount" << std::endl;
0220          return false;
0221       }
0222       // std::cout << "Allocator is in consistent state, nblocks = " << nblocks << std::endl;
0223       return true;
0224    }
0225 
0226 private:
0227    unsigned char *fStack;
0228    //   unsigned char fStack[default_size];
0229    int fStackOffset;
0230    int fBlockCount;
0231 };
0232 
0233 class StackAllocatorHolder {
0234 
0235    // t.b.d need to use same trick as  Boost singleton.hpp to be sure that
0236    // StackAllocator is created before main()
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 // Helper base class to delete assignment.
0250 //
0251 // Note that base classes without any data members or virtual functions don't
0252 // cause any runtime overhead.
0253 //
0254 // Assignment is often historically deleted (that was done probably to avoid
0255 // mistakes from accidental re-assignment). Also define destructor and copy
0256 // constructor in this case, according to the rule of five.
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 // templated scaling operator *
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 // templated operator /
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 // templated unary operator -
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 // factor * ABObj
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 // ABObj / factor
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 // -ABObj
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 // ABObj + ABObj
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 // ABObj - ABObj
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 // ABObj * ABObj (only supported for sym * vec)
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 // Matrix inverse of a vector is not possible.
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    Class describing a symmetric matrix of size n.
0431    The size is specified as a run-time argument passed in the
0432    constructor.
0433    The class uses expression templates for the operations and functions.
0434    Only the independent data are kept in the fdata array of size n*(n+1)/2
0435    containing the lower triangular data
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       //     assert(fSize>0);
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       //     std::cout<<"LASymMatrix(const ABObj<sym, LASymMatrix, T>& v)"<<std::endl;
0507       // std::cout<<"allocate "<<fSize<<std::endl;
0508       std::memcpy(fData, v.Obj().Data(), fSize * sizeof(double));
0509       Mndscal(fSize, double(v.f()), fData);
0510       // std::cout<<"fData= "<<fData[0]<<" "<<fData[1]<<std::endl;
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       //     std::cout<<"template<class A, class B, class T> LASymMatrix(const ABObj<sym, ABSum<ABObj<sym, A, T>,
0517       //     ABObj<sym, B, T> > >& sum)"<<std::endl; recursive construction
0518       (*this) = sum.Obj().A();
0519       (*this) += sum.Obj().B();
0520       // std::cout<<"leaving template<class A, class B, class T> LASymMatrix(const ABObj..."<<std::endl;
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       //     std::cout<<"template<class A, class T> LASymMatrix(const ABObj<sym, ABSum<ABObj<sym, LASymMatrix, T>,
0527       //     ABObj<sym, A, T> >,T>& sum)"<<std::endl;
0528 
0529       // recursive construction
0530       // std::cout<<"(*this)=sum.Obj().B();"<<std::endl;
0531       (*this) = sum.Obj().B();
0532       // std::cout<<"(*this)+=sum.Obj().A();"<<std::endl;
0533       (*this) += sum.Obj().A();
0534       // std::cout<<"leaving template<class A, class T> LASymMatrix(const ABObj<sym, ABSum<ABObj<sym,
0535       // LASymMatrix,.."<<std::endl;
0536    }
0537 
0538    template <class A, class T>
0539    LASymMatrix(const ABObj<sym, ABObj<sym, A, T>, T> &something)
0540    {
0541       //     std::cout<<"template<class A, class T> LASymMatrix(const ABObj<sym, ABObj<sym, A, T>, T>&
0542       //     something)"<<std::endl;
0543       (*this) = something.Obj();
0544       (*this) *= something.f();
0545       // std::cout<<"leaving template<class A, class T> LASymMatrix(const ABObj<sym, ABObj<sym, A, T>, T>&
0546       // something)"<<std::endl;
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       //     std::cout<<"template<class A, class T> LASymMatrix(const ABObj<sym, ABSum<ABObj<sym, MatrixInverse<sym,
0567       //     ABObj<sym, LASymMatrix, T>, T>, T>, ABObj<sym, A, T> >, T>& sum)"<<std::endl;
0568 
0569       // recursive construction
0570       (*this) = sum.Obj().B();
0571       (*this) += sum.Obj().A();
0572       // std::cout<<"leaving template<class A, class T> LASymMatrix(const ABObj<sym, ABSum<ABObj<sym,
0573       // LASymMatrix,.."<<std::endl;
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       //     std::cout<<"template<class A, class T> LASymMatrix(const ABObj<sym, ABSum<ABObj<sym,
0583       //     VectorOuterProduct<ABObj<vec, LAVector, T>, T>, T> ABObj<sym, A, T> >,T>& sum)"<<std::endl;
0584 
0585       // recursive construction
0586       (*this) = sum.Obj().B();
0587       (*this) += sum.Obj().A();
0588       // std::cout<<"leaving template<class A, class T> LASymMatrix(const ABObj<sym, ABSum<ABObj<sym,
0589       // LASymMatrix,.."<<std::endl;
0590    }
0591 
0592    LASymMatrix &operator+=(const LASymMatrix &m)
0593    {
0594       //     std::cout<<"LASymMatrix& operator+=(const LASymMatrix& m)"<<std::endl;
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       //     std::cout<<"LASymMatrix& operator-=(const LASymMatrix& m)"<<std::endl;
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       //     std::cout<<"template<class T> LASymMatrix& operator+=(const ABObj<sym, LASymMatrix, T>& m)"<<std::endl;
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       // std::cout<<"fData= "<<fData[0]<<" "<<fData[1]<<std::endl;
0619       return *this;
0620    }
0621 
0622    template <class A, class T>
0623    LASymMatrix &operator+=(const ABObj<sym, A, T> &m)
0624    {
0625       //     std::cout<<"template<class A, class T> LASymMatrix& operator+=(const ABObj<sym, A,T>& m)"<<std::endl;
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       //     std::cout<<"template<class T> LASymMatrix& operator+=(const ABObj<sym, MatrixInverse<sym, ABObj<sym,
0634       //     LASymMatrix, T>, T>, T>& m)"<<std::endl;
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       //     std::cout<<"template<class T> LASymMatrix& operator+=(const ABObj<sym, VectorOuterProduct<ABObj<vec,
0647       //     LAVector, T>, T>, T>&"<<std::endl;
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       // std::cout<<"template<class T> LASymMatrix& operator=(ABObj<sym, LASymMatrix, T>& v)"<<std::endl;
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       // std::cout<<"fData= "<<fData[0]<<" "<<fData[1]<<std::endl;
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       // std::cout<<"template<class A, class T> LASymMatrix& operator=(const ABObj<sym, ABObj<sym, A, T>, T>&
0714       // something)"<<std::endl;
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       // std::cout<<"template<class A, class T> LASymMatrix& operator=(const ABObj<sym, ABObj<sym, A, T>, T>&
0725       // something)"<<std::endl;
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       // std::cout<<"template<class A, class B, class T> LASymMatrix& operator=(const ABObj<sym, ABSum<ABObj<sym, A, T>,
0733       // ABObj<sym, B, T> >,T>& sum)"<<std::endl;
0734       // recursive construction
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       // std::cout<<"template<class A, class T> LASymMatrix& operator=(const ABObj<sym, ABSum<ABObj<sym, LASymMatrix,
0753       // T>, ABObj<sym, A, T> >,T>& sum)"<<std::endl;
0754 
0755       if (fSize == 0 && fData == nullptr) {
0756          // std::cout<<"fSize == 0 && fData == 0"<<std::endl;
0757          (*this) = sum.Obj().B();
0758          (*this) += sum.Obj().A();
0759          (*this) *= sum.f();
0760       } else {
0761          // std::cout<<"creating tmp variable"<<std::endl;
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       // std::cout<<"leaving LASymMatrix& operator=(const ABObj<sym, ABSum<ABObj<sym, LASymMatrix..."<<std::endl;
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       // implement proper copy constructor in case size is different
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       //     std::cout<<"LAVector(const ABObj<LAVector, T>& v)"<<std::endl;
0887       //     std::cout<<"allocate "<<fSize<<std::endl;
0888       std::memcpy(fData, v.Obj().Data(), fSize * sizeof(T));
0889       (*this) *= T(v.f());
0890       //     std::cout<<"fData= "<<fData[0]<<" "<<fData[1]<<std::endl;
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       //     std::cout<<"template<class A, class B, class T> LAVector(const ABObj<ABSum<ABObj<A, T>, ABObj<B, T> > >&
0897       //     sum)"<<std::endl;
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       //     std::cout<<"template<class A, class T> LAVector(const ABObj<ABSum<ABObj<LAVector, T>, ABObj<A, T> >,T>&
0907       //     sum)"<<std::endl;
0908 
0909       // recursive construction
0910       //     std::cout<<"(*this)=sum.Obj().B();"<<std::endl;
0911       (*this) = sum.Obj().B();
0912       //     std::cout<<"(*this)+=sum.Obj().A();"<<std::endl;
0913       (*this) += sum.Obj().A();
0914       (*this) *= double(sum.f());
0915       //     std::cout<<"leaving template<class A, class T> LAVector(const ABObj<ABSum<ABObj<LAVector,.."<<std::endl;
0916    }
0917 
0918    template <class A, class T>
0919    LAVector(const ABObj<vec, ABObj<vec, A, T>, T> &something)
0920    {
0921       //     std::cout<<"template<class A, class T> LAVector(const ABObj<ABObj<A, T>, T>& something)"<<std::endl;
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       //     std::cout<<"template<class T> LAVector(const ABObj<vec, ABProd<ABObj<sym, LASymMatrix, T>, ABObj<vec,
0933       //     LAVector, T> >, T>& prod)"<<std::endl;
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       //     std::cout<<"LAVector& operator+=(const LAVector& m)"<<std::endl;
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       //     std::cout<<"LAVector& operator-=(const LAVector& m)"<<std::endl;
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       //     std::cout<<"template<class T> LAVector& operator+=(const ABObj<LAVector, T>& m)"<<std::endl;
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       //     std::cout<<"fData= "<<fData[0]<<" "<<fData[1]<<std::endl;
0979       return *this;
0980    }
0981 
0982    template <class A, class T>
0983    LAVector &operator+=(const ABObj<vec, A, T> &m)
0984    {
0985       //     std::cout<<"template<class A, class T> LAVector& operator+=(const ABObj<A,T>& m)"<<std::endl;
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       //     std::cout<<"template<class T> LAVector& operator=(ABObj<LAVector, T>& v)"<<std::endl;
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       //     std::cout<<"template<class A, class T> LAVector& operator=(const ABObj<ABObj<A, T>, T>&
1058       //     something)"<<std::endl;
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          //       std::cout<<"creating tmp variable"<<std::endl;
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 // Matrix-vector product
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 ///    LAPACK Algebra functions
1181 ///    specialize the Invert function for LASymMatrix
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 ///    LAPACK Algebra function
1193 ///    specialize the Outer_product function for LAVector;
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 } // namespace Minuit2
1212 
1213 } // namespace ROOT
1214 
1215 #endif // ROOT_Minuit2_MnMatrix