/*
Copyright (C) 2011 Richard Gomes

This source code is release under the BSD License.

This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/

JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license.  You should have received a
copy of the license along with this program; if not, please email
. The license is also available online at
.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.

JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
 */
package org.jquantlib.termstructures;

import java.util.Arrays;

import org.jquantlib.QL;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.lang.reflect.ReflectConstants;
import org.jquantlib.math.interpolations.Interpolation;
import org.jquantlib.math.interpolations.Interpolation.Interpolator;
import org.jquantlib.math.interpolations.factories.Linear;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.math.solvers1D.Brent;
import org.jquantlib.termstructures.yieldcurves.PiecewiseCurve;
import org.jquantlib.termstructures.yieldcurves.PiecewiseYieldCurve;
import org.jquantlib.termstructures.yieldcurves.Traits;
import org.jquantlib.time.Date;

/**
 * Universal piecewise-term-structure boostrapper.
 * 
 * @author Richard Gomes
 */


//FIXME: This class needs full code review


public class IterativeBootstrap implements Bootstrap {

    //
    // private fields
    //

    private boolean         validCurve;
    private PiecewiseCurve  ts;
    private RateHelper[]    instruments;

    private Traits          traits;
    private Interpolator    interpolator;
    private Interpolation   interpolation;

    //
    // final private fields
    //

    final private Class  typeCurve;


    //
    // public constructors
    //

    public IterativeBootstrap(final Class typeCurve) {
        QL.validateExperimentalMode();
        
        if (typeCurve==null) {
            throw new LibraryException("null PiecewiseCurve"); // TODO: message
        }
        if (!PiecewiseCurve.class.isAssignableFrom(typeCurve)) {
            throw new LibraryException(ReflectConstants.WRONG_ARGUMENT_TYPE);
        }
        this.typeCurve = typeCurve;

        this.validCurve = false;
        this.ts = null;
    }


    //
    // implements Bootstrap
    //

    @Override
    public void setup(final Curve ts) {

        QL.ensure (ts != null, "TermStructure cannot be null");
        if (!this.typeCurve.isAssignableFrom(ts.getClass())) {
            throw new LibraryException(ReflectConstants.WRONG_ARGUMENT_TYPE);
        }

        this.ts            = ts;
        this.interpolator  = ts.interpolator();
        this.interpolation = ts.interpolation();
        this.traits        = ts.traits();
        this.instruments   = ts.instruments();

        final int n = instruments.length;
        QL.require(n+1 >= ts.interpolator().requiredPoints(), "not enough instruments provided");

        for (int i=0; i0) {
                    guess = ts.data()[i];
                } else if (i==1) {
                    guess = traits.initialGuess();
                } else {
                    // most traits extrapolate
                    guess = traits.guess(ts, dates[i]);
                }

                //QL.debug (" Guess : " + ((Double)(guess)).toString());

                // bracket
                final double min = traits.minValueAfter(i, data);
                final double max = traits.maxValueAfter(i, data);

                if (guess <= min || guess >= max) {
                    guess = (min + max) / 2.0;
                }

                if (! validCurve && iteration == 0) {
                    // extend interpolation a point at a time
                    try {
                        ts.setInterpolation(interpolator.interpolate (new Array(times, i+1), new Array(data)));
                    } catch (final Exception e) {
                        // no chance to fix it in a later iteration
                        if (ts.interpolator().global()) {
                            throw new LibraryException("no chance to fix it in a later iteration");
                        }

                        // otherwise, if the target interpolation is not usable yet
                        ts.setInterpolation(new Linear().interpolate (new Array(times, i+1), new Array(data)));
                    }
                }
                // required because we just changed the data
                // is it really required?
                ts.interpolation().update();

                try {
                    final BootstrapError error = new BootstrapError(traits, ts, instrument, i);
                    final double r = solver.solve (error, ts.accuracy(), guess, min, max);
                    // redundant assignment (as it has been already performed
                    // by BootstrapError in solve procedure), but safe
                    data[i] = r;
                } catch (final Exception e) {
                    validCurve = false;
                    QL.error ("could not bootstrap");
                }
            }

            if (!interpolator.global ()) {
                break; // no need for convergence loop
            } else if (!validCurve && iteration == 0) {
                // ensure the target interpolation is used
                ts.setInterpolation(interpolator.interpolate (new Array(times), new Array(data)));

                // at least one more iteration is needed to check convergence
                continue;
            }

            // exit conditions
            double improvement = 0.0;
            for (int i=1; i 

Ads help maintain this website.