// MutKalmanTrack.C 
//
// Kalman track for muon tracker: implementation file
//---------------------------------------------------------------------

#include <iostream>

#include "TClonesArray.h"
#include "TMatrixD.h"
#include "TVectorD.h"
#include "TRandom.h"

#include "dMutArrayParams.h" // to be included in "dMuoTracksClass.h"????
#include "dMuoTracksClass.h"
#include "MutKalmanTrack.h"
#include "MutKalmanTrackFitParam.h"
#include "MutKalmanTrackHit.h"

#define MUPLUS 5
#define MUMINUS 6


// Prototypes for product of 3 matrices: internal methods
TMatrixD* AtBCptr(TMatrixD A, TMatrixD B, TMatrixD C);
TMatrixD AtBC(TMatrixD* A, TMatrixD* B, TMatrixD* C);
TMatrixD ABtC(TMatrixD* A, TMatrixD* B, TMatrixD* C);
TMatrixD* ABCtptr(TMatrixD A, TMatrixD B, TMatrixD C);
//TMatrixD* ABCt(TMatrixD* A, TMatrixD* B, TMatrixD* C);

ClassImp(MutKalmanTrack) // Class implementation in ROOT context

  //__________________________________________________________________________
 MutKalmanTrack::MutKalmanTrack(const MutKalmanTrack& Track)
{
  // Copy constructor
  // Track parameters at vertex
  fTrackParamAtVertex = Track.fTrackParamAtVertex;
  // TClonesArray for track hits, with 10 hits at the beginning
  fTrackHitsPtr = new TClonesArray("MutKalmanTrackHit", 10);
  (Track.fTrackHitsPtr)->Compress(); // to make easier the copy loop
  MutKalmanTrackHit *oldTrackHit;
  for (Int_t hit = 0; hit < (Track.fTrackHitsPtr)->GetEntriesFast(); hit++) {
    oldTrackHit =
      (MutKalmanTrackHit*) ((Track.fTrackHitsPtr)->UncheckedAt(hit));
    new ((*fTrackHitsPtr)[hit]) MutKalmanTrackHit(*oldTrackHit);
  }
  fChi2 = Track.fChi2;
  return;
}

  //__________________________________________________________________________
MutKalmanTrack& MutKalmanTrack::operator=(const MutKalmanTrack& Track)
{
  // Assignment operator
  // Delete the objects pointed to, if not empty
  if (fTrackHitsPtr) {fTrackHitsPtr->Delete(); delete fTrackHitsPtr;}
  // Track parameters at vertex
  fTrackParamAtVertex = Track.fTrackParamAtVertex;
  // TClonesArray for track hits, with 10 hits at the beginning
  fTrackHitsPtr = new TClonesArray("MutKalmanTrackHit", 10);
  (Track.fTrackHitsPtr)->Compress(); // to make easier the copy loop
  MutKalmanTrackHit *oldTrackHit;
  for (Int_t hit = 0; hit < (Track.fTrackHitsPtr)->GetEntriesFast(); hit++) {
    oldTrackHit =
      (MutKalmanTrackHit*) ((Track.fTrackHitsPtr)->UncheckedAt(hit));
    new ((*fTrackHitsPtr)[hit]) MutKalmanTrackHit(*oldTrackHit);
  }
  fChi2 = Track.fChi2;
  // Return the pointer to the object
  return (*this);
}

  //__________________________________________________________________________
 MutKalmanTrack::~MutKalmanTrack()
{
  // Destructor
  fTrackHitsPtr->Delete();
  delete fTrackHitsPtr;
  fTrackHitsPtr = NULL;
  return;
}

  //__________________________________________________________________________
 MutKalmanTrack::MutKalmanTrack(Int_t TrackNumber, TABLE_HEAD_ST* Mumhits_h, MUMHITS_ST* Mumhits, Double_t SigmaR, Double_t SigmaRPhi)
{
  // Constructor from the Geant track with track number "TrackNumber".
  // One needs the PISA hit table, and more explicitly:
  // * a pointer to the header of this table, "Mumhits_h",
  // * a pointer to this table, "Mumhits",
  // * the Gaussian error for R, "SigmaR",
  // * R times the Gaussian error for Phi, "SigmaRPhi"
  Double_t cosPhi, phi, phiTrue, r, rTrue, sCur, sinPhi,
    xPrime, xTrue, yPrime, yTrue;
  Int_t charge = 0;
  Int_t numberOfPisaHits, pisaHitNumber, trackHitNumber;
  MUMHITS_ST* pGeantHit;
  MutKalmanTrackHit *trackHit;
  TMatrixD covMeas(2,2);
  TMatrixD dMeasDXY(2,2);
  Int_t printLevel = (MutKalmanTrackFitParam::Instance())->GetPrintLevel();
  // The field "fTrackParamAtVertex" is constructed automatically.
  // TClonesArray for track hits, with 10 hits at the beginning
  fTrackHitsPtr = new TClonesArray("MutKalmanTrackHit", 10);
  // Loop over the hits in the table
  // access to "Mumhits_h" data through "get" methods????
  numberOfPisaHits = Mumhits_h->nok; // number of hits in the table
  if (printLevel >= 1) {
    cout << "Geant track number : " << TrackNumber
	 << " from PISA " << numberOfPisaHits << " hits" << endl;
  }
  trackHitNumber = 0;
  for (pisaHitNumber = 0; pisaHitNumber < numberOfPisaHits; pisaHitNumber++) {
    pGeantHit = &(Mumhits[pisaHitNumber]);
    // access to "pGeantHit" data through "get" methods????
    // Test whether the hit belongs to the track and the track is a muon track
    if ((pGeantHit->track == TrackNumber) &&
	((pGeantHit->pid == MUPLUS) || (pGeantHit->pid == MUMINUS))) {
      // Yes: one adds one hit to the track
      if (pGeantHit->pid == MUPLUS) charge = 1;
      if (pGeantHit->pid == MUMINUS) charge = -1;
      trackHit = new ((*fTrackHitsPtr)[trackHitNumber]) MutKalmanTrackHit(2);
      // with the right data members
      trackHit->SetTrack(this);
      // Z
      trackHit->SetZ(pGeantHit->x[2]);
      // X and Y from X1=R and Y1=RPhi with random values around the true ones
      // according to the covariance matrix
      xTrue = pGeantHit->x[0];
      yTrue = pGeantHit->x[1];
      rTrue = TMath::Sqrt(xTrue * xTrue + yTrue * yTrue);
      phiTrue = TMath::ATan2(yTrue, xTrue);
      r = gRandom->Gaus(rTrue, SigmaR);
      phi = gRandom->Gaus(phiTrue, (SigmaRPhi / rTrue));
      cosPhi = TMath::Cos(phi);
      sinPhi = TMath::Sin(phi);
//       trackHit->SetMeas(r * cosPhi, r * sinPhi);
      // Measurements = Y1, X1
      Double_t y1 = r * (sinPhi * TMath::Cos(phiTrue) -
			 cosPhi * TMath::Sin(phiTrue));
      Double_t x1 = r * (sinPhi * TMath::Sin(phiTrue) +
			 cosPhi * TMath::Cos(phiTrue));
//       trackHit->SetMeas(rTrue * (phi-phiTrue), r);
      trackHit->SetMeas2(y1, x1);
      // Covariance matrix for measurements
//       // use matrix multiplication????
//       covMeas(0,0) = (xTrue * xTrue * SigmaR * SigmaR +
// 		    yTrue * yTrue * SigmaRPhi * SigmaRPhi) / rTrue / rTrue;
//       covMeas(0,1) = covMeas(1,0) = xTrue * yTrue *
// 	(SigmaR * SigmaR - SigmaRPhi * SigmaRPhi) / rTrue / rTrue;
//       covMeas(1,1) = (yTrue * yTrue * SigmaR * SigmaR +
// 		    xTrue * xTrue * SigmaRPhi * SigmaRPhi) / rTrue / rTrue;
      covMeas(0,0) = SigmaRPhi * SigmaRPhi;
      covMeas(0,1) = covMeas(1,0) = 0.0;
      covMeas(1,1) = SigmaR * SigmaR;
      trackHit->SetCovMeas(&covMeas);
      // Matrix for derivatives of measurements with respect to X and Y
      dMeasDXY(0,0) = -TMath::Sin(phiTrue); // d(R*Phi)/dX
      dMeasDXY(0,1) = TMath::Cos(phiTrue); // d(R*Phi)/dY
      dMeasDXY(1,0) = dMeasDXY(0,1); // dR/dX
      dMeasDXY(1,1) = -dMeasDXY(0,0); // dR/dY
      trackHit->SetDMeasDXY(&dMeasDXY);
      // True parameters
      sCur = 1.0 / (charge * TMath::Sqrt(pGeantHit->p[0] * pGeantHit->p[0] +
					 pGeantHit->p[1] * pGeantHit->p[1] +
					 pGeantHit->p[2] * pGeantHit->p[2]));
      xPrime = pGeantHit->p[0] / pGeantHit->p[2];
      yPrime = pGeantHit->p[1] / pGeantHit->p[2];
      trackHit->SetTrueParam(sCur, xPrime, yPrime, xTrue, yTrue);
      if (printLevel >= 1) {
	cout << "KalmanTrack hit number : " << trackHitNumber
	     << " from PISA hit number : " << pisaHitNumber << endl;
	cout << "X = " << pGeantHit->x[0]
	     << "; Y = " << pGeantHit->x[1]
	     << "; Z = " << pGeantHit->x[2] << endl;
	cout << "t = " << pGeantHit->t << "; e = " << pGeantHit->e << endl;
	cout << "pX = " << pGeantHit->p[0]
	     << "; pY = " << pGeantHit->p[1]
	     << "; pZ = " << pGeantHit->p[2] << endl;
	cout << "track = " << pGeantHit->track
	     << "; pid = " << pGeantHit->pid
	     << "; plane(A:1N-2S/O:1-8/S:1-3/P:1-3) = "
	     << pGeantHit->plane << endl;
      }
      // increment trackHitNumber
      trackHitNumber++;
    }
  }
  fChi2 = 0.0;
  return;
}

  //__________________________________________________________________________
 MutKalmanTrack::MutKalmanTrack(long int NHits, float Xmeas[MAXPLANES][3], float CathodeAngle[MAXPLANES], float Res[MAXPLANES][2])
{
  // Constructor from the same information
  // as given to Fortran subroutine "mum_geafit"
  Double_t cosCathAngle, sig2, sinCathAngle;
  Int_t hitNumber;
  MutKalmanTrackHit *trackHit;
  TMatrixD *covMeas, *dMeasDXY;
  // TClonesArray for track hits, with "NHits" hits
  fTrackHitsPtr = new TClonesArray("MutKalmanTrackHit", NHits);
  // Loop over hits
  for (hitNumber = 0; hitNumber < NHits; hitNumber++) {
    // track hit added to the track, with 2 measurements
    trackHit = new ((*fTrackHitsPtr)[hitNumber]) MutKalmanTrackHit(2);
    // with the right data members
    trackHit->SetTrack(this);
    // Z
    trackHit->SetZ(Double_t(Xmeas[hitNumber][2]));
    // measurements, in the same order as for "mum_geafit",
    // i.e. index = 0 (1) for "bad" ("good") measurement
    trackHit->SetMeas2(Double_t(Xmeas[hitNumber][0]),
		       Double_t(Xmeas[hitNumber][1]));
    // variance of measurements
    covMeas = trackHit->GetCovMeas();
    sig2 = Double_t(Res[hitNumber][0]);
    (*covMeas)(0, 0) = sig2 * sig2;
    sig2 = Double_t(Res[hitNumber][1]);
    (*covMeas)(1, 1) = sig2 * sig2;
    // derivatives of measurements with respect to X and Y????
    dMeasDXY = trackHit->GetDMeasDXY();
    cosCathAngle = TMath::Cos(Double_t(CathodeAngle[hitNumber]));
    sinCathAngle = TMath::Sin(Double_t(CathodeAngle[hitNumber]));
    (*dMeasDXY)(0, 0) = cosCathAngle;
    (*dMeasDXY)(0, 1) = sinCathAngle;
    (*dMeasDXY)(1, 0) = -sinCathAngle;
    (*dMeasDXY)(1, 1) = cosCathAngle;
    // true parameters????
  }
  fChi2 = 0.0;
  return;
}

  //__________________________________________________________________________
// MutKalmanTrack::MutKalmanTrack(dMuoTracksClass* MuoTrack)
// // MutKalmanTrack::MutKalmanTrack(dMuoTracksClass* MuoTrack, dMutCathodeClustersN_ST* dMutCathodeClustersN[NumberOfArms][NumberOfStations][NumberOfOctants][NumberOfHalfOctants][3][NumberOfCathodePlanes], DMUTCSCGEOM_ST* dMutCSCGeom)
// {
//   // Constructor from one "dMuoTracksClass" object
//   // Problems if one wants to use dMutCathodeClustersN in argument!!!!
//   Int_t arm, nMuoHits, kalmanHitNumber;
//   MutKalmanTrackHit *kalmanHit;
//   // pointer to structure for TrackHits
//   TrackHits_ST* muoHits = &(MuoTrack->TrackHits);
//   // number of hits in MuoTrack
//   nMuoHits = muoHits->nhitstot;
//   // What to do if not enough hits,
//   // as compared to dMuoFindTracksPar->min_track_hits????
//   // Arm number
//   arm = MuoTrack->arm;
//   // What to do if invalid arm number????
//   // TClonesArray for track hits, with 16 hits at the beginning
//   fTrackHitsPtr = new TClonesArray("MutKalmanTrackHit", 16);
//   // Loop over hits in MuoTrack
//   kalmanHitNumber = 0;
//   // loop over stations
//   for (Int_t st = 0; st < NumberOfStations; st++) {
//     // loop over track hits in station
//     Int_t nStHits = MuoTrack->TrackHits.nhits[st];
//     cout << nStHits << " hits in station " << st << endl;
//     for (Int_t stHit = 0; stHit < nStHits; stHit++) {
//       // nothing if not cathode signal
//       if (MuoTrack->TrackHits.signaltype[stHit][st] != 1) continue;
//       // Add a new MutKalmanTrackHit
//       kalmanHit = new ((*fTrackHitsPtr)[kalmanHitNumber]) MutKalmanTrackHit(1);
//       // with the right data members
//       kalmanHit->SetTrack(this);
//       // filled from this track hit in this station in MuoTrack
//       kalmanHit->FillWithHitFromDMuoTracksClass(MuoTrack, st, stHit);
//       kalmanHitNumber++;
//     }
//   }
//   fChi2 = 0.0;
//   return;
// }

  //__________________________________________________________________________
 void MutKalmanTrack::Fit(MutKalmanTrackParam *StartParam, Double_t StartZ)
{
  // Complete fit of the current MutKalmanTrack
  // Argument for starting parameters????
  // Return argument for success/failure????
  // Assumes that the MutKalmanTrack hits are sorted
  // according to increasing values of abs(Z)
  Filter(StartParam, StartZ); // Filter
  Smoother(); // Smoother
  return;
}

  //__________________________________________________________________________
 void MutKalmanTrack::Filter(MutKalmanTrackParam *StartParam, Double_t StartZ)
{
  // Kalman filter on the current MutKalmanTrack
  // Argument for starting parameters????
  //    (parameters and covariance/weight matrix)
  // Return argument for success/failure????
  // Assumes that the MutKalmanTrack hits are sorted
  // according to increasing values of abs(Z)

  Int_t printLevel = (MutKalmanTrackFitParam::Instance())->GetPrintLevel();
  fChi2 = 0.0; // important for successive fits
  MutKalmanTrackHit *hit = this->LastHit();
  // Loop over track hits from the last one
  // sorting hits according to abs(Z)????
  MutKalmanTrackParam *previousParam = StartParam;
  Double_t previousZ = StartZ;
  if (printLevel >= 2) {
    cout << endl;
    cout << "**MutKalmanTrack::Filter" << endl;
    cout << "StartZ = " << StartZ << endl;
    cout << "StartParam" << endl;
    StartParam->Print();
  }

  while (hit) {
    // Predicted parameters,
    //   and first derivatives or covariance matrix,
    // should be returned by something like ERTRAK

    MutKalmanTrackHit* prevHit = hit->Prev();
    if (!hit) continue;
    // extrapolation
    MutKalmanTrackParam* extrapParam = (previousParam)->
      ExtrapBackward(previousZ, hit->GetZ(),
		     hit->GetPropagatorParDeriv());
    
    // assuming that we have the full covariance matrix
    
    ////////////////////////////
    // Prediction
    // Ppred = F * Pfit (Pfit of the previous plan)
    // C_(k/k-1) = F_(k-1) * C_(k-1) * F_(k-1)^{Trans} + MS_(k-1) calculeted in MutKalmanTrackHit
    TMatrixD Pfit(5, 1); // Fitted state vector
    TMatrixDColumn(Pfit,0)       = *(previousParam->GetParameters()); // Convertion type TVector in type TMatrix
    TMatrixD Ppred(5, 1); // Predicted state vector
    TMatrixDColumn(Ppred,0)       = *(extrapParam->GetParameters()); // Convertion type TVector in type TMatrix
    (hit->GetTrackParam(0))->SetParameters(&Ppred); // transfert of the predicted state vector in MutKalmanTrackHit
    (hit->GetTrackParam(0))->SetCovarianceMatrix(extrapParam->GetCovarianceMatrix()); // transfert of the predicted state vector in MutKalmanTrackHit

    //////////////////////////////////////////////////////////  
    // Theorical Fitted state vector (Weighted means formalism)
    //   Pfit = (C_(k/k-1)^{-1} + H^{Trans} * G * H)^{-1} * (C_(k/k-1)^{-1} * Ppred + H^{Trans} * G * Meas)
    TMatrixD CInv (TMatrixD::kInverted,
		   *(hit->GetTrackParam(0)->GetCovarianceMatrix())); // Inverse of the transport covariance Matrix with multi scattering
    TMatrixD Meas (hit->GetNMeas(), 1); // Measured vector
    TMatrixDColumn(Meas,0)       = *(hit->GetMeas());
    TMatrixD H (hit->GetNMeas(), 5);   // H Linear Matrix which ought to passe from the work space to measur space, 
//     H(0, 3) = 1.0;
//     H(1, 4) = 1.0;
    // simpler with submatrix????
    // faster if 0 in H taken into account explicitly in formal calculation????
    TMatrixD *dMeasDXY = hit->GetDMeasDXY();
    for (Int_t meas = 0; meas < hit->GetNMeas(); meas++) {
      H(meas, 3) = (*dMeasDXY)(meas, 0);
      H(meas, 4) = (*dMeasDXY)(meas, 1);
      //     H(0, 3) = (*dMeasDXY)(0, 0);
      //     H(0, 4) = (*dMeasDXY)(0, 1);
      //     H(1, 3) = (*dMeasDXY)(1, 0);
      //     H(1, 4) = (*dMeasDXY)(1, 1);
    }
    TMatrixD G (TMatrixD::kInverted, *(hit->GetCovMeas())); // Inverse of the covariance matrix
    TMatrixD CP (CInv, TMatrixD::kMult, Ppred);
    TMatrixD HGM                 = AtBC (&H, &G, &Meas);
    CP                          += HGM;
    TMatrixD HGH = AtBC (&H, &G, &H);
    HGH                         += CInv;
    TMatrixD *Cnew               = new TMatrixD(TMatrixD::kInverted, HGH); // Update of the covariance for the next step
    (hit->GetTrackParam(1))->SetCovarianceMatrix(Cnew); // transfert of the update convariance matrix in MutKalmanTrackHit
    Pfit                         = TMatrixD(*Cnew, TMatrixD::kMult, CP);
    (hit->GetTrackParam(1))->SetParameters(&Pfit); // transfert of the fitted state vector in MutKalmanTrackHit
 
    /////////////////////////////////////////////////////
    // Theorical value of the Chi2 incrementation
    //  DeltaChi2 = (Pfit - Pexp)^{Trans}     * C^{-1} *  (Pfit - Pexp)
    //            + (H * Pfit - Meas)^{Trans} *   G    *  (H * Pfit - Meas);
    TMatrixD DiffPP(5, 1);
    DiffPP                       = Pfit;
    DiffPP                      -= Ppred;
    TMatrixD HP (H, TMatrixD::kMult, Pfit);
    TMatrixD DiffPM (hit->GetNMeas(), 1);
    DiffPM                       =  HP;
    DiffPM                      -= Meas;
    TMatrixD *Chi2P          = AtBCptr (DiffPP, CInv, DiffPP);
    hit->SetChi2P(Chi2P);
    TMatrixD *Chi2M          = AtBCptr (DiffPM, G, DiffPM);
    hit->SetChi2M(Chi2M);
    AddToChi2(hit->GetChi2M(), hit->GetChi2P());

    // Prepare next step
    previousParam                = hit->GetTrackParam(1);
    previousZ                    = hit->GetZ();
    hit                          = prevHit;

    delete Cnew;
    Cnew =  NULL;
    delete extrapParam;
    extrapParam = NULL;
  }
  if (printLevel >= 2) {
    cout << endl;
    cout << "**MutKalmanTrack::Filter" << endl;
    cout << "MutKalmanTrack printout after Filter, before Smoother" << endl;
    this->Print();
  }
  return;
}

//__________________________________________________________________________
 void MutKalmanTrack::Smoother()
{
  // Kalman smoother on the current MutKalmanTrack
  // Return argument for success/failure????
  // Assumes that the MutKalmanTrack hits are sorted
  // according to increasing values of abs(Z)

  MutKalmanTrackHit *prevHit = this->FirstHit();
  // For first hit: smoother result = filter result
  MutKalmanTrackParam *prevParam = prevHit->GetTrackParam(2);
  *prevParam = *(prevHit->GetTrackParam(1));
  MutKalmanTrackHit *hit = prevHit->Next();

  // We are in the hit (k+1) and we are going to the hit k
  while (hit) {

    ///////////////////////////////
    // Smooth state vector
    // Psmo_{k} = Pfit_{k} + Cnew * FTrans * C_{k/k+1}^{-1} * (Psmo_{k+1} - Ppred_{k/k+1})
    // Cn/k = Cnew + Ak * (Cn/k+1 - Ck/k+1)  Ak^{Trans}
    // Ak = Cnew * FTrans * Cnew^{-1}
    TMatrixD Pfit(5, 1); // Fitted state vector
    TMatrixDColumn(Pfit,0)       = *(hit->GetTrackParam(1))->GetParameters(); // Convertion type TVector in type TMatrix
    TMatrixD CInv (TMatrixD::kInverted, *(prevHit->GetTrackParam(0)->GetCovarianceMatrix())); // Inverse of the transport covariance Matrix with multi scattering
    TMatrixD Psmo (5, 1); // Smooth state vector
    TMatrixDColumn(Psmo,0)       = *((prevHit->GetTrackParam(2))->GetParameters()); // Convertion type TVector in type TMatrix
    
    TMatrixD Ppred (5, 1);
    TMatrixDColumn(Ppred,0) = *((prevHit->GetTrackParam(0))->GetParameters()); // Predicted value of the state vector
    TMatrixD CFC = ABtC (((hit->GetTrackParam(1))->GetCovarianceMatrix()), (prevHit->GetPropagatorParDeriv()), &CInv);

    TMatrixD DiffPP (5, 1);
    DiffPP                       = Psmo;
    DiffPP                      -= Ppred;
    TMatrixD CFCDiffPP (CFC, TMatrixD::kMult, DiffPP);
    
    Psmo                         = Pfit;
    Psmo                        += CFCDiffPP;
    
//     TVectorD *PsmoV = new TVectorD(5);
//     *PsmoV                       = TMatrixDColumn(Psmo,0);
    (hit->GetTrackParam(2))->SetParameters(&Psmo); // Update of the smoothe state vector

    TMatrixD *DiffMat = new TMatrixD(*prevParam->GetCovarianceMatrix());
    *DiffMat -= *(prevHit->GetTrackParam(0))->GetCovarianceMatrix();
    TMatrixD *Cov = ABCtptr (CFC, *DiffMat, CFC);
    *Cov += *(hit->GetTrackParam(1))->GetCovarianceMatrix();
    (hit->GetTrackParam(2))->SetCovarianceMatrix(Cov); // Update of the covariance matrix of the smoothed state vector
    
    // Prepare next step
    prevParam                    = hit->GetTrackParam(2);
    prevHit = hit;
    hit                          = hit->Next();

    delete DiffMat;
    DiffMat = NULL;
    delete Cov;
    Cov = NULL;
  }

  return;
}

  //__________________________________________________________________________
 void MutKalmanTrack::Print()
{
  // Print method
  cout << "***** MutKalmanTrack::Print" << endl;
  cout << "TrackParamAtVertex";
  fTrackParamAtVertex.Print();
  cout << "fChi2 = " << fChi2 << endl;
  // Loop over track hits
  MutKalmanTrackHit *hit = this->FirstHit();
  while (hit) {
    hit->Print();
    hit = hit->Next();
  }
  return;
}

  //__________________________________________________________________________
TMatrixD AtBC(TMatrixD* A, TMatrixD* B, TMatrixD* C)
{
  TMatrixD AtB (*A, TMatrixD::kTransposeMult, *B);
  return (TMatrixD (AtB, TMatrixD::kMult, *C));
}

TMatrixD* AtBCptr(TMatrixD A, TMatrixD B, TMatrixD C)
{
  TMatrixD AtB (A, TMatrixD::kTransposeMult, B);
  return (new TMatrixD (AtB, TMatrixD::kMult, C));
}

//   //__________________________________________________________________________
// TMatrixD* AtBC(TMatrixD *A, TMatrixD *B, TMatrixD *C)
// {
//   TMatrixD *AtB  = new TMatrixD(*A, TMatrixD::kTransposeMult, *B);
//   return (new TMatrixD(*AtB, TMatrixD::kMult, *C));
// }

  //__________________________________________________________________________
TMatrixD ABtC(TMatrixD* A, TMatrixD* B, TMatrixD* C)
{
  TMatrixD BtC(*B, TMatrixD::kTransposeMult, *C);
  return (TMatrixD (*A, TMatrixD::kMult, BtC));
}


  //__________________________________________________________________________
//TMatrixD* ABCt(TMatrixD *A, TMatrixD *B, TMatrixD *C)
//{
//  TMatrixD *Ct  = new TMatrixD(TMatrixD::kTransposed, *C);
//  TMatrixD *AB = new TMatrixD(*A, TMatrixD::kMult, *B);
//  return (new TMatrixD(*AB, TMatrixD::kMult, Ct));
//}

TMatrixD* ABCtptr(TMatrixD A, TMatrixD B, TMatrixD C)
{
  TMatrixD Ct  (TMatrixD::kTransposed, C);
  TMatrixD BCt  (B, TMatrixD::kMult, Ct);
  return (new TMatrixD (A, TMatrixD::kMult, BCt));
}


ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.