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

spire.syntax.std.Ops.scala Maven / Gradle / Ivy

The newest version!
package spire
package syntax
package std

import scala.collection.generic.CanBuildFrom
import spire.algebra.{AdditiveMonoid, Field, Monoid, MultiplicativeMonoid, NRoot, Order, PartialOrder, Signed}
import spire.math.{Natural, Number, QuickSort, SafeLong, Searching, ULong}
import spire.syntax.cfor._
import spire.syntax.monoid._
import spire.syntax.field._
import spire.syntax.nroot._
import spire.syntax.order._
import spire.syntax.signed._

final class LiteralIntOps(val lhs: Int) extends AnyVal {
  def /~(rhs: Int): Int = lhs / rhs
  def /%(rhs: Int): (Int, Int) = (lhs / rhs, lhs % rhs)
  def pow(rhs: Int): Int = Math.pow(lhs, rhs).toInt
  def **(rhs: Int): Int = Math.pow(lhs, rhs).toInt
  def !(): BigInt = spire.math.fact(lhs)
  def choose(rhs: Int): BigInt = spire.math.choose(lhs, rhs)
}

final class LiteralLongOps(val lhs: Long) extends AnyVal {
  def /~(rhs: Long): Long = lhs / rhs
  def /%(rhs: Long): (Long, Long) = (lhs / rhs, lhs % rhs)
  def pow(rhs: Long): Long = spire.math.pow(lhs, rhs)
  def **(rhs: Long): Long = spire.math.pow(lhs, rhs)
  def !(): BigInt = spire.math.fact(lhs)
  def choose(rhs: Long): BigInt = spire.math.choose(lhs, rhs)
}

final class LiteralDoubleOps(val lhs: Double) extends AnyVal {
  def pow(rhs: Double): Double = spire.math.pow(lhs, rhs)
  def **(rhs: Double): Double = spire.math.pow(lhs, rhs)
}

class LiteralBigIntOps(val lhs: BigInt) extends AnyVal {
  def /~(rhs: BigInt): BigInt = lhs / rhs
  def pow(rhs: BigInt): BigInt = spire.math.pow(lhs, rhs)
  def **(rhs: BigInt): BigInt = spire.math.pow(lhs, rhs)

  def +(rhs: SafeLong): SafeLong = SafeLong(lhs) + rhs
  def *(rhs: SafeLong): SafeLong = SafeLong(lhs) * rhs
  def -(rhs: SafeLong): SafeLong = SafeLong(lhs) - rhs
  def /(rhs: SafeLong): SafeLong = SafeLong(lhs) / rhs
  def /~(rhs: SafeLong): SafeLong = SafeLong(lhs) /~ rhs
  def %(rhs: SafeLong): SafeLong = SafeLong(lhs) % rhs
  def /%(rhs: SafeLong): (SafeLong, SafeLong) = SafeLong(lhs) /% rhs

  def +(rhs: Natural): BigInt = lhs + rhs.toBigInt
  def *(rhs: Natural): BigInt = lhs * rhs.toBigInt
  def -(rhs: Natural): BigInt = lhs - rhs.toBigInt
  def /(rhs: Natural): BigInt = lhs / rhs.toBigInt
  def /~(rhs: Natural): BigInt = lhs / rhs.toBigInt
  def %(rhs: Natural): BigInt = lhs % rhs.toBigInt
  def /%(rhs: Natural): (BigInt, BigInt) = lhs /% rhs.toBigInt

  def +(rhs: ULong): BigInt = lhs + rhs.toBigInt
  def *(rhs: ULong): BigInt = lhs * rhs.toBigInt
  def -(rhs: ULong): BigInt = lhs - rhs.toBigInt
  def /(rhs: ULong): BigInt = lhs / rhs.toBigInt
  def /~(rhs: ULong): BigInt = lhs / rhs.toBigInt
  def %(rhs: ULong): BigInt = lhs % rhs.toBigInt
  def /%(rhs: ULong): (BigInt, BigInt) = lhs /% rhs.toBigInt

  def +(rhs: Number): Number = Number(lhs) + rhs
  def *(rhs: Number): Number = Number(lhs) * rhs
  def -(rhs: Number): Number = Number(lhs) - rhs
  def /(rhs: Number): Number = Number(lhs) / rhs
  def /~(rhs: Number): Number = Number(lhs) / rhs
  def %(rhs: Number): Number = Number(lhs) % rhs
  def /%(rhs: Number): (Number, Number) = Number(lhs) /% rhs
}

final class ArrayOps[@sp A](arr: Array[A]) {
  def qsum(implicit ev: AdditiveMonoid[A]): A = {
    var result = ev.zero
    cfor(0)(_ < arr.length, _ + 1) { i => result += arr(i) }
    result
  }

  def qproduct(implicit ev: MultiplicativeMonoid[A]): A = {
    var result = ev.one
    cfor(0)(_ < arr.length, _ + 1) { i => result *= arr(i) }
    result
  }

  def qcombine(implicit ev: Monoid[A]): A = {
    var result = ev.id
    cfor(0)(_ < arr.length, _ + 1) { i => result |+|= arr(i) }
    result
  }

  def qnorm(p: Int)(implicit ev: Field[A], s: Signed[A], nr: NRoot[A]): A = {
    var result = ev.one
    cfor(0)(_ < arr.length, _ + 1) { i => result += arr(i).abs.pow(p) }
    result.nroot(p)
  }

  def qnormWith[@sp(Double) R](p: Int)(f: A => R)(implicit ev: Field[R], s: Signed[R], nr: NRoot[R]): R = {
    var result: R = ev.one
    cfor(0)(_ < arr.length, _ + 1) { i => result += f(arr(i)).abs.pow(p) }
    result.nroot(p)
  }

  def qmin(implicit ev: Order[A]): A = {
    if (arr.length == 0) throw new UnsupportedOperationException("empty array")
    var result = arr(0)
    cfor(1)(_ < arr.length, _ + 1) { i =>
      result = result min arr(i)
    }
    result
  }

  def qmax(implicit ev: Order[A]): A = {
    if (arr.length == 0) throw new UnsupportedOperationException("empty array")
    var result = arr(0)
    cfor(1)(_ < arr.length, _ + 1) { i =>
      result = result max arr(i)
    }
    result
  }

  def qmean(implicit ev: Field[A]): A = {
    if (arr.length == 0) throw new UnsupportedOperationException("empty array")
    var result = ev.zero
    cfor(0)(_ < arr.length, _ + 1) { i =>
      result = (result * i / (i + 1)) + (arr(i) / (i + 1))
    }
    result
  }

  def qmeanWith[@sp(Double) R](f: A => R)(implicit ev: Field[R]): R = {
    if (arr.length == 0) throw new UnsupportedOperationException("empty array")
    var result: R = ev.zero
    cfor(0)(_ < arr.length, _ + 1) { i =>
      result = (result * i / (i + 1)) + (f(arr(i)) / (i + 1))
    }
    result
  }

  import spire.math.{Sorting, Selection, Searching}

  def qsearch(a: A)(implicit ev: Order[A]): Int = {
    Searching.search(arr, a)
  }

  def qsort(implicit ev: Order[A], ct: ClassTag[A]): Unit = {
    Sorting.sort(arr)
  }

  def qsortBy[@sp B](f: A => B)(implicit ev: Order[B], ct: ClassTag[A]): Unit = {
    implicit val ord: Order[A] = ev.on(f)
    Sorting.sort(arr)
  }

  def qsortWith(f: (A, A) => Int)(implicit ct: ClassTag[A]): Unit = {
    implicit val ord: Order[A] = Order.from(f)
    Sorting.sort(arr)
  }

  def qsorted(implicit ev: Order[A], ct: ClassTag[A]): Array[A] = {
    val arr2 = arr.clone
    Sorting.sort(arr2)
    arr2
  }

  def qsortedBy[@sp B](f: A => B)(implicit ev: Order[B], ct: ClassTag[A]): Array[A] = {
    implicit val ord: Order[A] = ev.on(f)
    val arr2 = arr.clone
    Sorting.sort(arr2)
    arr2
  }

  def qsortedWith(f: (A, A) => Int)(implicit ct: ClassTag[A]): Array[A] = {
    implicit val ord: Order[A] = Order.from(f)
    val arr2 = arr.clone
    Sorting.sort(arr2)
    arr2
  }

  def qselect(k: Int)(implicit ev: Order[A], ct: ClassTag[A]): Unit = {
    Selection.select(arr, k)
  }

  def qselected(k: Int)(implicit ev: Order[A], ct: ClassTag[A]): Array[A] = {
    val arr2 = arr.clone
    Selection.select(arr2, k)
    arr2
  }

  import spire.random.Generator

  def qshuffle()(implicit gen: Generator): Unit = gen.shuffle(arr)

  def qshuffled(implicit gen: Generator): Array[A] = {
    val arr2 = arr.clone
    gen.shuffle(arr2)
    arr2
  }

  def qsampled(n: Int)(implicit gen: Generator, ct: ClassTag[A]): Array[A] =
    gen.sampleFromArray(arr, n)
}

final class IndexedSeqOps[@sp A, CC[A] <: IndexedSeq[A]](as: CC[A]) {
  def qsearch(a: A)(implicit ev: Order[A]): Int =
    Searching.search(as, a)
}

final class SeqOps[@sp A, CC[A] <: Iterable[A]](as: CC[A]) { //fixme
  def qsum(implicit ev: AdditiveMonoid[A]): A =
    as.aggregate(ev.zero)(ev.plus, ev.plus)

  def qproduct(implicit ev: MultiplicativeMonoid[A]): A =
    as.aggregate(ev.one)(ev.times, ev.times)

  def qcombine(implicit ev: Monoid[A]): A =
    as.aggregate(ev.id)(ev.op, ev.op)

  def qnorm(p: Int)(implicit ev: Field[A], s: Signed[A], nr: NRoot[A]): A =
    as.aggregate(ev.one)(_ + _.abs.pow(p), _ + _).nroot(p)

  def qnormWith[R](p: Int)(f: A => R)(implicit ev: Field[R], s: Signed[R], nr: NRoot[R]): R =
    as.aggregate(ev.one)((t, a) => t + f(a).abs.pow(p), _ + _).nroot(p)

  /** Computes the minimal elements of a partially ordered set.
   * If the poset contains multiple copies of a minimal element, the function
   * will only return a single copy of it.
   */
  def pmin(implicit ev: PartialOrder[A]): Seq[A] =
    Searching.minimalElements(as)(ev)

  /** Computes the maximal elements of a partially ordered set.
   * If the posset contains multiple copies of a maximal element, the function
   * will only return a single copy of it.
   */
  def pmax(implicit ev: PartialOrder[A]): Seq[A] =
    Searching.minimalElements(as)(ev.reverse)

  def qmin(implicit ev: Order[A]): A = {
    if (as.isEmpty) throw new UnsupportedOperationException("empty seq")
    as.aggregate(as.head)(ev.min, ev.min)
  }

  def qmax(implicit ev: Order[A]): A = {
    if (as.isEmpty) throw new UnsupportedOperationException("empty seq")
    as.aggregate(as.head)(ev.max, ev.max)
  }

  def qmean(implicit ev: Field[A]): A = {
    if (as.isEmpty) throw new UnsupportedOperationException("empty seq")
    var mean = ev.zero
    var i = 0
    var j = 1
    as.foreach { a =>
      val t = ev.div(ev.times(mean, ev.fromInt(i)), ev.fromInt(j))
      val z = ev.div(a, ev.fromInt(j))
      mean = ev.plus(t, z)
      i += 1
      j += 1
    }
    mean
  }

  def qmeanWith[R](f: A => R)(implicit ev: Field[R]): R = {
    if (as.isEmpty) throw new UnsupportedOperationException("empty seq")
    var mean = ev.zero
    var i = 0
    var j = 1
    as.foreach { a =>
      val t = ev.div(ev.times(mean, ev.fromInt(i)), ev.fromInt(j))
      val z = ev.div(f(a), ev.fromInt(j))
      mean = ev.plus(t, z)
      i += 1
      j += 1
    }
    mean
  }

  import spire.math.{Sorting, Selection}

  protected[this] def fromArray(arr: Array[A])(implicit cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val b = cbf(as)
    b.sizeHint(arr.length)
    cfor(0)(_ < arr.length, _ + 1) { i => b += arr(i) }
    b.result
  }

  protected[this] def fromSizeAndArray(size: Int, arr: Array[A])(implicit cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val b = cbf(as)
    b.sizeHint(size)
    cfor(0)(_ < size, _ + 1) { i => b += arr(i) }
    b.result
  }

  def qsorted(implicit ev: Order[A], ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val arr = as.toArray
    Sorting.sort(arr)
    fromArray(arr)
  }

  def qsortedBy[@sp B](f: A => B)(implicit ev: Order[B], ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    implicit val ord: Order[A] = ev.on(f)
    val arr = as.toArray
    Sorting.sort(arr)
    fromArray(arr)
  }

  def qsortedWith(f: (A, A) => Int)(implicit ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    implicit val ord: Order[A] = Order.from(f)
    val arr = as.toArray
    Sorting.sort(arr)
    fromArray(arr)
  }

  def qselected(k: Int)(implicit ev: Order[A], ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val arr = as.toArray
    Selection.select(arr, k)
    fromArray(arr)
  }

  def qselectk(k: Int)(implicit ev: Order[A], ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val arr = as.toArray
    if (arr.length <= k) {
      fromArray(arr)
    } else {
      Selection.select(arr, k)
      fromSizeAndArray(k, arr)
    }
  }

  def qtopk(k: Int)(implicit ev: Order[A], ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val arr = as.toArray
    if (arr.length <= k) {
      Sorting.sort(arr)
      fromArray(arr)
    } else {
      Selection.select(arr, k)
      QuickSort.qsort(arr, 0, k)
      fromSizeAndArray(k, arr)
    }
  }

  import spire.random.Generator

  def qshuffled(implicit gen: Generator, ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    val arr = as.toArray
    gen.shuffle(arr)
    fromArray(arr)
  }

  def qsampled(n: Int)(implicit gen: Generator, ct: ClassTag[A], cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] =
    fromArray(gen.sampleFromTraversable(as, n))

  def qchoose(implicit gen: Generator): A =
    gen.chooseFromIterable(as)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy