Array Examples
Some basic examples with doubles.
import vecxt.all.*
import vecxt.BoundsCheck.DoBoundsCheck.yes
val v1 = Array[Double](1, 2, 3)
// v1: Array[Double] = Array(
// 0.6663667453928805,
// 0.6143002821164822,
// 0.9900590857598653
// )
val v2 = Array[Double](4, 5, 6)
// v2: Array[Double] = Array(4.0, 5.0, 6.0)
v1.dot(v2)
// res0: Double = 32.0
v1.sumSIMD // .sum std is slow. We can't squat on `sum` so we need a new name
// res1: Double = 6.0
v1.mean
// res2: Double = 2.0
v1.variance
// res3: Double = 1.0
v1.productSIMD
// res4: Double = 6.0
v1.norm
// res5: Double = 3.7416573867739413
v1.clampMin(1.5).printArr
// res6: String = "[1.5,2.0,3.0]"
v2.clampMax(1.5).printArr
// res7: String = "[1.5,1.5,1.5]"
v1.clamp(1.5, 2.5 ).printArr
// res8: String = "[1.5,2.0,2.5]"
v1.maxSIMD
// res9: Double = 3.0
v1.minSIMD
// res10: Double = 1.0
v1.corr(v2)
// res11: Double = 1.0
v1.spearmansRankCorrelation(v2)
// res12: Double = 1.0
cosineSimilarity(v1, v2)
// res13: Double = 0.9746318461970762
v1.productExceptSelf.printArr
// res14: String = "[6.0,3.0,2.0]"
v1.increments.printArr
// res15: String = "[1.0,1.0,1.0]"
v1.logSumExp
// res16: Double = 3.4076059644443806
v1.cumsum.printArr
// res17: String = "[1.0,3.0,6.0]"
(v1 + 1.0).printArr
// res18: String = "[2.0,3.0,4.0]"
(v1 + v2).printArr
// res19: String = "[5.0,7.0,9.0]"
(v1 - 1.0).printArr
// res20: String = "[0.0,1.0,2.0]"
(v1 - v2).printArr
// res21: String = "[-3.0,-3.0,-3.0]"
(v1 * 2.0).printArr
// res22: String = "[2.0,4.0,6.0]"
(v1 * v2).printArr
// res23: String = "[4.0,10.0,18.0]"
(v1 / 2.0).printArr
// res24: String = "[0.5,1.0,1.5]"
(v1 / v2).printArr
// res25: String = "[0.25,0.4,0.5]"
(v1.exp).printArr
// res26: String = "[2.718281828459045,7.38905609893065,20.085536923187668]"
(v1.log).printArr
// res27: String = "[0.0,0.6931471805599453,1.0986122886681098]"
(v1 > 2).printArr
// res28: String = "[false,false,true]"
(v1 >= 2).printArr
// res29: String = "[false,true,true]"
(v1 < 2).printArr
// res30: String = "[true,false,false]"
(v1 <= 2).printArr
// res31: String = "[true,true,false]"
(v1(v1 <= 2)).printArr
// res32: String = "[1.0,2.0]"
(v1.outer(v2)).printMat
// res33: String = """4.0 5.0 6.0
// 8.0 10.0 12.0
// 12.0 15.0 18.0"""
v1.exp.printArr
// res34: String = "[2.718281828459045,7.38905609893065,20.085536923187668]"
v1.log.printArr
// res35: String = "[0.0,0.6931471805599453,1.0986122886681098]"
v1.sin.printArr
// res36: String = "[0.8414709848078965,0.9092974268256817,0.1411200080598672]"
(-v1).printArr
// res37: String = "[-1.0,-2.0,-3.0]"
// Many of the urnary ops also have in place version, which would prevent an extra allocation. They have a `!` in their name by convention, and return `Unit`
// Most trig operations are available but not listed here.
v1.`exp!`
v1.printArr
// res39: String = "[2.718281828459045,7.38905609893065,20.085536923187668]"
v1.`log!`
v1.printArr
// res41: String = "[1.0,2.0,3.0]"
v1.`sin!`
v1.printArr
// res43: String = "[0.8414709848078965,0.9092974268256817,0.1411200080598672]"
v1.`cos!`
v1.printArr
// res45: String = "[0.6663667453928805,0.6143002821164822,0.9900590857598653]"
v1.sin.printArr
// res46: String = "[0.6181340709529279,0.5763868701035372,0.8360583968985081]"
v1.cos.printArr
// res47: String = "[0.7860726876868072,0.8171769551157498,0.5486404623936305]"
And Ints. Note that the API here is more limited at the moment.
import vecxt.all.*
import narr.*
import vecxt.BoundsCheck.DoBoundsCheck.yes
val v1 = NArray(1, 2, 3)
// v1: Array[Int] = Array(1, 2, 3)
val v2 = NArray(4, 5, 6)
// v2: Array[Int] = Array(4, 5, 6)
v1.dot(v2)
// res49: Int = 32
(v1 + v2).printArr
// res50: String = "[5,7,9]"
(v1 - v2).printArr
// res51: String = "[-3,-3,-3]"
(v1 > 2).printArr
// res52: String = "[false,false,true]"
(v1 >= 2).printArr
// res53: String = "[false,true,true]"
(v1 < 2).printArr
// res54: String = "[true,false,false]"
(v1 <= 2).printArr
// res55: String = "[true,true,false]"
(v1(v1 <= 2)).printArr
// res56: String = "[1,2]"
Risk Measures (TVaR/VaR)
The library includes methods for calculating Tail Value at Risk (TVaR) and Value at Risk (VaR), which are commonly used in reinsurance and risk management.
import vecxt.all.*
import narr.*
import vecxt.reinsurance.*
import vecxt.BoundsCheck.DoBoundsCheck.yes
// Create a sample loss distribution
val losses = NArray[Double](10.0, 25.0, 15.0, 50.0, 5.0, 30.0, 20.0, 8.0, 45.0, 12.0)
// losses: Array[Double] = Array(
// 5.0,
// 8.0,
// 10.0,
// 12.0,
// 15.0,
// 20.0,
// 25.0,
// 30.0,
// 45.0,
// 50.0
// )
// Calculate Value at Risk (VaR) at 90% confidence level
// VaR represents the threshold value - 90% of losses are above this value
val var90 = losses.VaR(0.90)
// var90: Double = 5.0
// Calculate Tail Value at Risk (TVaR) at 90% confidence level
// TVaR is the expected loss in the worst 10% of cases (average of the tail)
val tvar90 = losses.tVar(0.90)
// tvar90: Double = 5.0
// Calculate both TVaR and VaR together (more efficient)
val result = losses.tVarWithVaR(0.90)
// result: NamedTuple[Tuple3["cl", "VaR", "TVaR"], Tuple3[Double, Double, Double]] = (
// 0.09999999999999998,
// 5.0,
// 5.0
// )
val confidenceLevel = result.cl // = 0.10 (1 - 0.90)
// confidenceLevel: Double = 0.09999999999999998
val varValue = result.VaR
// varValue: Double = 5.0
val tvarValue = result.TVaR
// tvarValue: Double = 5.0
// Calculate multiple confidence levels at once (most efficient for batch analysis)
val alphas = NArray[Double](0.85, 0.90, 0.95, 0.99)
// alphas: Array[Double] = Array(0.85, 0.9, 0.95, 0.99)
val results = losses.tVarWithVaRBatch(alphas)
// results: Array[NamedTuple[Tuple3["cl", "VaR", "TVaR"], Tuple3[Double, Double, Double]]] = Array(
// (0.15000000000000002, 5.0, 5.0),
// (0.09999999999999998, 5.0, 5.0),
// (0.050000000000000044, 5.0, NaN),
// (0.010000000000000009, 5.0, NaN)
// )
// Each result contains (cl, VaR, TVaR)
results(0).cl // Confidence level for first alpha
// res58: Double = 0.15000000000000002
results(0).VaR // VaR for 85% confidence
// res59: Double = 5.0
results(0).TVaR // TVaR for 85% confidence
// res60: Double = 5.0
// Get a boolean mask indicating which values are in the tail
val tailMask = losses.tVarIdx(0.90)
// tailMask: Array[Boolean] = Array(
// true,
// false,
// false,
// false,
// false,
// false,
// false,
// false,
// false,
// false
// )
// tailMask(i) is true if losses(i) is in the worst 10%
// Calculate tail dependence between two distributions
// Measures how often extreme values occur together
val losses1 = NArray[Double](5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0)
// losses1: Array[Double] = Array(
// 5.0,
// 10.0,
// 15.0,
// 20.0,
// 25.0,
// 30.0,
// 35.0,
// 40.0,
// 45.0,
// 50.0
// )
val losses2 = NArray[Double](8.0, 12.0, 18.0, 22.0, 28.0, 32.0, 38.0, 42.0, 48.0, 52.0)
// losses2: Array[Double] = Array(
// 8.0,
// 12.0,
// 18.0,
// 22.0,
// 28.0,
// 32.0,
// 38.0,
// 42.0,
// 48.0,
// 52.0
// )
val tailDep = losses1.qdep(0.90, losses2)
// tailDep: Double = 0.0
// Returns proportion of tail observations that are shared (0.0 to 1.0)