#include "AdvBSpline.hh"

const string AdvBSpline::className=string("AdvBSpline");

/* key for parameters */
const string AdvBSpline::ORDER=string("order");
const string AdvBSpline::AUTOMATIC_KNOTS=string("automatic knots");
const string AdvBSpline::USE_UNIFORM_BREAK_POINTS=string("use uniform break points");
const string AdvBSpline::NUMBER_OF_BREAK_POINTS=string("number of break points");
const string AdvBSpline::BREAK_POINTS=string("break points");

/* default values of paramters */
const UInt4 AdvBSpline::DEFAULT_ORDER_OF_POLYNOMINAL=3;
const Bool  AdvBSpline::DEFAULT_AUTOMATIC_KNOTS=false;
const Bool  AdvBSpline::DEFAULT_USE_UNIFORM_BREAK_POINTS=true;
const UInt4 AdvBSpline::DEFAULT_NUMBER_OF_BREAK_POINTS=10;

/**
 *  constructor
 */
AdvBSpline::AdvBSpline() : AdvMethod( string("B-spline") ) {
}

/**
 *  destructor
 */
AdvBSpline::~AdvBSpline() {
}

AdvParamSet AdvBSpline::setDefaultParam(ElementContainer &src) {

    AdvParamSet *param = new AdvParamSet();

    param->add(ORDER,                    DEFAULT_ORDER_OF_POLYNOMINAL    );
    param->add(AUTOMATIC_KNOTS,          DEFAULT_AUTOMATIC_KNOTS         );
    param->add(USE_UNIFORM_BREAK_POINTS, DEFAULT_USE_UNIFORM_BREAK_POINTS);
    param->add(NUMBER_OF_BREAK_POINTS,   DEFAULT_NUMBER_OF_BREAK_POINTS  );

    return *param;
}

Bool AdvBSpline::checkParam(ElementContainer &src, AdvDomain &domain, AdvParamSet &param) {

    const string memberName=string("checkParam(ElementContainer &, AdvDomain &, AdvParamSet &)");

    string xKey=src.PutXKey();
    string yKey=src.PutYKey();
    string eKey=src.PutEKey();

    UInt4 lower=domain.getLowerBoundID();
    UInt4 upper=domain.getUpperBoundID();
    UInt4 number_of_data_points=upper-lower+1;

    if (number_of_data_points <= 0) {
        errorMessage(className, memberName, "no domain for the method: number of source data points=", number_of_data_points);
        return false;
    }

    size_t user_specified_order;
    if ( param.contain(ORDER) ) {
        user_specified_order=param.getUInt4(ORDER);
        infoMessage(className, memberName, "the highest order of B-Spline polynominals is user-specified value: %d\n", user_specified_order);
        if ( user_specified_order <= 0 ) {
            warningMessage(className, memberName, "the highest order of B-spline polynominals must be larger than 0.");
            warningMessage(className, memberName, "the user-defined order %u.", user_specified_order);
            warningMessage(className, memberName, "set the highest order of B-Spline polynominals to the the default value: %u\n", DEFAULT_ORDER_OF_POLYNOMINAL);
        }
    } else {
        infoMessage(className, memberName, "set the highest order of B-Spline basis by the default value: %u\n", DEFAULT_ORDER_OF_POLYNOMINAL);
    }

    //Bool automatic_knots;
    if ( param.contain( AUTOMATIC_KNOTS ) ) {
        infoMessage(className, memberName, "the functonality is not implemented yet: %s\n", AUTOMATIC_KNOTS.c_str());
        //automatic_knots=param.getBool( AUTOMATIC_KNOTS );
    } else {
        //automatic_knots=DEFAULT_AUTOMATIC_KNOTS;
        infoMessage(className, memberName, "set \"%s\" to the default value %d\n", AUTOMATIC_KNOTS.c_str(), DEFAULT_AUTOMATIC_KNOTS);
    }

    Bool use_uniform_break_points;
    if ( param.contain( USE_UNIFORM_BREAK_POINTS ) ) {
        use_uniform_break_points=param.getBool( USE_UNIFORM_BREAK_POINTS );
        infoMessage(className, memberName, "use uniform break points: %d\n", use_uniform_break_points);
    } else {
        use_uniform_break_points=DEFAULT_USE_UNIFORM_BREAK_POINTS;
        warningMessage(className, memberName, "not specified to use uniform break points or not\n");
        warningMessage(className, memberName, "set the use flag by default value:  %d\n", DEFAULT_USE_UNIFORM_BREAK_POINTS);
    }

    size_t number_of_break_points;
    if ( param.contain( NUMBER_OF_BREAK_POINTS ) ) {
        number_of_break_points=param.getUInt4( NUMBER_OF_BREAK_POINTS );
        infoMessage(className, memberName, "the number of break points: %u\n", number_of_break_points);
    } else {
        number_of_break_points=DEFAULT_NUMBER_OF_BREAK_POINTS;
        warningMessage(className, memberName, "not specified the number of break points\n");
        warningMessage(className, memberName, "set the number of break points by the default value=%u\n", number_of_break_points);
    }

    if ( use_uniform_break_points == false )  {
        if ( param.contain( BREAK_POINTS ) ) {
            vector<Double> tmp=param.getVector(BREAK_POINTS);
            if (tmp.size() != number_of_break_points ) {
                warningMessage(className, memberName, 
                     "the given the number of break points \"%d\" is not equal to the size of the list break points \"%d\".",
                     number_of_break_points, tmp.size());
                warningMessage(className, memberName,
                     "change the given the number of break points from \"%d\" to \"%d\".",
                     number_of_break_points, tmp.size());
            }
        } else {
            use_uniform_break_points=true;
            warningMessage(className, memberName, "no break points, though use_uniforn_break_points=false\n");
            warningMessage(className, memberName, "set use_uniforn_break_points=false to true\n");
        }
    }
    /*
    */
    return true;
}

void AdvBSpline::toInnerForm(ElementContainer &src, AdvDomain &domain, AdvParamSet &param) {

    const string memberName=string("toInnerForm(ElementContainer&, AdvDomain&, AdvParamSet&)");

    const string xKey=src.PutXKey();
    const string yKey=src.PutYKey();
    const string eKey=src.PutEKey();

    UInt4 lower=domain.getLowerBoundID();
    UInt4 upper=domain.getUpperBoundID();

    //resultBin=new vector<Double>();
    this->resultBin = domain.getBin();
    //for (UInt4 i=lower; i<=upper; ++i) {
    //    resultBin->push_back(src.Put(xKey, i));
    //}

    //number_of_data_points=upper-lower+1;
    number_of_data_points=domain.getNumberOfBin();
    DebugMessage(className, memberName, "the number of data points: %u\n", number_of_data_points);
    this->resultX=domain.createXCAsGslVector();
    //resultX=gsl_vector_alloc(number_of_data_points);
    DebugMessage(className, memberName, "the number of data points: %u\n", this->resultX->size);
     
    this->srcY=gsl_vector_alloc(number_of_data_points);
    this->srcW=gsl_vector_alloc(number_of_data_points);
    for (UInt4 i = lower; i < upper; ++i) {
        Double xi, yi, wi;
        //xi=(src.Put(xKey, i) + src.Put(xKey, i+1))/2.0;
        xi=gsl_vector_get(resultX, i);
        yi=src.Put(yKey, i);
        wi=pow(src.Put(eKey, i), -2.0);
        //gsl_vector_set(resultX, i, (src.Put(xKey, i) + src.Put(xKey, i+1))/2.0 );
        gsl_vector_set(srcY, i, src.Put(yKey, i)                            );
        gsl_vector_set(srcW, i, pow(src.Put(eKey, i), -2.0)                 );

        DebugMessage(className, memberName, "source data: %5u %7.4f %23.15e %23.15e\n", i, xi, yi, wi);
    }
    resultY=static_cast<gsl_vector*>(NULL);
    resultYError=static_cast<gsl_vector*>(NULL);

    UInt4 user_specified_order;
    if ( param.contain(ORDER) ) {
        user_specified_order=param.getUInt4(ORDER);
        //infoMessage(className, memberName, "the highest order of B-Spline basis is user-specified value: %d\n", user_specified_order);
    } else {
        user_specified_order=DEFAULT_ORDER_OF_POLYNOMINAL;
        infoMessage(className, memberName, "set the highest order of B-Spline basis by the default value: %d\n", user_specified_order);
    }
    order = user_specified_order+1;

    if ( param.contain( AUTOMATIC_KNOTS ) ) {
        automatic_knots=param.getBool( AUTOMATIC_KNOTS );
        if ( automatic_knots ) {
            param.replace(AUTOMATIC_KNOTS, false);
            automatic_knots=false;
            warningMessage(className, memberName, "%s : the functonality is not implemented yet\n", AUTOMATIC_KNOTS.c_str());
        }
    } else {
        automatic_knots=DEFAULT_AUTOMATIC_KNOTS;
        //infoMessage(className, memberName, "");
        infoMessage(className, memberName, "the functonality is not implemented yet\n");
    }
    //infoMessage(className, memberName, "set %s to the default value %d\n", AUTOMATIC_KNOTS.c_str(), automatic_knots);

    if ( param.contain( USE_UNIFORM_BREAK_POINTS ) ) {
        use_uniform_break_points=param.getBool( USE_UNIFORM_BREAK_POINTS );
        //infoMessage(className, memberName, "uniform break points: %d\n", use_uniform_break_points);
    } else {
        use_uniform_break_points=DEFAULT_USE_UNIFORM_BREAK_POINTS;
        warningMessage(className, memberName, "not specified to use uniform break points or not\n");
        warningMessage(className, memberName, "set the use flag by default value:  %d\n", use_uniform_break_points);
    }

    if ( param.contain( NUMBER_OF_BREAK_POINTS ) ) {
        number_of_break_points=param.getUInt4( NUMBER_OF_BREAK_POINTS );
        //infoMessage(className, memberName, "the number of break points: %u\n", number_of_break_points);
    } else {
        //number_of_break_points=order;
        number_of_break_points=DEFAULT_NUMBER_OF_BREAK_POINTS;
        warningMessage(className, memberName, "not specified the number of break points\n");
        warningMessage(className, memberName, "set the number of break points by the default value=%u\n", number_of_break_points);
    }

    number_of_coefficients=number_of_break_points+order-2;
    //infoMessage(className, memberName, "the number of coefficients: %u\n", number_of_coefficients);

    if ( use_uniform_break_points == false )  {
        if ( param.contain( BREAK_POINTS ) ) {
            vector<Double> tmp=param.getVector(BREAK_POINTS);

            if (tmp.size() != number_of_break_points) {
                warningMessage(className, memberName, 
                     "the given the number of break points \"%d\" is not equal to the size of the list break points \"%d\".",
                     number_of_break_points, tmp.size());
                warningMessage(className, memberName,
                     "changed the given the number of break points from \"%d\" to \"%d\".",
                     number_of_break_points, tmp.size());
                number_of_break_points=tmp.size();
            }

            if ( break_points != (gsl_vector *)NULL ) {
                gsl_vector_free(break_points);
            }
            break_points=gsl_vector_alloc(tmp.size());

            for (UInt4 i=0U; i<tmp.size(); ++i) {
                gsl_vector_set(break_points, i, tmp.at(i));
            }
        } else {
            use_uniform_break_points=true;
            warningMessage(className, memberName, "no break points, though use_uniforn_break_points=false\n");
            warningMessage(className, memberName, "set use_uniforn_break_points=false to true\n");
        }
    }

}


/**
 *  one shot fitting
 */
void AdvBSpline::fit() {

    string memberName=string("fit()");

    DebugMessage(className, memberName, "enter\n");

    B = gsl_vector_alloc(number_of_coefficients);
    c = gsl_vector_alloc(number_of_coefficients);

    X = gsl_matrix_alloc(number_of_data_points, number_of_coefficients);
    cov = gsl_matrix_alloc(number_of_coefficients, number_of_coefficients);

    bspline_workspace = gsl_bspline_alloc(order, number_of_break_points);
    multifit_workspace = gsl_multifit_linear_alloc(number_of_data_points, number_of_coefficients);

    DebugMessage(className, memberName, "x(%5d)=%7.4f\n", 0,               gsl_vector_get(resultX, 0)                );
    DebugMessage(className, memberName, "x(%5d)=%7.4f\n", resultX->size-1, gsl_vector_get(resultX, (resultX->size)-1));

    message("use_uniform_break_knots: %s\n", (use_uniform_break_points ? "true" : "false"));
    if ( use_uniform_break_points ) {
        message("uniform knots\n");
        gsl_bspline_knots_uniform( gsl_vector_get(resultX, 0), gsl_vector_get(resultX, (resultX->size)-1), bspline_workspace );
    } else {
        message("user-defined knots\n");
        gsl_bspline_knots(break_points, bspline_workspace);
    }


    DebugMessage(className, memberName, "fitting\n");
    for (UInt4 i=0U; i<number_of_data_points; ++i) {
        double xi=gsl_vector_get(resultX, i);
        //DebugMessage(className, memberName, "fitting initialization %u %e\n", i, xi);
        gsl_bspline_eval(xi, B, bspline_workspace);
        for (UInt4 j=0U; j < number_of_coefficients; ++j) {
            double Bj=gsl_vector_get(B, j);
            gsl_matrix_set(X, i, j, Bj);
        }
    }
    Int4 err=gsl_multifit_wlinear(X, srcW, srcY, c, cov, &chisq, multifit_workspace);
    if (err != 0) {
        DebugMessage(className, memberName, "error: %d\n", err);
    } else {
        DebugMessage(className, memberName, "no error: %d\n", err);
    }

    dof = number_of_data_points - number_of_coefficients;
    Rsq = 1.0 - chisq/gsl_stats_wtss(srcW->data, 1, srcY->data, 1, srcY->size);
    std::cout << "chi_square/dof=" << chisq << "/" << dof << "=" << chisq/dof << ", Rsq=" << Rsq << endl;
    std::cout << endl;

    Int4 indentDepth=4;
    std::cout << "B-Spline parameters" << endl;

    std::cout << setw(indentDepth) << " ";
    std::cout << "number of polynominal pieces" << bspline_workspace->n;
    std::cout << endl;
    std::cout << setw(indentDepth) << " ";
    std::cout << "a list of knots";
    std::cout << endl;
    std::cout << setw(indentDepth*2) << " ";
    std::cout << setw(5) << "No.";
    std::cout << setw(23) << "position";
    std::cout << endl;
    for (size_t i=0; i < ((bspline_workspace->knots)->size); ++i) {
         std::cout << setw(indentDepth*2) << " ";
         std::cout << setw(5)  << i;
         std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::scientific) << gsl_vector_get(bspline_workspace->knots, i);
         std::cout << endl;
    }
    std::cout << endl;

    std::cout << setw(indentDepth) << " ";
    std::cout << "coefficient";
    std::cout << endl;
    std::cout << setw(indentDepth*2) << " ";
    std::cout << setw(5) << "No.";
    std::cout << setw(23) << "value";
    std::cout << setw(23) << "error";
    std::cout << endl;
    for (size_t i=0; i < (c->size); ++i) {
         std::cout << setw(indentDepth) << " ";
         std::cout << setw(indentDepth) << " ";
         std::cout << setw(5)  << i;
         std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::scientific) << gsl_vector_get(c, i);
         std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::scientific) << sqrt(gsl_matrix_get(cov, i, i));
         std::cout << endl;
    }
    std::cout << endl;

    std::cout << setw(indentDepth) << " ";
    std::cout << "covariance matrix";
    std::cout << endl;
    this->outputMatrix(std::cout, indentDepth*2, cov, 0, cov->size1, 0, cov->size2, false, 15, true, true, 150);

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

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


void AdvBSpline::eval() {

    string memberName=string("eval()");

    resultY     =gsl_vector_alloc(number_of_data_points);
    resultYError=gsl_vector_alloc(number_of_data_points);
    for (UInt4 i=0U; i<(resultX->size); ++i) {
        Double x, y, yerr, residue;
        x=gsl_vector_get(resultX, i);
        gsl_bspline_eval(x, B, bspline_workspace);
        gsl_multifit_linear_est(B, c, cov, &y, &yerr);

        residue=gsl_vector_get(srcY, i) - y;

        //DebugMessage(className, memberName, "results %7.4f %23.15e %23.15e %23.15e %23.15e\n", x, gsl_vector_get(srcY, i), y, yerr, residue);

        gsl_vector_set(resultY,      i, y   );
        gsl_vector_set(resultYError, i, yerr);

    }


    // evaluate the first and the second derivatives

//    size_t nderiv=2;  // up to the second derivative
//    dB=gsl_matrix_alloc(gsl_bspline_ncoeffs(bspline_workspace), nderiv+1); // values of derived B-splines (order: 0, 1, ... deriv )
//    deriv_workspace=gsl_bspline_deriv_alloc(order);
//    //gsl_vector *derived_value;
//    gsl_matrix *derived_value;
//    //derived_value=gsl_vector_alloc(nderiv+1);
//    derived_value=gsl_matrix_alloc(nderiv+1, number_of_data_points);
//
//    //DebugMessage(className, memberName, "ncoeffs=%u, nderiv=%u\n", gsl_bspline_ncoeffs(bspline_workspace), nderiv);
//    //DebugMessage(className, memberName, "size of c=%u\n", c->size);
//
//    DebugMessage(className, memberName, "derivatives %7s %23s %23s %23s", "x", "src", "f", "f error");
//    for (int i=0; i<=nderiv; ++i) {
//            fprintf(stderr, "         %1d%14s", i, "th. derivative");
//    }
//    fprintf(stderr, "\n");
//    for (UInt4 i=0U; i< (resultX->size); ++i) {
//        Double x=gsl_vector_get(resultX, i);
//        gsl_bspline_deriv_eval(x, nderiv, dB, bspline_workspace, deriv_workspace);
//        for (UInt4 j=0U; j<=nderiv; ++j) {
//            Double v=0.0;
//            for (UInt4 k=0U; k<(c->size); ++k) {
//                v = v + gsl_vector_get(c, k)*gsl_matrix_get(dB, k, j);
//            }
//            //gsl_vector_set(derived_value, j, v);
//            gsl_matrix_set(derived_value, j, i, v);
//        }
//
//        DebugMessage(className, memberName, "derivatives %7.4f %23.15e %23.15e %23.15e", x, gsl_vector_get(srcY, i), gsl_vector_get(resultY, i), gsl_vector_get(resultYError, i));
//        for (int j=0; j<=nderiv; ++j) {
//            //fprintf(stderr, " %23.15e", gsl_vector_get(derived_value, j));
//            fprintf(stderr, " %23.15e", gsl_matrix_get(derived_value, j, i));
//        }
//        fprintf(stderr, "\n");
//        /*
//        */
//    }
}

void AdvBSpline::toElementContainer(ElementContainer &src, ElementContainer &dest) const {

    vector<Double> *Y=new vector<Double>();
    vector<Double> *Yerror=new vector<Double>();
    for (UInt4 i=0U; i<(resultY->size); ++i) {
        Y->push_back(gsl_vector_get(resultY, i));
        Yerror->push_back(gsl_vector_get(resultYError, i));
    }

    dest.Add(src.PutXKey(), *resultBin, src.PutUnit(src.PutXKey()));
    dest.Add(src.PutYKey(), *Y,         src.PutUnit(src.PutYKey()));
    dest.Add(src.PutEKey(), *Yerror,    src.PutUnit(src.PutEKey()));
    dest.SetKeys(src.PutXKey(), src.PutYKey(), src.PutEKey());

    dest.AddToHeader("Method", this->getMethodName());
    dest.AddToHeader(this->ORDER,                    static_cast<Int4>(order-1));
    dest.AddToHeader(this->AUTOMATIC_KNOTS,          automatic_knots);
    dest.AddToHeader(this->USE_UNIFORM_BREAK_POINTS, use_uniform_break_points);
    dest.AddToHeader(this->NUMBER_OF_BREAK_POINTS,   static_cast<Int4>(number_of_break_points));
    if (! use_uniform_break_points ) {
        vector<Double> v=*(new vector<Double>(break_points->size));
        for (UInt4 i=0; i<break_points->size; ++i) {
            v.at(i)=gsl_vector_get(break_points, i);
        }
        dest.AddToHeader(this->BREAK_POINTS, v);
    }

}

void AdvBSpline::getParamDescription() const {
    char fmt[]="%s %s %s %s\n";

    printf(fmt, ORDER.c_str(),                    "mandatry", "UInt4", "the hightest order of the B-spline polynominal");
    printf(fmt, USE_UNIFORM_BREAK_POINTS.c_str(), "mandatry", "Bool",  "use uniform break points");
    printf(fmt, NUMBER_OF_BREAK_POINTS.c_str(),   "mandatry", "UInt4", "the number of break points");
    printf(fmt, BREAK_POINTS.c_str(),             "optional", "vector<Double>", "a list of break points");
}

AdvParamSet AdvBSpline::getFittedParam() const {

    string memberName=string("getFittedParam()");

    AdvParamSet *new_param=new AdvParamSet();
    new_param->add(ORDER, static_cast<UInt4>(order-1U));

    //DebugMessage(className, memberName, "%s %d\n", AUTOMATIC_KNOTS.c_str(), automatic_knots);
    std::cerr << "Debug: AdvBSpline::" << memberName << ": " << AUTOMATIC_KNOTS << " = " << automatic_knots << endl;
    new_param->add(AUTOMATIC_KNOTS, automatic_knots);

    new_param->add(USE_UNIFORM_BREAK_POINTS, use_uniform_break_points);
    new_param->add(NUMBER_OF_BREAK_POINTS, static_cast<UInt4>(number_of_break_points));

    //fprintf(stderr, "knots=(\n");
    //for (int i=0; i < ((bspline_workspace->knots)->size); ++i) {
    //        fprintf(stderr, "%5d %23.15e\n", i, gsl_vector_get(bspline_workspace->knots, i));
    //}
    //fprintf(stderr, ")\n");
    if (! use_uniform_break_points) {
        vector<Double> *bp = new vector<Double>();
        for (UInt4 i=order-1U; i < (bspline_workspace->knots)->size - (order-1U); ++i) {
            bp->push_back(gsl_vector_get(bspline_workspace->knots, i));
        }
        new_param->add(BREAK_POINTS, *bp);
    }

    return *new_param;
    
}

Double AdvBSpline::likehood() {
    return 0.0;
}


/**
 *  evaluate the first and the second derivatives
 */
vector< vector<Double> > AdvBSpline::getTrend() {

    string memberName=string("getTrend()");

    vector< vector<Double> > inc_dec_table;
    inc_dec_table.push_back(*(new vector<double>));
    inc_dec_table.push_back(*(new vector<double>));
    inc_dec_table.push_back(*(new vector<double>));

    size_t nderiv=2;  // up to the second derivative
    dB=gsl_matrix_alloc(gsl_bspline_ncoeffs(bspline_workspace), nderiv+1); // values of derived B-splines (order: 0, 1, ... deriv )
    deriv_workspace=gsl_bspline_deriv_alloc(order);
    //gsl_vector *derived_value;
    gsl_matrix *derived_value;
    //derived_value=gsl_vector_alloc(nderiv+1);
    derived_value=gsl_matrix_alloc(nderiv+1, number_of_data_points);

    DebugMessage(className, memberName, "size of resultX      = %lu\n", resultX->size);
    if (resultY==NULL) {
        eval();
    }
    DebugMessage(className, memberName, "size of resultY      = %lu\n", resultY->size);
    DebugMessage(className, memberName, "size of resultYError = %lu\n", resultYError->size);
    DebugMessage(className, memberName, "size of c=%u\n", c->size);

    DebugMessage(className, memberName, "derivatives %7s %23s %23s %23s", "x", "src", "f", "f error");
    for (UInt4 i=0U; i<=nderiv; ++i) {
            fprintf(stderr, "         %1d%14s", i, "th. derivative");
    }
    fprintf(stderr, "\n");
    //DebugMessage(className, memberName, "title\n");
    //DebugMessage(className, memberName, "resultX->size=%lu\n", resultX->size);
    int status;
    for (UInt4 i=0U; i< (resultX->size); ++i) {
        //DebugMessage(className, memberName, "resultX->size=%lu\n", resultX->size);
        Double x=gsl_vector_get(resultX, i);
        status=gsl_bspline_deriv_eval(x, nderiv, dB, bspline_workspace, deriv_workspace);
        DebugMessage(className, memberName, "evaluated derived values of bspline bases at i=%lu statud=%d\n", i, status);

        for (UInt4 j=0; j<=nderiv; ++j) {
            Double v=0.0;
            for (UInt4 k=0U; k<(c->size); ++k) {
                v = v + gsl_vector_get(c, k)*gsl_matrix_get(dB, k, j);
            }
            //gsl_vector_set(derived_value, j, v);
            gsl_matrix_set(derived_value, j, i, v);
            inc_dec_table[j].push_back(v);
            //DebugMessage(className, memberName, "evaluated %u-th. derived values of moothed spline at i=%lu, value=%23.15e\n", j, i, v);
        }
        //DebugMessage(className, memberName, "evaluated derived values of moothed spline at i=%lu\n", i);

        DebugMessage(className, memberName, "derivatives %7.4f %23.15e %23.15e %23.15e\n", \
            x, gsl_vector_get(srcY, i), gsl_vector_get(resultY, i), gsl_vector_get(resultYError, i));
        DebugMessage(className, memberName, "derivatives %7.4f %23.15e %23.15e", x, gsl_vector_get(srcY, i), gsl_vector_get(resultY, i));
        for (UInt4 j=0U; j<=nderiv; ++j) {
            //fprintf(stderr, " %23.15e", gsl_vector_get(derived_value, j));
            fprintf(stderr, " %23.15e", gsl_matrix_get(derived_value, j, i));
            fprintf(stderr, " %23.15e", inc_dec_table[j][i]);
            //DebugMessage(className, memberName, "print %u-th. derived values of moothed spline at i=%lu\n", j, i);
        }
        fprintf(stderr, "\n");
        DebugMessage(className, memberName, "print derived values of moothed spline at i=%lu\n", i);

    }

    return inc_dec_table;
}
