Skip to content

Commit

Permalink
What if we just have a seperate set of JS methods?
Browse files Browse the repository at this point in the history
  • Loading branch information
Quafadas committed Nov 7, 2023
1 parent 72f6505 commit a68edca
Show file tree
Hide file tree
Showing 13 changed files with 738 additions and 5 deletions.
318 changes: 318 additions & 0 deletions core/js/src/main/scala/vecxt/array.extensions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
/*
* Copyright 2023 quafadas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package vecxt
import vecxt.Limits.Limit
import vecxt.Retentions.Retention

import scala.util.chaining.*
import vecxt.BoundsCheck
import scala.scalajs.js.typedarray.Float64Array
import scala.scalajs.js
import scala.scalajs.js.annotation.JSBracketAccess


extension (v: Float64Array)
inline def sort(): Unit = v.asInstanceOf[TypedArrayFacade].sort()
inline def reverse(): Unit = v.asInstanceOf[TypedArrayFacade].reverse()
inline def slice(): Float64Array = v.asInstanceOf[TypedArrayFacade].slice()

@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

extension [A](v: js.Array[A])
inline def fill(a: A): Unit = v.asInstanceOf[JsArrayFacade].fill(a)

@js.native
trait JsArrayFacade extends js.Object :
def fill[A](a: A): Unit = js.native


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)

def idxBoolean(index: js.Array[Boolean]) =
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 => 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 -(vec2: Float64Array)(using inline boundsCheck : BoundsCheck) =
dimCheck(vec, vec2)
val out = Float64Array(vec.length)
var i = 0
while i < vec.length do
out(i) = vec(i) - vec2(i)
i = i + 1
end while
out
end -

inline def -=(vec2: Float64Array): Unit =
var i = 0
while i < vec.length do
vec(i) = vec(i) - vec2(i)
i = i + 1
end while
end -=

inline def +(vec2: Float64Array) =
val out = new Array[Double](vec.length)
var i = 0
while i < vec.length do
out(i) = vec(i) + vec2(i)
i = i + 1
end while
out
end +

inline def +=(vec2: Float64Array): Unit =
var i = 0
while i < vec.length do
vec(i) = vec(i) + vec2(i)
i = i + 1
end while
end +=

inline def *=(d: Double) =
var i = 0
while i < vec.length do
vec(i) = vec(i) * d
i = i + 1
end while
vec
end *=

inline def *(d: Double) =
val out = Float64Array(vec.length)
var i = 0
while i < vec.length do
out(i) = vec(i) * d
i = i + 1
end while
out
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

/*
Retention and limit are known constants
In excel f(x) = min(max(x - retention, 0), limit))
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) => ()

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
28 changes: 28 additions & 0 deletions core/js/src/main/scala/vecxt/dimCheck.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2023 quafadas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package vecxt

import scala.scalajs.js.typedarray.Float64Array

object dimCheck:
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)

case class VectorDimensionMismatch(givenDimension:Int, requiredDimension:Int) extends Exception(
s"Expected Vector dimensions to match. First dimension was : $requiredDimension, second was : $givenDimension ."
)
14 changes: 14 additions & 0 deletions core/js/src/main/scala/vecxt/main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import scala.scalajs.js.typedarray.Float64Array

import scala.util.chaining.*
import vecxt.*

@main def checkBytecode =
val a = Float64Array(3).tap(_.fill(1.0))
val a1 = Float64Array(3).tap(_.fill(2.0))
// val b = Array[Boolean](true, false, true)
// val c = Array[Boolean](false, true, true)

import vecxt.BoundsCheck.yes

a - a1
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ import scala.util.chaining.*
import vecxt.BoundsCheck


enum LossCalc:
case Agg, Occ
end LossCalc

extension (vec: Array[Boolean])
inline def countTrue: Int =
var sum = 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package vecxt

import vecxt.*

@main def checkBytecode =
val a = Array[Double](1,2,3)
Expand Down
5 changes: 5 additions & 0 deletions core/shared/src/main/scala/vecxt/loss.calc.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package vecxt

enum LossCalc:
case Agg, Occ
end LossCalc
Loading

0 comments on commit a68edca

Please sign in to comment.