#include "AdvReportConvergenceProcess.hh"

const std::string AdvReportConvergenceProcess::className=std::string("AdvReportConvergenceProcess");

/**
 *  constructor
 *
 *  \param[in] im   the pointer to the immutable data
 *  \param[in] stat the pointer to the convergence stat buffer
 */
AdvReportConvergenceProcess::AdvReportConvergenceProcess(AdvLevmarImmutables *im, AdvConvergenceStat *stat, AdvConvergenceStat *history) {
    this->im = im;
    this->stat=stat;
    this->history=history;
    this->setStreamFlags();
}

/**
 *  destructor
 */
AdvReportConvergenceProcess::~AdvReportConvergenceProcess() {
    this->im=NULL;
    this->stat=NULL;
    this->resetStreamFlags();
};


/**
 *  set IterationCount from a paraeter set
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Int4 AdvReportConvergenceProcess::setIterationCount(const AdvParamSet *p) {
    return p->getInt4(AdvLevmarConsts::ITERATION_COUNT);
}

/**
 *  set R-factor from a paraeter set
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Double AdvReportConvergenceProcess::setRFactor(const AdvParamSet *p) {
    return p->getDouble(AdvLevmarConsts::R_FACTOR);
}

/**
 *  set the norm of residual error from a paraeter set
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Double AdvReportConvergenceProcess::setResidualErrNorm(const AdvParamSet *p) {
    return p->getDouble(AdvLevmarConsts::RESIDUAL_ERR_NORM);
}

/**
 *  set the norm of the gradient of a object function from a paraeter set
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Double AdvReportConvergenceProcess::setGradientNorm(const AdvParamSet *p) {
    return p->getDouble(AdvLevmarConsts::GRADIENT_NORM);
}

/**
 *  set the norm of the difference of fitting parameters from a paraeter set
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Double AdvReportConvergenceProcess::setParamDiffNorm(const AdvParamSet *p) {
    return p->getDouble(AdvLevmarConsts::PARAM_DIFF_NORM);
}

/**
 *  set mu ration i.e. mu/max{ grad_ii; 0 <= i < n }
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Double AdvReportConvergenceProcess::setMuRatio(const AdvParamSet *p) const {
    return p->getDouble(AdvLevmarConsts::MU_RATIO);
}

/**
 *  set the termination stat of fitting from a paraeter set
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
AdvLevmarConsts::LevmarStat AdvReportConvergenceProcess::setTerminationStat(const AdvParamSet *p) {
    return static_cast<AdvLevmarConsts::LevmarStat>(p->getInt4(AdvLevmarConsts::TERMINATION_STAT));
}

/**
 *  get the number times of function evaluations
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Int4 AdvReportConvergenceProcess::setFunctionEvaluations(const AdvParamSet *p) const {
    return p->getInt4(AdvLevmarConsts::FUNCTION_EVALUATIONS);
}

/**
 *  get the number times of Jacobian evaluations
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Int4 AdvReportConvergenceProcess::setJacobianEvaluations(const AdvParamSet *p) const {
    return p->getInt4(AdvLevmarConsts::JACOBIAN_EVALUATIONS);
}

/**
 *  get the number times of linear systems solved
 *
 *  \param[in] p  the pointer to the parameter container the include convergence stat
 */
Int4 AdvReportConvergenceProcess::setLinearSystemsSolved(const AdvParamSet *p) const {
    return p->getInt4(AdvLevmarConsts::LINEAR_SYSTEMS_SOLVED);
}

/**
 *  get the time took for iterations
 */
Int4 AdvReportConvergenceProcess::setIterationTime(const AdvParamSet *p) const {
    return p->getInt4(AdvLevmarConsts::ITERATION_TIME);
}

std::vector<Double> AdvReportConvergenceProcess::setParameterValues(const AdvParamSet *p) const {
    return p->getVector(AdvLevmarConsts::PARAMETER_VALUES);
}

/**
 *  set parameters for output stream
 */
void AdvReportConvergenceProcess::setStreamFlags() {
    this->flags = std::cout.flags();
    std::cout << std::setiosflags(std::ios::boolalpha);
    std::cout << std::setiosflags(std::ios::scientific);

    this->indentWidth=4;
    this->intWidth=5;
    this->doublePrecision=16;               // max 16
    this->doubleWidth=doublePrecision+4+3;  // digits([0-9], doublePrecision) + exponent((-|+)([0-9](3,3)), 4) 
}

/**
 *  set parameters for output stream
 */
void AdvReportConvergenceProcess::resetStreamFlags() {
    std::cout << std::resetiosflags(std::ios::boolalpha);
    std::cout << std::resetiosflags(std::ios::scientific);
    std::cout << std::setw(0);
    std::cout << std::setprecision(6);
    std::cout << std::setiosflags(std::ios::right);
}

#define indent()          std::cout << std::setw(this->indentWidth) << " "
#define space()           std::cout << std::setw(1) << " "
#define doubleHeaderFmt() std::setw(this->doubleWidth) << std::setiosflags(std::ios::right)
#define doubleFmt()       std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::right)
#define intHeaderFmt()    std::setw(this->intWidth) << std::setiosflags(std::ios::right)
#define intFmt()          std::setw(this->intWidth) << std::setiosflags(std::ios::right)

void AdvReportConvergenceProcess::outputConvergenceProcessHeader() {
    std::string dashes = std::string("-----------------------");
    std::string normHeader=std::string("Norm");
    std::string evaluationHeader = std::string("evaluations") ;
    Int4 leftDashLength;
    Int4 rightDashLength;

    // line header 1
    //std::cout << std::setw(this->indentWidth)  << " " ;
    indent() ;
    std::cout << std::setw(10) << " " ;
    space() ;
    std::cout << std::setw(this->doubleWidth) << " " ;
    space() ;
    std::cout << std::setw(this->doubleWidth) << dashes.substr(0, this->doubleWidth);
    std::cout << std::setw(1) << "-" ;
    leftDashLength =(this->doubleWidth-normHeader.size())/2 + ((this->doubleWidth -normHeader.size()) % 2);
    rightDashLength=(this->doubleWidth-normHeader.size())/2;
    std::cout << std::setw(this->doubleWidth) << dashes.substr(0, leftDashLength) + normHeader + dashes.substr(0, rightDashLength);
    std::cout << std::setw(1) << "-" ;
    std::cout << std::setw(this->doubleWidth) << dashes.substr(0, this->doubleWidth);
    space() ;
    std::cout << std::setw(this->doubleWidth) << " ";
    space() ;
    leftDashLength =( (this->intWidth*3+2-evaluationHeader.size())/2 + ((this->intWidth*3+2-evaluationHeader.size())%2)) ;
    rightDashLength=( (this->intWidth*3+2-evaluationHeader.size())/2) ;
    std::cout << std::setw(this->intWidth*3 + 2) << dashes.substr(0, leftDashLength) + evaluationHeader + dashes.substr(0, rightDashLength);
    std::cout << std::endl;

    // line header 2
    indent() ;
    std::cout << std::setw(10) << "iterations" ;
    space() ;
    std::cout << std::setw(this->doubleWidth) << "R-factor";
    space() ;
    //std::cout << std::setw(this->doubleWidth) << AdvLevmarConsts::RESIDUAL_ERR_NORM;
    std::cout << std::setw(this->doubleWidth) << "residu err. (L2)";
    space() ;
    //std::cout << std::setw(this->doubleWidth) << AdvLevmarConsts::GRADIENT_NORM;
    std::cout << std::setw(this->doubleWidth) << "gradient (Inf.)";
    space() ;
    //std::cout << std::setw(this->doubleWidth) << AdvLevmarConsts::PARAM_DIFF_NORM;
    std::cout << std::setw(this->doubleWidth) << "param diff (L2)";
    space() ;
    std::cout << std::setw(this->doubleWidth) << "mu/max{ [J^T J]_ii }" ;
    space() ;
    std::cout << std::setw(this->intWidth) << "func" ;
    space() ;
    std::cout << std::setw(this->intWidth) << "Jac" ;
    space() ;
    std::cout << std::setw(this->intWidth) << "LSS" ;
    space() ;
    std::cout << std::setw(10) << "time (us)";
    space() ;
    std::cout << "stat";
    std::cout << std::endl;

}

/**
 *  output the given status
 *
 *  \param[in] p a data container for convergence stat
 */
void AdvReportConvergenceProcess::outputStat(const AdvParamSet *p) {
    
            indent() ;
            std::cout << std::setw(10) << this->setIterationCount(p);
            space() ;
            std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << this->setRFactor(p);
            space() ;
            std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << this->setResidualErrNorm(p);
            space() ;
            std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << this->setGradientNorm(p);
            space() ;
            std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << this->setParamDiffNorm(p);
            space() ;
            std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << this->setMuRatio(p);
            space() ;
            std::cout << std::setw(this->intWidth) << std::setiosflags(std::ios::right) << this->setFunctionEvaluations(p);
            space() ;
            std::cout << std::setw(this->intWidth) << std::setiosflags(std::ios::right) << this->setJacobianEvaluations(p);
            space() ;
            std::cout << std::setw(this->intWidth) << std::setiosflags(std::ios::right) << this->setLinearSystemsSolved(p);
            space() ;
            std::cout << std::setw(10) << this->setIterationTime(p);
            space() ;
            std::cout << AdvLevmarConsts::TERMINATION_REASON[setTerminationStat(p)];
            std::cout << std::endl;
            std::cout.flush();
}

/**
 *  output the convergence process
 */
void AdvReportConvergenceProcess::outputConvergenceProcess() {

    std::string memberName = std::string("outputConvergenceProcess()");



    // titie
    std::cout << "Convergence Process" << std::endl;
    this->outputConvergenceProcessHeader();

    AdvParamSet *p;
    Int4 prevIterationCount=-1;
    Int4 iterationCount;
    AdvLevmarConsts::LevmarStat terminationStat;
    do {
        //p=this->stat->referLatestStat();
        p=this->stat->pop();
        DebugMessage(className, memberName, __FILE__, __LINE__, "p is NULL:    %s\n", ((p != NULL) ? "true" : "false"));
        DebugMessage(className, memberName, __FILE__, __LINE__, "size of stat:    %d\n", this->stat->size());
        DebugMessage(className, memberName, __FILE__, __LINE__, "p containe ITERATION_COUBT:    %d\n", p->contain(AdvLevmarConsts::ITERATION_COUNT));
        iterationCount = this->setIterationCount(p);
        DebugMessage(className, memberName, __FILE__, __LINE__, "%s: %d\n", AdvLevmarConsts::ITERATION_COUNT.c_str(), iterationCount);
        terminationStat = this->setTerminationStat(p);
        DebugMessage(className, memberName, __FILE__, __LINE__, "%s: %d (%s)\n", AdvLevmarConsts::TERMINATION_STAT.c_str(), terminationStat, AdvLevmarConsts::TERMINATION_REASON[terminationStat].c_str());
        if ( (terminationStat == AdvLevmarConsts::CONTINUE && iterationCount > prevIterationCount) || (terminationStat != AdvLevmarConsts::CONTINUE) ) {
            this->outputStat(p);
            prevIterationCount=iterationCount;
        }
        this->history->push(p);
        DebugMessage(className, memberName, __FILE__, __LINE__, "size of history: %d\n", this->history->size());
    } while ( terminationStat == AdvLevmarConsts::CONTINUE );
    std::cout << std::endl;

}


/**
 *  outpur the termination stat
 *
 *  \param[in] p  parameter set
 */
void AdvReportConvergenceProcess::outputTerminationStat(const AdvParamSet *p) {

    std::cout << std::resetiosflags(std::ios::right);

    std::cout << std::setw(this->indentWidth) << "    " << "Termination Stat" << std::endl;

    std::cout << std::setw(this->indentWidth) << " " << std::setw(this->indentWidth) << " " ;
    std::cout << std::setw(19) << std::setiosflags(std::ios::left) << AdvLevmarConsts::ITERATION_COUNT ;
    std::cout << " : ";
    std::cout << std::setw(this->intWidth) << std::setiosflags(std::ios::left) << this->setIterationCount(p);
    std::cout << std::endl;

    std::cout << std::setw(this->indentWidth) << " " << std::setw(this->indentWidth) << " ";
    std::cout << std::setw(19) << std::setiosflags(std::ios::left) << AdvLevmarConsts::TERMINATION_STAT ;
    std::cout << " : ";
    std::cout << AdvLevmarConsts::TERMINATION_REASON[this->setTerminationStat(p)];
    std::cout << std::endl;

    std::cout << std::setw(this->indentWidth) << " " << std::setw(this->indentWidth) << " ";
    std::cout << std::setw(19) << std::setiosflags(std::ios::left) << AdvLevmarConsts::R_FACTOR ;
    std::cout << " : ";
    std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::left) << this->setRFactor(p);
    std::cout << std::endl;

    std::cout << std::setw(this->indentWidth) << " " << std::setw(this->indentWidth) << " " ;
    std::cout << std::setw(19) << std::setiosflags(std::ios::left) << AdvLevmarConsts::RESIDUAL_ERR_NORM ;
    std::cout << " : ";
    std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::left) << this->setResidualErrNorm(p);
    std::cout << std::endl;

    std::cout << std::setw(this->indentWidth) << " " << std::setw(this->indentWidth) << " ";
    std::cout << std::setw(19) << std::setiosflags(std::ios::left) << AdvLevmarConsts::GRADIENT_NORM ;
    std::cout << " : ";
    std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::left) << this->setGradientNorm(p);
    std::cout << std::endl;

    std::cout << std::setw(this->indentWidth) << " " << std::setw(this->indentWidth) << " ";
    std::cout << std::setw(19) << std::setiosflags(std::ios::left) << AdvLevmarConsts::PARAM_DIFF_NORM ;
    std::cout << " : ";
    std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::left) << this->setParamDiffNorm(p);
    std::cout << std::endl;

    std::cout << std::endl;

    std::cout.flush();
}

/**
 *  output the fitted parameters
 *
 *  \param[in] p  parameter set
 */
void AdvReportConvergenceProcess::outputFittedParam(const AdvParamSet *p) {
    std::string memberName=std::string("outputFittedParam(const AdvParamSet *)");
    std::cout << std::setw(this->indentWidth) << " " << "Values of Fitted Parameters and Their Errors" << std::endl;

    Int4 offset=0;
    Int4 no=0;
    if (this->im->args.funcList.size() == 1) {
        for (std::vector<AdvFuncBase*>::const_iterator fp=this->im->args.funcList.at(0).begin(); fp != this->im->args.funcList.at(0).end(); ++fp) {

            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::string("function");
            std::cout << std::setw(5) << no;
            std::cout << std::setw(2) << ": ";
            std::cout << (*fp)->getName();
            std::cout << std::endl;

            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << std::setiosflags(std::ios::left)  << " ";
            for (UInt4 i=offset; i< offset+(*fp)->getNumberOfParam(); ++i) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(doubleWidth) << std::setiosflags(std::ios::right) << i;
            }
            std::cout << std::endl;

            /* output initial values of fitting parameters */
            //std::cout << std::resetiosflags(std::ios::left);
            std::cout << std::resetiosflags(std::ios::right);
            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << std::setiosflags(std::ios::left)  << "initial";
            for (UInt4 i=offset; i< offset+(*fp)->getNumberOfParam(); ++i) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::right) << this->im->args.param[i];
            }
            std::cout << std::endl;

            /* output fitted values of fitting parameters */
            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << std::setiosflags(std::ios::left)  << "result";
            for (UInt4 i=offset; i< offset+(*fp)->getNumberOfParam(); ++i) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::right) << p->getDouble(AdvLevmarConsts::PARAMETER_VALUES, i);
            }
            std::cout << std::endl;

            /* output estimated values of fitting parameter errors */
            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << std::setiosflags(std::ios::right)  << "error";
            for (UInt4 i=offset; i< offset+(*fp)->getNumberOfParam(); ++i) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::right) << p->getDouble(AdvLevmarConsts::PARAM_ERRORS, i);
            }
            std::cout << std::endl;
            std::cout << std::endl;

            offset += (*fp)->getNumberOfParam();
            ++no;
        }
    } else if (this->im->args.funcList.size() > 1) {
        for (UInt4 i=0; i<this->im->args.funcList.at(0).size(); ++i) {

            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::string("function");
            std::cout << std::setw(5) << no;
            std::cout << std::setw(1) << ":";
            for (UInt4 j=0; j<this->im->args.funcList.size(); ++j) {
                std::cout << " " << this->im->args.funcList.at(j).at(i)->getName();
                std::cout << "(" << j << ")";
            }
            std::cout << std::endl;

            UInt4 last=offset+this->im->args.funcList.at(0).at(i)->getNumberOfParam();

            /* output initial values of fitting parameters */
            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << "seq No.";
            for (UInt4 j=offset; j<last; ++j) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(doubleWidth) << std::setiosflags(std::ios::right) << j;
            }
            std::cout << std::endl;

            /* output initial values of fitting parameters */
            //std::cout << std::resetiosflags(std::ios::left);
            std::cout << std::resetiosflags(std::ios::right);
            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << std::setiosflags(std::ios::left)  << "initial";
            for (UInt4 j=offset; j< last; ++j) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::right) << this->im->args.param[j];
            }
            std::cout << std::endl;

            /* output fitted values of fitting parameters */
            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << std::setiosflags(std::ios::left)  << "result";
            for (UInt4 j=offset; j< last; ++j) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::right) << p->getDouble(AdvLevmarConsts::PARAMETER_VALUES, j);
            }
            std::cout << std::endl;

            /* output estimated values of fitting parameter errors */
            std::cout << std::setw(this->indentWidth*2) << " ";
            std::cout << std::setw(7)  << std::setiosflags(std::ios::right)  << "error";
            for (UInt4 j=offset; j< last; ++j) {
                std::cout << std::setw(1)  << " ";
                std::cout << std::setw(this->doubleWidth) << std::setprecision(this->doublePrecision) << std::setiosflags(std::ios::right) << p->getDouble(AdvLevmarConsts::PARAM_ERRORS, j);
            }
            std::cout << std::endl;
            std::cout << std::endl;

            offset += this->im->args.funcList.at(0).at(i)->getNumberOfParam();;
            ++no;
        }
    } else {
        errorMessage(className, memberName, "never reached: this->im-args.funclist.size=%d\n", this->im->args.funcList.size());
    }
    std::cout.flush();
}

/**
 *  output the covariance matrix for fitting
 *
 *  \param[in] p  parameter set
 */
void AdvReportConvergenceProcess::outputCovarianceMatrix(const AdvParamSet *p) {

    std::cout << std::setw(this->indentWidth) << " " << "Covariance Matrix for Fitteng" << std::endl;

    std::vector< std::vector<Double> > m=p->getMatrix(AdvLevmarConsts::COVARIANCE_MATRIX);
    UInt4 offset=0;
    for (std::vector<AdvFuncBase*>::const_iterator fp=this->im->args.funcList.at(0).begin(); fp != this->im->args.funcList.at(0).end(); ++fp) {
        this->outputMatrix(std::cout, (this->indentWidth)*2, m, 0, m.size(), offset, (*fp)->getNumberOfParam(),
                           false, this->doublePrecision, true, true, 160);
        offset += (*fp)->getNumberOfParam();
    }
}

/**
 *  output the convergence history
 */
void AdvReportConvergenceProcess::outputConvergenceHistory() {
    std::string memberName=std::string("outputConvergnceHistory()");
    DebugMessage(className, memberName, "enter\n");

    AdvParamSet *pp;
    std::vector<Int4> iterationCount;
    //std::vector<Double> fittedParam;
    std::vector< std::vector<Double> > m;
    //std::vector< std::vector<Double> > m = *(new std::vector< std::vector<Double> >(this->im->args.nParam, *(new std::vector<Double>()) ));
    //DebugMessage(className, memberName, "this->history->sise() %u\n", this->history->size());

    for (UInt4 i=0; i<this->history->size(); ++i) {
        DebugMessage(className, memberName, "i=%u\n", i);
        pp=this->history->at(i);
        iterationCount.push_back(this->setIterationCount(pp));
        m.push_back(pp->getVector(AdvLevmarConsts::PARAMETER_VALUES));
        //for (Int4 j=0; j < this->im->args.nParam; ++j) {
        //    m.at(j).push_back(pp->getDouble(AdvLevmarConsts::PARAMETER_VALUES, j));
        //}
    }

    std::cout << std::setw(this->indentWidth) << "    ";
    std::cout << "Convergence History";
    std::cout << std::endl;

    std::cout << std::setw(this->indentWidth) << " " << std::setw(this->indentWidth) << " ";
    std::cout << "Fitting Parameters";
    std::cout << std::endl;

    //this->outputMatrixWithUsersRowHeader(std::cout, (this->indentWidth)*3, m, iterationCount, 0, m.size(), 0, m.at(0).size(), false, this->doublePrecision, true, 200);

    UInt4 offset=0;
    UInt4 no=0;
    for (std::vector<AdvFuncBase*>::const_iterator fp=this->im->args.funcList.at(0).begin(); fp != this->im->args.funcList.at(0).end(); ++fp) {

        std::cout << std::setw(this->indentWidth*3) << " ";
        std::cout << std::string("function");
        std::cout << std::setw(5) << no;
        std::cout << std::setw(2) << ": ";
        std::cout << (*fp)->getName();
        std::cout << std::endl;

        this->outputMatrixWithUsersRowHeader(
            std::cout, (this->indentWidth)*3, m, iterationCount, 0, m.size(), offset, (*fp)->getNumberOfParam(), false, this->doublePrecision, true, 200);
        offset += (*fp)->getNumberOfParam();
        ++no;
    }

    DebugMessage(className, memberName, "exit\n");
}

/**
 *  output the results of the fitting
 */
void AdvReportConvergenceProcess::outputResult() {
    std::string memberName=std::string("outputResult()");
    DebugMessage(className, memberName, "enter\n");

    DebugMessage(className, memberName, "size of histrory %u\n", this->history->size());
    AdvParamSet *p=this->history->referLatestStat();
    std::cout << "Fitting Results" << std::endl;
    this->outputTerminationStat(p);
    this->outputFittedParam(p);
    this->outputCovarianceMatrix(p);
    this->outputConvergenceHistory();
    DebugMessage(className, memberName, "exit\n");
}

/**
 *  Run : report the convergence process
 */
void AdvReportConvergenceProcess::Run() {
    std::string memberName=std::string("Run");
    DebugMessage(className, memberName, "enter\n");

    this->im->output();
    this->outputConvergenceProcess();
    this->outputResult();
    DebugMessage(className, memberName, "exit\n");
}
