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

algebra.ring.Multiplicative.scala Maven / Gradle / Ivy

The newest version!
package algebra
package ring

import scala.{ specialized => sp }
import scala.annotation.tailrec

trait MultiplicativeSemigroup[@sp(Int, Long, Float, Double) A] extends Any with Serializable {
  def multiplicative: Semigroup[A] =
    new Semigroup[A] {
      def combine(x: A, y: A): A = times(x, y)
    }

  def times(x: A, y: A): A

  def pow(a: A, n: Int): A =
    if (n > 0) positivePow(a, n)
    else throw new IllegalArgumentException("Illegal non-positive exponent to pow: %s" format n)

  protected[this] def positivePow(a: A, n: Int): A = {
    @tailrec def loop(b: A, k: Int, extra: A): A =
      if (k == 1) times(b, extra) else {
        val x = if ((k & 1) == 1) times(b, extra) else extra
        loop(times(b, b), k >>> 1, x)
      }
    if (n == 1) a else loop(a, n - 1, a)
  }

  /**
   * Given a sequence of `as`, combine them and return the total.
   *
   * If the sequence is empty, returns None. Otherwise, returns Some(total).
   */
  def tryProduct(as: TraversableOnce[A]): Option[A] =
    as.reduceOption(times)
}

trait MultiplicativeCommutativeSemigroup[@sp(Int, Long, Float, Double) A] extends Any with MultiplicativeSemigroup[A] {
  override def multiplicative: CommutativeSemigroup[A] = new CommutativeSemigroup[A] {
    def combine(x: A, y: A): A = times(x, y)
  }
}

trait MultiplicativeMonoid[@sp(Int, Long, Float, Double) A] extends Any with MultiplicativeSemigroup[A] {
  override def multiplicative: Monoid[A] = new Monoid[A] {
    def empty = one
    def combine(x: A, y: A): A = times(x, y)
  }

  def one: A

  /**
    * Tests if `a` is one.
    */
  def isOne(a: A)(implicit ev: Eq[A]): Boolean = ev.eqv(a, one)

  override def pow(a: A, n: Int): A =
    if (n > 0) positivePow(a, n)
    else if (n == 0) one
    else throw new IllegalArgumentException("Illegal negative exponent to pow: %s" format n)

  /**
   * Given a sequence of `as`, compute the product.
   */
  def product(as: TraversableOnce[A]): A =
    as.foldLeft(one)(times)
}

trait MultiplicativeCommutativeMonoid[@sp(Int, Long, Float, Double) A] extends Any with MultiplicativeMonoid[A] with MultiplicativeCommutativeSemigroup[A] {
  override def multiplicative: CommutativeMonoid[A] = new CommutativeMonoid[A] {
    def empty = one
    def combine(x: A, y: A): A = times(x, y)
  }
}

trait MultiplicativeGroup[@sp(Int, Long, Float, Double) A] extends Any with MultiplicativeMonoid[A] {
  override def multiplicative: Group[A] = new Group[A] {
    def empty = one
    def combine(x: A, y: A): A = times(x, y)
    override def remove(x: A, y: A): A = div(x, y)
    def inverse(x: A): A = reciprocal(x)
  }

  def reciprocal(x: A): A = div(one, x)
  def div(x: A, y: A): A

  override def pow(a: A, n: Int): A =
    if (n > 0) positivePow(a, n)
    else if (n == 0) one
    else if (n == Int.MinValue) positivePow(reciprocal(times(a, a)), 1073741824)
    else positivePow(reciprocal(a), -n)
}

trait MultiplicativeCommutativeGroup[@sp(Int, Long, Float, Double) A] extends Any with MultiplicativeGroup[A] with MultiplicativeCommutativeMonoid[A] {
  override def multiplicative: CommutativeGroup[A] = new CommutativeGroup[A] {
    def empty = one
    def combine(x: A, y: A): A = times(x, y)
    override def remove(x: A, y: A): A = div(x, y)
    def inverse(x: A): A = reciprocal(x)
  }
}

trait MultiplicativeSemigroupFunctions[S[T] <: MultiplicativeSemigroup[T]] {
  def isMultiplicativeCommutative[A](implicit ev: S[A]): Boolean =
    ev.isInstanceOf[MultiplicativeCommutativeSemigroup[A]]

  def times[@sp(Int, Long, Float, Double) A](x: A, y: A)(implicit ev: S[A]): A =
    ev.times(x, y)
  def pow[@sp(Int, Long, Float, Double) A](a: A, n: Int)(implicit ev: S[A]): A =
    ev.pow(a, n)

  def tryProduct[A](as: TraversableOnce[A])(implicit ev: S[A]): Option[A] =
    ev.tryProduct(as)
}

trait MultiplicativeMonoidFunctions[M[T] <: MultiplicativeMonoid[T]] extends MultiplicativeSemigroupFunctions[M] {
  def one[@sp(Int, Long, Float, Double) A](implicit ev: M[A]): A =
    ev.one

  def isOne[@sp(Int, Long, Float, Double) A](a: A)(implicit ev0: M[A], ev1: Eq[A]): Boolean =
    ev0.isOne(a)

  def product[@sp(Int, Long, Float, Double) A](as: TraversableOnce[A])(implicit ev: M[A]): A =
    ev.product(as)
}

trait MultiplicativeGroupFunctions[G[T] <: MultiplicativeGroup[T]] extends MultiplicativeMonoidFunctions[G] {
  def reciprocal[@sp(Int, Long, Float, Double) A](x: A)(implicit ev: G[A]): A =
    ev.reciprocal(x)
  def div[@sp(Int, Long, Float, Double) A](x: A, y: A)(implicit ev: G[A]): A =
    ev.div(x, y)
}

object MultiplicativeSemigroup extends MultiplicativeSemigroupFunctions[MultiplicativeSemigroup] {
  @inline final def apply[A](implicit ev: MultiplicativeSemigroup[A]): MultiplicativeSemigroup[A] = ev
  /**
   * This method converts a multiplicative instance into a generic
   * instance.
   *
   * Given an implicit `MultiplicativeSemigroup[A]`, this method returns
   * a `Semigroup[A]`.
   */
  @inline final def multiplicative[A](implicit ev: MultiplicativeSemigroup[A]): Semigroup[A] =
    ev.multiplicative
}

object MultiplicativeCommutativeSemigroup extends MultiplicativeSemigroupFunctions[MultiplicativeCommutativeSemigroup] {
  @inline final def apply[A](implicit ev: MultiplicativeCommutativeSemigroup[A]): MultiplicativeCommutativeSemigroup[A] = ev
  /**
   * This method converts a multiplicative instance into a generic
   * instance.
   *
   * Given an implicit `MultiplicativeCommutativeSemigroup[A]`, this method returns
   * a `CommutativeSemigroup[A]`.
   */
  @inline final def multiplicative[A](implicit ev: MultiplicativeCommutativeSemigroup[A]): CommutativeSemigroup[A] =
    ev.multiplicative
}

object MultiplicativeMonoid extends MultiplicativeMonoidFunctions[MultiplicativeMonoid] {
  @inline final def apply[A](implicit ev: MultiplicativeMonoid[A]): MultiplicativeMonoid[A] = ev
  /**
   * This method converts a multiplicative instance into a generic
   * instance.
   *
   * Given an implicit `MultiplicativeMonoid[A]`, this method returns
   * a `Monoid[A]`.
   */
  @inline final def multiplicative[A](implicit ev: MultiplicativeMonoid[A]): Monoid[A] =
    ev.multiplicative
}

object MultiplicativeCommutativeMonoid extends MultiplicativeMonoidFunctions[MultiplicativeCommutativeMonoid] {
  @inline final def apply[A](implicit ev: MultiplicativeCommutativeMonoid[A]): MultiplicativeCommutativeMonoid[A] = ev
  /**
   * This method converts a multiplicative instance into a generic
   * instance.
   *
   * Given an implicit `MultiplicativeCommutativeMonoid[A]`, this method returns
   * a `CommutativeMonoid[A]`.
   */
  @inline final def multiplicative[A](implicit ev: MultiplicativeCommutativeMonoid[A]): CommutativeMonoid[A] =
    ev.multiplicative
}

object MultiplicativeGroup extends MultiplicativeGroupFunctions[MultiplicativeGroup] {
  @inline final def apply[A](implicit ev: MultiplicativeGroup[A]): MultiplicativeGroup[A] = ev
  /**
   * This method converts a multiplicative instance into a generic
   * instance.
   *
   * Given an implicit `MultiplicativeGroup[A]`, this method returns
   * a `Group[A]`.
   */
  @inline final def multiplicative[A](implicit ev: MultiplicativeGroup[A]): Group[A] =
    ev.multiplicative
}

object MultiplicativeCommutativeGroup extends MultiplicativeGroupFunctions[MultiplicativeCommutativeGroup] {
  @inline final def apply[A](implicit ev: MultiplicativeCommutativeGroup[A]): MultiplicativeCommutativeGroup[A] = ev
  /**
   * This method converts a multiplicative instance into a generic
   * instance.
   *
   * Given an implicit `MultiplicativeCommutativeGroup[A]`, this method returns
   * a `CommutativeGroup[A]`.
   */
  @inline final def multiplicative[A](implicit ev: MultiplicativeCommutativeGroup[A]): CommutativeGroup[A] =
    ev.multiplicative
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy