public double value(PathType path)
        {
            if (calibrationPhase_)
            {
                // store paths for the calibration
                paths_.Add((PathType)path.Clone());
                // result doesn't matter
                return(0.0);
            }

            int len = EarlyExerciseTraits <PathType> .pathLength(path);

            double price = pathPricer_.value(path, len - 1);

            for (int i = len - 2; i > 0; --i)
            {
                price *= dF_[i];

                double exercise = pathPricer_.value(path, i);
                if (exercise > 0.0)
                {
                    double regValue = pathPricer_.state(path, i);

                    double continuationValue = 0.0;
                    for (int l = 0; l < v_.Count; ++l)
                    {
                        continuationValue += coeff_[i][l] * v_[l](regValue);
                    }

                    if (continuationValue < exercise)
                    {
                        price = exercise;
                    }
                }
            }

            return(price * dF_[0]);
        }
        public void calibrate()
        {
            int    n = paths_.Count;
            Vector prices = new Vector(n), exercise = new Vector(n);
            int    len = EarlyExerciseTraits <PathType> .pathLength(paths_[0]);

            for (int i = 0; i < paths_.Count; i++)
            {
                prices[i] = pathPricer_.value(paths_[i], len - 1);
            }

            for (int i = len - 2; i > 0; --i)
            {
                List <double> y = new List <double>();
                List <double> x = new List <double>();

                //roll back step
                for (int j = 0; j < n; ++j)
                {
                    exercise[j] = pathPricer_.value(paths_[j], i);

                    if (exercise[j] > 0.0)
                    {
                        x.Add(pathPricer_.state(paths_[j], i));
                        y.Add(dF_[i] * prices[j]);
                    }
                }

                if (v_.Count <= x.Count)
                {
                    coeff_[i] = new LinearLeastSquaresRegression <double>(x, y, v_).coefficients();
                }
                else
                {
                    // if number of itm paths is smaller then the number of
                    // calibration functions -> no early exercise
                    coeff_[i] = new Vector(v_.Count);
                }

                for (int j = 0, k = 0; j < n; ++j)
                {
                    prices[j] *= dF_[i];
                    if (exercise[j] > 0.0)
                    {
                        double continuationValue = 0.0;
                        for (int l = 0; l < v_.Count; ++l)
                        {
                            continuationValue += coeff_[i][l] * v_[l](x[k]);
                        }
                        if (continuationValue < exercise[j])
                        {
                            prices[j] = exercise[j];
                        }
                        ++k;
                    }
                }
            }

            // remove calibration paths
            paths_.Clear();
            // entering the calculation phase
            calibrationPhase_ = false;
        }