All Downloads are FREE. Search and download functionalities are using the official Maven repository.

geotrellis.statistics.CompressedArrayHistogram.scala Maven / Gradle / Ivy

The newest version!
package geotrellis.statistics

import math.{abs, ceil, min, max, sqrt}

object CompressedArrayHistogram {
  def apply(size:Int) = {
    val counts = Array.ofDim[Int](size)
    new CompressedArrayHistogram(counts, 0, Int.MinValue, Int.MaxValue)
  }

  def apply(vmin:Int, vmax:Int) = {
    val counts = Array.ofDim[Int](vmax + 1 - vmin)
    new CompressedArrayHistogram(counts, 0, vmin, vmax)
  }

  def apply(vmin:Int, vmax:Int, size:Int) = {
    val counts = Array.ofDim[Int](size)
    new CompressedArrayHistogram(counts, 0, vmin, vmax)
  }
}

// TODO: can currently only handle non-negative integers

/**
  * Data object representing a histogram using an array for internal storage,
  * which requires an initial minimum and maximum val and a specified number of 'breaks' which
  * are used to group values together into ranges.
  *
  * @note   CompressedArrayHistogram can currently only handle non-negative integers.
  */
class CompressedArrayHistogram(counts:Array[Int], total:Int,
                               vmin:Int, vmax:Int) extends ArrayHistogram(counts, total) {
  val divisor = ceil((vmax - vmin).toFloat / counts.length).toInt

  //@inline
  final def compress(i:Int) = {
    val j = if (i >= vmax) { vmax - 1 } else if (i <= vmin) { vmin } else { i }
    (j - vmin) / divisor
  }

  //@inline
  final def decompress(i:Int) = (i * divisor) + vmin

  override def mutable() = new CompressedArrayHistogram(counts.clone, getTotalCount, vmin, vmax)

  override def rawValues = {
    val zmin = getMinValue
    val zmax = getMaxValue
    (zmin until zmax).filter(getItemCount(_) > 0).toArray
  }

  override def getValues() = rawValues()

  override def foreachValue(f:Int => Unit) {
    getValues().foreach(f) //FIXME
  }

  override def setItem(i:Int, count:Int) { super.setItem(compress(i), count) }
  override def countItem(i:Int, count:Int=1) { super.countItem(compress(i), count) }
  override def uncountItem(i:Int) { super.uncountItem(compress(i)) }

  override def getItemCount(i:Int) = {
    // once we compress, all values become equal to the maximum value of their
    // range, e.g. [0-9] becomes 9; this means that if our inputs are:
    // [0,1,4,6,9] the count for 9 is 5 and for all others is 0.
    if ((i + 1) % divisor == 0) {
      counts(compress(i))
    } else {
      0
    }
  }

  override def getMinValue:Int = {
    val x = super.getMinValue
    if (x == Int.MaxValue) x else decompress(x)
  }

  override def getMaxValue:Int = {
    val x = super.getMaxValue
    if (x == Int.MinValue) x else decompress(x)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy