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

spire.random.Dist.scala Maven / Gradle / Ivy

package spire.random

import spire.algebra._
import spire.syntax.all._
import spire.math.{Complex, Interval, Natural, Rational, SafeLong, UByte, UShort, UInt, ULong}

import scala.collection.mutable.ArrayBuffer
import scala.collection.SeqLike
import scala.collection.generic.CanBuildFrom
import scala.annotation.tailrec
import scala.{specialized => spec}
import scala.reflect.ClassTag

trait Dist[@spec A] extends Any { self =>

  def apply(gen: Generator): A

  def fill(gen: Generator, arr: Array[A]): Unit = {
    var i = 0
    while (i < arr.length) {
      arr(i) = apply(gen)
      i += 1
    }
  }

  final def map[B](f: A => B): Dist[B] =
    new DistFromGen(g => f(apply(g)))

  final def flatMap[B](f: A => Dist[B]): Dist[B] =
    new DistFromGen(g => f(apply(g))(g))

  final def filter(pred: A => Boolean): Dist[A] =
    new Dist[A] {
      @tailrec final def apply(gen: Generator): A = {
        val a = self(gen)
        if (pred(a)) a else apply(gen)
      }
    }

  final def given(pred: A => Boolean): Dist[A] =
    filter(pred)

  def until(pred: A => Boolean): Dist[Seq[A]] = {
    @tailrec def loop(gen: Generator, a: A, buf: ArrayBuffer[A]): Seq[A] = {
      buf.append(a)
      if (pred(a)) buf else loop(gen, self(gen), buf)
    }
    new DistFromGen(g => loop(g, self(g), ArrayBuffer.empty[A]))
  }

  def foldn[B](init: B, n: Int)(f: (B, A) => B): Dist[B] = {
    @tailrec def loop(gen: Generator, i: Int, b: B): B =
      if (i == 0) b else loop(gen, i - 1, f(b, self(gen)))
    new DistFromGen(g => loop(g, n, init))
  }

  def unfold[B](init: B)(f: (B, A) => B)(pred: B => Boolean): Dist[B] = {
    @tailrec def loop(gen: Generator, b: B): B =
      if (pred(b)) b else loop(gen, f(b, self(gen)))
    new DistFromGen(g => loop(g, init))
  }

  def pack(n: Int)(implicit ct: ClassTag[A]): Dist[Array[A]] = new Dist[Array[A]] {
    def apply(gen: Generator): Array[A] = {
      var i = 0
      val arr = new Array[A](n)
      while (i < arr.length) {
        arr(i) = self(gen)
        i += 1
      }
      arr
    }
  }

  def repeat[CC[X] <: Seq[X]](n: Int)(implicit cbf: CanBuildFrom[Nothing, A, CC[A]]): Dist[CC[A]] =
    new Dist[CC[A]] {
      def apply(gen: Generator): CC[A] = {
        val builder = cbf()
        builder.sizeHint(n)
        var i = 0
        while (i < n) {
          builder += self(gen)
          i += 1
        }
        builder.result()
      }
    }

  def iterate(n: Int, f: A => Dist[A]): Dist[A] =
    if (n == 0) this else flatMap(f).iterate(n - 1 ,f)

  def iterateUntil(pred: A => Boolean, f: A => Dist[A]): Dist[A] = new Dist[A] {
    @tailrec def loop(gen: Generator, a: A): A =
      if (pred(a)) a else loop(gen, f(a)(gen))

    def apply(gen: Generator): A = loop(gen, self(gen))
  }

  final def zip[B](that: Dist[B]): Dist[(A, B)] =
    new DistFromGen(g => (this(g), that(g)))

  def zipWith[B, C](that: Dist[B])(f: (A, B) => C): Dist[C] =
    new DistFromGen(g => f(this(g), that(g)))

  final def toIterator(gen: Generator): Iterator[A] =
    new DistIterator(this, gen)

  final def toStream(gen: Generator): Stream[A] =
    this(gen) #:: toStream(gen)

  import scala.collection.generic.CanBuildFrom

  def sample[CC[X] <: Iterable[X]](n: Int)(implicit gen: Generator, cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val b = cbf()
    b.sizeHint(n)
    var i = 0
    while (i < n) {
      b += self(gen)
      i += 1
    }
    b.result
  }

  final def count(pred: A => Boolean, n: Int)(implicit gen: Generator): Int = {
    @tailrec def loop(num: Int, i: Int): Int =
      if (i == 0) num else loop(num + (if (pred(self(gen))) 1 else 0), i - 1)
    loop(0, n)
  }

  def pr(pred: A => Boolean, n: Int)(implicit gen: Generator): Double =
    1.0 * count(pred, n) / n

  def sum(n: Int)(implicit gen: Generator, alg: Rig[A]): A = {
    @tailrec def loop(total: A, i: Int): A =
      if (i == 0) total else loop(alg.plus(total, self(gen)), i - 1)
    loop(alg.zero, n)
  }

  def ev(n: Int)(implicit gen: Generator, alg: Field[A]): A =
    alg.div(sum(n), alg.fromInt(n))

  def histogram(n: Int)(implicit gen: Generator): Map[A, Double] =
    rawHistogram(n).map { case (k, v) => (k, 1.0 * v / n) }

  def rawHistogram(n: Int)(implicit gen: Generator): Map[A, Int] =
    toStream(gen).take(n).foldLeft(Map.empty[A, Int]) { case (h, a) =>
      h.updated(a, h.getOrElse(a, 0) + 1)
    }
}

final class DistIterator[A](next: Dist[A], gen: Generator) extends Iterator[A] {
  final def hasNext: Boolean = true
  final def next(): A = next(gen)
}

class DistFromGen[@spec A](f: Generator => A) extends Dist[A] {
  def apply(gen: Generator): A = f(gen)
}

trait DistSemiring[A] extends Semiring[Dist[A]] {
  implicit def alg: Semiring[A]
  def zero: Dist[A] = Dist.constant(alg.zero)
  def plus(x: Dist[A], y: Dist[A]): Dist[A] = new DistFromGen(g => x(g) + y(g))
  def times(x: Dist[A], y: Dist[A]): Dist[A] = new DistFromGen(g => x(g) * y(g))
}

trait DistRng[A] extends DistSemiring[A] with Rng[Dist[A]] {
  implicit def alg: Rng[A]
  def negate(x: Dist[A]): Dist[A] = new DistFromGen(g => alg.negate(x(g)))
}

trait DistRig[A] extends DistSemiring[A] with Rig[Dist[A]] {
  implicit def alg: Rig[A]
  def one: Dist[A] = Dist.constant(alg.one)
}

trait DistRing[A] extends DistRng[A] with Ring[Dist[A]] {
  def alg: Ring[A]
  def one: Dist[A] = Dist.constant(alg.one)
}

trait DistEuclideanRing[A] extends EuclideanRing[Dist[A]] with DistRing[A] {
  def alg: EuclideanRing[A]
  def quot(x: Dist[A], y: Dist[A]): Dist[A] = new DistFromGen(g => alg.quot(x(g), y(g)))
  def mod(x: Dist[A], y: Dist[A]): Dist[A] = new DistFromGen(g => alg.mod(x(g), y(g)))
  def gcd(x: Dist[A], y: Dist[A]): Dist[A] = new DistFromGen(g => alg.gcd(x(g), y(g)))
}

trait DistField[A] extends Field[Dist[A]] with DistEuclideanRing[A] {
  def alg: Field[A]
  def div(x: Dist[A], y: Dist[A]): Dist[A] = new DistFromGen(g => alg.div(x(g), y(g)))
  override def reciprocal(x: Dist[A]): Dist[A] = new DistFromGen(g => alg.reciprocal(x(g)))
}

trait DistModule[V, K] extends Module[Dist[V], Dist[K]] {
  implicit def alg: Module[V, K]

  def scalar: Rng[Dist[K]] = Dist.rng(alg.scalar)
  def zero: Dist[V] = Dist.constant(alg.zero)
  def plus(x: Dist[V], y: Dist[V]): Dist[V] = new DistFromGen(g => x(g) + y(g))
  def negate(x: Dist[V]): Dist[V] = new DistFromGen(g => -x(g))
  override def minus(x: Dist[V], y: Dist[V]): Dist[V] = new DistFromGen(g => x(g) - y(g))
  def timesl(k: Dist[K], v: Dist[V]): Dist[V] = new DistFromGen(g => k(g) *: v(g))
  def timesr(k: Dist[K], v: Dist[V]): Dist[V] = new DistFromGen(g => v(g) :* k(g))
}

trait DistVectorSpace[V, K] extends DistModule[V, K] with VectorSpace[Dist[V], Dist[K]] {
  implicit def alg: VectorSpace[V, K]

  override def scalar: Field[Dist[K]] = Dist.field(alg.scalar)

  override def divr(v: Dist[V], k: Dist[K]): Dist[V] = new DistFromGen(g => v(g) :/ k(g))
}

trait DistNormedVectorSpace[V, K] extends DistVectorSpace[V, K]
with NormedVectorSpace[Dist[V], Dist[K]] {
  implicit def alg: NormedVectorSpace[V, K]

  def norm(v: Dist[V]): Dist[K] = v map alg.norm
}

trait DistInnerProductSpace[V, K] extends DistVectorSpace[V, K]
with InnerProductSpace[Dist[V], Dist[K]] {
  implicit def alg: InnerProductSpace[V, K]

  def dot(v: Dist[V], w: Dist[V]): Dist[K] = new DistFromGen(g => v(g) dot w(g))
}

object Dist extends DistInstances8 {
  @inline final def apply[A](implicit na: Dist[A]): Dist[A] = na

  final def apply[A, B](f: A => B)(implicit na: Dist[A]): Dist[B] =
    na.map(f)

  final def apply[A, B, C](f: (A, B) => C)(implicit na: Dist[A], nb: Dist[B]): Dist[C] =
    na.zipWith(nb)(f)

  final def gen[A](f: Generator => A): Dist[A] =
    new DistFromGen(g => f(g))

  def uniform[A: Uniform](low: A, high: A): Dist[A] = Uniform[A].apply(low, high)

  def gaussian[A: Gaussian](mean: A, stdDev: A): Dist[A] = Gaussian[A].apply(mean, stdDev)

  def reduce[A](ns: Dist[A]*)(f: (A, A) => A): Dist[A] =
    new DistFromGen(g => ns.map(_(g)).reduceLeft(f))

  def fromBytes[A](n: Int)(f: Array[Byte] => A): Dist[A] =
    new DistFromGen(g => f(g.generateBytes(n)))

  def fromInts[A](n: Int)(f: Array[Int] => A): Dist[A] =
    new DistFromGen(g => f(g.generateInts(n)))

  def fromLongs[A](n: Int)(f: Array[Long] => A): Dist[A] =
    new DistFromGen(g => f(g.generateLongs(n)))

  def mix[A](ds: Dist[A]*): Dist[A] =
    Dist.oneOf(ds:_*).flatMap(identity)

  def weightedMix[A](tpls: (Double, Dist[A])*): Dist[A] = {
    val ds = new Array[Dist[A]](tpls.length)
    val ws = new Array[Double](tpls.length)
    var i = 0
    var total = 0.0
    tpls.foreach { case (w, d) =>
      total += w
      ws(i) = total
      ds(i) = d
      i += 1
    }

    new DistFromGen({ g =>
      val w = g.nextDouble(total)
      var i = 0
      while (ws(i) < w) i += 1
      ds(i).apply(g)
    })
  }

  implicit val unit: Dist[Unit] = new DistFromGen[Unit](g => ())
  implicit val boolean: Dist[Boolean] = new DistFromGen[Boolean](_.nextBoolean)
  implicit val byte: Dist[Byte] = new DistFromGen[Byte](_.nextInt.toByte)
  implicit val short: Dist[Short] = new DistFromGen[Short](_.nextInt.toShort)
  implicit val char: Dist[Char] = new DistFromGen[Char](_.nextInt.toChar)
  implicit val int: Dist[Int] = new DistFromGen[Int](_.nextInt)
  implicit val float: Dist[Float] = new DistFromGen[Float](_.nextFloat)
  implicit val long: Dist[Long] = new DistFromGen[Long](_.nextLong)
  implicit val double: Dist[Double] = new DistFromGen[Double](_.nextDouble)

  implicit val ubyte: Dist[UByte] = new DistFromGen[UByte](g => UByte(g.nextInt))
  implicit val ushort: Dist[UShort] = new DistFromGen[UShort](g => UShort(g.nextInt))
  implicit val uint: Dist[UInt] = new DistFromGen[UInt](g => UInt(g.nextInt))
  implicit val ulong: Dist[ULong] = new DistFromGen[ULong](g => ULong(g.nextLong))

  implicit def complex[A: Fractional: Trig: IsReal: Dist]: Dist[Complex[A]] =
    Dist(Complex(_: A, _: A))

  implicit def interval[A](implicit na: Dist[A], order: Order[A], r: AdditiveMonoid[A]): Dist[Interval[A]] =
    Dist((x: A, y: A) => if (order.lt(x, y)) Interval(x, y) else Interval(y, x))

  implicit def option[A](implicit no: Dist[Boolean], na: Dist[A]): Dist[Option[A]] =
    new DistFromGen(g => if (no(g)) Some(na(g)) else None)

  implicit def either[A, B](implicit no: Dist[Boolean], na: Dist[A], nb: Dist[B]): Dist[Either[A, B]] =
    new DistFromGen[Either[A, B]](g => if (no(g)) Right(nb(g)) else Left(na(g)))

  implicit def tuple2[A: Dist, B: Dist]: Dist[(A, B)] =
    Dist((_: A, _: B))

  def intrange(from: Int, to: Int): Dist[Int] = {
    val d = to - from + 1
    new DistFromGen(_.nextInt(d) + from)
  }

  def natural(maxDigits: Int): Dist[Natural] = new Dist[Natural] {
    @tailrec
    private def loop(g: Generator, i: Int, size: Int, n: Natural): Natural =
      if (i < size) loop(g, i + 1, size, Natural.Digit(g.next[UInt], n)) else n

    def apply(gen: Generator): Natural =
      loop(gen, 1, gen.nextInt(maxDigits) + 1, Natural.End(gen.next[UInt]))
  }

  def safelong(maxBytes: Int): Dist[SafeLong] = if (maxBytes <= 0) {
    throw new IllegalArgumentException("need positive maxBytes, got %s" format maxBytes)
  } else if (maxBytes < 8) {
    val n = (8 - maxBytes) * 8
    new DistFromGen(g => SafeLong(g.nextLong >>> n))
  } else if (maxBytes == 8) {
    new DistFromGen(g => SafeLong(g.nextLong))
  } else  {
    bigint(maxBytes).map(SafeLong(_))
  }

  def bigint(maxBytes: Int): Dist[BigInt] = new Dist[BigInt] {
    def apply(gen: Generator): BigInt = BigInt(gen.generateBytes(gen.nextInt(maxBytes) + 1))
  }

  def bigdecimal(maxBytes: Int, maxScale: Int): Dist[BigDecimal] = new Dist[BigDecimal] {
    private val nb = bigint(maxBytes)
    def apply(gen: Generator): BigDecimal = BigDecimal(nb(gen), gen.nextInt(maxScale) + 1)
  }

  implicit def rational(implicit next: Dist[BigInt]): Dist[Rational] =
    Dist(Rational(_: BigInt, _: BigInt))(next, next.filter(_ != 0))

  def longrational: Dist[Rational] =
    Dist(Rational(_: Long, _: Long))(Dist[Long], Dist[Long].filter(_ != 0))

  def bigrational(maxBytes: Int): Dist[Rational] =
    rational(bigint(maxBytes))

  def constant[A](a: A): Dist[A] = new DistFromGen[A](g => a)
  def always[A](a: A): Dist[A] = new DistFromGen[A](g => a)

  implicit def array[A: Dist: ClassTag](minSize: Int, maxSize: Int): Dist[Array[A]] =
    new Dist[Array[A]] {
      private val d = maxSize - minSize + 1
      def apply(gen: Generator): Array[A] = gen.generateArray[A](gen.nextInt(d) + minSize)
    }

  implicit def list[A: Dist](minSize: Int, maxSize: Int): Dist[List[A]] =
    new Dist[List[A]] {
      private val d = maxSize - minSize + 1
      private def loop(g: Generator, n: Int, sofar: List[A]): List[A] =
        if (n > 0) loop(g, n - 1, g.next[A] :: sofar) else sofar

      def apply(gen: Generator): List[A] =
        loop(gen, gen.nextInt(d) + minSize, Nil)
    }

  implicit def set[A: Dist](minInputs: Int, maxInputs: Int): Dist[Set[A]] =
    list[A](minInputs, maxInputs).map(_.toSet)

  implicit def map[A: Dist, B: Dist](minInputs: Int, maxInputs: Int): Dist[Map[A, B]] =
    list[(A, B)](minInputs, maxInputs).map(_.toMap)

  def oneOf[A: ClassTag](as: A*): Dist[A] = new Dist[A] {
    private val arr = as.toArray
    def apply(gen: Generator): A = arr(gen.nextInt(arr.length))
  }

  def cycleOf[A: ClassTag](as: A*): Dist[A] = new Dist[A] {
    private val arr = as.toArray
    private var i = 0
    def apply(gen: Generator): A = {
      val a = arr(i)
      i = (i + 1) % arr.length
      a
    }
  }

  def gaussianFromDouble[A: Field]: DistFromGen[A] = new DistFromGen[A](g => Field[A].fromDouble(g.nextGaussian))
}

trait DistInstances0 {
  implicit def semiring[A](implicit ev: Semiring[A]): Semiring[Dist[A]] =
    new DistSemiring[A] { def alg = ev }
}

trait DistInstances1 extends DistInstances0 {
  implicit def rig[A](implicit ev: Rig[A]): Rig[Dist[A]] =
    new DistRig[A] { def alg = ev }

  implicit def rng[A](implicit ev: Rng[A]): Rng[Dist[A]] =
    new DistRng[A] { def alg = ev }
}

trait DistInstances2 extends DistInstances1 {
  implicit def ring[A](implicit ev: Ring[A]): Ring[Dist[A]] =
    new DistRing[A] { def alg = ev }
}

trait DistInstances3 extends DistInstances2 {
  implicit def euclideanRing[A](implicit ev: EuclideanRing[A]): EuclideanRing[Dist[A]] =
    new DistEuclideanRing[A] { def alg = ev }
}

trait DistInstances4 extends DistInstances3 {
  implicit def field[A](implicit ev: Field[A]): Field[Dist[A]] =
    new DistField[A] { def alg = ev }
}

trait DistInstances5 extends DistInstances4 {
  implicit def module[V,K](implicit ev: Module[V,K]): Module[Dist[V],Dist[K]] =
    new DistModule[V,K] { def alg = ev }
}

trait DistInstances6 extends DistInstances5 {
  implicit def vectorSpace[V,K](implicit ev: VectorSpace[V,K]): VectorSpace[Dist[V],Dist[K]] =
    new DistVectorSpace[V,K] { def alg = ev }
}

trait DistInstances7 extends DistInstances6 {
  implicit def NormedVectorSpace[V,K](implicit ev: NormedVectorSpace[V,K]): NormedVectorSpace[Dist[V],Dist[K]] =
    new DistNormedVectorSpace[V,K] { def alg = ev }
}

trait DistInstances8 extends DistInstances7 {
  implicit def InnerProductSpace[V,K](implicit ev: InnerProductSpace[V,K]): InnerProductSpace[Dist[V],Dist[K]] =
    new DistInnerProductSpace[V,K] { def alg = ev }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy