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

poly.algebra.Monoid.scala Maven / Gradle / Ivy

package poly.algebra

import poly.algebra.factory._

/**
 *
 * Represents a monoid, i.e., a semigroup with an identity element.
 *
 * An instance of this typeclass should satisfy the following axioms:
 *  - $lawAssociativity
 *  - $lawIdentity
 * @author Tongfei Chen
 */
trait Monoid[M] extends Semigroup[M] with HasIdentity[M] { self =>

  /**
   * Computes x <> x <> ... <> x (''n'' times) using the binary exponentiation algorithm.
   */
  override def combineN(x: M, n: Int): M = {
    if (n == 0) return id
    var y = x
    var m = n
    while (m % 2 == 0) {
      m >>= 1
      y = op(y, y)
    }
    var r = y
    while (m > 1) {
      m >>= 1
      y = op(y, y)
      if (m % 2 == 1)
        r = op(r, y)
    }
    r
  }

  /** Returns the product monoid of two monoids. */
  def product[N](that: Monoid[N]): Monoid[(M, N)] = new MonoidT.Product(self, that)

}

object Monoid extends ImplicitGetter[Monoid] {

  /** Creates an monoid of the specific type using the binary operation and the identity element provided. */
  def create[X](f: (X, X) => X, idElem: X): Monoid[X] = new Monoid[X] {
    def op(x: X, y: X): X = f(x, y)
    val id: X = idElem
  }

  def product[X, Y](implicit mx: Monoid[X], my: Monoid[Y]): Monoid[(X, Y)] = new MonoidT.Product(mx, my)

}

private[poly] object MonoidT {

  class Product[X, Y](mx: Monoid[X], my: Monoid[Y]) extends SemigroupT.Product(mx, my) with Monoid[(X, Y)] {
    def id = (mx.id, my.id)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy