
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.tools
import cats.kernel.*
import cats.Later
import org.apache.commons.math3.random.RandomGenerator
import scala.collection.mutable
import java.lang.Math.{abs, max, min, pow, sqrt}
import scala.reflect.ClassTag
// 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 = 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: ImplementEqualMethod as eqm](f: A => K): collection.Map[ImplementEqualMethod.EQM[K], List[A]] =
val map = mutable.LinkedHashMap[ImplementEqualMethod.EQM[K], List[A]]()
for (i <- t)
do
val key = eqm(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: IArray[(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()
extension [A, B](f: A => B)
def memoized: A => B =
val memo =
import scala.jdk.CollectionConverters.*
java.util.IdentityHashMap[A, B]().asScala
(a: A) =>
memo.synchronized:
memo.getOrElseUpdate(a, f(a))
def median(sequence: Vector[Double]) =
val sorted = sequence.toArray.filterNot(_.isNaN).sorted
val size = sorted.length
if size == sequence.size
then
if size % 2 == 0
then (sorted(size / 2) + sorted((size / 2) - 1)) / 2
else sorted(size / 2)
else Double.NaN
def findFirstUnder(target: Double, f: Double => Double, start: Double, precision: Double): Double =
require(precision > 0, "Precision should be positive.")
var low = start
var highRange = precision
while f(low + highRange) >= target
do
low = low + highRange
highRange *= 2
var high = low + highRange
while high - low > precision
do
val mid = low + (high - low) / 2
val midValue = f(mid)
if midValue < target
then high = mid
else low = mid
if f(low) < target then low else high
/** standard C-style for loop */
inline def loop[A](
inline start: A,
inline condition: A => Boolean,
inline advance: A => A)(inline loopBody: A => Any): Unit =
var a = start
while condition(a) do
loopBody(a)
a = advance(a)
inline def map[A, B: ClassTag](a: IArray[A])(f: A => B) =
val length = a.length
val result = Array.ofDim[B](length)
loop(0, _ < length, _ + 1): i =>
result(i) = f(a(i))
IArray.unsafeFromArray(result)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy