Sunday, September 18, 2016

Algebird Decayed Value

Since it took me some time to understand how decayed values in algebird work, I thought I'd document it here.

A DecayedValue conveys the idea of a value that is exponentially decaying over time. The DecayedValue itself just represents a snapshot of such a decaying value, it has a value and time. The time is actually scaled time, different exponentially decaying values can be normalized to the same timescale such that they decay at the same rate. The value of a DecayedValue at any other time can be computed by exponentially scaling the value.

e.g. Let's say we have DecayedValue(1.0, 100) i.e. value of 1.0 and scaledTime of  100. Let's say we want to find out what this DecayedValue will be at time 101. For this we basically just need to decay the value by one unit of exponential decay i.e. to 1.0 * Math.exp(-1). So the new value will be:
DecayedValue(Math.exp(-1), 101). Similarly the value at time 99 would be DecayedValue(Math.exp(1), 99). Note that all of these represent the exact same thing i.e

DecayedValue(1.0, 100) === DecayedValue(Math.exp(-1), 101) === DecayedValue(Math.exp(1), 99)

See how we've represented a varying value immutably. This is general concept, values varying with time can be made immutable by capturing their value at a specific time along with the timestamp.

Here's some more sample code to illustrate the concept:
  def decayedValueTry() = {
    // Choosing values so that x decayed at y's time is equal to y's value
    val x = DecayedValue(Math.exp(2), 1)
    val y = DecayedValue(Math.exp(1), 2)

    // eps is a value below which we consider decayed value to be 0
    val monoid = DecayedValueMonoid(0.01)
    val sum =, y)

    // We are expecting double of y's value since x is chosen such that
    // it decays to y's value, with infinitesimally small error.
    assert(Math.abs(2 * y.value - sum.value) < 0.00001)