#include "QFramework/TQPCA.h"
#include <TMatrixDEigen.h>
#include <TMatrixDSymEigen.h>
#include <iostream>
#include <math.h>
#include "QFramework/TQStringUtils.h"

////////////////////////////////////////////////////////////////////////////////////////////////
//
// TQPCA
// 
// The TQPCA is a improved version of the standard root class TPrincipal. 
// It provides extended functionality, including management of metadata and event weights.
// It is integrated to the HWWAnalysisCode and used by the TQPCAAnalysisJob.
// Interfaces for adding and scaling TQPCA objects are provided and intertwined with 
// the TQSampleDataReader facilities.
// 
////////////////////////////////////////////////////////////////////////////////////////////////

ClassImp(TQPCA)

TQPCA::TQPCA() :
TQNamedTaggable("TQPCA"),
  nDim(0),
  sumWeights(0),
  nEntries(0),
  calculated(false),
  besselCorrection(false),
  vEigenValues(NULL),
  mEigenVectors(NULL)
{
  // default constructor
}

TQPCA::TQPCA(const TString& name, int nDim) :
  TQNamedTaggable(name),
  nDim(nDim),
  sumWeights(0),
  nEntries(0),
  covMatrixA(nDim),
  covMatrixB(nDim),
  calculated(false),
  besselCorrection(false),
  vEigenValues(NULL),
  mEigenVectors(NULL)
{
  // default constructor
}

TQPCA::~TQPCA(){
  // destructor
  this->clear();
}

void TQPCA::useBesselCorrection(bool val){
  // control the use of the Bessel correction
  // for the calculation of the (co)variance,
  // i.e. the use of 1/(n-1) instead of 1/n
  // in the (co)variance formula
  this->besselCorrection = val;
}

void TQPCA::clear(){
  // clear all data
  // the user needs to call TQPCA::init to reinitialize
  // before re-use of the instance is sensible
  this->calculated = false;
  this->covMatrixA.Clear();
  this->covMatrixB.clear();
}

int TQPCA::getNDim(){
  // retrieve the number of dimensions
  return this->nDim;
}

double TQPCA::getSumWeights(){
  // retrieve the total sum of weights
  return this->sumWeights;
}

int TQPCA::getNEntries(){
  // retrieve the total number of entries
  return this->nEntries;
}

TString TQPCA::getDetailsAsString(int/*option*/) {
  // retrieve an info-string 
  std::vector<TString> varnames;
  TString retval = TString::Format("%g entries",this->getSumWeights());
  if(this->getTag("varname",varnames) > 0){
    retval += " in " + TQStringUtils::concat(varnames,",");
  } else {
    retval += TString::Format(" in %d dimensions",this->getNDim());
  }
  return retval;
}

void TQPCA::init(int nDim){
  // initialize the object based on given dimensionality
  this->clear();
  this->nDim = nDim;
  this->nEntries = 0;
  this->sumWeights = 0;
  this->covMatrixA.ResizeTo(this->nDim,this->nDim);
  this->covMatrixB.reserve(this->nDim);

  for(size_t i=0; i<this->nDim; i++){
    covMatrixB[i] = 0;
    for(size_t j=0; j<=this->nDim; j++){
      covMatrixA[i][j] = 0;
    }
  }
}

void TQPCA::print(const TString&/*opts*/){
  // print some information about the object
  std::cout << this->getDetailsAsString() << std::endl;
}

bool TQPCA::fill(double weight, const std::vector<double>& row){
  // fill values from a std::vector<double>
  if(row.size() != this->nDim) return false;
  this->fill(weight,&(row[0]));
  return true;
}
 

void TQPCA::printRawData(){
  this->printMatrix(this->covMatrixA,"covMatrixA");
  std::cout << TQStringUtils::makeBoldWhite("covMatrixB") << " ";
  for(size_t i=0; i<this->nDim; i++){
    std::cout << this->covMatrixB[i] << " ";
  }
  std::cout << std::endl;
}
 

void TQPCA::fill(double weight, const double* row){
  // fill values from an array
  this->sumWeights += weight;
  this->nEntries++;
  for(size_t i=0; i<this->nDim; i++){
    covMatrixB[i] += weight*row[i];
    for(size_t j=0; j<=i; j++){
      covMatrixA[j][i] += weight*row[i]*row[j]; 
    }
  }
}

TMatrixDSym TQPCA::getCovarianceMatrix(){
  // retrieve the covariance matrix
  TMatrixDSym covMatrix(this->nDim);
  double sw = this->sumWeights - this->besselCorrection;
  for(size_t i=0; i<this->nDim; i++){
    for(size_t j=0; j<=i; j++){
      covMatrix[i][j] = (this->covMatrixA[j][i] - (covMatrixB[i]*covMatrixB[j]/sw))/sw;
    }
    for(size_t j=i; j<this->nDim; j++){
      covMatrix[i][j] = (this->covMatrixA[i][j] - (covMatrixB[i]*covMatrixB[j]/sw))/sw;
    }
  }
  return covMatrix;
}


TMatrixDSym TQPCA::getCorrelationMatrix(){
  // retrieve the correlation matrix
  TMatrixDSym corrMatrix = this->getCovarianceMatrix();
  TMatrixDSym covMatrix = this->getCovarianceMatrix();
  // W = 1/W^2 as normalization factor for averages
  for(size_t i=0; i<this->nDim; ++i) {
    for(size_t j=0; j<this->nDim; ++j) {
      // corr[i,j] = cov[i,j] / (s_i * s_j)
      // with s_k = sqrt(cov[k,k]) the standard deviation
      // of variable k
      corrMatrix[i][j] /= sqrt(covMatrix[i][i] * covMatrix[j][j]);
    }
  }
  return corrMatrix;
}

TVectorD TQPCA::getEigenValues(){
  // retrieve the TVectorD of all eigenvectors
  if(!calculated) this->calculate();
  return *this->vEigenValues;
}

double TQPCA::getEigenValue(size_t i){
  // retrieve the i-th eigenvalue as a double
  if(!calculated) this->calculate();
  return (*(this->vEigenValues))[i];
}

TMatrixD TQPCA::getEigenVectors(){
  // retrieve the TMatrixD of all eigenvectors
  if(!calculated) this->calculate();
  return *this->mEigenVectors;
}

TVectorD TQPCA::getEigenVector(size_t i){
  // retrieve the i-th eigenvector as a TVectorD
  if(!calculated) this->calculate();
  TVectorD ev;
  for(size_t j=0; j<this->nDim; j++){
    ev[j] = (*(this->mEigenVectors))[j][i];
  }
  return ev;
}

void TQPCA::clearResults(){
  // delete all matrix operation results and reset the calculation status
  if(this->mEigenVectors) delete this->mEigenVectors;
  if(this->vEigenValues) delete this->vEigenValues;
  this->mEigenVectors = NULL;
  this->vEigenValues = NULL;
  this->calculated = false;
}

void TQPCA::calculate(){
  // calculate the eigenvectors and eigenvalues
  this->clearResults();
  TMatrixDSymEigen covMatrix = this->getCovarianceMatrix(); 
  this->mEigenVectors = new TMatrixD(covMatrix.GetEigenVectors());
  this->vEigenValues = new TVectorD(covMatrix.GetEigenValues());
  this->calculated = true;
}

void TQPCA::calculateFromCorrelationMatrix(){
  // calculate the eigenvectors and eigenvalues
  // from the correlation matrix instead of the covariance matrix
  this->clearResults();
  TMatrixDSymEigen corrMatrix(this->getCorrelationMatrix()); 
  this->mEigenVectors = new TMatrixD(corrMatrix.GetEigenVectors());
  this->vEigenValues = new TVectorD(corrMatrix.GetEigenValues());
  this->calculated = true;
}

bool TQPCA::add(const TQPCA* other, double /*factor*/){
  // add another TQPCA instance to this one
  if(!other) return false;
  return this->add(*other);
}

bool TQPCA::add(const TQPCA& other, double factor){
  // add two objects of type TQPCA
  this->clearResults();
  if(other.nDim != this->nDim) return false;

  this->sumWeights += other.sumWeights*factor;
  this->nEntries += other.nEntries;

  for(size_t i=0; i<this->nDim; i++){
    covMatrixB[i] += other.covMatrixB[i]*factor;
    for(size_t j=0; j<=i; j++){
      covMatrixA[i][j] += other.covMatrixA[i][j]*factor;
    }
  }
  return true;
}

void TQPCA::scale(double factor){
  // scale the entries with some given factor
  this->clearResults();
  this->sumWeights *= factor;

  for(size_t i=0; i<this->nDim; i++){
    this->covMatrixB[i] *= factor;
    for(size_t j=0; j<=i; j++){
      covMatrixA[i][j] *= factor;
    }
  }
}

void TQPCA::printMatrix(const TMatrixD& mat, const TString& title){
  // print any matrix to std::cout, nicely formatted
  std::cout << TQStringUtils::makeBoldWhite(TQStringUtils::fixedWidth(title,12,"c"));
  for(size_t i=0; i<this->nDim; i++){
    std::cout << TQStringUtils::fixedWidth(this->getTagStringDefault(TString::Format("varname.%d",(int)i),TString::Format("var%d",(int)i)),12,"r") << " ";
  }
  std::cout << std::endl;
  for(size_t i=0; i<this->nDim; i++){
    std::cout <<TQStringUtils::fixedWidth(this->getTagStringDefault(TString::Format("varname.%d",(int)i),TString::Format("var%d",(int)i)),12,"r") << " ";
    for(size_t j=0; j<this->nDim; j++){
      std::cout << TQStringUtils::fixedWidth(TString::Format("%g",mat[i][j]),12,"r");
    }
    std::cout << std::endl;
  }
}

void TQPCA::printCovarianceMatrix(){
  // print the covariance matrix to std::cout, nicely formatted
  TMatrixDSym cov(this->getCovarianceMatrix());
  this->printMatrix(cov,"cov(i,j)");
}

void TQPCA::printCorrelationMatrix(){
  // print the correlation matrix to std::cout, nicely formatted
  TMatrixDSym corr(this->getCorrelationMatrix());
  this->printMatrix(corr,"corr(i,j)");
}

void TQPCA::printResults(){
  // print the results to std::cout, nicely formatted
  if(!this->calculated) this->calculate();
  std::cout << TQStringUtils::makeBoldWhite(TQStringUtils::fixedWidth("PCA",12,"r"));
  for(size_t j=0; j<this->nDim; j++){
    std::cout << TQStringUtils::fixedWidth(TString::Format("#%d",(int)j),12,"c") << " ";
  }
  std::cout << std::endl;
  std::cout << TQStringUtils::fixedWidth("eigenvalue",12,"r");
  for(size_t j=0; j<this->nDim; j++){
    std::cout << TQStringUtils::fixedWidth(TString::Format("%g",(*(this->vEigenValues))[j]),12,"r") << " ";
  }
  std::cout << std::endl;
  for(size_t i=0; i<this->nDim; i++){
    std::cout <<TQStringUtils::fixedWidth(this->getTagStringDefault(TString::Format("varname.%d",(int)i),TString::Format("var%d",(int)i)),12,"r") << " ";
    for(size_t j=0; j<this->nDim; j++){
      std::cout << TQStringUtils::fixedWidth(TString::Format("%g",(*(this->mEigenVectors))[i][j]),12,"r") << " ";
    }
    std::cout << std::endl;
  }
}

double TQPCA::getVariance(size_t i){
  // retrieve the gaussian variance on variable i
  if(i>=this->nDim) return std::numeric_limits<double>::quiet_NaN();
  TMatrixD covMatrix(this->getCovarianceMatrix());
  return covMatrix[i][i];
}

double TQPCA::getMean(size_t i){
  // retrieve the weighted mean
  if(i>=this->nDim) return std::numeric_limits<double>::quiet_NaN();
  return this->covMatrixB[i]/this->sumWeights;
}

double TQPCA::getPCVariance(size_t i){
  // retrieve the gaussian variance on principal component i
  if(i>=this->nDim) return std::numeric_limits<double>::quiet_NaN();
  if(!this->calculated) this->calculate();
  return (*(this->vEigenValues))[i];
}

double TQPCA::getPCMean(size_t i){
  // retrieve the mean of the principal component i
  if(i>=this->nDim) return std::numeric_limits<double>::quiet_NaN();
  if(!this->calculated) this->calculate();
  double mean = 0;
  for(size_t j=0; j<this->nDim; j++){
    mean += this->getMean(j) * (*(this->mEigenVectors))[j][i];
  }
  return mean;
}

TString TQPCA::getProjection(size_t index, bool normalize){
  // retrieve the arithmetic expression for the projection
  // onto the principal component with the given index 
  // if normalize is true, the prefactors will be normalized
  // to their respective dimensional weighted averages
  if(index >= this->nDim) return "";
  if(!this->calculated) this->calculate();
  TString retval;
  for(size_t i=0; i<this->nDim; i++){
    if(normalize){
      retval += TString::Format("%g",(*(this->mEigenVectors))[i][index] / sqrt(this->getPCVariance(index)));
    } else {
      retval += TString::Format("%g",(*(this->mEigenVectors))[i][index]);
    }
    retval += " * ";
    if(normalize){
      retval += "( ";
      retval += this->getTagStringDefault(TString::Format("varexpression.%d",(int)i),"Var1");
      retval += TString::Format(" - %g",this->getMean(i));
      retval += " )";
    } else {
      retval += this->getTagStringDefault(TString::Format("varexpression.%d",(int)i),"Var1");
    }
    if(i < this->nDim-1) retval += " + ";
  }
  return retval;
}

double TQPCA::evaluateProjection(size_t index, const std::vector<double>& values, bool normalize){
  // evaluate the projection of the given coordinates
  // onto the principal component with the given index 
  // if normalize is true, the prefactors will be normalized
  // to their respective dimensional weighted averages
  if(index >= this->nDim) return std::numeric_limits<double>::quiet_NaN();
  if(!this->calculated) this->calculate();
  double retval = 0;
  for(size_t i=0; i<this->nDim; i++){
    if(normalize){
      retval += (*(this->mEigenVectors))[i][index] / sqrt(this->getPCVariance(index)) * (values[i] - this->getMean(i));
    } else {
      retval += (*(this->mEigenVectors))[i][index] * values[i];
    }
  }
  return retval;
}


TString TQPCA::getReverseProjection(size_t index, bool normalize){
  // retrieve the arithmetic expression for the projection
  // onto the input variable with the given index
  // if normalize is true, the prefactors will be normalized
  // to their respective dimensional weighted averages
  if(index >= this->nDim) return "";
  if(!this->calculated) this->calculate();
  TString retval;
  for(size_t i=0; i<this->nDim; i++){
    if(normalize){
      retval += TString::Format("%g",(*(mEigenVectors))[index][i] * sqrt(this->getPCVariance(i)));
    } else {
      retval += TString::Format("%g",(*(mEigenVectors))[index][i]);
    }
    retval += TString::Format(" * e%d",(int)i);
    if(i < this->nDim-1) retval += " + ";
  }
  return retval;
}

double TQPCA::evaluateReverseProjection(size_t index, const std::vector<double>& values, bool normalize){
  // evaluate the projection of the given coordinates
  // onto the input variable with the given index
  // if normalize is true, the prefactors will be normalized
  // to their respective dimensional weighted averages
  if(index >= this->nDim) return std::numeric_limits<double>::quiet_NaN();
  if(!this->calculated) this->calculate();
  double retval = normalize ? this->getMean(index) : 0;
  for(size_t i=0; i<this->nDim; i++){
    if(normalize){
      retval += (*(mEigenVectors))[index][i] * sqrt(this->getPCVariance(i)) * values[i];
    } else {
      retval += (*(mEigenVectors))[index][i] * values[i];
    }
  }
  return retval;
}


TString TQPCA::getHistogramDefinition2D(size_t iX, size_t iY, size_t nBinsXplus, size_t nBinsXminus, size_t nBinsYplus, size_t nBinsYminus){
  // retrieve the definition string for a 2d histogram
  return TString::Format("TH2F('pc_%d_%d','',%d,%g,%g,%d,%g,%g) << (%s : 'Principal Component %d', %s : 'Principal Component %d')",
                         (int)iX,(int)iY,
                         (int)(nBinsXplus+nBinsXminus),
                         this->getMean(iX) - nBinsXminus*sqrt(this->getVariance(iX)),
                         this->getMean(iX) + nBinsXplus *sqrt(this->getVariance(iX)),
                         (int)(nBinsXplus+nBinsXminus),
                         this->getMean(iY) - nBinsYminus*sqrt(this->getVariance(iY)),
                         this->getMean(iY) + nBinsYplus *sqrt(this->getVariance(iY)),
                         this->getProjection(iX,false).Data(),
                         (int)iX,
                         this->getProjection(iY,false).Data(),
                         (int)iY);
}

TString TQPCA::getNormalizedHistogramDefinition2D(size_t iX, size_t iY, size_t nBinsX, double xMin, double xMax, size_t nBinsY, double yMin, double yMax){
  // retrieve the definition string for a 2d histogram in normalized coordinates
  return TString::Format("TH2F('pc_%d_%d','',%d,%g,%g,%d,%g,%g) << (%s : 'Principal Component %d', %s : 'Principal Component %d')",
                         (int)iX,(int)iY,
                         (int)(nBinsX),
                         xMin,
                         xMax,
                         (int)(nBinsY),
                         yMin,
                         yMax,
                         this->getProjection(iX,true).Data(),
                         (int)iX,
                         this->getProjection(iY,true).Data(),
                         (int)iY);
}

TString TQPCA::getHistogramDefinition(size_t i, size_t nBinsPlus, size_t nBinsMinus){
  // retrieve the definition string for a histogram
  return TString::Format("TH1F('pc_%d','',%d,%g,%g) << (%s : 'Principal Component %d')",
                         (int)i,
                         (int)(nBinsPlus+nBinsMinus),
                         this->getMean(i) - nBinsMinus*sqrt(this->getVariance(i)),
                         this->getMean(i) + nBinsPlus *sqrt(this->getVariance(i)),
                         this->getProjection(i,false).Data(),
                         (int)i);
}

TString TQPCA::getNormalizedHistogramDefinition(size_t i, size_t nBins, double min, double max){
  // retrieve the definition string for a histogram in normalized coordinates
  return TString::Format("TH1F('pc_%d','',%d,%g,%g) << (%s : 'Principal Component %d')",
                         (int)i,
                         (int)(nBins),
                         min,
                         max,
                         this->getProjection(i,true).Data(),
                         (int)i);
}

bool TQPCA::exportEigenSystemTags(TQTaggable& tags, size_t iX, size_t iY, double nSigma1, double nSigma2, bool normalize){
  // export the TQPlotter tags required to draw the Eigen coordinate system
  if(std::max(iX,iY) >= this->nDim) return false;
  if(!this->calculated) this->calculate();

  std::vector<double> vals(this->nDim, 0.0);

  tags.setTagBool("axis.0.show",true);
  tags.setTagString("axis.0.title",TString::Format("PC %d",(int)iX));
  vals[iX] = 0; 
  tags.setTagDouble("axis.0.xMin",this->evaluateReverseProjection(iX,vals,normalize));
  tags.setTagDouble("axis.0.yMin",this->evaluateReverseProjection(iY,vals,normalize));
  vals[iX] = nSigma1; 
  tags.setTagDouble("axis.0.xMax",this->evaluateReverseProjection(iX,vals,normalize));
  tags.setTagDouble("axis.0.yMax",this->evaluateReverseProjection(iY,vals,normalize));
  vals[iX] = 0;
  tags.setTagDouble("axis.0.wMin",0);
  tags.setTagDouble("axis.0.wMax",nSigma1);
 
  tags.setTagBool("axis.1.show",true);
  tags.setTagString("axis.1.title",TString::Format("PC %d",(int)iY));
  vals[iY] = 0; 
  tags.setTagDouble("axis.1.xMin",this->evaluateReverseProjection(iX,vals,normalize));
  tags.setTagDouble("axis.1.yMin",this->evaluateReverseProjection(iY,vals,normalize));
  vals[iY] = nSigma2; 
  tags.setTagDouble("axis.1.xMax",this->evaluateReverseProjection(iX,vals,normalize));
  tags.setTagDouble("axis.1.yMax",this->evaluateReverseProjection(iY,vals,normalize));
  vals[iY] = 0;
  tags.setTagDouble("axis.1.wMin",0);
  tags.setTagDouble("axis.1.wMax",nSigma2);

  return true;
}

bool TQPCA::exportEigenSystemTags(TQTaggable& tags, size_t iX, size_t iY, double nSigma1, double nSigma2, double normX, double normY){
  // export the TQPlotter tags required to draw the Eigen coordinate system
  if(std::max(iX,iY) >= this->nDim) return false;
  if(!this->calculated) this->calculate();

  std::vector<double> vals(this->nDim, 0.0);
  bool normalize = false;

  tags.setTagBool("axis.0.show",true);
  tags.setTagString("axis.0.title",TString::Format("PC %d",(int)iX));
  vals[iX] = 0; 
  tags.setTagDouble("axis.0.xMin",this->evaluateReverseProjection(iX,vals,normalize) * normX);
  tags.setTagDouble("axis.0.yMin",this->evaluateReverseProjection(iY,vals,normalize) * normY);
  vals[iX] = nSigma1; 
  tags.setTagDouble("axis.0.xMax",this->evaluateReverseProjection(iX,vals,normalize) * normX);
  tags.setTagDouble("axis.0.yMax",this->evaluateReverseProjection(iY,vals,normalize) * normY);
  vals[iX] = 0;
  tags.setTagDouble("axis.0.wMin",0);
  tags.setTagDouble("axis.0.wMax",fabs(nSigma1));
 
  tags.setTagBool("axis.1.show",true);
  tags.setTagString("axis.1.title",TString::Format("PC %d",(int)iY));
  vals[iY] = 0; 
  tags.setTagDouble("axis.1.xMin",this->evaluateReverseProjection(iX,vals,normalize) * normX);
  tags.setTagDouble("axis.1.yMin",this->evaluateReverseProjection(iY,vals,normalize) * normY);
  vals[iY] = nSigma2; 
  tags.setTagDouble("axis.1.xMax",this->evaluateReverseProjection(iX,vals,normalize) * normX);
  tags.setTagDouble("axis.1.yMax",this->evaluateReverseProjection(iY,vals,normalize) * normY);
  vals[iY] = 0;
  tags.setTagDouble("axis.1.wMin",0);
  tags.setTagDouble("axis.1.wMax",fabs(nSigma2));

  return true;
}

TQTaggable* TQPCA::getEigenSystemTags(size_t iX, size_t iY, double nSigma1, double nSigma2, bool normalize){
  // export the TQPlotter tags required to draw the Eigen coordinate system
  TQTaggable* tags = new TQTaggable();
  this->exportEigenSystemTags(*tags,iX,iY,nSigma1,nSigma2, normalize);
  return tags;
}

TString TQPCA::getEigenSystemTagsAsString(size_t iX, size_t iY, double nSigma1,double nSigma2,bool normalize){
  // export the TQPlotter tags required to draw the Eigen coordinate system
  TQTaggable tags;
  this->exportEigenSystemTags(tags,iX,iY,nSigma1,nSigma2,normalize);
  return tags.exportTagsAsString();
}

TQTaggable* TQPCA::getEigenSystemTags(size_t iX, size_t iY, double nSigma1, double nSigma2, double normX, double normY){
  // export the TQPlotter tags required to draw the Eigen coordinate system
  TQTaggable* tags = new TQTaggable();
  this->exportEigenSystemTags(*tags,iX,iY,nSigma1,nSigma2, normX, normY);
  return tags;
}

TString TQPCA::getEigenSystemTagsAsString(size_t iX, size_t iY, double nSigma1,double nSigma2, double normX, double normY){
  // export the TQPlotter tags required to draw the Eigen coordinate system
  TQTaggable tags;
  this->exportEigenSystemTags(tags,iX,iY,nSigma1,nSigma2, normX, normY);
  return tags.exportTagsAsString();
}
 TQPCA.cxx:1
 TQPCA.cxx:2
 TQPCA.cxx:3
 TQPCA.cxx:4
 TQPCA.cxx:5
 TQPCA.cxx:6
 TQPCA.cxx:7
 TQPCA.cxx:8
 TQPCA.cxx:9
 TQPCA.cxx:10
 TQPCA.cxx:11
 TQPCA.cxx:12
 TQPCA.cxx:13
 TQPCA.cxx:14
 TQPCA.cxx:15
 TQPCA.cxx:16
 TQPCA.cxx:17
 TQPCA.cxx:18
 TQPCA.cxx:19
 TQPCA.cxx:20
 TQPCA.cxx:21
 TQPCA.cxx:22
 TQPCA.cxx:23
 TQPCA.cxx:24
 TQPCA.cxx:25
 TQPCA.cxx:26
 TQPCA.cxx:27
 TQPCA.cxx:28
 TQPCA.cxx:29
 TQPCA.cxx:30
 TQPCA.cxx:31
 TQPCA.cxx:32
 TQPCA.cxx:33
 TQPCA.cxx:34
 TQPCA.cxx:35
 TQPCA.cxx:36
 TQPCA.cxx:37
 TQPCA.cxx:38
 TQPCA.cxx:39
 TQPCA.cxx:40
 TQPCA.cxx:41
 TQPCA.cxx:42
 TQPCA.cxx:43
 TQPCA.cxx:44
 TQPCA.cxx:45
 TQPCA.cxx:46
 TQPCA.cxx:47
 TQPCA.cxx:48
 TQPCA.cxx:49
 TQPCA.cxx:50
 TQPCA.cxx:51
 TQPCA.cxx:52
 TQPCA.cxx:53
 TQPCA.cxx:54
 TQPCA.cxx:55
 TQPCA.cxx:56
 TQPCA.cxx:57
 TQPCA.cxx:58
 TQPCA.cxx:59
 TQPCA.cxx:60
 TQPCA.cxx:61
 TQPCA.cxx:62
 TQPCA.cxx:63
 TQPCA.cxx:64
 TQPCA.cxx:65
 TQPCA.cxx:66
 TQPCA.cxx:67
 TQPCA.cxx:68
 TQPCA.cxx:69
 TQPCA.cxx:70
 TQPCA.cxx:71
 TQPCA.cxx:72
 TQPCA.cxx:73
 TQPCA.cxx:74
 TQPCA.cxx:75
 TQPCA.cxx:76
 TQPCA.cxx:77
 TQPCA.cxx:78
 TQPCA.cxx:79
 TQPCA.cxx:80
 TQPCA.cxx:81
 TQPCA.cxx:82
 TQPCA.cxx:83
 TQPCA.cxx:84
 TQPCA.cxx:85
 TQPCA.cxx:86
 TQPCA.cxx:87
 TQPCA.cxx:88
 TQPCA.cxx:89
 TQPCA.cxx:90
 TQPCA.cxx:91
 TQPCA.cxx:92
 TQPCA.cxx:93
 TQPCA.cxx:94
 TQPCA.cxx:95
 TQPCA.cxx:96
 TQPCA.cxx:97
 TQPCA.cxx:98
 TQPCA.cxx:99
 TQPCA.cxx:100
 TQPCA.cxx:101
 TQPCA.cxx:102
 TQPCA.cxx:103
 TQPCA.cxx:104
 TQPCA.cxx:105
 TQPCA.cxx:106
 TQPCA.cxx:107
 TQPCA.cxx:108
 TQPCA.cxx:109
 TQPCA.cxx:110
 TQPCA.cxx:111
 TQPCA.cxx:112
 TQPCA.cxx:113
 TQPCA.cxx:114
 TQPCA.cxx:115
 TQPCA.cxx:116
 TQPCA.cxx:117
 TQPCA.cxx:118
 TQPCA.cxx:119
 TQPCA.cxx:120
 TQPCA.cxx:121
 TQPCA.cxx:122
 TQPCA.cxx:123
 TQPCA.cxx:124
 TQPCA.cxx:125
 TQPCA.cxx:126
 TQPCA.cxx:127
 TQPCA.cxx:128
 TQPCA.cxx:129
 TQPCA.cxx:130
 TQPCA.cxx:131
 TQPCA.cxx:132
 TQPCA.cxx:133
 TQPCA.cxx:134
 TQPCA.cxx:135
 TQPCA.cxx:136
 TQPCA.cxx:137
 TQPCA.cxx:138
 TQPCA.cxx:139
 TQPCA.cxx:140
 TQPCA.cxx:141
 TQPCA.cxx:142
 TQPCA.cxx:143
 TQPCA.cxx:144
 TQPCA.cxx:145
 TQPCA.cxx:146
 TQPCA.cxx:147
 TQPCA.cxx:148
 TQPCA.cxx:149
 TQPCA.cxx:150
 TQPCA.cxx:151
 TQPCA.cxx:152
 TQPCA.cxx:153
 TQPCA.cxx:154
 TQPCA.cxx:155
 TQPCA.cxx:156
 TQPCA.cxx:157
 TQPCA.cxx:158
 TQPCA.cxx:159
 TQPCA.cxx:160
 TQPCA.cxx:161
 TQPCA.cxx:162
 TQPCA.cxx:163
 TQPCA.cxx:164
 TQPCA.cxx:165
 TQPCA.cxx:166
 TQPCA.cxx:167
 TQPCA.cxx:168
 TQPCA.cxx:169
 TQPCA.cxx:170
 TQPCA.cxx:171
 TQPCA.cxx:172
 TQPCA.cxx:173
 TQPCA.cxx:174
 TQPCA.cxx:175
 TQPCA.cxx:176
 TQPCA.cxx:177
 TQPCA.cxx:178
 TQPCA.cxx:179
 TQPCA.cxx:180
 TQPCA.cxx:181
 TQPCA.cxx:182
 TQPCA.cxx:183
 TQPCA.cxx:184
 TQPCA.cxx:185
 TQPCA.cxx:186
 TQPCA.cxx:187
 TQPCA.cxx:188
 TQPCA.cxx:189
 TQPCA.cxx:190
 TQPCA.cxx:191
 TQPCA.cxx:192
 TQPCA.cxx:193
 TQPCA.cxx:194
 TQPCA.cxx:195
 TQPCA.cxx:196
 TQPCA.cxx:197
 TQPCA.cxx:198
 TQPCA.cxx:199
 TQPCA.cxx:200
 TQPCA.cxx:201
 TQPCA.cxx:202
 TQPCA.cxx:203
 TQPCA.cxx:204
 TQPCA.cxx:205
 TQPCA.cxx:206
 TQPCA.cxx:207
 TQPCA.cxx:208
 TQPCA.cxx:209
 TQPCA.cxx:210
 TQPCA.cxx:211
 TQPCA.cxx:212
 TQPCA.cxx:213
 TQPCA.cxx:214
 TQPCA.cxx:215
 TQPCA.cxx:216
 TQPCA.cxx:217
 TQPCA.cxx:218
 TQPCA.cxx:219
 TQPCA.cxx:220
 TQPCA.cxx:221
 TQPCA.cxx:222
 TQPCA.cxx:223
 TQPCA.cxx:224
 TQPCA.cxx:225
 TQPCA.cxx:226
 TQPCA.cxx:227
 TQPCA.cxx:228
 TQPCA.cxx:229
 TQPCA.cxx:230
 TQPCA.cxx:231
 TQPCA.cxx:232
 TQPCA.cxx:233
 TQPCA.cxx:234
 TQPCA.cxx:235
 TQPCA.cxx:236
 TQPCA.cxx:237
 TQPCA.cxx:238
 TQPCA.cxx:239
 TQPCA.cxx:240
 TQPCA.cxx:241
 TQPCA.cxx:242
 TQPCA.cxx:243
 TQPCA.cxx:244
 TQPCA.cxx:245
 TQPCA.cxx:246
 TQPCA.cxx:247
 TQPCA.cxx:248
 TQPCA.cxx:249
 TQPCA.cxx:250
 TQPCA.cxx:251
 TQPCA.cxx:252
 TQPCA.cxx:253
 TQPCA.cxx:254
 TQPCA.cxx:255
 TQPCA.cxx:256
 TQPCA.cxx:257
 TQPCA.cxx:258
 TQPCA.cxx:259
 TQPCA.cxx:260
 TQPCA.cxx:261
 TQPCA.cxx:262
 TQPCA.cxx:263
 TQPCA.cxx:264
 TQPCA.cxx:265
 TQPCA.cxx:266
 TQPCA.cxx:267
 TQPCA.cxx:268
 TQPCA.cxx:269
 TQPCA.cxx:270
 TQPCA.cxx:271
 TQPCA.cxx:272
 TQPCA.cxx:273
 TQPCA.cxx:274
 TQPCA.cxx:275
 TQPCA.cxx:276
 TQPCA.cxx:277
 TQPCA.cxx:278
 TQPCA.cxx:279
 TQPCA.cxx:280
 TQPCA.cxx:281
 TQPCA.cxx:282
 TQPCA.cxx:283
 TQPCA.cxx:284
 TQPCA.cxx:285
 TQPCA.cxx:286
 TQPCA.cxx:287
 TQPCA.cxx:288
 TQPCA.cxx:289
 TQPCA.cxx:290
 TQPCA.cxx:291
 TQPCA.cxx:292
 TQPCA.cxx:293
 TQPCA.cxx:294
 TQPCA.cxx:295
 TQPCA.cxx:296
 TQPCA.cxx:297
 TQPCA.cxx:298
 TQPCA.cxx:299
 TQPCA.cxx:300
 TQPCA.cxx:301
 TQPCA.cxx:302
 TQPCA.cxx:303
 TQPCA.cxx:304
 TQPCA.cxx:305
 TQPCA.cxx:306
 TQPCA.cxx:307
 TQPCA.cxx:308
 TQPCA.cxx:309
 TQPCA.cxx:310
 TQPCA.cxx:311
 TQPCA.cxx:312
 TQPCA.cxx:313
 TQPCA.cxx:314
 TQPCA.cxx:315
 TQPCA.cxx:316
 TQPCA.cxx:317
 TQPCA.cxx:318
 TQPCA.cxx:319
 TQPCA.cxx:320
 TQPCA.cxx:321
 TQPCA.cxx:322
 TQPCA.cxx:323
 TQPCA.cxx:324
 TQPCA.cxx:325
 TQPCA.cxx:326
 TQPCA.cxx:327
 TQPCA.cxx:328
 TQPCA.cxx:329
 TQPCA.cxx:330
 TQPCA.cxx:331
 TQPCA.cxx:332
 TQPCA.cxx:333
 TQPCA.cxx:334
 TQPCA.cxx:335
 TQPCA.cxx:336
 TQPCA.cxx:337
 TQPCA.cxx:338
 TQPCA.cxx:339
 TQPCA.cxx:340
 TQPCA.cxx:341
 TQPCA.cxx:342
 TQPCA.cxx:343
 TQPCA.cxx:344
 TQPCA.cxx:345
 TQPCA.cxx:346
 TQPCA.cxx:347
 TQPCA.cxx:348
 TQPCA.cxx:349
 TQPCA.cxx:350
 TQPCA.cxx:351
 TQPCA.cxx:352
 TQPCA.cxx:353
 TQPCA.cxx:354
 TQPCA.cxx:355
 TQPCA.cxx:356
 TQPCA.cxx:357
 TQPCA.cxx:358
 TQPCA.cxx:359
 TQPCA.cxx:360
 TQPCA.cxx:361
 TQPCA.cxx:362
 TQPCA.cxx:363
 TQPCA.cxx:364
 TQPCA.cxx:365
 TQPCA.cxx:366
 TQPCA.cxx:367
 TQPCA.cxx:368
 TQPCA.cxx:369
 TQPCA.cxx:370
 TQPCA.cxx:371
 TQPCA.cxx:372
 TQPCA.cxx:373
 TQPCA.cxx:374
 TQPCA.cxx:375
 TQPCA.cxx:376
 TQPCA.cxx:377
 TQPCA.cxx:378
 TQPCA.cxx:379
 TQPCA.cxx:380
 TQPCA.cxx:381
 TQPCA.cxx:382
 TQPCA.cxx:383
 TQPCA.cxx:384
 TQPCA.cxx:385
 TQPCA.cxx:386
 TQPCA.cxx:387
 TQPCA.cxx:388
 TQPCA.cxx:389
 TQPCA.cxx:390
 TQPCA.cxx:391
 TQPCA.cxx:392
 TQPCA.cxx:393
 TQPCA.cxx:394
 TQPCA.cxx:395
 TQPCA.cxx:396
 TQPCA.cxx:397
 TQPCA.cxx:398
 TQPCA.cxx:399
 TQPCA.cxx:400
 TQPCA.cxx:401
 TQPCA.cxx:402
 TQPCA.cxx:403
 TQPCA.cxx:404
 TQPCA.cxx:405
 TQPCA.cxx:406
 TQPCA.cxx:407
 TQPCA.cxx:408
 TQPCA.cxx:409
 TQPCA.cxx:410
 TQPCA.cxx:411
 TQPCA.cxx:412
 TQPCA.cxx:413
 TQPCA.cxx:414
 TQPCA.cxx:415
 TQPCA.cxx:416
 TQPCA.cxx:417
 TQPCA.cxx:418
 TQPCA.cxx:419
 TQPCA.cxx:420
 TQPCA.cxx:421
 TQPCA.cxx:422
 TQPCA.cxx:423
 TQPCA.cxx:424
 TQPCA.cxx:425
 TQPCA.cxx:426
 TQPCA.cxx:427
 TQPCA.cxx:428
 TQPCA.cxx:429
 TQPCA.cxx:430
 TQPCA.cxx:431
 TQPCA.cxx:432
 TQPCA.cxx:433
 TQPCA.cxx:434
 TQPCA.cxx:435
 TQPCA.cxx:436
 TQPCA.cxx:437
 TQPCA.cxx:438
 TQPCA.cxx:439
 TQPCA.cxx:440
 TQPCA.cxx:441
 TQPCA.cxx:442
 TQPCA.cxx:443
 TQPCA.cxx:444
 TQPCA.cxx:445
 TQPCA.cxx:446
 TQPCA.cxx:447
 TQPCA.cxx:448
 TQPCA.cxx:449
 TQPCA.cxx:450
 TQPCA.cxx:451
 TQPCA.cxx:452
 TQPCA.cxx:453
 TQPCA.cxx:454
 TQPCA.cxx:455
 TQPCA.cxx:456
 TQPCA.cxx:457
 TQPCA.cxx:458
 TQPCA.cxx:459
 TQPCA.cxx:460
 TQPCA.cxx:461
 TQPCA.cxx:462
 TQPCA.cxx:463
 TQPCA.cxx:464
 TQPCA.cxx:465
 TQPCA.cxx:466
 TQPCA.cxx:467
 TQPCA.cxx:468
 TQPCA.cxx:469
 TQPCA.cxx:470
 TQPCA.cxx:471
 TQPCA.cxx:472
 TQPCA.cxx:473
 TQPCA.cxx:474
 TQPCA.cxx:475
 TQPCA.cxx:476
 TQPCA.cxx:477
 TQPCA.cxx:478
 TQPCA.cxx:479
 TQPCA.cxx:480
 TQPCA.cxx:481
 TQPCA.cxx:482
 TQPCA.cxx:483
 TQPCA.cxx:484
 TQPCA.cxx:485
 TQPCA.cxx:486
 TQPCA.cxx:487
 TQPCA.cxx:488
 TQPCA.cxx:489
 TQPCA.cxx:490
 TQPCA.cxx:491
 TQPCA.cxx:492
 TQPCA.cxx:493
 TQPCA.cxx:494
 TQPCA.cxx:495
 TQPCA.cxx:496
 TQPCA.cxx:497
 TQPCA.cxx:498
 TQPCA.cxx:499
 TQPCA.cxx:500
 TQPCA.cxx:501
 TQPCA.cxx:502
 TQPCA.cxx:503
 TQPCA.cxx:504
 TQPCA.cxx:505
 TQPCA.cxx:506
 TQPCA.cxx:507
 TQPCA.cxx:508
 TQPCA.cxx:509
 TQPCA.cxx:510
 TQPCA.cxx:511
 TQPCA.cxx:512
 TQPCA.cxx:513
 TQPCA.cxx:514
 TQPCA.cxx:515
 TQPCA.cxx:516
 TQPCA.cxx:517
 TQPCA.cxx:518
 TQPCA.cxx:519
 TQPCA.cxx:520
 TQPCA.cxx:521
 TQPCA.cxx:522
 TQPCA.cxx:523
 TQPCA.cxx:524
 TQPCA.cxx:525
 TQPCA.cxx:526
 TQPCA.cxx:527
 TQPCA.cxx:528
 TQPCA.cxx:529
 TQPCA.cxx:530
 TQPCA.cxx:531
 TQPCA.cxx:532
 TQPCA.cxx:533
 TQPCA.cxx:534
 TQPCA.cxx:535
 TQPCA.cxx:536
 TQPCA.cxx:537
 TQPCA.cxx:538
 TQPCA.cxx:539
 TQPCA.cxx:540
 TQPCA.cxx:541
 TQPCA.cxx:542
 TQPCA.cxx:543
 TQPCA.cxx:544
 TQPCA.cxx:545
 TQPCA.cxx:546
 TQPCA.cxx:547
 TQPCA.cxx:548
 TQPCA.cxx:549
 TQPCA.cxx:550
 TQPCA.cxx:551
 TQPCA.cxx:552
 TQPCA.cxx:553
 TQPCA.cxx:554
 TQPCA.cxx:555
 TQPCA.cxx:556
 TQPCA.cxx:557
 TQPCA.cxx:558
 TQPCA.cxx:559
 TQPCA.cxx:560
 TQPCA.cxx:561
 TQPCA.cxx:562
 TQPCA.cxx:563
 TQPCA.cxx:564
 TQPCA.cxx:565
 TQPCA.cxx:566
 TQPCA.cxx:567
 TQPCA.cxx:568
 TQPCA.cxx:569
 TQPCA.cxx:570
 TQPCA.cxx:571
 TQPCA.cxx:572
 TQPCA.cxx:573
 TQPCA.cxx:574
 TQPCA.cxx:575
 TQPCA.cxx:576
 TQPCA.cxx:577
 TQPCA.cxx:578
 TQPCA.cxx:579
 TQPCA.cxx:580
 TQPCA.cxx:581
 TQPCA.cxx:582
 TQPCA.cxx:583
 TQPCA.cxx:584
 TQPCA.cxx:585
 TQPCA.cxx:586
 TQPCA.cxx:587
 TQPCA.cxx:588
 TQPCA.cxx:589
 TQPCA.cxx:590
 TQPCA.cxx:591