/// <summary> /// Returns the value of the density function of a copula, given two input cumulative distribution fucntions, u and v. /// </summary> public static double CopulaDensityFunction(CopulaType type, double u, double v, double alpha) { CheckCopulaAlpha(type, alpha); switch (type) { case CopulaType.Clayton: return (1.0 + alpha) * Math.Pow(u * v, -alpha - 1.0) * Math.Pow(Math.Pow(u, -alpha) + Math.Pow(v, -alpha) - 1.0, -1.0 / alpha - 2.0); case CopulaType.FGM: return 1.0 + alpha * (1.0 - 2.0 * u) * (1.0 - 2.0 * v); case CopulaType.Frank: double d1 = FrankPart(u, alpha) * FrankPart(v, alpha) + FrankPart(1, alpha); return -alpha * FrankPart(1, alpha) * Math.Exp(-alpha * (u + v)) / (d1 * d1); case CopulaType.Gumbel: double lnu = Math.Log(u); double lnv = Math.Log(v); double g1 = Math.Pow(lnu * lnv, alpha - 1.0) / (u * v); double g2 = CopulaCumulativeDistributionFunction(type, u, v, alpha); double g3 = Math.Pow(-lnu + -lnv, 1.0 / alpha - 2.0); double g4 = alpha - 1.0 + Math.Pow(-lnu + -lnv, 1.0 / alpha); return g1 * g2 * g3 * g4; case CopulaType.Independent: return 1.0; case CopulaType.Joe: double ju = Math.Pow(1.0 - u, alpha); double jv = Math.Pow(1.0 - v, alpha); double d3 = ju + jv - ju * jv; return Math.Pow(1.0 - u, alpha - 1.0) * Math.Pow(1.0 - v, alpha) * Math.Pow(d3, (1.0 / alpha) - 2.0) * (1.0 - alpha - d3); default: throw new ArgumentException("Copula type not expected."); } }
/// <summary> /// Returns the value of a copula, given two input cumulative distribution fucntions, u and v. /// </summary> public static double CopulaCumulativeDistributionFunction(CopulaType type, double u, double v, double alpha) { CheckCopulaAlpha(type, alpha); switch (type) { case CopulaType.Clayton: return Math.Pow(Math.Pow(u, -alpha) + Math.Pow(v, -alpha) - 1.0, -1.0 / alpha); case CopulaType.FGM: return u * v * (1.0 + alpha * (1.0 - u) * (1.0 - v)); case CopulaType.Frank: double d1 = 1 + (FrankPart(u, alpha) * FrankPart(v, alpha)) / FrankPart(1.0, alpha); return -(1.0/alpha) * Math.Log(d1); case CopulaType.Gumbel: double d2 = -Math.Pow(Math.Pow(-Math.Log(u), alpha) + Math.Pow(-Math.Log(v), alpha), 1.0 / alpha); return Math.Exp(d2); case CopulaType.Independent: return u * v; case CopulaType.Joe: double ju = Math.Pow(1.0 - u, alpha); double jv = Math.Pow(1.0 - v, alpha); double d3 = ju + jv - ju * jv; return 1 - Math.Pow(d3, 1.0 / alpha); default: throw new ArgumentException("Copula type not expected."); } }
private static void CheckCopulaAlpha(CopulaType type, double alpha) { switch (type) { case CopulaType.Clayton: if (alpha <= 0.0) throw new ArgumentException("Invalid alpha. Alpha should be greater than zero."); return; case CopulaType.FGM: if (alpha < -1.0 || alpha > 1.0) throw new ArgumentException("Invalid alpha. Should be: -1 <= alpha <= +1."); return; case CopulaType.Frank: if (alpha == 0.0) throw new ArgumentException("Invalid alpha. Alpha cannot equal zero."); return; case CopulaType.Gumbel: if (alpha < 1.0) throw new ArgumentException("Invalid alpha. Should be: alpha >= 1."); return; case CopulaType.Independent: return; //no alpha for independent case CopulaType.Joe: if (alpha < 0.0) throw new ArgumentException("Invalid alpha. Should be: alpha >= 0."); return; default: throw new ArgumentException("Copula type not expected."); } }
/// <summary> /// Returns the inverse of the first marginal CDF of a copula, for two cumulative distribution fucntions, u and v. /// Used in Monte Carlo simulation. /// </summary> /// <param name="type"></param> /// <param name="u">random number [0-1]</param> /// <param name="C1">random number [0-1], independent of u</param> /// <param name="alpha"></param> /// <returns>v, random number [0-1]</returns> public static double CopulaFirstMarginalInverse(CopulaType type, double u, double C1, double alpha) { CheckCopulaAlpha(type, alpha); switch (type) { case CopulaType.Clayton: double d = Math.Pow(C1, -alpha / (1.0 + alpha)) + Math.Pow(u, alpha) - 1.0; return u * Math.Pow(d, -1.0 / alpha); case CopulaType.Frank: double f1 = C1 * (Math.Exp(-alpha) - 1.0); double f2 = 1.0 + (Math.Exp(-alpha * u) - 1.0) * (1.0 - C1); return -(1.0 / alpha) * Math.Log(1.0 + f1 / f2); case CopulaType.Independent: return C1; default: throw new ArgumentException("Copula type not expected."); } }