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

spire.algebra.PartialOrder.scala Maven / Gradle / Ivy

The newest version!
package spire
package algebra

/**
  * The `PartialOrder` type class is used to define a partial ordering on some type `A`.
  *
  * A partial order is defined by a relation <=, which obeys the following laws:
  *
  * - x <= x (reflexivity)
  * - if x <= y and y <= x, then x === y (anti-symmetry)
  * - if x <= y and y <= z, then x <= z (transitivity)
  *
  * To compute both <= and >= at the same time, we use a Double number
  * to encode the result of the comparisons x <= y and x >= y.
  * The truth table is defined as follows:
  *
  * x <= y    x >= y      Double
  * true      true        = 0.0     (corresponds to x === y)
  * false     false       = NaN     (x and y cannot be compared)
  * true      false       = -1.0    (corresponds to x < y)
  * false     true        = 1.0     (corresponds to x > y)
  *
  */
trait PartialOrder[@sp A] extends Any with Eq[A] {
  self =>
  /** Result of comparing `x` with `y`. Returns NaN if operands
    * are not comparable. If operands are comparable, returns a
    * Double whose sign is:
    * - negative iff `x < y`
    * - zero     iff `x === y`
    * - positive iff `x > y`
    */
  def partialCompare(x: A, y: A): Double
  /** Result of comparing `x` with `y`. Returns None if operands
    * are not comparable. If operands are comparable, returns Some[Int]
    * where the Int sign is:
    * - negative iff `x < y`
    * - zero     iff `x == y`
    * - positive iff `x > y`
    */
  def tryCompare(x: A, y: A): Option[Int] = {
    val c = partialCompare(x, y)
    if (c.isNaN) None else Some(c.signum)
  }

  /** Returns Some(x) if x <= y, Some(y) if x > y, otherwise None. */
  def pmin(x: A, y: A): Option[A] = {
    val c = partialCompare(x, y)
    if (c <= 0) Some(x)
    else if (c > 0) Some(y)
    else None
  }

  /** Returns Some(x) if x >= y, Some(y) if x < y, otherwise None. */
  def pmax(x: A, y: A): Option[A] = {
    val c = partialCompare(x, y)
    if (c >= 0)  Some(x)
    else if (c < 0) Some(y)
    else None
  }

  // The following should be overriden in priority for performance
  def eqv(x: A, y: A): Boolean = partialCompare(x, y) == 0
  def lteqv(x: A, y: A): Boolean = partialCompare(x, y) <= 0
  def lt(x: A, y: A): Boolean = partialCompare(x, y) < 0

  def gteqv(x: A, y: A): Boolean = lteqv(y, x)
  def gt(x: A, y: A): Boolean = lt(y, x)

  /**
   * Defines a partial order on `B` by mapping `B` to `A` using `f` and using `A`s
   * order to order `B`.
   */
  override def on[@sp B](f: B => A): PartialOrder[B] = new MappedPartialOrder(this)(f)

  /**
   * Defines a partial order on `A` where all arrows switch direction.
   */
  def reverse: PartialOrder[A] = new ReversedPartialOrder(this)
}

private[algebra] class MappedPartialOrder[@sp A, @sp B](partialOrder: PartialOrder[B])(f: A => B) extends PartialOrder[A] {
  def partialCompare(x: A, y: A): Double = partialOrder.partialCompare(f(x), f(y))
}

private[algebra] class ReversedPartialOrder[@sp A](partialOrder: PartialOrder[A]) extends PartialOrder[A] {
  def partialCompare(x: A, y: A): Double = partialOrder.partialCompare(y, x)
}

object PartialOrder {
  @inline final def apply[A](implicit po: PartialOrder[A]): PartialOrder[A] = po

  def by[@sp A, @sp B](f: A => B)(implicit po: PartialOrder[B]): PartialOrder[A] = po.on(f)

  def from[@sp A](f: (A, A) => Double): PartialOrder[A] = new PartialOrder[A] {
    def partialCompare(x: A, y: A): Double = f(x, y)
  }

  implicit def partialOrdering[A](implicit po: PartialOrder[A]): PartialOrdering[A] = new PartialOrdering[A] {
    def tryCompare(x: A, y: A): Option[Int] = po.tryCompare(x, y)
    def lteq(x: A, y: A): Boolean = po.lteqv(x, y)
  }
}

private[algebra] class DerivedPartialOrdering[@sp A](partialOrder: PartialOrder[A]) extends PartialOrdering[A] {
  def tryCompare(x: A, y: A): Option[Int] = partialOrder.tryCompare(x, y)
  def lteq(x: A, y: A): Boolean = partialOrder.lteqv(x, y)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy