Skip to content

Commit

Permalink
Sadly undo scala spire type trickery of N:Fractional because it gobbl…
Browse files Browse the repository at this point in the history
…es up RAM: typelevel/spire#879
  • Loading branch information
glorat committed Feb 1, 2020
1 parent 044b961 commit 9b4b5f3
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,23 @@ import scala.collection.{GenMap, SortedMap}

class TimeSeriesInterpolator {
import TimeSeriesInterpolator._


// @deprecated("Pass SortedColumnMap for performance")
// def getValue[FROM,N](timeSeries:SortedMap[LocalDate,FROM], date:LocalDate)(implicit interpolator:Interpolator[FROM,N]) : Option[N] = {
// getValue(SortedColumnMap.from(timeSeries),date)
// }

def getValue[FROM,N](timeSeries:SortedColumnMap[LocalDate, FROM], date:LocalDate)(implicit interpolator:Interpolator[FROM,N]) : Option[N] = {
val nearest = getNearest(timeSeries,date)
interpolator(nearest, date)
}

def interpValue[N:Fractional](timeSeries:SortedColumnMap[LocalDate, N], date:LocalDate) : Option[Double] = {
getValue(timeSeries, date)(linear)
}

// @deprecated("Pass SortedColumnMap for performance")
// def interpValue[N:Fractional](timeSeries:SortedMap[LocalDate,N], date:LocalDate) : Option[Double] = {
// def interpValue[N:Fractional](timeSeries:SortedColumnMap[LocalDate, N], date:LocalDate) : Option[Double] = {
// getValue(timeSeries, date)(linear)
// }

def interpValueFraction(timeSeries:SortedColumnMap[LocalDate, Fraction], date:LocalDate) : Option[Double] = {
getValue(timeSeries, date)(linearFraction)
}

def interpValueDouble(timeSeries:SortedColumnMap[LocalDate, Double], date:LocalDate) : Option[Double] = {
getValue(timeSeries, date)(linearDouble)
}

def getNearest[N](timeSeries:SortedColumnMap[LocalDate,N], date:LocalDate) : InterpolationOption[N] = {
if (timeSeries.isEmpty) {
Empty()
Expand Down Expand Up @@ -65,7 +61,10 @@ object TimeSeriesInterpolator {

type Interpolator[FROM,N] = ((InterpolationOption[FROM], LocalDate) => Option[N])

def linear[N:Fractional]: Interpolator[N,Double] = (nearest, date) => {
// def linear[N:Fractional]: Interpolator[N,Double] = (nearest, date) => {

def linearFraction: Interpolator[Fraction,Double] = (nearest, date) => {
type N= Fraction
import spire.implicits._

val ret: Option[Double] = nearest match {
Expand All @@ -89,6 +88,30 @@ object TimeSeriesInterpolator {
ret
}

def linearDouble: Interpolator[Double,Double] = (nearest, date) => {
type N = Double
import spire.implicits._

val ret: Option[Double] = nearest match {
case _: Empty[N] => None
case e: Exact[N] => {
Some(e.value.toDouble())
}
case e: ExtrapolateLow[N] => Some(e.value.toDouble)
case e: ExtrapolateHigh[N] => Some(e.value.toDouble)
case e: Interpolate[N] => {
// Linear interpolation
val all: N = Fractional[N].fromLong(ChronoUnit.DAYS.between(e.before._1, e.after._1))
val n: N = Fractional[N].fromLong(ChronoUnit.DAYS.between(e.before._1, date))
val ratio: Double = (n / all).toDouble
val diff: Double = (e.after._2 - e.before._2).toDouble
val ret: Double = (diff * ratio) + e.before._2.toDouble
Some(ret)
}
case _ => None
}
ret
}

val step : Interpolator[Fraction, Fraction] = (nearest,date) => {
nearest match {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/com/gainstrack/report/PriceState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class PriceFXConverter(val ccys: Set[AssetId], val prices: Map[AssetPair, Sorted
}
else {
val timeSeries:SortedColumnMap[LocalDate, Double] = prices.getOrElse(tuple, SortedColumnMap())
val ret:Option[Double] = interp.interpValue(timeSeries, date).map(x => x)
val ret:Option[Double] = interp.interpValueDouble(timeSeries, date).map(x => x)
ret
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ case class SingleFXConversion(data:Map[AssetId, SortedColumnMap[LocalDate, Doubl
}
else if (fx2 == baseCcy) {
data.get(fx1).flatMap ( series =>
interp.getValue(series, date)(TimeSeriesInterpolator.linear)
interp.getValue(series, date)(TimeSeriesInterpolator.linearDouble)
)
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ class TestTimeSeriesInterpolator extends FlatSpec {
val interp = new TimeSeriesInterpolator

{
implicit val linear = TimeSeriesInterpolator.linear[Fraction]
// implicit val linear = TimeSeriesInterpolator.linearFraction
"TimeSeriesTest" should "extrapolate before start" in {
assert(interp.interpValue(data, parseDate("2018-01-01")) == Some(1))
assert(interp.interpValueFraction(data, parseDate("2018-01-01")) == Some(1))
}
it should "extrapolate after end" in {
assert(interp.interpValue(data, parseDate("2020-01-01")) == Some(365))
assert(interp.interpValueFraction(data, parseDate("2020-01-01")) == Some(365))
}
it should "return exact values" in {
assert(interp.interpValue(data, parseDate("2019-01-01")) == Some(1))
assert(interp.interpValue(data, parseDate("2019-12-31")) == Some(365))
assert(interp.interpValueFraction(data, parseDate("2019-01-01")) == Some(1))
assert(interp.interpValueFraction(data, parseDate("2019-12-31")) == Some(365))
}
it should "linearly interpolate in between" in {
assert(interp.interpValue(data, parseDate("2019-01-02")) == Some(2))
assert(interp.interpValue(data, parseDate("2019-12-30")) == Some(364))
assert(interp.interpValueFraction(data, parseDate("2019-01-02")) == Some(2))
assert(interp.interpValueFraction(data, parseDate("2019-12-30")) == Some(364))
}
}

Expand Down
2 changes: 1 addition & 1 deletion web/src/main/scala/JettyLauncher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ object JettyLauncher { // this is my entry object as specified in sbt project de
import com.gainstrack.core._
val interp = new TimeSeriesInterpolator
val timeSeries2: SortedColumnMap[LocalDate, Double] = SortedColumnMap()
interp.interpValue(timeSeries2, today())
interp.interpValueDouble(timeSeries2, today())
}
}

0 comments on commit 9b4b5f3

Please sign in to comment.