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

mgo.tools.package.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 09/01/13 Romain Reuillon
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package mgo

import cats.kernel._
import cats.Later

import org.apache.commons.math3.random.RandomGenerator

import scala.collection.mutable
import scala.math.{ abs, max, min, pow, sqrt }

package object tools {

  //  implicit def lazyOrdering[T](implicit ord: scala.Ordering[T]): scala.Ordering[Lazy[T]] = scala.Ordering.by(_.value)
  //
  //  implicit def lazyOrder[T](implicit OT: Order[T]): Order[Lazy[T]] = new Order[Lazy[T]] {
  //    def compare(x: Lazy[T], y: Lazy[T]) = OT.compare(x.value, y.value)
  //  }

  implicit class ArrayDecorator[A](array: Array[A]) {
    def get(i: Int): Option[A] =
      if (i < array.size) Some(array(i)) else None

  }

  implicit class IteratorDecorator[A](i: Iterator[A]) {
    def nextOption: Option[A] =
      if (i.hasNext) Some(i.next) else None
  }

  implicit class IterableDecorator[A](t: Iterable[A]) {
    def merge(t2: Iterable[A])(op: (A, A) => A): IndexedSeq[A] = {
      val size = scala.math.max(t.size, t2.size)

      val i1 = t.iterator
      val i2 = t2.iterator

      (0 until size) map {
        i =>
          val x = i1.nextOption
          val y = i2.nextOption

          (x, y) match {
            case (Some(v1), Some(v2)) => op(v1, v2)
            case (o1, o2) => o1 orElse o2 get
          }

      }
    }
  }

  implicit class VectorDecorator[A](xs: Vector[A]) {
    /**
     * Shadow each element of a set
     */
    def shadows[B]: IndexedSeq[Vector[A]] =
      for (i <- xs.indices; (as, bs) = xs splitAt i) yield as ++ bs.tail
  }

  def rndmChoice[T](t1: T, t2: T)(implicit rng: util.Random): T = {
    if (rng.nextDouble < 0.5) t1 else t2
  }

  implicit class ScalaToApacheRng(rng: util.Random) extends RandomGenerator {
    override def setSeed(i: Int): Unit = rng.setSeed(i)
    override def setSeed(ints: Array[Int]): Unit = ???
    override def setSeed(l: Long): Unit = rng.setSeed(l)

    override def nextBoolean(): Boolean = rng.nextBoolean
    override def nextBytes(bytes: Array[Byte]): Unit = rng.nextBytes(bytes)
    override def nextDouble(): Double = rng.nextDouble()
    override def nextLong(): Long = rng.nextLong()
    override def nextFloat(): Float = rng.nextFloat()
    override def nextGaussian(): Double = rng.nextGaussian()
    override def nextInt(): Int = rng.nextInt()
    override def nextInt(i: Int): Int = rng.nextInt(i)
  }

  //implicit def lazyOrdering[T](implicit ord: Ordering[T]) = tools.Lazy.lazyOrdering(ord)

  /*implicit class OptionDecorator[A](option: Option[A]) {
    def getOrElse(a: A) =
      option match {
        case Some(v) => v
        case None => a
      }
  }     */

  implicit class GroupByOrderedImplicitImpl[A](val t: Traversable[A]) extends AnyVal {
    def groupByOrdered[K](f: A => K): collection.Map[K, List[A]] = {
      val map = mutable.LinkedHashMap[K, List[A]]()
      for (i <- t) {
        val key = f(i)
        map(key) = i :: map.getOrElse(key, Nil)
      }
      map.mapValues(_.reverse).toMap
    }
  }

  def time[R](label: String, block: => R): (R, Long) = {
    val t0 = java.lang.System.nanoTime()
    val result = block // call-by-name
    val t1 = java.lang.System.nanoTime()
    (result, t1 - t0)
  }

  /* ------------------ Math ------------------ */

  type Point2D = (Double, Double)

  implicit class Point2DDecorator(p: Point2D) {
    def x = p._1
    def y = p._2
  }

  def clamp(value: Double, min_v: Double = 0.0, max_v: Double = 1.0): Double =
    max(min(value, max_v), min_v)

  /// Definintion of epsilon
  val epsilon = 1.0e-30

  def same(i1: Iterable[Double], i2: Iterable[Double]): Boolean =
    (i1.headOption, i2.headOption) match {
      case (None, None) => true
      case (None, _) => false
      case (_, None) => false
      case (Some(h1), Some(h2)) => if (abs(h2 - h1) < epsilon) same(i1.tail, i2.tail) else false
    }

  def allTheSame(i1: Vector[Iterable[Double]], i2: Vector[Iterable[Double]]): Boolean = allTheSameSorted(i1.sorted, i2.sorted)

  def allTheSameSorted(i1: Vector[Iterable[Double]], i2: Vector[Iterable[Double]]): Boolean = {
    if (i1.isEmpty || i2.isEmpty) false
    else if (i1.size == 1) allEquals(i1.head, i2)
    else if (i2.size == 1) allEquals(i2.head, i1)
    else if (same(i1.head, i2.head)) allTheSameSorted(i1.tail, i2.tail) else false
  }

  def allEquals(i: Iterable[Double], in: Vector[Iterable[Double]]): Boolean = !in.exists(i2 => !same(i, i2))

  def centroid(e: Vector[Vector[Double]]): Vector[Double] = e.reduce((x, y) => add(x, y)).map { x => x / e.size }

  def add(x: Vector[Double], y: Vector[Double]): Vector[Double] = x zip y map { case (x, y) => x + y }

  def squareDist(x: Vector[Double], y: Vector[Double]): Double = x zip y map { case (x, y) => pow(x + y, 2) } sum

  def integral(points: Vector[Point2D]): Double =
    if (points.size < 2) 0.0
    else
      points.sortBy(_._1).sliding(2, 1).map {
        bounds =>
          val min = bounds(0)
          val max = bounds(1)
          ((max.y + min.y) / 2) * (max.x - min.x)
      }.sum

  def surface(a: Double, b: Double, c: Double): Double = {
    val s = (a + b + c) / 2
    sqrt(s * (s - a) * (s - b) * (s - c))
  }

  def surface(p1: Point2D, p2: Point2D, p3: Point2D): Double = {
    val a = euclideanNorm(p1, p2)
    val b = euclideanNorm(p2, p3)
    val c = euclideanNorm(p3, p1)
    surface(a, b, c)
  }

  def euclideanNorm(p1: Point2D, p2: Point2D) =
    sqrt(pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2))

  def isUpper(line1: Point2D, line2: Point2D, c: Point2D) =
    (line2.x - line1.x) * (c.y - line1.y) - (line2.y - line1.y) * (c.x - line1.x) > 0

  def average(sequence: Vector[Double]): Double = sequence.sum / sequence.size

  def mse(sequence: Vector[Double]): Double = {
    val avg = average(sequence)
    average(sequence.map { v ⇒ pow(v - avg, 2) })
  }

  def multinomialDraw[T](s: Vector[(Double, T)], rng: util.Random): (T, List[(Double, T)]) = {
    assert(!s.isEmpty, "Input sequence should not be empty")
    def select(remaining: List[(Double, T)], value: Double, begin: List[(Double, T)] = List.empty): (T, List[(Double, T)]) =
      remaining match {
        case (weight, e) :: tail =>
          if (value <= weight) (e, begin.reverse ::: tail)
          else select(tail, value - weight, (weight, e) :: begin)
        case _ => sys.error(s"Bug $remaining $value $begin")
      }
    val totalWeight = s.unzip._1.sum
    select(s.toList, rng.nextDouble * totalWeight)
  }

  def findInterval[A: Ordering](s: Vector[A], v: A): Int = {
    import scala.collection.Searching._
    s.search(v) match {
      case InsertionPoint(x) => x - 1
      case Found(x) => x
    }
  }

  def randomInt(random: util.Random, discrete: mgo.evolution.D): Int =
    ((random.nextDouble() * (discrete.high - discrete.low + 1)) + discrete.low).floor.toInt

  def apacheRandom(random: util.Random): RandomGenerator = new org.apache.commons.math3.random.RandomGenerator {
    override def setSeed(seed: Int): Unit = ???
    override def setSeed(seed: Array[Int]): Unit = ???
    override def setSeed(seed: Long): Unit = ???

    override def nextBytes(bytes: Array[Byte]): Unit = random.nextBytes(bytes)
    override def nextInt(): Int = random.nextInt()
    override def nextInt(n: Int): Int = random.nextInt(n)
    override def nextLong(): Long = random.nextLong()
    override def nextBoolean(): Boolean = random.nextBoolean()
    override def nextFloat(): Float = random.nextFloat()
    override def nextDouble(): Double = random.nextDouble()
    override def nextGaussian(): Double = random.nextGaussian()
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy