/* *
 * Title:        

* Description:

* Copyright: Copyright (c)

* Company:

* @author * @version 1.0 */ package umontreal.iro.lecuyer.stochprocess; import umontreal.iro.lecuyer.rng.*; import umontreal.iro.lecuyer.probdist.*; import umontreal.iro.lecuyer.randvar.*; import umontreal.iro.lecuyer.hups.*; /** * This class represents a normal inverse gaussian process (NIG). * It obeys the stochastic differential equation *

*

*
* dX(t) = μdt + dB(h(t)), *

* where * {B(t), t >= 0} is a {@link BrownianMotion} * with drift β and variance 1, * and h(t) is an {@link InverseGaussianProcess} * IG(ν/γ, ν2), with * * ν = δdt and * γ = (α^2 - β^2)1/2. * *

* In this class, the process is generated using the sequential * technique: X(0) = x0 and *

*

*
* X(tj) - X(tj-1) = μdt + βYj + (Y_j)1/2Zj, *

* where * Zj∼N(0, 1), and * Yj∼IG(ν/γ, ν2) * with * ν = δ(tj - tj-1). * *

* There is one {@link umontreal.iro.lecuyer.rng.RandomStream RandomStream} * used to generate the Zj's and * there are one or two streams used to generate the underlying * {@link InverseGaussianProcess}, depending on which IG subclass * is used. * *

* In finance, a NIG process usually means that * the log-return is given by a NIG process; * {@link GeometricNormalInverseGaussianProcess} * should be used in that case. * */ public class NormalInverseGaussianProcess extends StochasticProcess { protected RandomStream streamIG1; // U[0,1) gen used in the inverse gaussian protected RandomStream streamIG2; // U[0,1) gen used (maybe) in the inverse gaussian protected RandomStream streamBrownian; // U[0,1) gen for the normal "Brownian" protected InverseGaussianProcess igProcess; protected NormalGen normalGen; // Randomized time generated by the InverseGaussianProcess. protected double[] stochTime; double[] dt; double[] mudt; // Parameters of the normal inverse gaussian protected double mu; protected double delta; protected double alpha; protected double beta; protected double gamma; /** * Given an {@link InverseGaussianProcess} igP, constructs a * new NormalInverseGaussianProcess. The parameters and observation * times of the IG process will be overriden by the parameters * of the NIG process. If there are two * {@link umontreal.iro.lecuyer.rng.RandomStream RandomStream}'s in the * {@link InverseGaussianProcess}, this constructor assumes that * both streams have been set to the same stream. * */ public NormalInverseGaussianProcess (double x0, double alpha, double beta, double mu, double delta, RandomStream streamBrownian, InverseGaussianProcess igP) { setParams (x0, alpha, beta, mu, delta); this.streamBrownian = streamBrownian; normalGen = new NormalGen(streamBrownian); // N(0,1) igProcess = igP; // its params will be set in init(). this.streamIG1 = igProcess.getStream(); this.streamIG2 = streamIG1; } /** * Constructs a new NormalInverseGaussianProcess. * The string argument corresponds to the type of underlying * {@link InverseGaussianProcess}. The choices are SEQUENTIAL_SLOW, * SEQUENTIAL_MSH, BRIDGE and PCA, which correspond * respectively to {@link InverseGaussianProcess}, {@link InverseGaussianProcessMSH}, * {@link InverseGaussianProcessBridge} and {@link InverseGaussianProcessPCA}. * The third {@link umontreal.iro.lecuyer.rng.RandomStream RandomStream}, streamIG2, * will not be used at all if the SEQUENTIAL_SLOW or PCA methods are chosen. * */ public NormalInverseGaussianProcess (double x0, double alpha, double beta, double mu, double delta, RandomStream streamBrownian, RandomStream streamIG1, RandomStream streamIG2, String igType) { setParams (x0, alpha, beta, mu, delta); this.streamIG1 = streamIG1; this.streamIG2 = streamIG2; this.streamBrownian = streamBrownian; normalGen = new NormalGen(streamBrownian); // N(0,1) // The initial time of igProcess here, 0., is arbitrary: // init() sets igProcess.x0 = t[0]. if(igType.compareTo("SEQUENTIAL_SLOW") == 0) // the initial value, 0.0, of the IG will be overriden by // the initial time, when it will be set. igProcess = new InverseGaussianProcess(0.0, delta, gamma, streamIG1); else if(igType.compareTo("SEQUENTIAL_MSH") == 0) igProcess = new InverseGaussianProcessMSH (0.0, delta, gamma, streamIG1, streamIG2); else if(igType.compareTo("BRIDGE") == 0) igProcess = new InverseGaussianProcessBridge (0.0, delta, gamma, streamIG1, streamIG2); else if(igType.compareTo("PCA") == 0) igProcess = new InverseGaussianProcessPCA (0.0, delta, gamma, streamIG1); else throw new IllegalArgumentException("Unrecognized igType"); } /** * Same as above, but all {@link umontreal.iro.lecuyer.rng.RandomStream RandomStream}'s * are set to the same stream, streamAll. * */ public NormalInverseGaussianProcess (double x0, double alpha, double beta, double mu, double delta, RandomStream streamAll, String igType) { this(x0, alpha, beta, mu, delta, streamAll, streamAll, streamAll, igType); } /** * Generates the path. * This method samples each stream alternatively, * which is useful for quasi-Monte Carlo, where * all streams are in fact the same iterator on * a {@link umontreal.iro.lecuyer.hups.PointSet PointSet}. * */ public double[] generatePath() { if(igProcess.getNumberOfRandomStreams() != 1) return generatePathTwoIGStreams(); double x = x0; double[] randomNormal = new double[d]; double[] randomIG1 = new double[d]; for (int j = 0; j < d; j++) { randomIG1[j] = streamIG1.nextDouble(); randomNormal[j] = streamBrownian.nextDouble(); } stochTime = igProcess.generatePath(randomIG1); for (int j = 0; j < d; j++) { double dy = stochTime[j + 1] - stochTime[j]; x += mudt[j] + beta*dy + Math.sqrt(dy) * NormalDistQuick.inverseF01(randomNormal[j]); path[j + 1] = x; } observationIndex = d; return path; } protected double[] generatePathTwoIGStreams() { double x = x0; double[] uniformNormal = new double[d]; double[] uniformIG1 = new double[d]; double[] uniformIG2 = new double[d]; for (int j = 0; j < d; j++) { uniformIG1[j] = streamIG1.nextDouble(); uniformNormal[j] = streamBrownian.nextDouble(); uniformIG2[j] = streamIG2.nextDouble(); } stochTime = igProcess.generatePath(uniformIG1, uniformIG2); for (int j = 0; j < d; j++) { double dy = stochTime[j + 1] - stochTime[j]; x += mudt[j] + beta*dy + Math.sqrt(dy) * NormalDistQuick.inverseF01(uniformNormal[j]); path[j + 1] = x; } observationIndex = d; return path; } /** * Returns the value of the process for the next time step. * If the underlying {@link InverseGaussianProcess} * is of type {@link InverseGaussianProcessPCA}, this method cannot be * used. It will work with {@link InverseGaussianProcessBridge}, but * the return order of the observations is the bridge order. * */ public double nextObservation() { double igNext = igProcess.nextObservation(); observationIndex = igProcess.getCurrentObservationIndex(); stochTime[observationIndex] = igNext; double dY = igNext - stochTime[0]; double dT = t[observationIndex] - t[0]; path[observationIndex] = x0 + mu * dT + beta * dY + Math.sqrt(dY) * normalGen.nextDouble(); return path[observationIndex]; } protected void init() { super.init(); igProcess.setParams(delta, gamma); if(observationTimesSet){ stochTime = new double[d+1]; stochTime[0] = t[0]; dt = new double[d]; mudt = new double[d]; for(int i = 0; i < d; i++){ dt[i] = t[i+1] - t[i]; mudt[i] = dt[i] * mu; } } } /** * Sets the observation times on the NIG process as usual, * but also sets the observation times of the underlying {@link InverseGaussianProcess}. * It furthermore sets the starting value of the {@link InverseGaussianProcess} * to t[0]. * */ public void setObservationTimes(double t[], int d) { super.setObservationTimes(t, d); igProcess.setObservationTimes(t, d); igProcess.x0 = t[0]; } /** * Sets the parameters. Also, computes * * γ = (α^2-β^2)1/2. * */ public void setParams (double x0, double alpha, double beta, double mu, double delta) { // Initializes the parameters of the process if (delta <= 0.0) throw new IllegalArgumentException ("delta <= 0"); if (alpha <= 0.0) throw new IllegalArgumentException ("alpha <= 0"); if (Math.abs(beta) >= alpha) throw new IllegalArgumentException ("|beta| >= alpha"); this.x0 = x0; this.mu = mu; this.delta = delta; this.beta = beta; this.alpha = alpha; gamma = Math.sqrt(alpha*alpha - beta*beta); if (observationTimesSet) init(); } /** * Returns alpha. * */ public double getAlpha() { return alpha; } /** * Returns beta. * */ public double getBeta() { return beta; } /** * Returns mu. * */ public double getMu() { return mu; } /** * Returns delta. * */ public double getDelta() { return delta; } /** * Returns gamma. * */ public double getGamma() { return gamma; } /** * Returns the analytic average, which * is * μt + δtβ/γ. * */ public double getAnalyticAverage (double time) { return mu*time+delta*time*beta/gamma; } /** * Returns the analytic variance, which is * * δtα2/γ3. * */ public double getAnalyticVariance (double time) { return delta*time*alpha*alpha/gamma/gamma/gamma; } /** * Only returns the stream if all streams are equal, * including the stream(s) in the underlying {@link InverseGaussianProcess}. * */ public RandomStream getStream() { if( (streamIG1 != streamIG2) || (streamIG1 != streamBrownian) || (streamIG1 != normalGen.getStream()) || (streamIG1 != igProcess.getStream()) ) throw new UnsupportedOperationException ("Two different streams or more are present"); return streamIG1; } /** * Sets all internal streams to stream, * including the stream(s) of the underlying {@link InverseGaussianProcess}. * */ public void setStream (RandomStream stream) { streamIG1 = streamIG2 = streamBrownian = stream; normalGen.setStream(stream); igProcess.setStream(stream); } }

Ads help maintain this website.