diff --git a/.scalafmt.conf b/.scalafmt.conf index 74e72e1..db7feb5 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -9,5 +9,5 @@ runner.dialectOverride.withAllowEndMarker = true runner.dialectOverride.allowSignificantIndentation = true rewrite.scala3.countEndMarkerLines = lastBlockOnly rewrite.scala3.insertEndMarkerMinLines = 1 -indent.defnSite = 4 +indent.main = 4 maxColumn = 120 \ No newline at end of file diff --git a/build.sbt b/build.sbt index 99cde08..4a19d8c 100644 --- a/build.sbt +++ b/build.sbt @@ -61,94 +61,94 @@ lazy val core = crossProject( JVMPlatform, NativePlatform ) - .crossType(CrossType.Full) - .settings( - name := "vecxt", - description := """High performance extensions for numeric workloads for + .crossType(CrossType.Full) + .settings( + name := "vecxt", + description := """High performance extensions for numeric workloads for - Array[Double] on JVM - Array[Double] on native. - Float64Array on JS""", - libraryDependencies ++= Seq( - // ai.dragonfly" %%% "narr" % "0.103", I do'nt think we need this as a dependance ... it can be added seperately in userland! - "dev.ludovic.netlib" % "blas" % "3.0.3" + libraryDependencies ++= Seq( + // ai.dragonfly" %%% "narr" % "0.103", I do'nt think we need this as a dependance ... it can be added seperately in userland! + "dev.ludovic.netlib" % "blas" % "3.0.3" + ) + ) + .jvmSettings( + ) + .jsSettings( + scalaJSUseMainModuleInitializer := false, + scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)), + jsEnv := { + import org.scalajs.jsenv.nodejs.NodeJSEnv + new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--enable-source-maps"))) + } + ) + .nativeSettings( + libraryDependencies += "org.ekrich" %%% "sblas" % "0.5.0" ) - ) - .jvmSettings( - ) - .jsSettings( - scalaJSUseMainModuleInitializer := false, - scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)), - jsEnv := { - import org.scalajs.jsenv.nodejs.NodeJSEnv - new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--enable-source-maps"))) - } - ) - .nativeSettings( - libraryDependencies += "org.ekrich" %%% "sblas" % "0.5.0" - ) lazy val docs = project - .in(file("site")) - .enablePlugins(TypelevelSitePlugin) - .dependsOn(core.jvm) - .settings( - laikaConfig ~= { _.withRawContent }, - laikaExtensions := Seq( - GitHubFlavor, - SyntaxHighlighting - ), - libraryDependencies ++= Seq( - "ai.dragonfly" %%% "narr" % "0.103" - ), - tlSiteHelium := { - Helium.defaults.site - .metadata( - title = Some("vecxt"), - language = Some("en"), - description = Some("vecxt"), - authors = Seq("Simon Parten"), - datePublished = Some(OffsetDateTime.now) - ) - .site - .topNavigationBar( - homeLink = IconLink.internal(laika.ast.Path(List("index.md")), HeliumIcon.home), - navLinks = Seq(IconLink.external("https://github.com/Quafadas/vecxt", HeliumIcon.github)) - ) - Helium.defaults.site - .externalJS( - url = "https://cdn.jsdelivr.net/npm/vega@5" - ) - .site - .externalJS( - url = "https://cdn.jsdelivr.net/npm/vega-lite@5" - ) - .site - .externalJS( - url = "https://cdn.jsdelivr.net/npm/vega-embed@6" - ) - } - ) + .in(file("site")) + .enablePlugins(TypelevelSitePlugin) + .dependsOn(core.jvm) + .settings( + laikaConfig ~= { _.withRawContent }, + laikaExtensions := Seq( + GitHubFlavor, + SyntaxHighlighting + ), + libraryDependencies ++= Seq( + "ai.dragonfly" %%% "narr" % "0.103" + ), + tlSiteHelium := { + Helium.defaults.site + .metadata( + title = Some("vecxt"), + language = Some("en"), + description = Some("vecxt"), + authors = Seq("Simon Parten"), + datePublished = Some(OffsetDateTime.now) + ) + .site + .topNavigationBar( + homeLink = IconLink.internal(laika.ast.Path(List("index.md")), HeliumIcon.home), + navLinks = Seq(IconLink.external("https://github.com/Quafadas/vecxt", HeliumIcon.github)) + ) + Helium.defaults.site + .externalJS( + url = "https://cdn.jsdelivr.net/npm/vega@5" + ) + .site + .externalJS( + url = "https://cdn.jsdelivr.net/npm/vega-lite@5" + ) + .site + .externalJS( + url = "https://cdn.jsdelivr.net/npm/vega-embed@6" + ) + } + ) lazy val tests = crossProject( JVMPlatform, JSPlatform, NativePlatform ) - .in(file("tests")) - .enablePlugins(NoPublishPlugin) - .dependsOn(core) - .settings( - name := "tests", - libraryDependencies ++= Seq( - "org.scalameta" %%% "munit" % "1.0.0-M10" % Test, - "ai.dragonfly" %%% "narr" % "0.103" % Test + .in(file("tests")) + .enablePlugins(NoPublishPlugin) + .dependsOn(core) + .settings( + name := "tests", + libraryDependencies ++= Seq( + "org.scalameta" %%% "munit" % "1.0.0-M10" % Test, + "ai.dragonfly" %%% "narr" % "0.103" % Test + ) + ) + .jsSettings( + scalaJSUseMainModuleInitializer := true, + scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)), + jsEnv := { + import org.scalajs.jsenv.nodejs.NodeJSEnv + new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--enable-source-maps"))) + } ) - ) - .jsSettings( - scalaJSUseMainModuleInitializer := true, - scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)), - jsEnv := { - import org.scalajs.jsenv.nodejs.NodeJSEnv - new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--enable-source-maps"))) - } - ) diff --git a/core/js/src/main/scala/vecxt/array.extensions.scala b/core/js/src/main/scala/vecxt/array.extensions.scala index 40f72b4..0cc7be9 100644 --- a/core/js/src/main/scala/vecxt/array.extensions.scala +++ b/core/js/src/main/scala/vecxt/array.extensions.scala @@ -24,356 +24,358 @@ import scala.util.chaining.* package object vecxt: - extension (v: Float64Array) - inline def nativeSort(): Unit = v.asInstanceOf[TypedArrayFacade].sort() - inline def nativeReverse(): Unit = v.asInstanceOf[TypedArrayFacade].reverse() - inline def nativeSlice(): Float64Array = v.asInstanceOf[TypedArrayFacade].slice() - end extension - - @js.native - trait TypedArrayFacade extends js.Object: - - def sort(): Unit = js.native - def reverse(): Unit = - js.native // mutable https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/reverse - def slice(): Float64Array = js.native - end TypedArrayFacade - - @js.native - trait JsArrayFacade extends js.Object: - def fill[A](a: A): Unit = js.native - end JsArrayFacade - - extension [A](v: js.Array[A]) inline def fill(a: A): Unit = v.asInstanceOf[JsArrayFacade].fill(a) - extension (vec: js.Array[Boolean]) - inline def countTrue: Int = - var sum = 0 - for i <- 0 until vec.length do if vec(i) then sum = sum + 1 - sum - end countTrue - - inline def &&(thatIdx: js.Array[Boolean]): js.Array[Boolean] = - val result = new js.Array[Boolean](vec.length) - for i <- 0 until vec.length do result(i) = vec(i) && thatIdx(i) - result - end && - - inline def ||(thatIdx: js.Array[Boolean]): js.Array[Boolean] = - val result = new js.Array[Boolean](vec.length) - for i <- 0 until vec.length do result(i) = vec(i) || thatIdx(i) - result - end || - - // def copy: Array[Boolean] = - // val copyOfThisVector: Array[Boolean] = new Array[Boolean](vec.length) - // var i = 0 - // while i < vec.length do - // copyOfThisVector(i) = vec(i) - // i = i + 1 - // end while - // copyOfThisVector - // end copy - end extension - - extension (vec: Float64Array) - - inline def idxBoolean(index: js.Array[Boolean])(using inline boundsCheck: BoundsCheck) = - dimCheck(vec, index) - val trues = index.countTrue - val newVec = Float64Array(trues) - var j = 0 - for i <- 0 to trues do - // println(s"i: $i || j: $j || ${index(i)} ${vec(i)} ") - if index(i) then - newVec(j) = vec(i) - j += 1 - end for - newVec - end idxBoolean - - def increments: Float64Array = - val out = Float64Array(vec.length) - out(0) = vec(0) - var i = 1 - while i < vec.length do - out(i) = vec(i) - vec(i - 1) - i = i + 1 - end while - out - end increments - - inline def stdDev: Double = - // https://www.cuemath.com/data/standard-deviation/ - val mu = vec.mean - val diffs_2 = vec.map(num => (num - mu) * (num - mu)) - Math.sqrt(diffs_2.sum / (vec.length - 1)) - end stdDev - - inline def mean: Double = vec.sum / vec.length - - inline def sum: Double = - var sum = 0.0 - var i = 0; - while i < vec.length do - sum = sum + vec(i) - i = i + 1 - end while - sum - end sum - - def variance: Double = - // https://www.cuemath.com/sample-variance-formula/ - val μ = vec.mean - vec.map(i => (i - μ) * (i - μ)).sum / (vec.length - 1) - end variance - - inline def pearsonCorrelationCoefficient(thatVector: Float64Array)(using inline boundsCheck: BoundsCheck): Double = - dimCheck(vec, thatVector) - val n = vec.length - var i = 0 - - var sum_x = 0.0 - var sum_y = 0.0 - var sum_xy = 0.0 - var sum_x2 = 0.0 - var sum_y2 = 0.0 - - while i < n do - sum_x = sum_x + vec(i) - sum_y = sum_y + thatVector(i) - sum_xy = sum_xy + vec(i) * thatVector(i) - sum_x2 = sum_x2 + vec(i) * vec(i) - sum_y2 = sum_y2 + thatVector(i) * thatVector(i) - i = i + 1 - end while - (n * sum_xy - (sum_x * sum_y)) / Math.sqrt( - (sum_x2 * n - sum_x * sum_x) * (sum_y2 * n - sum_y * sum_y) - ) - end pearsonCorrelationCoefficient - - inline def spearmansRankCorrelation(thatVector: Float64Array)(using inline boundsCheck: BoundsCheck): Double = - dimCheck(vec, thatVector) - val theseRanks = vec.elementRanks - val thoseRanks = thatVector.elementRanks - theseRanks.pearsonCorrelationCoefficient(thoseRanks) - end spearmansRankCorrelation - - // An alias - pearson is the most commonly requested type of correlation - inline def corr(thatVector: Float64Array)(using inline boundsCheck: BoundsCheck): Double = - pearsonCorrelationCoefficient(thatVector) - - def elementRanks: Float64Array = - val indexed1 = vec.zipWithIndex - val indexed = indexed1.toArray.sorted(Ordering.by(_._1)) - - val ranks: Array[Double] = new Array(vec.length) // faster than zeros. - ranks(indexed.last._2) = vec.length - var currentValue: Double = indexed(0)._1 - var r0: Int = 0 - var rank: Int = 1 - while rank < vec.length do - val temp: Double = indexed(rank)._1 - val end: Int = - if temp != currentValue then rank - else if rank == vec.length - 1 then rank + 1 - else -1 - if end > -1 then - val avg: Double = (1.0 + (end + r0)) / 2.0 - var i: Int = r0; - while i < end do - ranks(indexed(i)._2) = avg - i += 1 - end while - r0 = rank - currentValue = temp - end if - rank += 1 - end while - Float64Array.of(ranks*) - end elementRanks - - inline def cumsum = - var i = 1 - while i < vec.length do - vec(i) = vec(i - 1) + vec(i) - i = i + 1 - end while - end cumsum - - inline def norm: Double = blas.dnrm2(vec.length, vec, 1) - - inline def -(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Float64Array = - dimCheck(vec, vec2) - vec.nativeSlice().tap(_ -= vec2) - end - - - inline def -=(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Unit = - dimCheck(vec, vec2) - blas.daxpy(vec.length, -1.0, vec2, 1, vec, 1) - end -= - - inline def +(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Float64Array = - dimCheck(vec, vec2) - vec.nativeSlice().tap(_ += vec2) - end + - - inline def +=(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Unit = - dimCheck(vec, vec2) - blas.daxpy(vec.length, 1.0, vec2, 1, vec, 1) - end += - - inline def *=(d: Double): Unit = - blas.dscal(vec.length, d, vec, 1) - end *= - - inline def *(d: Double): Float64Array = - vec.nativeSlice().tap(_ *= d) - end * - - inline def <(num: Double): js.Array[Boolean] = - logicalIdx((a, b) => a < b, num) - - inline def <=(num: Double): js.Array[Boolean] = - logicalIdx((a, b) => a <= b, num) - - inline def >(num: Double): js.Array[Boolean] = - logicalIdx((a, b) => a > b, num) - - inline def >=(num: Double): js.Array[Boolean] = - logicalIdx((a, b) => a >= b, num) - - inline def logicalIdx( - inline op: (Double, Double) => Boolean, - inline num: Double - ): js.Array[Boolean] = - val n = vec.length - val idx = new js.Array[Boolean](n).tap(_.fill(false)) - - var i = 0 - while i < n do - if op(vec(i), num) then idx(i) = true - i = i + 1 - end while - idx - end logicalIdx - - def covariance(thatVector: Float64Array): Double = - val μThis = vec.mean - val μThat = thatVector.mean - var cv: Double = 0 - var i: Int = 0; - while i < vec.length do - cv += (vec(i) - μThis) * (thatVector(i) - μThat) - i += 1 - end while - cv / (vec.length - 1) - end covariance - - // def maxElement: Double = - // val t = js.Math.max( vec.toArray: _* ) - - /* + extension (v: Float64Array) + inline def nativeSort(): Unit = v.asInstanceOf[TypedArrayFacade].sort() + inline def nativeReverse(): Unit = v.asInstanceOf[TypedArrayFacade].reverse() + inline def nativeSlice(): Float64Array = v.asInstanceOf[TypedArrayFacade].slice() + end extension + + @js.native + trait TypedArrayFacade extends js.Object: + + def sort(): Unit = js.native + def reverse(): Unit = + js.native // mutable https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/reverse + def slice(): Float64Array = js.native + end TypedArrayFacade + + @js.native + trait JsArrayFacade extends js.Object: + def fill[A](a: A): Unit = js.native + end JsArrayFacade + + extension [A](v: js.Array[A]) inline def fill(a: A): Unit = v.asInstanceOf[JsArrayFacade].fill(a) + extension (vec: js.Array[Boolean]) + inline def countTrue: Int = + var sum = 0 + for i <- 0 until vec.length do if vec(i) then sum = sum + 1 + sum + end countTrue + + inline def &&(thatIdx: js.Array[Boolean]): js.Array[Boolean] = + val result = new js.Array[Boolean](vec.length) + for i <- 0 until vec.length do result(i) = vec(i) && thatIdx(i) + result + end && + + inline def ||(thatIdx: js.Array[Boolean]): js.Array[Boolean] = + val result = new js.Array[Boolean](vec.length) + for i <- 0 until vec.length do result(i) = vec(i) || thatIdx(i) + result + end || + + // def copy: Array[Boolean] = + // val copyOfThisVector: Array[Boolean] = new Array[Boolean](vec.length) + // var i = 0 + // while i < vec.length do + // copyOfThisVector(i) = vec(i) + // i = i + 1 + // end while + // copyOfThisVector + // end copy + end extension + + extension (vec: Float64Array) + + inline def idxBoolean(index: js.Array[Boolean])(using inline boundsCheck: BoundsCheck) = + dimCheck(vec, index) + val trues = index.countTrue + val newVec = Float64Array(trues) + var j = 0 + for i <- 0 to trues do + // println(s"i: $i || j: $j || ${index(i)} ${vec(i)} ") + if index(i) then + newVec(j) = vec(i) + j += 1 + end for + newVec + end idxBoolean + + def increments: Float64Array = + val out = Float64Array(vec.length) + out(0) = vec(0) + var i = 1 + while i < vec.length do + out(i) = vec(i) - vec(i - 1) + i = i + 1 + end while + out + end increments + + inline def stdDev: Double = + // https://www.cuemath.com/data/standard-deviation/ + val mu = vec.mean + val diffs_2 = vec.map(num => (num - mu) * (num - mu)) + Math.sqrt(diffs_2.sum / (vec.length - 1)) + end stdDev + + inline def mean: Double = vec.sum / vec.length + + inline def sum: Double = + var sum = 0.0 + var i = 0; + while i < vec.length do + sum = sum + vec(i) + i = i + 1 + end while + sum + end sum + + def variance: Double = + // https://www.cuemath.com/sample-variance-formula/ + val μ = vec.mean + vec.map(i => (i - μ) * (i - μ)).sum / (vec.length - 1) + end variance + + inline def pearsonCorrelationCoefficient(thatVector: Float64Array)(using + inline boundsCheck: BoundsCheck + ): Double = + dimCheck(vec, thatVector) + val n = vec.length + var i = 0 + + var sum_x = 0.0 + var sum_y = 0.0 + var sum_xy = 0.0 + var sum_x2 = 0.0 + var sum_y2 = 0.0 + + while i < n do + sum_x = sum_x + vec(i) + sum_y = sum_y + thatVector(i) + sum_xy = sum_xy + vec(i) * thatVector(i) + sum_x2 = sum_x2 + vec(i) * vec(i) + sum_y2 = sum_y2 + thatVector(i) * thatVector(i) + i = i + 1 + end while + (n * sum_xy - (sum_x * sum_y)) / Math.sqrt( + (sum_x2 * n - sum_x * sum_x) * (sum_y2 * n - sum_y * sum_y) + ) + end pearsonCorrelationCoefficient + + inline def spearmansRankCorrelation(thatVector: Float64Array)(using inline boundsCheck: BoundsCheck): Double = + dimCheck(vec, thatVector) + val theseRanks = vec.elementRanks + val thoseRanks = thatVector.elementRanks + theseRanks.pearsonCorrelationCoefficient(thoseRanks) + end spearmansRankCorrelation + + // An alias - pearson is the most commonly requested type of correlation + inline def corr(thatVector: Float64Array)(using inline boundsCheck: BoundsCheck): Double = + pearsonCorrelationCoefficient(thatVector) + + def elementRanks: Float64Array = + val indexed1 = vec.zipWithIndex + val indexed = indexed1.toArray.sorted(Ordering.by(_._1)) + + val ranks: Array[Double] = new Array(vec.length) // faster than zeros. + ranks(indexed.last._2) = vec.length + var currentValue: Double = indexed(0)._1 + var r0: Int = 0 + var rank: Int = 1 + while rank < vec.length do + val temp: Double = indexed(rank)._1 + val end: Int = + if temp != currentValue then rank + else if rank == vec.length - 1 then rank + 1 + else -1 + if end > -1 then + val avg: Double = (1.0 + (end + r0)) / 2.0 + var i: Int = r0; + while i < end do + ranks(indexed(i)._2) = avg + i += 1 + end while + r0 = rank + currentValue = temp + end if + rank += 1 + end while + Float64Array.of(ranks*) + end elementRanks + + inline def cumsum = + var i = 1 + while i < vec.length do + vec(i) = vec(i - 1) + vec(i) + i = i + 1 + end while + end cumsum + + inline def norm: Double = blas.dnrm2(vec.length, vec, 1) + + inline def -(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Float64Array = + dimCheck(vec, vec2) + vec.nativeSlice().tap(_ -= vec2) + end - + + inline def -=(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Unit = + dimCheck(vec, vec2) + blas.daxpy(vec.length, -1.0, vec2, 1, vec, 1) + end -= + + inline def +(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Float64Array = + dimCheck(vec, vec2) + vec.nativeSlice().tap(_ += vec2) + end + + + inline def +=(vec2: Float64Array)(using inline boundsCheck: BoundsCheck): Unit = + dimCheck(vec, vec2) + blas.daxpy(vec.length, 1.0, vec2, 1, vec, 1) + end += + + inline def *=(d: Double): Unit = + blas.dscal(vec.length, d, vec, 1) + end *= + + inline def *(d: Double): Float64Array = + vec.nativeSlice().tap(_ *= d) + end * + + inline def <(num: Double): js.Array[Boolean] = + logicalIdx((a, b) => a < b, num) + + inline def <=(num: Double): js.Array[Boolean] = + logicalIdx((a, b) => a <= b, num) + + inline def >(num: Double): js.Array[Boolean] = + logicalIdx((a, b) => a > b, num) + + inline def >=(num: Double): js.Array[Boolean] = + logicalIdx((a, b) => a >= b, num) + + inline def logicalIdx( + inline op: (Double, Double) => Boolean, + inline num: Double + ): js.Array[Boolean] = + val n = vec.length + val idx = new js.Array[Boolean](n).tap(_.fill(false)) + + var i = 0 + while i < n do + if op(vec(i), num) then idx(i) = true + i = i + 1 + end while + idx + end logicalIdx + + def covariance(thatVector: Float64Array): Double = + val μThis = vec.mean + val μThat = thatVector.mean + var cv: Double = 0 + var i: Int = 0; + while i < vec.length do + cv += (vec(i) - μThis) * (thatVector(i) - μThat) + i += 1 + end while + cv / (vec.length - 1) + end covariance + + // def maxElement: Double = + // val t = js.Math.max( vec.toArray: _* ) + + /* Retention and limit are known constants In excel f(x) = min(max(x - retention, 0), limit)) - */ - inline def reinsuranceFunction(limitOpt: Option[Limit], retentionOpt: Option[Retention]): Unit = - (limitOpt, retentionOpt) match - case (Some(limit), Some(retention)) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - retention - if tmp < 0.0 then vec(i) = 0.0 - else if tmp > limit then vec(i) = limit.toDouble - else vec(i) = tmp - end if - i = i + 1 - end while - - case (None, Some(retention)) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - retention - if tmp < 0.0 then vec(i) = 0.0 - else vec(i) = tmp - i = i + 1 - end while - - case (Some(limit), None) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > limit then vec(i) = limit.toDouble - else vec(i) = tmp - i = i + 1 - end while - - case (None, None) => () - - end reinsuranceFunction - - /* + */ + inline def reinsuranceFunction(limitOpt: Option[Limit], retentionOpt: Option[Retention]): Unit = + (limitOpt, retentionOpt) match + case (Some(limit), Some(retention)) => + var i = 0; + while i < vec.length do + val tmp = vec(i) - retention + if tmp < 0.0 then vec(i) = 0.0 + else if tmp > limit then vec(i) = limit.toDouble + else vec(i) = tmp + end if + i = i + 1 + end while + + case (None, Some(retention)) => + var i = 0; + while i < vec.length do + val tmp = vec(i) - retention + if tmp < 0.0 then vec(i) = 0.0 + else vec(i) = tmp + i = i + 1 + end while + + case (Some(limit), None) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > limit then vec(i) = limit.toDouble + else vec(i) = tmp + i = i + 1 + end while + + case (None, None) => () + + end reinsuranceFunction + + /* Retention and limit are known constants In excel f(x) = if(x < retention, 0, if(x > limit, limit, x) - */ - inline def franchiseFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = - (limitOpt, retentionOpt) match - case (None, None) => () - - case (Some(limit), Some(retention)) => - var i = 0; - val maxLim = limit.toDouble + retention.toDouble - while i < vec.length do - val tmp = vec(i) - if tmp < retention then vec(i) = 0.0 - else if tmp > maxLim then vec(i) = maxLim - else vec(i) = tmp - end if - i = i + 1 - end while - - case (Some(limit), None) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > limit.toDouble then vec(i) = limit.toDouble - else vec(i) = tmp - end if - i = i + 1 - end while - case (None, Some(retention)) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > retention.toDouble then vec(i) = tmp - else vec(i) = 0.0 - end if - i = i + 1 - end while - end franchiseFunction - - end extension - - extension (vec: js.Array[Float64Array]) - inline def horizontalSum: Float64Array = - val out = new Float64Array(vec.head.length) - var i = 0 - while i < vec.head.length do - var sum = 0.0 - var j = 0 - while j < vec.length do - sum += vec(j)(i) - // pprint.pprintln(s"j : $j i : $i vecij : ${vec(j)(i)} out : ${out(i)} sum : $sum") - j = j + 1 - end while - out(i) = sum - i = i + 1 - end while - out - end extension + */ + inline def franchiseFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = + (limitOpt, retentionOpt) match + case (None, None) => () + + case (Some(limit), Some(retention)) => + var i = 0; + val maxLim = limit.toDouble + retention.toDouble + while i < vec.length do + val tmp = vec(i) + if tmp < retention then vec(i) = 0.0 + else if tmp > maxLim then vec(i) = maxLim + else vec(i) = tmp + end if + i = i + 1 + end while + + case (Some(limit), None) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > limit.toDouble then vec(i) = limit.toDouble + else vec(i) = tmp + end if + i = i + 1 + end while + case (None, Some(retention)) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > retention.toDouble then vec(i) = tmp + else vec(i) = 0.0 + end if + i = i + 1 + end while + end franchiseFunction + + end extension + + extension (vec: js.Array[Float64Array]) + inline def horizontalSum: Float64Array = + val out = new Float64Array(vec.head.length) + var i = 0 + while i < vec.head.length do + var sum = 0.0 + var j = 0 + while j < vec.length do + sum += vec(j)(i) + // pprint.pprintln(s"j : $j i : $i vecij : ${vec(j)(i)} out : ${out(i)} sum : $sum") + j = j + 1 + end while + out(i) = sum + i = i + 1 + end while + out + end extension end vecxt diff --git a/core/js/src/main/scala/vecxt/dimCheck.scala b/core/js/src/main/scala/vecxt/dimCheck.scala index 229ad8d..c26a847 100644 --- a/core/js/src/main/scala/vecxt/dimCheck.scala +++ b/core/js/src/main/scala/vecxt/dimCheck.scala @@ -22,11 +22,11 @@ import scala.scalajs.js.typedarray.Float64Array import BoundsChecks.BoundsCheck object dimCheck: - inline def apply[A](a: Float64Array, b: js.Array[A])(using inline doCheck: BoundsCheck) = - inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) + inline def apply[A](a: Float64Array, b: js.Array[A])(using inline doCheck: BoundsCheck) = + inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) - inline def apply(a: Float64Array, b: Float64Array)(using inline doCheck: BoundsCheck) = - inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) + inline def apply(a: Float64Array, b: Float64Array)(using inline doCheck: BoundsCheck) = + inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) end dimCheck case class VectorDimensionMismatch(givenDimension: Int, requiredDimension: Int) extends Exception( diff --git a/core/js/src/main/scala/vecxt/stdlib.facade.scala b/core/js/src/main/scala/vecxt/stdlib.facade.scala index 7e02901..88eb06e 100644 --- a/core/js/src/main/scala/vecxt/stdlib.facade.scala +++ b/core/js/src/main/scala/vecxt/stdlib.facade.scala @@ -26,9 +26,9 @@ object blas extends ArrayOps @js.native trait ArrayOps extends js.Object: - def daxpy(N: Int, alpha: Double, x: Float64Array, strideX: Int, y: Float64Array, strideY: Int): Unit = - js.native + def daxpy(N: Int, alpha: Double, x: Float64Array, strideX: Int, y: Float64Array, strideY: Int): Unit = + js.native - def dscal(N: Int, alpha: Double, x: Float64Array, strideX: Int): Unit = js.native - def dnrm2(N: Int, x: Float64Array, strideX: Int): Double = js.native + def dscal(N: Int, alpha: Double, x: Float64Array, strideX: Int): Unit = js.native + def dnrm2(N: Int, x: Float64Array, strideX: Int): Double = js.native end ArrayOps diff --git a/core/jvm/src/main/scala/vecxt/array.extensions.scala b/core/jvm/src/main/scala/vecxt/array.extensions.scala index a9f6718..9754493 100644 --- a/core/jvm/src/main/scala/vecxt/array.extensions.scala +++ b/core/jvm/src/main/scala/vecxt/array.extensions.scala @@ -15,366 +15,371 @@ */ import dev.ludovic.netlib.blas.JavaBLAS.getInstance as blas +import jdk.incubator.vector.* import vecxt.BoundsChecks.* import vecxt.Limits.Limit import vecxt.Retentions.Retention -import jdk.incubator.vector.* + import scala.util.chaining.* package object vecxt: - val SPECIES = DoubleVector.SPECIES_PREFERRED; - - extension (vec: Array[Boolean]) - inline def countTrue: Int = - var sum = 0 - for i <- 0 until vec.length do if vec(i) then sum = sum + 1 - sum - end countTrue - - inline def &&(thatIdx: Array[Boolean]): Array[Boolean] = - val result: Array[Boolean] = new Array[Boolean](vec.length) - for i <- 0 until vec.length do result(i) = vec(i) && thatIdx(i) - result - end && - - inline def ||(thatIdx: Array[Boolean]): Array[Boolean] = - val result: Array[Boolean] = new Array[Boolean](vec.length) - for i <- 0 until vec.length do result(i) = vec(i) || thatIdx(i) - result - end || - end extension - - extension (vec: Array[Double]) - - inline def idxBoolean(index: Array[Boolean])(using inline boundsCheck: BoundsCheck) = - dimCheck(vec, index) - val trues = index.countTrue - val newVec: Array[Double] = new Array[Double](trues) - var j = 0 - for i <- 0 to trues do - // println(s"i: $i || j: $j || ${index(i)} ${vec(i)} ") - if index(i) then - newVec(j) = vec(i) - j += 1 - end for - newVec - end idxBoolean - - def increments: Array[Double] = - val out = new Array[Double](vec.length) - out(0) = vec(0) - var i = 1 - while i < vec.length do - out(i) = vec(i) - vec(i - 1) - i = i + 1 - end while - out - end increments - - inline def pearsonCorrelationCoefficient(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = - dimCheck(vec, thatVector) - val n = vec.length - var i = 0 - - var sum_x = 0.0 - var sum_y = 0.0 - var sum_xy = 0.0 - var sum_x2 = 0.0 - var sum_y2 = 0.0 - - while i < n do - sum_x = sum_x + vec(i) - sum_y = sum_y + thatVector(i) - sum_xy = sum_xy + vec(i) * thatVector(i) - sum_x2 = sum_x2 + vec(i) * vec(i) - sum_y2 = sum_y2 + thatVector(i) * thatVector(i) - i = i + 1 - end while - (n * sum_xy - (sum_x * sum_y)) / Math.sqrt( - (sum_x2 * n - sum_x * sum_x) * (sum_y2 * n - sum_y * sum_y) - ) - end pearsonCorrelationCoefficient - - inline def spearmansRankCorrelation(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = - dimCheck(vec, thatVector) - val theseRanks = vec.elementRanks - val thoseRanks = thatVector.elementRanks - theseRanks.pearsonCorrelationCoefficient(thoseRanks) - end spearmansRankCorrelation - - // An alias - pearson is the most commonly requested type of correlation - inline def corr(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = - pearsonCorrelationCoefficient(thatVector) - - inline def elementRanks: Array[Double] = - val indexed: Array[(Double, Int)] = vec.zipWithIndex - indexed.sortInPlace()(Ordering.by(_._1)) - - val ranks: Array[Double] = new Array[Double](vec.length) - ranks(indexed.last._2) = vec.length - var currentValue: Double = indexed(0)._1 - var r0: Int = 0 - var rank: Int = 1 - while rank < vec.length do - val temp: Double = indexed(rank)._1 - val end: Int = - if temp != currentValue then rank - else if rank == vec.length - 1 then rank + 1 - else -1 - if end > -1 then - val avg: Double = (1.0 + (end + r0)) / 2.0 - var i: Int = r0; - while i < end do - ranks(indexed(i)._2) = avg - i += 1 - end while - r0 = rank - currentValue = temp - end if - rank += 1 - end while - ranks - end elementRanks - - def variance: Double = - // https://www.cuemath.com/sample-variance-formula/ - val μ = vec.mean - vec.map(i => (i - μ) * (i - μ)).sum / (vec.length - 1) - end variance - - inline def stdDev: Double = - // https://www.cuemath.com/data/standard-deviation/ - val mu = vec.mean - val diffs_2 = vec.map(num => Math.pow(num - mu, 2)) - Math.sqrt(diffs_2.sum / (vec.length - 1)) - end stdDev - - inline def mean: Double = vec.sum / vec.length - - inline def sum: Double = - var sum = 0.0 - var i = 0; - while i < vec.length do - sum = sum + vec(i) - i = i + 1 - end while - sum - end sum - - inline def cumsum: Unit = - var i = 1 - while i < vec.length do - vec(i) = vec(i - 1) + vec(i) - i = i + 1 - end while - end cumsum - - inline def norm: Double = blas.dnrm2(vec.length, vec, 1) - - inline def -(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Array[Double] = - dimCheck(vec, vec2) - vec.clone.tap(_ -= vec2) - end - - - inline def -=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = - dimCheck(vec, vec2) - blas.daxpy(vec.length, -1.0, vec2, 1, vec, 1) - end -= - - inline def +(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Array[Double] = - dimCheck(vec, vec2) - vec.clone.tap(_ += vec2) - end + - - inline def +=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = - dimCheck(vec, vec2) - blas.daxpy(vec.length, 1.0, vec2, 1, vec, 1) - end += - - inline def *=(d: Double): Array[Double] = - vec.tap(v => blas.dscal(v.length, d, v, 1)) - end *= - - inline def *(d: Double): Array[Double] = - vec.clone.tap(_ *= d) - end * - - inline def <(num: Double): Array[Boolean] = - logicalIdx((a, b) => a < b, num) - - inline def <=(num: Double): Array[Boolean] = - logicalIdx((a, b) => a <= b, num) - - inline def >(num: Double): Array[Boolean] = - logicalIdx((a, b) => a > b, num) - - inline def >=(num: Double): Array[Boolean] = - logicalIdx((a, b) => a >= b, num) - - inline def logicalIdx( - inline op: (Double, Double) => Boolean, - inline num: Double - ): Array[Boolean] = - val n = vec.length - val idx = new Array[Boolean](n) - var i = 0 - while i < n do - if op(vec(i), num) then idx(i) = true - i = i + 1 - end while - idx - end logicalIdx - - def covariance(thatVector: Array[Double]): Double = - val μThis = vec.mean - val μThat = thatVector.mean - var cv: Double = 0 - var i: Int = 0; - while i < vec.length do - cv += (vec(i) - μThis) * (thatVector(i) - μThat) - i += 1 - end while - cv / (vec.length - 1) - end covariance - - // def max: Double = - // vec(blas.idamax(vec.length, vec, 1)) // No JS version - - /* + val SPECIES = DoubleVector.SPECIES_PREFERRED; + + extension (vec: Array[Boolean]) + inline def countTrue: Int = + var sum = 0 + for i <- 0 until vec.length do if vec(i) then sum = sum + 1 + sum + end countTrue + + inline def &&(thatIdx: Array[Boolean]): Array[Boolean] = + val result: Array[Boolean] = new Array[Boolean](vec.length) + for i <- 0 until vec.length do result(i) = vec(i) && thatIdx(i) + result + end && + + inline def ||(thatIdx: Array[Boolean]): Array[Boolean] = + val result: Array[Boolean] = new Array[Boolean](vec.length) + for i <- 0 until vec.length do result(i) = vec(i) || thatIdx(i) + result + end || + end extension + + extension (vec: Array[Double]) + + inline def idxBoolean(index: Array[Boolean])(using inline boundsCheck: BoundsCheck) = + dimCheck(vec, index) + val trues = index.countTrue + val newVec: Array[Double] = new Array[Double](trues) + var j = 0 + for i <- 0 to trues do + // println(s"i: $i || j: $j || ${index(i)} ${vec(i)} ") + if index(i) then + newVec(j) = vec(i) + j += 1 + end for + newVec + end idxBoolean + + def increments: Array[Double] = + val out = new Array[Double](vec.length) + out(0) = vec(0) + var i = 1 + while i < vec.length do + out(i) = vec(i) - vec(i - 1) + i = i + 1 + end while + out + end increments + + inline def pearsonCorrelationCoefficient(thatVector: Array[Double])(using + inline boundsCheck: BoundsCheck + ): Double = + dimCheck(vec, thatVector) + val n = vec.length + var i = 0 + + var sum_x = 0.0 + var sum_y = 0.0 + var sum_xy = 0.0 + var sum_x2 = 0.0 + var sum_y2 = 0.0 + + while i < n do + sum_x = sum_x + vec(i) + sum_y = sum_y + thatVector(i) + sum_xy = sum_xy + vec(i) * thatVector(i) + sum_x2 = sum_x2 + vec(i) * vec(i) + sum_y2 = sum_y2 + thatVector(i) * thatVector(i) + i = i + 1 + end while + (n * sum_xy - (sum_x * sum_y)) / Math.sqrt( + (sum_x2 * n - sum_x * sum_x) * (sum_y2 * n - sum_y * sum_y) + ) + end pearsonCorrelationCoefficient + + inline def spearmansRankCorrelation(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = + dimCheck(vec, thatVector) + val theseRanks = vec.elementRanks + val thoseRanks = thatVector.elementRanks + theseRanks.pearsonCorrelationCoefficient(thoseRanks) + end spearmansRankCorrelation + + // An alias - pearson is the most commonly requested type of correlation + inline def corr(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = + pearsonCorrelationCoefficient(thatVector) + + inline def elementRanks: Array[Double] = + val indexed: Array[(Double, Int)] = vec.zipWithIndex + indexed.sortInPlace()(Ordering.by(_._1)) + + val ranks: Array[Double] = new Array[Double](vec.length) + ranks(indexed.last._2) = vec.length + var currentValue: Double = indexed(0)._1 + var r0: Int = 0 + var rank: Int = 1 + while rank < vec.length do + val temp: Double = indexed(rank)._1 + val end: Int = + if temp != currentValue then rank + else if rank == vec.length - 1 then rank + 1 + else -1 + if end > -1 then + val avg: Double = (1.0 + (end + r0)) / 2.0 + var i: Int = r0; + while i < end do + ranks(indexed(i)._2) = avg + i += 1 + end while + r0 = rank + currentValue = temp + end if + rank += 1 + end while + ranks + end elementRanks + + def variance: Double = + // https://www.cuemath.com/sample-variance-formula/ + val μ = vec.mean + vec.map(i => (i - μ) * (i - μ)).sum / (vec.length - 1) + end variance + + inline def stdDev: Double = + // https://www.cuemath.com/data/standard-deviation/ + val mu = vec.mean + val diffs_2 = vec.map(num => Math.pow(num - mu, 2)) + Math.sqrt(diffs_2.sum / (vec.length - 1)) + end stdDev + + inline def mean: Double = vec.sum / vec.length + + inline def sum: Double = + var sum = 0.0 + var i = 0; + while i < vec.length do + sum = sum + vec(i) + i = i + 1 + end while + sum + end sum + + inline def cumsum: Unit = + var i = 1 + while i < vec.length do + vec(i) = vec(i - 1) + vec(i) + i = i + 1 + end while + end cumsum + + inline def norm: Double = blas.dnrm2(vec.length, vec, 1) + + inline def -(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Array[Double] = + dimCheck(vec, vec2) + vec.clone.tap(_ -= vec2) + end - + + inline def -=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = + dimCheck(vec, vec2) + blas.daxpy(vec.length, -1.0, vec2, 1, vec, 1) + end -= + + inline def +(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Array[Double] = + dimCheck(vec, vec2) + vec.clone.tap(_ += vec2) + end + + + inline def +=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = + dimCheck(vec, vec2) + blas.daxpy(vec.length, 1.0, vec2, 1, vec, 1) + end += + + inline def *=(d: Double): Array[Double] = + vec.tap(v => blas.dscal(v.length, d, v, 1)) + end *= + + inline def *(d: Double): Array[Double] = + vec.clone.tap(_ *= d) + end * + + inline def <(num: Double): Array[Boolean] = + logicalIdx((a, b) => a < b, num) + + inline def <=(num: Double): Array[Boolean] = + logicalIdx((a, b) => a <= b, num) + + inline def >(num: Double): Array[Boolean] = + logicalIdx((a, b) => a > b, num) + + inline def >=(num: Double): Array[Boolean] = + logicalIdx((a, b) => a >= b, num) + + inline def logicalIdx( + inline op: (Double, Double) => Boolean, + inline num: Double + ): Array[Boolean] = + val n = vec.length + val idx = new Array[Boolean](n) + var i = 0 + while i < n do + if op(vec(i), num) then idx(i) = true + i = i + 1 + end while + idx + end logicalIdx + + def covariance(thatVector: Array[Double]): Double = + val μThis = vec.mean + val μThat = thatVector.mean + var cv: Double = 0 + var i: Int = 0; + while i < vec.length do + cv += (vec(i) - μThis) * (thatVector(i) - μThat) + i += 1 + end while + cv / (vec.length - 1) + end covariance + + // def max: Double = + // vec(blas.idamax(vec.length, vec, 1)) // No JS version + + /* Retention and limit are known constants f(X;retention, limit) = MIN(MAX(X - retention, 0), limit)) Note: mutates the input array - */ - inline def reinsuranceFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = - (limitOpt, retentionOpt) match - case (Some(limit), Some(retention)) => - var i = 0; - val upperBound = SPECIES.loopBound(vec.length); - while i < upperBound do - val tmp = DoubleVector.fromArray(SPECIES, vec, i).lanewise(VectorOperators.SUB, retention.toDouble) - val belowAttach = tmp.compare(VectorOperators.LT, 0) - val greaterLimit = tmp.compare(VectorOperators.GT, limit.toDouble) - tmp - .blend(0, belowAttach) - .blend(limit.toDouble, greaterLimit) - .intoArray(vec, i) - i += SPECIES.length() - end while - while i < vec.length do - val tmp = vec(i) - retention - if tmp < 0.0 then vec(i) = 0.0 - else if tmp > limit then vec(i) = limit.toDouble - else vec(i) = tmp - end if - i = i + 1 - end while - - case (None, Some(retention)) => - var i = 0; - val upperBound = SPECIES.loopBound(vec.length); - while i < upperBound do - val tmp = DoubleVector.fromArray(SPECIES, vec, i).lanewise(VectorOperators.SUB, retention.toDouble) - val belowAttach = tmp.compare(VectorOperators.LT, 0) - tmp - .blend(0, belowAttach) - .intoArray(vec, i) - i += SPECIES.length() - end while - - while i < vec.length do - val tmp = vec(i) - retention - if tmp < 0.0 then vec(i) = 0.0 - else vec(i) = tmp - i = i + 1 - end while - - case (Some(limit), None) => - var i = 0; - val upperBound = SPECIES.loopBound(vec.length); - while i < upperBound do - val tmp = DoubleVector.fromArray(SPECIES, vec, i) - val greaterLimit = tmp.compare(VectorOperators.GT, limit.toDouble) - tmp - .blend(limit.toDouble, greaterLimit) - .intoArray(vec, i) - i += SPECIES.length() - end while - - while i < vec.length do - val tmp = vec(i) - if tmp > limit then vec(i) = limit.toDouble - else vec(i) = tmp - i = i + 1 - end while - - case (None, None) => - () - end reinsuranceFunction - - /* + */ + inline def reinsuranceFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = + (limitOpt, retentionOpt) match + case (Some(limit), Some(retention)) => + var i = 0; + val upperBound = SPECIES.loopBound(vec.length); + while i < upperBound do + val tmp = + DoubleVector.fromArray(SPECIES, vec, i).lanewise(VectorOperators.SUB, retention.toDouble) + val belowAttach = tmp.compare(VectorOperators.LT, 0) + val greaterLimit = tmp.compare(VectorOperators.GT, limit.toDouble) + tmp + .blend(0, belowAttach) + .blend(limit.toDouble, greaterLimit) + .intoArray(vec, i) + i += SPECIES.length() + end while + while i < vec.length do + val tmp = vec(i) - retention + if tmp < 0.0 then vec(i) = 0.0 + else if tmp > limit then vec(i) = limit.toDouble + else vec(i) = tmp + end if + i = i + 1 + end while + + case (None, Some(retention)) => + var i = 0; + val upperBound = SPECIES.loopBound(vec.length); + while i < upperBound do + val tmp = + DoubleVector.fromArray(SPECIES, vec, i).lanewise(VectorOperators.SUB, retention.toDouble) + val belowAttach = tmp.compare(VectorOperators.LT, 0) + tmp + .blend(0, belowAttach) + .intoArray(vec, i) + i += SPECIES.length() + end while + + while i < vec.length do + val tmp = vec(i) - retention + if tmp < 0.0 then vec(i) = 0.0 + else vec(i) = tmp + i = i + 1 + end while + + case (Some(limit), None) => + var i = 0; + val upperBound = SPECIES.loopBound(vec.length); + while i < upperBound do + val tmp = DoubleVector.fromArray(SPECIES, vec, i) + val greaterLimit = tmp.compare(VectorOperators.GT, limit.toDouble) + tmp + .blend(limit.toDouble, greaterLimit) + .intoArray(vec, i) + i += SPECIES.length() + end while + + while i < vec.length do + val tmp = vec(i) + if tmp > limit then vec(i) = limit.toDouble + else vec(i) = tmp + i = i + 1 + end while + + case (None, None) => + () + end reinsuranceFunction + + /* Retention and limit are known constants In excel f(x) = if(x < retention, 0, if(x > limit, limit, x) - */ - inline def franchiseFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = - (limitOpt, retentionOpt) match - case (None, None) => () - - case (Some(limit), Some(retention)) => - var i = 0; - val maxLim = limit.toDouble + retention.toDouble - while i < vec.length do - val tmp = vec(i) - if tmp < retention then vec(i) = 0.0 - else if tmp > maxLim then vec(i) = maxLim - else vec(i) = tmp - end if - i = i + 1 - end while - - case (Some(limit), None) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > limit.toDouble then vec(i) = limit.toDouble - else vec(i) = tmp - end if - i = i + 1 - end while - case (None, Some(retention)) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > retention.toDouble then vec(i) = tmp - else vec(i) = 0.0 - end if - i = i + 1 - end while - end franchiseFunction - - end extension - - extension (vec: Array[Array[Double]]) - inline def horizontalSum: Array[Double] = - val out = new Array[Double](vec.head.length) - var i = 0 - while i < vec.head.length do - var sum = 0.0 - var j = 0 - while j < vec.length do - sum += vec(j)(i) - // pprint.pprintln(s"j : $j i : $i vecij : ${vec(j)(i)} out : ${out(i)} sum : $sum") - j = j + 1 - end while - out(i) = sum - i = i + 1 - end while - out - end extension + */ + inline def franchiseFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = + (limitOpt, retentionOpt) match + case (None, None) => () + + case (Some(limit), Some(retention)) => + var i = 0; + val maxLim = limit.toDouble + retention.toDouble + while i < vec.length do + val tmp = vec(i) + if tmp < retention then vec(i) = 0.0 + else if tmp > maxLim then vec(i) = maxLim + else vec(i) = tmp + end if + i = i + 1 + end while + + case (Some(limit), None) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > limit.toDouble then vec(i) = limit.toDouble + else vec(i) = tmp + end if + i = i + 1 + end while + case (None, Some(retention)) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > retention.toDouble then vec(i) = tmp + else vec(i) = 0.0 + end if + i = i + 1 + end while + end franchiseFunction + + end extension + + extension (vec: Array[Array[Double]]) + inline def horizontalSum: Array[Double] = + val out = new Array[Double](vec.head.length) + var i = 0 + while i < vec.head.length do + var sum = 0.0 + var j = 0 + while j < vec.length do + sum += vec(j)(i) + // pprint.pprintln(s"j : $j i : $i vecij : ${vec(j)(i)} out : ${out(i)} sum : $sum") + j = j + 1 + end while + out(i) = sum + i = i + 1 + end while + out + end extension end vecxt diff --git a/core/jvm/src/main/scala/vecxt/dimCheck.scala b/core/jvm/src/main/scala/vecxt/dimCheck.scala index 4f1ad32..9cba3a3 100644 --- a/core/jvm/src/main/scala/vecxt/dimCheck.scala +++ b/core/jvm/src/main/scala/vecxt/dimCheck.scala @@ -19,8 +19,8 @@ package vecxt import BoundsChecks.BoundsCheck object dimCheck: - inline def apply[A, B](a: Array[A], b: Array[B])(using inline doCheck: BoundsCheck) = - inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) + inline def apply[A, B](a: Array[A], b: Array[B])(using inline doCheck: BoundsCheck) = + inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) end dimCheck case class VectorDimensionMismatch(givenDimension: Int, requiredDimension: Int) diff --git a/core/native/src/main/scala/vecxt/array.extensions.scala b/core/native/src/main/scala/vecxt/array.extensions.scala index a01e4e1..c8d47bd 100644 --- a/core/native/src/main/scala/vecxt/array.extensions.scala +++ b/core/native/src/main/scala/vecxt/array.extensions.scala @@ -23,231 +23,233 @@ import scala.scalanative.unsafe.* import scala.util.chaining.* package object vecxt: - extension (vec: Array[Boolean]) - inline def countTrue: Int = - var sum = 0 - for i <- 0 until vec.length do if vec(i) then sum = sum + 1 - sum - end countTrue - - inline def &&(thatIdx: Array[Boolean]): Array[Boolean] = - val result: Array[Boolean] = new Array[Boolean](vec.length) - for i <- 0 until vec.length do result(i) = vec(i) && thatIdx(i) - result - end && - - inline def ||(thatIdx: Array[Boolean]): Array[Boolean] = - val result: Array[Boolean] = new Array[Boolean](vec.length) - for i <- 0 until vec.length do result(i) = vec(i) || thatIdx(i) - result - end || - - // def copy: Array[Boolean] = - // val copyOfThisVector: Array[Boolean] = new Array[Boolean](vec.length) - // var i = 0 - // while i < vec.length do - // copyOfThisVector(i) = vec(i) - // i = i + 1 - // end while - // copyOfThisVector - // end copy - end extension - - extension (vec: Array[Double]) - - def idxBoolean(index: Array[Boolean]) = - val trues = index.countTrue - val newVec = new Array[Double](trues) - var j = 0 - for i <- 0 to trues do - // println(s"i: $i || j: $j || ${index(i)} ${vec(i)} ") - if index(i) then - newVec(j) = vec(i) - j += 1 - end for - newVec - end idxBoolean - - def increments: Array[Double] = - val out = new Array[Double](vec.length) - out(0) = vec(0) - var i = 1 - while i < vec.length do - out(i) = vec(i) - vec(i - 1) - i = i + 1 - end while - out - end increments - - inline def pearsonCorrelationCoefficient(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = - dimCheck(vec, thatVector) - val n = vec.length - var i = 0 - - var sum_x = 0.0 - var sum_y = 0.0 - var sum_xy = 0.0 - var sum_x2 = 0.0 - var sum_y2 = 0.0 - - while i < n do - sum_x = sum_x + vec(i) - sum_y = sum_y + thatVector(i) - sum_xy = sum_xy + vec(i) * thatVector(i) - sum_x2 = sum_x2 + vec(i) * vec(i) - sum_y2 = sum_y2 + thatVector(i) * thatVector(i) - i = i + 1 - end while - (n * sum_xy - (sum_x * sum_y)) / Math.sqrt( - (sum_x2 * n - sum_x * sum_x) * (sum_y2 * n - sum_y * sum_y) - ) - end pearsonCorrelationCoefficient - - inline def spearmansRankCorrelation(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = - dimCheck(vec, thatVector) - val theseRanks = vec.elementRanks - val thoseRanks = thatVector.elementRanks - theseRanks.pearsonCorrelationCoefficient(thoseRanks) - end spearmansRankCorrelation - - // An alias - pearson is the most commonly requested type of correlation - inline def corr(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = - pearsonCorrelationCoefficient(thatVector) - - def elementRanks: Array[Double] = - val indexed: Array[(Double, Int)] = vec.zipWithIndex - indexed.sortInPlace()(Ordering.by(_._1)) - - val ranks: Array[Double] = new Array[Double](vec.length) - ranks(indexed.last._2) = vec.length - var currentValue: Double = indexed(0)._1 - var r0: Int = 0 - var rank: Int = 1 - while rank < vec.length do - val temp: Double = indexed(rank)._1 - val end: Int = - if temp != currentValue then rank - else if rank == vec.length - 1 then rank + 1 - else -1 - if end > -1 then - val avg: Double = (1.0 + (end + r0)) / 2.0 - var i: Int = r0; - while i < end do - ranks(indexed(i)._2) = avg - i += 1 - end while - r0 = rank - currentValue = temp - end if - rank += 1 - end while - ranks - end elementRanks - - def variance: Double = - // https://www.cuemath.com/sample-variance-formula/ - val μ = vec.mean - vec.map(i => (i - μ) * (i - μ)).sum / (vec.length - 1) - end variance - - inline def stdDev: Double = - // https://www.cuemath.com/data/standard-deviation/ - val mu = vec.mean - val diffs_2 = vec.map(num => Math.pow(num - mu, 2)) - Math.sqrt(diffs_2.sum / (vec.length - 1)) - end stdDev - - inline def mean: Double = vec.sum / vec.length - - inline def sum: Double = - var sum = 0.0 - var i = 0; - while i < vec.length do - sum = sum + vec(i) - i = i + 1 - end while - sum - end sum - - inline def cumsum = - var i = 1 - while i < vec.length do - vec(i) = vec(i - 1) + vec(i) - i = i + 1 - end while - end cumsum - - inline def norm: Double = blas.cblas_dnrm2(vec.length, vec.at(0), 1) - - inline def -(vec2: Array[Double])(using inline boundsCheck: BoundsCheck) = - dimCheck(vec, vec2) - vec.clone.tap(_ -= vec2) - end - - - inline def -=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = - dimCheck(vec, vec2) - blas.cblas_daxpy(vec.length, -1.0, vec2.at(0), 1, vec.at(0), 1) - end -= - - inline def +(vec2: Array[Double])(using inline boundsCheck: BoundsCheck) = - dimCheck(vec, vec2) - vec.clone.tap(_ += vec2) - end + - - inline def +=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = - dimCheck(vec, vec2) - blas.cblas_daxpy(vec.length, 1.0, vec2.at(0), 1, vec.at(0), 1) - end += - - inline def *=(d: Double) = - blas.cblas_dscal(vec.length, d, vec.at(0), 1) - end *= - - inline def *(d: Double) = - vec.clone.tap(_ *= d) - end * - - inline def <(num: Double): Array[Boolean] = - logicalIdx((a, b) => a < b, num) - - inline def <=(num: Double): Array[Boolean] = - logicalIdx((a, b) => a <= b, num) - - inline def >(num: Double): Array[Boolean] = - logicalIdx((a, b) => a > b, num) - - inline def >=(num: Double): Array[Boolean] = - logicalIdx((a, b) => a >= b, num) - - inline def logicalIdx( - inline op: (Double, Double) => Boolean, - inline num: Double - ): Array[Boolean] = - val n = vec.length - val idx = new Array[Boolean](n) - var i = 0 - while i < n do - if op(vec(i), num) then idx(i) = true - i = i + 1 - end while - idx - end logicalIdx - - def covariance(thatVector: Array[Double]): Double = - val μThis = vec.mean - val μThat = thatVector.mean - var cv: Double = 0 - var i: Int = 0; - while i < vec.length do - cv += (vec(i) - μThis) * (thatVector(i) - μThat) - i += 1 - end while - cv / (vec.length - 1) - end covariance - - // def max: Double = vec(blas.cblas_idamax(vec.length, vec.at(0), 1)) // No JS version - - /* + extension (vec: Array[Boolean]) + inline def countTrue: Int = + var sum = 0 + for i <- 0 until vec.length do if vec(i) then sum = sum + 1 + sum + end countTrue + + inline def &&(thatIdx: Array[Boolean]): Array[Boolean] = + val result: Array[Boolean] = new Array[Boolean](vec.length) + for i <- 0 until vec.length do result(i) = vec(i) && thatIdx(i) + result + end && + + inline def ||(thatIdx: Array[Boolean]): Array[Boolean] = + val result: Array[Boolean] = new Array[Boolean](vec.length) + for i <- 0 until vec.length do result(i) = vec(i) || thatIdx(i) + result + end || + + // def copy: Array[Boolean] = + // val copyOfThisVector: Array[Boolean] = new Array[Boolean](vec.length) + // var i = 0 + // while i < vec.length do + // copyOfThisVector(i) = vec(i) + // i = i + 1 + // end while + // copyOfThisVector + // end copy + end extension + + extension (vec: Array[Double]) + + def idxBoolean(index: Array[Boolean]) = + val trues = index.countTrue + val newVec = new Array[Double](trues) + var j = 0 + for i <- 0 to trues do + // println(s"i: $i || j: $j || ${index(i)} ${vec(i)} ") + if index(i) then + newVec(j) = vec(i) + j += 1 + end for + newVec + end idxBoolean + + def increments: Array[Double] = + val out = new Array[Double](vec.length) + out(0) = vec(0) + var i = 1 + while i < vec.length do + out(i) = vec(i) - vec(i - 1) + i = i + 1 + end while + out + end increments + + inline def pearsonCorrelationCoefficient(thatVector: Array[Double])(using + inline boundsCheck: BoundsCheck + ): Double = + dimCheck(vec, thatVector) + val n = vec.length + var i = 0 + + var sum_x = 0.0 + var sum_y = 0.0 + var sum_xy = 0.0 + var sum_x2 = 0.0 + var sum_y2 = 0.0 + + while i < n do + sum_x = sum_x + vec(i) + sum_y = sum_y + thatVector(i) + sum_xy = sum_xy + vec(i) * thatVector(i) + sum_x2 = sum_x2 + vec(i) * vec(i) + sum_y2 = sum_y2 + thatVector(i) * thatVector(i) + i = i + 1 + end while + (n * sum_xy - (sum_x * sum_y)) / Math.sqrt( + (sum_x2 * n - sum_x * sum_x) * (sum_y2 * n - sum_y * sum_y) + ) + end pearsonCorrelationCoefficient + + inline def spearmansRankCorrelation(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = + dimCheck(vec, thatVector) + val theseRanks = vec.elementRanks + val thoseRanks = thatVector.elementRanks + theseRanks.pearsonCorrelationCoefficient(thoseRanks) + end spearmansRankCorrelation + + // An alias - pearson is the most commonly requested type of correlation + inline def corr(thatVector: Array[Double])(using inline boundsCheck: BoundsCheck): Double = + pearsonCorrelationCoefficient(thatVector) + + def elementRanks: Array[Double] = + val indexed: Array[(Double, Int)] = vec.zipWithIndex + indexed.sortInPlace()(Ordering.by(_._1)) + + val ranks: Array[Double] = new Array[Double](vec.length) + ranks(indexed.last._2) = vec.length + var currentValue: Double = indexed(0)._1 + var r0: Int = 0 + var rank: Int = 1 + while rank < vec.length do + val temp: Double = indexed(rank)._1 + val end: Int = + if temp != currentValue then rank + else if rank == vec.length - 1 then rank + 1 + else -1 + if end > -1 then + val avg: Double = (1.0 + (end + r0)) / 2.0 + var i: Int = r0; + while i < end do + ranks(indexed(i)._2) = avg + i += 1 + end while + r0 = rank + currentValue = temp + end if + rank += 1 + end while + ranks + end elementRanks + + def variance: Double = + // https://www.cuemath.com/sample-variance-formula/ + val μ = vec.mean + vec.map(i => (i - μ) * (i - μ)).sum / (vec.length - 1) + end variance + + inline def stdDev: Double = + // https://www.cuemath.com/data/standard-deviation/ + val mu = vec.mean + val diffs_2 = vec.map(num => Math.pow(num - mu, 2)) + Math.sqrt(diffs_2.sum / (vec.length - 1)) + end stdDev + + inline def mean: Double = vec.sum / vec.length + + inline def sum: Double = + var sum = 0.0 + var i = 0; + while i < vec.length do + sum = sum + vec(i) + i = i + 1 + end while + sum + end sum + + inline def cumsum = + var i = 1 + while i < vec.length do + vec(i) = vec(i - 1) + vec(i) + i = i + 1 + end while + end cumsum + + inline def norm: Double = blas.cblas_dnrm2(vec.length, vec.at(0), 1) + + inline def -(vec2: Array[Double])(using inline boundsCheck: BoundsCheck) = + dimCheck(vec, vec2) + vec.clone.tap(_ -= vec2) + end - + + inline def -=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = + dimCheck(vec, vec2) + blas.cblas_daxpy(vec.length, -1.0, vec2.at(0), 1, vec.at(0), 1) + end -= + + inline def +(vec2: Array[Double])(using inline boundsCheck: BoundsCheck) = + dimCheck(vec, vec2) + vec.clone.tap(_ += vec2) + end + + + inline def +=(vec2: Array[Double])(using inline boundsCheck: BoundsCheck): Unit = + dimCheck(vec, vec2) + blas.cblas_daxpy(vec.length, 1.0, vec2.at(0), 1, vec.at(0), 1) + end += + + inline def *=(d: Double) = + blas.cblas_dscal(vec.length, d, vec.at(0), 1) + end *= + + inline def *(d: Double) = + vec.clone.tap(_ *= d) + end * + + inline def <(num: Double): Array[Boolean] = + logicalIdx((a, b) => a < b, num) + + inline def <=(num: Double): Array[Boolean] = + logicalIdx((a, b) => a <= b, num) + + inline def >(num: Double): Array[Boolean] = + logicalIdx((a, b) => a > b, num) + + inline def >=(num: Double): Array[Boolean] = + logicalIdx((a, b) => a >= b, num) + + inline def logicalIdx( + inline op: (Double, Double) => Boolean, + inline num: Double + ): Array[Boolean] = + val n = vec.length + val idx = new Array[Boolean](n) + var i = 0 + while i < n do + if op(vec(i), num) then idx(i) = true + i = i + 1 + end while + idx + end logicalIdx + + def covariance(thatVector: Array[Double]): Double = + val μThis = vec.mean + val μThat = thatVector.mean + var cv: Double = 0 + var i: Int = 0; + while i < vec.length do + cv += (vec(i) - μThis) * (thatVector(i) - μThat) + i += 1 + end while + cv / (vec.length - 1) + end covariance + + // def max: Double = vec(blas.cblas_idamax(vec.length, vec.at(0), 1)) // No JS version + + /* Retention and limit are known constants @@ -255,120 +257,120 @@ package object vecxt: The implementation takes advantage of their existence or not, to optimise the number of operations required. - */ - inline def reinsuranceFunction(limitOpt: Option[Limit], retentionOpt: Option[Retention]): Unit = - (limitOpt, retentionOpt) match - case (Some(limit), Some(retention)) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - retention - if tmp < 0.0 then vec(i) = 0.0 - else if tmp > limit then vec(i) = limit.toDouble - else vec(i) = tmp - end if - i = i + 1 - end while - - case (None, Some(retention)) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - retention - if tmp < 0.0 then vec(i) = 0.0 - else vec(i) = tmp - i = i + 1 - end while - - case (Some(limit), None) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > limit then vec(i) = limit.toDouble - else vec(i) = tmp - i = i + 1 - end while - - case (None, None) => - () - - // def min(lt: Double): Unit = - // var i = 0; - // while i < thisVector.dimension do - // if thisVector(i) < lt then thisVector(i) = lt - // i = i + 1 - // end while - // end min - // end match - - // def MAX(gt: Double): Unit = - // var i = 0; - // while i < thisVector.dimension do - // if thisVector(i) > gt then thisVector(i) = gt - // i = i + 1 - // end while - // end MAX - - end reinsuranceFunction - - /* + */ + inline def reinsuranceFunction(limitOpt: Option[Limit], retentionOpt: Option[Retention]): Unit = + (limitOpt, retentionOpt) match + case (Some(limit), Some(retention)) => + var i = 0; + while i < vec.length do + val tmp = vec(i) - retention + if tmp < 0.0 then vec(i) = 0.0 + else if tmp > limit then vec(i) = limit.toDouble + else vec(i) = tmp + end if + i = i + 1 + end while + + case (None, Some(retention)) => + var i = 0; + while i < vec.length do + val tmp = vec(i) - retention + if tmp < 0.0 then vec(i) = 0.0 + else vec(i) = tmp + i = i + 1 + end while + + case (Some(limit), None) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > limit then vec(i) = limit.toDouble + else vec(i) = tmp + i = i + 1 + end while + + case (None, None) => + () + + // def min(lt: Double): Unit = + // var i = 0; + // while i < thisVector.dimension do + // if thisVector(i) < lt then thisVector(i) = lt + // i = i + 1 + // end while + // end min + // end match + + // def MAX(gt: Double): Unit = + // var i = 0; + // while i < thisVector.dimension do + // if thisVector(i) > gt then thisVector(i) = gt + // i = i + 1 + // end while + // end MAX + + end reinsuranceFunction + + /* Retention and limit are known constants In excel f(x) = if(x < retention, 0, if(x > limit, limit, x) - */ - inline def franchiseFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = - (limitOpt, retentionOpt) match - case (None, None) => () - - case (Some(limit), Some(retention)) => - var i = 0; - val maxLim = limit.toDouble + retention.toDouble - while i < vec.length do - val tmp = vec(i) - if tmp < retention then vec(i) = 0.0 - else if tmp > maxLim then vec(i) = maxLim - else vec(i) = tmp - end if - i = i + 1 - end while - - case (Some(limit), None) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > limit.toDouble then vec(i) = limit.toDouble - else vec(i) = tmp - end if - i = i + 1 - end while - case (None, Some(retention)) => - var i = 0; - while i < vec.length do - val tmp = vec(i) - if tmp > retention.toDouble then vec(i) = tmp - else vec(i) = 0.0 - end if - i = i + 1 - end while - end franchiseFunction - - end extension - - extension (vec: Array[Array[Double]]) - inline def horizontalSum: Array[Double] = - val out = new Array[Double](vec.head.length) - var i = 0 - while i < vec.head.length do - var sum = 0.0 - var j = 0 - while j < vec.length do - sum += vec(j)(i) - // pprint.pprintln(s"j : $j i : $i vecij : ${vec(j)(i)} out : ${out(i)} sum : $sum") - j = j + 1 - end while - out(i) = sum - i = i + 1 - end while - out - end extension + */ + inline def franchiseFunction(inline limitOpt: Option[Limit], inline retentionOpt: Option[Retention]): Unit = + (limitOpt, retentionOpt) match + case (None, None) => () + + case (Some(limit), Some(retention)) => + var i = 0; + val maxLim = limit.toDouble + retention.toDouble + while i < vec.length do + val tmp = vec(i) + if tmp < retention then vec(i) = 0.0 + else if tmp > maxLim then vec(i) = maxLim + else vec(i) = tmp + end if + i = i + 1 + end while + + case (Some(limit), None) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > limit.toDouble then vec(i) = limit.toDouble + else vec(i) = tmp + end if + i = i + 1 + end while + case (None, Some(retention)) => + var i = 0; + while i < vec.length do + val tmp = vec(i) + if tmp > retention.toDouble then vec(i) = tmp + else vec(i) = 0.0 + end if + i = i + 1 + end while + end franchiseFunction + + end extension + + extension (vec: Array[Array[Double]]) + inline def horizontalSum: Array[Double] = + val out = new Array[Double](vec.head.length) + var i = 0 + while i < vec.head.length do + var sum = 0.0 + var j = 0 + while j < vec.length do + sum += vec(j)(i) + // pprint.pprintln(s"j : $j i : $i vecij : ${vec(j)(i)} out : ${out(i)} sum : $sum") + j = j + 1 + end while + out(i) = sum + i = i + 1 + end while + out + end extension end vecxt diff --git a/core/native/src/main/scala/vecxt/dimCheck.scala b/core/native/src/main/scala/vecxt/dimCheck.scala index 4f1ad32..9cba3a3 100644 --- a/core/native/src/main/scala/vecxt/dimCheck.scala +++ b/core/native/src/main/scala/vecxt/dimCheck.scala @@ -19,8 +19,8 @@ package vecxt import BoundsChecks.BoundsCheck object dimCheck: - inline def apply[A, B](a: Array[A], b: Array[B])(using inline doCheck: BoundsCheck) = - inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) + inline def apply[A, B](a: Array[A], b: Array[B])(using inline doCheck: BoundsCheck) = + inline if doCheck then if a.length != b.length then throw VectorDimensionMismatch(a.length, b.length) end dimCheck case class VectorDimensionMismatch(givenDimension: Int, requiredDimension: Int) diff --git a/core/shared/src/main/scala/vecxt/bounds.check.scala b/core/shared/src/main/scala/vecxt/bounds.check.scala index 66198e4..f36dec5 100644 --- a/core/shared/src/main/scala/vecxt/bounds.check.scala +++ b/core/shared/src/main/scala/vecxt/bounds.check.scala @@ -24,10 +24,10 @@ package vecxt // extension (inline bc: BoundsCheck) inline def value: Boolean = bc.self package object BoundsChecks: - type BoundsCheck = Boolean + type BoundsCheck = Boolean - object BoundsCheck: - inline given yes: BoundsCheck = true - inline given no: BoundsCheck = false - end BoundsCheck + object BoundsCheck: + inline given yes: BoundsCheck = true + inline given no: BoundsCheck = false + end BoundsCheck end BoundsChecks diff --git a/core/shared/src/main/scala/vecxt/limit.rpt.scala b/core/shared/src/main/scala/vecxt/limit.rpt.scala index 3566244..027b03f 100644 --- a/core/shared/src/main/scala/vecxt/limit.rpt.scala +++ b/core/shared/src/main/scala/vecxt/limit.rpt.scala @@ -19,16 +19,16 @@ package vecxt import vecxt.Retentions.* object Limits: - opaque type Limit = Double + opaque type Limit = Double - object Limit: - inline def apply(d: Double): Limit = d - end Limit + object Limit: + inline def apply(d: Double): Limit = d + end Limit - extension (x: Limit) inline def toDouble: Double = x + extension (x: Limit) inline def toDouble: Double = x - extension (in: Double) - inline def >(l: Limit): Boolean = in > l - inline def +(l: Retention): Double = in + l.toDouble - end extension + extension (in: Double) + inline def >(l: Limit): Boolean = in > l + inline def +(l: Retention): Double = in + l.toDouble + end extension end Limits diff --git a/core/shared/src/main/scala/vecxt/loss.calc.scala b/core/shared/src/main/scala/vecxt/loss.calc.scala index 9f6051a..2a59155 100644 --- a/core/shared/src/main/scala/vecxt/loss.calc.scala +++ b/core/shared/src/main/scala/vecxt/loss.calc.scala @@ -17,5 +17,5 @@ package vecxt enum LossCalc: - case Agg, Occ + case Agg, Occ end LossCalc diff --git a/core/shared/src/main/scala/vecxt/retention.rpt.scala b/core/shared/src/main/scala/vecxt/retention.rpt.scala index fc64317..0fd8dc3 100644 --- a/core/shared/src/main/scala/vecxt/retention.rpt.scala +++ b/core/shared/src/main/scala/vecxt/retention.rpt.scala @@ -17,16 +17,16 @@ package vecxt object Retentions: - opaque type Retention = Double + opaque type Retention = Double - object Retention: - inline def apply(d: Double): Retention = d - end Retention + object Retention: + inline def apply(d: Double): Retention = d + end Retention - extension (x: Retention) inline def toDouble: Double = x + extension (x: Retention) inline def toDouble: Double = x - extension (loss: Double) - inline def -(l: Retention): Double = loss - l - inline def <(l: Retention): Boolean = loss < l - end extension + extension (loss: Double) + inline def -(l: Retention): Double = loss - l + inline def <(l: Retention): Boolean = loss < l + end extension end Retentions diff --git a/tests/js/src/test/scala/boundsCheck.scala b/tests/js/src/test/scala/boundsCheck.scala index ee77b99..66dcbd7 100644 --- a/tests/js/src/test/scala/boundsCheck.scala +++ b/tests/js/src/test/scala/boundsCheck.scala @@ -21,21 +21,21 @@ import scala.util.chaining.* class BoundsCheckSuite extends munit.FunSuite: - lazy val v_fill = Float64Array(5).tap(a => - a(0) = 1.0 - a(1) = 2.0 - a(2) = 3.0 - a(3) = 4.0 - a(4) = 5.0 - ) + lazy val v_fill = Float64Array(5).tap(a => + a(0) = 1.0 + a(1) = 2.0 + a(2) = 3.0 + a(3) = 4.0 + a(4) = 5.0 + ) - test("Bounds check") { - intercept[vecxt.VectorDimensionMismatch](v_fill.-(Float64Array(2))(using BoundsChecks.BoundsCheck.yes)) - } + test("Bounds check") { + intercept[vecxt.VectorDimensionMismatch](v_fill.-(Float64Array(2))(using BoundsChecks.BoundsCheck.yes)) + } - // I don't know how to do this. - // test("no bound check") { - // intercept[java.lang.ClassCastException](v_fill.-(Float64Array(2))(using vecxt.BoundsCheck.no)) - // } + // I don't know how to do this. + // test("no bound check") { + // intercept[java.lang.ClassCastException](v_fill.-(Float64Array(2))(using vecxt.BoundsCheck.no)) + // } end BoundsCheckSuite diff --git a/tests/jvm/src/test/scala/boundsCheck.scala b/tests/jvm/src/test/scala/boundsCheck.scala index 368e752..1f38c2e 100644 --- a/tests/jvm/src/test/scala/boundsCheck.scala +++ b/tests/jvm/src/test/scala/boundsCheck.scala @@ -18,14 +18,16 @@ package vecxt class BoundsCheckSuite extends munit.FunSuite: - lazy val v_fill = Array.tabulate(5)(i => i.toDouble) + lazy val v_fill = Array.tabulate(5)(i => i.toDouble) - test("Bounds check") { - intercept[vecxt.VectorDimensionMismatch](v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.yes)) - } + test("Bounds check") { + intercept[vecxt.VectorDimensionMismatch](v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.yes)) + } - test("no bound check") { - intercept[java.lang.IndexOutOfBoundsException](v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.no)) - } + test("no bound check") { + intercept[java.lang.IndexOutOfBoundsException]( + v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.no) + ) + } end BoundsCheckSuite diff --git a/tests/native/src/test/scala/boundsCheck.scala b/tests/native/src/test/scala/boundsCheck.scala index fc4e4c6..173cdd2 100644 --- a/tests/native/src/test/scala/boundsCheck.scala +++ b/tests/native/src/test/scala/boundsCheck.scala @@ -18,16 +18,16 @@ package vecxt class BoundsCheckSuite extends munit.FunSuite: - lazy val v_fill = Array.tabulate(5)(i => i.toDouble) + lazy val v_fill = Array.tabulate(5)(i => i.toDouble) - test("Bounds check") { - intercept[vecxt.VectorDimensionMismatch](v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.yes)) - } + test("Bounds check") { + intercept[vecxt.VectorDimensionMismatch](v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.yes)) + } - // test("no bound check") { - // intercept[java.lang.ArrayIndexOutOfBoundsException]( - // v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.no) - // ) - // } + // test("no bound check") { + // intercept[java.lang.ArrayIndexOutOfBoundsException]( + // v_fill.-(Array[Double](1, 2, 3))(using BoundsChecks.BoundsCheck.no) + // ) + // } end BoundsCheckSuite diff --git a/tests/shared/src/test/scala/arrayExtensions.test.scala b/tests/shared/src/test/scala/arrayExtensions.test.scala index 20f7b92..5c49d5f 100644 --- a/tests/shared/src/test/scala/arrayExtensions.test.scala +++ b/tests/shared/src/test/scala/arrayExtensions.test.scala @@ -21,145 +21,145 @@ import narr.* import scala.util.chaining.* class ArrayExtensionSuite extends munit.FunSuite: - import BoundsChecks.BoundsCheck.yes + import BoundsChecks.BoundsCheck.yes - lazy val v_fill = NArray[Double](0, 1, 2, 3, 4) + lazy val v_fill = NArray[Double](0, 1, 2, 3, 4) - test("Array horizontal sum") { - val v1 = NArray[Double](1.0, 2.0, 3.0) - val v2 = v1 * 2.0 - val v3 = v1 * 3.0 + test("Array horizontal sum") { + val v1 = NArray[Double](1.0, 2.0, 3.0) + val v2 = v1 * 2.0 + val v3 = v1 * 3.0 - val l = NArray(v1, v2, v3) - val summed = l.horizontalSum + val l = NArray(v1, v2, v3) + val summed = l.horizontalSum - assert(summed(0) == 1 + 2 + 3) - assert(summed(1) == 2 + 4 + 6) - assert(summed(2) == 3 + 6 + 9) + assert(summed(0) == 1 + 2 + 3) + assert(summed(1) == 2 + 4 + 6) + assert(summed(2) == 3 + 6 + 9) - } + } - test("cumsum") { - val v1 = NArray[Double](1.0, 2.0, 3.0).tap(_.cumsum) - assert(v1(0) == 1) - assert(v1(1) == 3) - assert(v1(2) == 6) - } + test("cumsum") { + val v1 = NArray[Double](1.0, 2.0, 3.0).tap(_.cumsum) + assert(v1(0) == 1) + assert(v1(1) == 3) + assert(v1(2) == 6) + } - test("Array += ") { - val v1 = NArray[Double](1.0, 2.0, 3.0) - v1 += NArray[Double](3.0, 2.0, 1.0) + test("Array += ") { + val v1 = NArray[Double](1.0, 2.0, 3.0) + v1 += NArray[Double](3.0, 2.0, 1.0) - assertEqualsDouble(v1(0), 4, 0.00001) - assertEqualsDouble(v1(1), 4, 0.00001) - assertEqualsDouble(v1(2), 4, 0.00001) + assertEqualsDouble(v1(0), 4, 0.00001) + assertEqualsDouble(v1(1), 4, 0.00001) + assertEqualsDouble(v1(2), 4, 0.00001) - } + } - test("Array + ") { - val v1 = NArray[Double](1.0, 2.0, 3.0) - val v2 = NArray[Double](3.0, 2.0, 1.0) + test("Array + ") { + val v1 = NArray[Double](1.0, 2.0, 3.0) + val v2 = NArray[Double](3.0, 2.0, 1.0) - val v3 = v1 + v2 + val v3 = v1 + v2 - assertEqualsDouble(v3(0), 4, 0.00001) - assertEqualsDouble(v3(1), 4, 0.00001) - assertEqualsDouble(v3(2), 4, 0.00001) + assertEqualsDouble(v3(0), 4, 0.00001) + assertEqualsDouble(v3(1), 4, 0.00001) + assertEqualsDouble(v3(2), 4, 0.00001) - } + } - test("Array -= ") { - val v1 = NArray[Double](1.0, 2.0, 3.0, 4.0, 5.0, 6.0) - v1 -= NArray[Double](3.0, 2.0, 1.0, 0.0, 0.0, 0.0) + test("Array -= ") { + val v1 = NArray[Double](1.0, 2.0, 3.0, 4.0, 5.0, 6.0) + v1 -= NArray[Double](3.0, 2.0, 1.0, 0.0, 0.0, 0.0) - assertEqualsDouble(v1(0), -2, 0.00001) - assertEqualsDouble(v1(1), 0, 0.00001) - assertEqualsDouble(v1(2), 2, 0.00001) - assertEqualsDouble(v1(5), 6, 0.00001) + assertEqualsDouble(v1(0), -2, 0.00001) + assertEqualsDouble(v1(1), 0, 0.00001) + assertEqualsDouble(v1(2), 2, 0.00001) + assertEqualsDouble(v1(5), 6, 0.00001) - } + } - test("Array - ") { - val v1 = NArray[Double](1.0, 2.0, 3.0) - val v2 = NArray[Double](3.0, 2.0, 1.0) + test("Array - ") { + val v1 = NArray[Double](1.0, 2.0, 3.0) + val v2 = NArray[Double](3.0, 2.0, 1.0) - val v3 = v1 - v2 + val v3 = v1 - v2 - assertEqualsDouble(v3(0), -2, 0.00001) - assertEqualsDouble(v3(1), 0, 0.00001) - assertEqualsDouble(v3(2), 2, 0.00001) - } + assertEqualsDouble(v3(0), -2, 0.00001) + assertEqualsDouble(v3(1), 0, 0.00001) + assertEqualsDouble(v3(2), 2, 0.00001) + } - test("Array *= ") { - val v1 = NArray[Double](1.0, 2.0, 3.0) - v1 *= 2 + test("Array *= ") { + val v1 = NArray[Double](1.0, 2.0, 3.0) + v1 *= 2 - assertEqualsDouble(v1(0), 2, 0.00001) - assertEqualsDouble(v1(1), 4, 0.00001) - assertEqualsDouble(v1(2), 6, 0.00001) + assertEqualsDouble(v1(0), 2, 0.00001) + assertEqualsDouble(v1(1), 4, 0.00001) + assertEqualsDouble(v1(2), 6, 0.00001) - } + } - test("Array * ") { - val v1 = NArray[Double](1.0, 2.0, 3.0) + test("Array * ") { + val v1 = NArray[Double](1.0, 2.0, 3.0) - val v2 = v1 * 2 + val v2 = v1 * 2 - assertEqualsDouble(v1(0), 1, 0.00001) - assertEqualsDouble(v2(1), 4, 0.00001) - assertEqualsDouble(v2(2), 6, 0.00001) - } + assertEqualsDouble(v1(0), 1, 0.00001) + assertEqualsDouble(v2(1), 4, 0.00001) + assertEqualsDouble(v2(2), 6, 0.00001) + } - test("<=") { - val v_idx2 = v_fill < 2.5 - assertEquals(v_idx2.countTrue, 3) - } + test("<=") { + val v_idx2 = v_fill < 2.5 + assertEquals(v_idx2.countTrue, 3) + } - test("<") { - val v_idx2 = v_fill < 3.0 - assertEquals(v_idx2.countTrue, 3) - } + test("<") { + val v_idx2 = v_fill < 3.0 + assertEquals(v_idx2.countTrue, 3) + } - test(">") { - val v_idx2 = v_fill > 2.5 - assertEquals(v_idx2.countTrue, 2) - } + test(">") { + val v_idx2 = v_fill > 2.5 + assertEquals(v_idx2.countTrue, 2) + } - test(">=") { - val v_idx2 = v_fill >= 3.0 - assertEquals(v_idx2.countTrue, 2) - } + test(">=") { + val v_idx2 = v_fill >= 3.0 + assertEquals(v_idx2.countTrue, 2) + } - test("&&") { - val v_idx2 = (v_fill < 3.0) && (v_fill > 1.0) - assertEquals(v_idx2.countTrue, 1) - } + test("&&") { + val v_idx2 = (v_fill < 3.0) && (v_fill > 1.0) + assertEquals(v_idx2.countTrue, 1) + } - test("||") { - val v_idx2 = (v_fill < 3.0) || (v_fill > 1.0) - assertEquals(v_idx2.countTrue, 5) + test("||") { + val v_idx2 = (v_fill < 3.0) || (v_fill > 1.0) + assertEquals(v_idx2.countTrue, 5) - val v_idx3 = (v_fill < 1.0) || (v_fill > 4.0) - assertEquals(v_idx3.countTrue, 1) - } + val v_idx3 = (v_fill < 1.0) || (v_fill > 4.0) + assertEquals(v_idx3.countTrue, 1) + } - test("norm") { - assertEqualsDouble(v_fill.norm, Math.sqrt(1 + 4 + 9 + 16), 0.00001) - } + test("norm") { + assertEqualsDouble(v_fill.norm, Math.sqrt(1 + 4 + 9 + 16), 0.00001) + } - test("Array indexing") { - val v1 = NArray[Double](1.0, 2.0, 3.0) - val vIdx = NArray[Boolean](true, false, true) - val afterIndex = v1.idxBoolean(vIdx) + test("Array indexing") { + val v1 = NArray[Double](1.0, 2.0, 3.0) + val vIdx = NArray[Boolean](true, false, true) + val afterIndex = v1.idxBoolean(vIdx) - assertEquals(afterIndex.length, 2) - assertEqualsDouble(afterIndex.head, 1, 0.0001) - assertEqualsDouble(afterIndex.last, 3.0, 0.0001) - } + assertEquals(afterIndex.length, 2) + assertEqualsDouble(afterIndex.head, 1, 0.0001) + assertEqualsDouble(afterIndex.last, 3.0, 0.0001) + } - // test("max element"){ - // val v2 = NArray[Double](3.0, 2.0, 4.0, 1.0) - // assertEqualsDouble(v2.max, 4.0, 0.00001) - // } + // test("max element"){ + // val v2 = NArray[Double](3.0, 2.0, 4.0, 1.0) + // assertEqualsDouble(v2.max, 4.0, 0.00001) + // } end ArrayExtensionSuite diff --git a/tests/shared/src/test/scala/cross.test.scala b/tests/shared/src/test/scala/cross.test.scala index 616a7ea..aeff36b 100644 --- a/tests/shared/src/test/scala/cross.test.scala +++ b/tests/shared/src/test/scala/cross.test.scala @@ -25,18 +25,18 @@ import Limits.* class XSuite extends munit.FunSuite: - // This test is a duplicate ... but if it works, it proves that the extension methods work on every platform with a common NArray supertype :-)... - test("reinsurance function - ret and limit") { - val v = NArray - .ofSize[Double](3) - .tap(n => - n(0) = 8 - n(1) = 11 - n(2) = 16 - ) - v.reinsuranceFunction(Some(Limit(5.0)), Some(Retention(10.0))) - assert(v(0) == 0.0) - assert(v(1) == 1.0) - assert(v(2) == 5.0) - } + // This test is a duplicate ... but if it works, it proves that the extension methods work on every platform with a common NArray supertype :-)... + test("reinsurance function - ret and limit") { + val v = NArray + .ofSize[Double](3) + .tap(n => + n(0) = 8 + n(1) = 11 + n(2) = 16 + ) + v.reinsuranceFunction(Some(Limit(5.0)), Some(Retention(10.0))) + assert(v(0) == 0.0) + assert(v(1) == 1.0) + assert(v(2) == 5.0) + } end XSuite diff --git a/tests/shared/src/test/scala/helpers.forTests.scala b/tests/shared/src/test/scala/helpers.forTests.scala index ab6d5c0..a6a4623 100644 --- a/tests/shared/src/test/scala/helpers.forTests.scala +++ b/tests/shared/src/test/scala/helpers.forTests.scala @@ -21,9 +21,9 @@ import narr.* extension [A <: AnyRef](o: A) def some: Some[A] = Some(o) inline def assertVecEquals(v1: NArray[Double], v2: NArray[Double])(implicit loc: munit.Location): Unit = - var i: Int = 0; - while i < v1.length do - munit.Assertions.assertEquals(v1(i), v2(i)) - i += 1 - end while + var i: Int = 0; + while i < v1.length do + munit.Assertions.assertEquals(v1(i), v2(i)) + i += 1 + end while end assertVecEquals diff --git a/tests/shared/src/test/scala/rpt.test.scala b/tests/shared/src/test/scala/rpt.test.scala index d7b471e..cb627a4 100644 --- a/tests/shared/src/test/scala/rpt.test.scala +++ b/tests/shared/src/test/scala/rpt.test.scala @@ -23,140 +23,140 @@ import Limits.* class ReinsurancePricingSuite extends munit.FunSuite: - def long_v = NArray[Double](8, 11, 16, 8, 11, 16, 8, 11, 16) - - test("reinsurance function - ret and limit") { - val v = long_v - val l = v.length - v.reinsuranceFunction(Some(Limit(5.0)), Some(Retention(10.0))) - assertEqualsDouble(v(0), 0.0, 0.0001) - assertEqualsDouble(v(1), 1.0, 0.0001) - assertEqualsDouble(v(2), 5.0, 0.0001) - assertEqualsDouble(v(l - 3), 0.0, 0.0001) - assertEqualsDouble(v(l - 2), 1.0, 0.0001) - assertEqualsDouble(v(l - 1), 5.0, 0.0001) - } - test("reinsurance function - ret only") { - val v = long_v - v.reinsuranceFunction(None, Some(Retention(10.0))) - assert(v(0) == 0.0) - assert(v(1) == 1.0) - assert(v(2) == 6.0) - assert(v(v.length - 3) == 0.0) - assert(v(v.length - 2) == 1.0) - assert(v(v.length - 1) == 6.0) - } - test("reinsurance function - limit only") { - val v = long_v - v.reinsuranceFunction(Some(Limit(15.0)), None) - assert(v(0) == 8.0) - assert(v(1) == 11.0) - assert(v(2) == 15.0) - assert(v(v.length - 3) == 8.0) - assert(v(v.length - 2) == 11.0) - assert(v(v.length - 1) == 15.0) - } - test("reinsurance function - no ret or limit") { - val v = NArray[Double](8, 11, 16) - v.reinsuranceFunction(None, None) - assert(v(0) == 8.0) - assert(v(1) == 11.0) - assert(v(2) == 16.0) - } - - test("franchise function - ret and limit") { - val v = NArray[Double](8, 11, 16) - v.franchiseFunction(Some(Limit(5.0)), Some(Retention(10.0))) - assert(v(0) == 0.0) - assert(v(1) == 11.0) - assert(v(2) == 15.0) - } - - test("franchise function - ret only") { - val v = NArray[Double](8, 11, 16) - v.franchiseFunction(None, Some(Retention(10.0))) - assert(v(0) == 0.0) - assert(v(1) == 11.0) - assert(v(2) == 16.0) - } - - test("franchise function - Limit only") { - val v = NArray[Double](8, 11, 16) - v.franchiseFunction(Some(Limit(10.0)), None) - assert(v(0) == 8.0) - assert(v(1) == 10.0) - assert(v(2) == 10.0) - } - - test("franchise function - No ret or limit") { - val v = NArray[Double](8, 11, 16) - v.franchiseFunction(None, None) - assert(v(0) == 8.0) - assert(v(1) == 11.0) - assert(v(2) == 16.0) - } - - // test("Simple Agg 10") { - // val l_10Agg = makeLayer(1.0, aggLimit = 10.0.some) - // val losses = Array[Double](7, 2, 2, 2) - // val coveredLosses = l_10Agg.coveredLosses(losses) - // assert(coveredLosses(0) == 7) - // assert(coveredLosses(1) == 2) - // assert(coveredLosses(2) == 1) - // assert(coveredLosses(3) == 0) - // } - - // test("Simple Agg ret 10") { - // val l_10Agg = makeLayer(1.0, aggRetention = 10.0.some) - // val losses = Array[Double](7, 2, 2, 2) - // val coveredLosses = l_10Agg.coveredLosses(losses) - // assertEqualsDouble(coveredLosses(0), 0, 0.0001) - // assert(coveredLosses(1) == 0) - // assert(coveredLosses(2) == 1.0) - // assert(coveredLosses(3) == 2.0) - // } - - // test("Simple occ ret 10") { - // val l_10Agg = makeLayer(1.0, occRetention = 10.0.some) - // val losses = Array[Double](9, 11) - // val coveredLosses = l_10Agg.coveredLosses(losses) - // assert(coveredLosses(0) == 0) - // assert(coveredLosses(1) == 1) - // } - - // test("share") { - // val l_10Agg = makeLayer(0.5) - // val losses = Array[Double](1, 2) - // val coveredLosses = l_10Agg.coveredLosses(losses) - // assert(coveredLosses(0) == 0.5) - // assert(coveredLosses(1) == 1) - // } - - // test("Simple Occ 10") { - // val l_10Agg = makeLayer(1.0, occLimit = 10.0.some) - // val losses = Array[Double](8, 12) - // val coveredLosses = l_10Agg.coveredLosses(losses) - // assert(coveredLosses(0) == 8) - // assert(coveredLosses(1) == 10) - // } - - // test("Simple Agg 10 xs 5") { - // val l_Agg_10xs5 = makeLayer(1.0, aggLimit = 5.0.some, aggRetention = 5.0.some) - // val losses = Array[Double](7, 2, 2, 2) - // val coveredLosses = l_Agg_10xs5.coveredLosses(losses) - // assert(coveredLosses(0) == 2) - // assert(coveredLosses(1) == 2) - // assert(coveredLosses(2) == 1) - // assert(coveredLosses(3) == 0) - // } - - // test("Simple Occ 10 xs 5") { - // val l_Occ_10xs5 = makeLayer(1.0, occLimit = 10.0.some, occRetention = 5.0.some) - // // pprint.pprintln(l_Occ_10xs5) - // val losses = Array[Double](3, 11, 16) - // val coveredLosses = l_Occ_10xs5.coveredLosses(losses) - // assert(coveredLosses(0) == 0) - // assert(coveredLosses(1) == 6) - // assert(coveredLosses(2) == 10) - // } + def long_v = NArray[Double](8, 11, 16, 8, 11, 16, 8, 11, 16) + + test("reinsurance function - ret and limit") { + val v = long_v + val l = v.length + v.reinsuranceFunction(Some(Limit(5.0)), Some(Retention(10.0))) + assertEqualsDouble(v(0), 0.0, 0.0001) + assertEqualsDouble(v(1), 1.0, 0.0001) + assertEqualsDouble(v(2), 5.0, 0.0001) + assertEqualsDouble(v(l - 3), 0.0, 0.0001) + assertEqualsDouble(v(l - 2), 1.0, 0.0001) + assertEqualsDouble(v(l - 1), 5.0, 0.0001) + } + test("reinsurance function - ret only") { + val v = long_v + v.reinsuranceFunction(None, Some(Retention(10.0))) + assert(v(0) == 0.0) + assert(v(1) == 1.0) + assert(v(2) == 6.0) + assert(v(v.length - 3) == 0.0) + assert(v(v.length - 2) == 1.0) + assert(v(v.length - 1) == 6.0) + } + test("reinsurance function - limit only") { + val v = long_v + v.reinsuranceFunction(Some(Limit(15.0)), None) + assert(v(0) == 8.0) + assert(v(1) == 11.0) + assert(v(2) == 15.0) + assert(v(v.length - 3) == 8.0) + assert(v(v.length - 2) == 11.0) + assert(v(v.length - 1) == 15.0) + } + test("reinsurance function - no ret or limit") { + val v = NArray[Double](8, 11, 16) + v.reinsuranceFunction(None, None) + assert(v(0) == 8.0) + assert(v(1) == 11.0) + assert(v(2) == 16.0) + } + + test("franchise function - ret and limit") { + val v = NArray[Double](8, 11, 16) + v.franchiseFunction(Some(Limit(5.0)), Some(Retention(10.0))) + assert(v(0) == 0.0) + assert(v(1) == 11.0) + assert(v(2) == 15.0) + } + + test("franchise function - ret only") { + val v = NArray[Double](8, 11, 16) + v.franchiseFunction(None, Some(Retention(10.0))) + assert(v(0) == 0.0) + assert(v(1) == 11.0) + assert(v(2) == 16.0) + } + + test("franchise function - Limit only") { + val v = NArray[Double](8, 11, 16) + v.franchiseFunction(Some(Limit(10.0)), None) + assert(v(0) == 8.0) + assert(v(1) == 10.0) + assert(v(2) == 10.0) + } + + test("franchise function - No ret or limit") { + val v = NArray[Double](8, 11, 16) + v.franchiseFunction(None, None) + assert(v(0) == 8.0) + assert(v(1) == 11.0) + assert(v(2) == 16.0) + } + + // test("Simple Agg 10") { + // val l_10Agg = makeLayer(1.0, aggLimit = 10.0.some) + // val losses = Array[Double](7, 2, 2, 2) + // val coveredLosses = l_10Agg.coveredLosses(losses) + // assert(coveredLosses(0) == 7) + // assert(coveredLosses(1) == 2) + // assert(coveredLosses(2) == 1) + // assert(coveredLosses(3) == 0) + // } + + // test("Simple Agg ret 10") { + // val l_10Agg = makeLayer(1.0, aggRetention = 10.0.some) + // val losses = Array[Double](7, 2, 2, 2) + // val coveredLosses = l_10Agg.coveredLosses(losses) + // assertEqualsDouble(coveredLosses(0), 0, 0.0001) + // assert(coveredLosses(1) == 0) + // assert(coveredLosses(2) == 1.0) + // assert(coveredLosses(3) == 2.0) + // } + + // test("Simple occ ret 10") { + // val l_10Agg = makeLayer(1.0, occRetention = 10.0.some) + // val losses = Array[Double](9, 11) + // val coveredLosses = l_10Agg.coveredLosses(losses) + // assert(coveredLosses(0) == 0) + // assert(coveredLosses(1) == 1) + // } + + // test("share") { + // val l_10Agg = makeLayer(0.5) + // val losses = Array[Double](1, 2) + // val coveredLosses = l_10Agg.coveredLosses(losses) + // assert(coveredLosses(0) == 0.5) + // assert(coveredLosses(1) == 1) + // } + + // test("Simple Occ 10") { + // val l_10Agg = makeLayer(1.0, occLimit = 10.0.some) + // val losses = Array[Double](8, 12) + // val coveredLosses = l_10Agg.coveredLosses(losses) + // assert(coveredLosses(0) == 8) + // assert(coveredLosses(1) == 10) + // } + + // test("Simple Agg 10 xs 5") { + // val l_Agg_10xs5 = makeLayer(1.0, aggLimit = 5.0.some, aggRetention = 5.0.some) + // val losses = Array[Double](7, 2, 2, 2) + // val coveredLosses = l_Agg_10xs5.coveredLosses(losses) + // assert(coveredLosses(0) == 2) + // assert(coveredLosses(1) == 2) + // assert(coveredLosses(2) == 1) + // assert(coveredLosses(3) == 0) + // } + + // test("Simple Occ 10 xs 5") { + // val l_Occ_10xs5 = makeLayer(1.0, occLimit = 10.0.some, occRetention = 5.0.some) + // // pprint.pprintln(l_Occ_10xs5) + // val losses = Array[Double](3, 11, 16) + // val coveredLosses = l_Occ_10xs5.coveredLosses(losses) + // assert(coveredLosses(0) == 0) + // assert(coveredLosses(1) == 6) + // assert(coveredLosses(2) == 10) + // } end ReinsurancePricingSuite diff --git a/tests/shared/src/test/scala/simple.stats.scala b/tests/shared/src/test/scala/simple.stats.scala index 76593ec..5475994 100644 --- a/tests/shared/src/test/scala/simple.stats.scala +++ b/tests/shared/src/test/scala/simple.stats.scala @@ -20,76 +20,76 @@ import narr.* class StatsSuite extends munit.FunSuite: - // import vecxt.BoundsCheck.yes - - test("sample covariance") { - // Sample version - // https://corporatefinanceinstitute.com/resources/data-science/covariance/ - - val vector1 = NArray[Double](1692.0, 1978.0, 1884.0, 2151.0, 2519.0) - val vector2 = NArray[Double](68.0, 102.0, 110.0, 112.0, 154.0) - - val result = vector1.covariance(vector2) - - assertEqualsDouble(result, 9107.3, 0.001) - } - - test("sample variance and std") { - val v = NArray[Double](2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0) - assertEqualsDouble(v.variance, 4.571429, 0.00001) - assertEqualsDouble(v.stdDev, 2.13809, 0.00001) - } - - test("elementRanks") { - - assertVecEquals( - NArray.tabulate[Double](10)((i: Int) => 11.0 - i).elementRanks, - NArray[Double](10, 9, 8, 7, 6, 5, 4, 3, 2, 1) - ) - assertVecEquals( - NArray.fill[Double](5)(42.0).elementRanks, - NArray[Double](3, 3, 3, 3, 3) - ) - assertVecEquals( - NArray[Double](1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5).elementRanks, - NArray[Double](1, 2.5, 2.5, 5, 5, 5, 8.5, 8.5, 8.5, 8.5, 13, 13, 13, 13, 13) - ) - assertVecEquals( - NArray[Double](1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5).elementRanks, - NArray[Double](3, 3, 3, 3, 3, 7.5, 7.5, 7.5, 7.5, 11, 11, 11, 13.5, 13.5, 15) - ) - } - - test("pearson correlation coefficient") { - // https://www.statisticshowto.com/probability-and-statistics/correlation-coefficient-formula/ - val v1 = NArray[Double](43.0, 21.0, 25.0, 42.0, 57.0, 59.0) - val v2 = NArray[Double](99.0, 65.0, 79.0, 75.0, 87.0, 81.0) - assertEqualsDouble(v1.pearsonCorrelationCoefficient(v2)(using BoundsChecks.BoundsCheck.yes), 0.529809, 0.0001) - - } - - test("element rank") { - val v = NArray[Double](1.0, 5.0, 3.0, 6.0, 1.0, 5.0) - /* + // import vecxt.BoundsCheck.yes + + test("sample covariance") { + // Sample version + // https://corporatefinanceinstitute.com/resources/data-science/covariance/ + + val vector1 = NArray[Double](1692.0, 1978.0, 1884.0, 2151.0, 2519.0) + val vector2 = NArray[Double](68.0, 102.0, 110.0, 112.0, 154.0) + + val result = vector1.covariance(vector2) + + assertEqualsDouble(result, 9107.3, 0.001) + } + + test("sample variance and std") { + val v = NArray[Double](2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0) + assertEqualsDouble(v.variance, 4.571429, 0.00001) + assertEqualsDouble(v.stdDev, 2.13809, 0.00001) + } + + test("elementRanks") { + + assertVecEquals( + NArray.tabulate[Double](10)((i: Int) => 11.0 - i).elementRanks, + NArray[Double](10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + ) + assertVecEquals( + NArray.fill[Double](5)(42.0).elementRanks, + NArray[Double](3, 3, 3, 3, 3) + ) + assertVecEquals( + NArray[Double](1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5).elementRanks, + NArray[Double](1, 2.5, 2.5, 5, 5, 5, 8.5, 8.5, 8.5, 8.5, 13, 13, 13, 13, 13) + ) + assertVecEquals( + NArray[Double](1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5).elementRanks, + NArray[Double](3, 3, 3, 3, 3, 7.5, 7.5, 7.5, 7.5, 11, 11, 11, 13.5, 13.5, 15) + ) + } + + test("pearson correlation coefficient") { + // https://www.statisticshowto.com/probability-and-statistics/correlation-coefficient-formula/ + val v1 = NArray[Double](43.0, 21.0, 25.0, 42.0, 57.0, 59.0) + val v2 = NArray[Double](99.0, 65.0, 79.0, 75.0, 87.0, 81.0) + assertEqualsDouble(v1.pearsonCorrelationCoefficient(v2)(using BoundsChecks.BoundsCheck.yes), 0.529809, 0.0001) + + } + + test("element rank") { + val v = NArray[Double](1.0, 5.0, 3.0, 6.0, 1.0, 5.0) + /* 1.0 is the first, but has as tied rank. Take the average - 1.5 - */ - assertVecEquals( - v.elementRanks, - NArray[Double](1.5, 4.5, 3.0, 6.0, 1.5, 4.5) - ) - } - - test("spearmans rank") { - // https://statistics.laerd.com/statistical-guides/spearmans-rank-order-correlation-statistical-guide-2.php - val v1 = NArray[Double](56.0, 75.0, 45.0, 71.0, 62.0, 64.0, 58.0, 80.0, 76.0, 61.0) - val v2 = NArray[Double](66.0, 70.0, 40.0, 60.0, 65.0, 56.0, 59.0, 77.0, 67.0, 63.0) - assertEqualsDouble(v1.spearmansRankCorrelation(v2)(using BoundsChecks.BoundsCheck.yes), 0.6727, 0.001) - - // https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient - - val v3 = NArray[Double](86.0, 97.0, 99.0, 100.0, 101.0, 103.0, 106.0, 110.0, 112.0, 113.0) - val v4 = NArray[Double](2, 20.0, 28.0, 27.0, 50.0, 29.0, 7.0, 17.0, 6.0, 12.0) - assertEqualsDouble(-0.1757575, v3.spearmansRankCorrelation(v4)(using BoundsChecks.BoundsCheck.yes), 0.000001) - } + */ + assertVecEquals( + v.elementRanks, + NArray[Double](1.5, 4.5, 3.0, 6.0, 1.5, 4.5) + ) + } + + test("spearmans rank") { + // https://statistics.laerd.com/statistical-guides/spearmans-rank-order-correlation-statistical-guide-2.php + val v1 = NArray[Double](56.0, 75.0, 45.0, 71.0, 62.0, 64.0, 58.0, 80.0, 76.0, 61.0) + val v2 = NArray[Double](66.0, 70.0, 40.0, 60.0, 65.0, 56.0, 59.0, 77.0, 67.0, 63.0) + assertEqualsDouble(v1.spearmansRankCorrelation(v2)(using BoundsChecks.BoundsCheck.yes), 0.6727, 0.001) + + // https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient + + val v3 = NArray[Double](86.0, 97.0, 99.0, 100.0, 101.0, 103.0, 106.0, 110.0, 112.0, 113.0) + val v4 = NArray[Double](2, 20.0, 28.0, 27.0, 50.0, 29.0, 7.0, 17.0, 6.0, 12.0) + assertEqualsDouble(-0.1757575, v3.spearmansRankCorrelation(v4)(using BoundsChecks.BoundsCheck.yes), 0.000001) + } end StatsSuite