Skip to content

Commit

Permalink
Use standard algebra types (twitter#523)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnynek authored and sritchie committed Dec 2, 2016
1 parent 3c0d3a5 commit c1ede45
Show file tree
Hide file tree
Showing 24 changed files with 420 additions and 342 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ matrix:
script: ./sbt ++$TRAVIS_SCALA_VERSION clean test

- scala: 2.11.8
script: ./sbt ++$TRAVIS_SCALA_VERSION clean coverage test coverageReport mimaReportBinaryIssues docs/makeMicrosite
#script: ./sbt ++$TRAVIS_SCALA_VERSION clean coverage test coverageReport mimaReportBinaryIssues docs/makeMicrosite
script: ./sbt ++$TRAVIS_SCALA_VERSION clean coverage test coverageReport docs/makeMicrosite
after_success:
- bash <(curl -s https://codecov.io/bash)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

package com.twitter.algebird.bijection

import com.twitter.algebird.{ Field, Group, Monoid, Ring, Semigroup }
import com.twitter.algebird.{ Group, Monoid, Ring, Semigroup }
import com.twitter.bijection.{ AbstractBijection, Bijection, ImplicitBijection, Conversion, Reverse }

import Conversion.asMethod // "as" syntax
Expand Down Expand Up @@ -51,11 +51,6 @@ class BijectedRing[T, U](implicit val ring: Ring[T], bij: ImplicitBijection[T, U
ring.product(iter map { _.as[T] }).as[U]
}

class BijectedField[T, U](implicit val field: Field[T], bij: ImplicitBijection[T, U]) extends BijectedRing[T, U] with Field[U] {
override def div(l: U, r: U): U = field.div(l.as[T], r.as[T]).as[U]
override def inverse(u: U): U = field.inverse(u.as[T]).as[U]
}

trait AlgebirdBijections {
implicit def semigroupBijection[T, U](implicit bij: ImplicitBijection[T, U]): Bijection[Semigroup[T], Semigroup[U]] =
new AbstractBijection[Semigroup[T], Semigroup[U]] {
Expand All @@ -80,12 +75,6 @@ trait AlgebirdBijections {
override def apply(ring: Ring[T]) = new BijectedRing[T, U]()(ring, bij)
override def invert(ring: Ring[U]) = new BijectedRing[U, T]()(ring, Reverse(bij.bijection))
}

implicit def fieldBijection[T, U](implicit bij: ImplicitBijection[T, U]): Bijection[Field[T], Field[U]] =
new AbstractBijection[Field[T], Field[U]] {
override def apply(field: Field[T]) = new BijectedField[T, U]()(field, bij)
override def invert(field: Field[U]) = new BijectedField[U, T]()(field, Reverse(bij.bijection))
}
}

object AlgebirdBijections extends AlgebirdBijections
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package com.twitter.algebird

import scala.annotation.tailrec

import algebra.ring.Rng

/**
* This is for the case where your Ring[T] is a Rng (i.e. there is no unit).
* @see http://en.wikipedia.org/wiki/Pseudo-ring#Adjoining_an_identity_element
Expand All @@ -27,33 +29,36 @@ case class AdjoinedUnit[T](ones: BigInt, get: T) {

object AdjoinedUnit {
def apply[T](item: T): AdjoinedUnit[T] = new AdjoinedUnit[T](BigInt(0), item)
implicit def ring[T](implicit ring: Ring[T]): Ring[AdjoinedUnit[T]] = new AdjoinedUnitRing[T]
implicit def ring[T](implicit ring: Rng[T]): Ring[AdjoinedUnit[T]] = new AdjoinedUnitRing[T]
}

class AdjoinedUnitRing[T](implicit ring: Ring[T]) extends Ring[AdjoinedUnit[T]] {
val one = AdjoinedUnit[T](BigInt(1), ring.zero)
val zero = AdjoinedUnit[T](ring.zero)
class AdjoinedUnitRing[T](implicit rng: Rng[T]) extends Ring[AdjoinedUnit[T]] {
val one = AdjoinedUnit[T](BigInt(1), rng.zero)
val zero = AdjoinedUnit[T](rng.zero)

private[this] val group: Group[T] =
new FromAlgebraGroup(rng.additive)

override def isNonZero(it: AdjoinedUnit[T]) =
(it.ones != 0) || ring.isNonZero(it.get)
(it.ones != 0) || group.isNonZero(it.get)

def plus(left: AdjoinedUnit[T], right: AdjoinedUnit[T]) =
AdjoinedUnit(left.ones + right.ones, ring.plus(left.get, right.get))
AdjoinedUnit(left.ones + right.ones, rng.plus(left.get, right.get))

override def negate(it: AdjoinedUnit[T]) =
AdjoinedUnit(-it.ones, ring.negate(it.get))
AdjoinedUnit(-it.ones, rng.negate(it.get))
override def minus(left: AdjoinedUnit[T], right: AdjoinedUnit[T]) =
AdjoinedUnit(left.ones - right.ones, ring.minus(left.get, right.get))
AdjoinedUnit(left.ones - right.ones, rng.minus(left.get, right.get))

def times(left: AdjoinedUnit[T], right: AdjoinedUnit[T]) = {
// (n1, g1) * (n2, g2) = (n1*n2, (n1*g1) + (n2*g1) + (g1*g2))
import Group.intTimes

val ones = left.ones * right.ones
val part0 = intTimes(left.ones, right.get)(ring)
val part1 = intTimes(right.ones, left.get)(ring)
val part2 = ring.times(left.get, right.get)
val nonUnit = ring.plus(part0, ring.plus(part1, part2))
val part0 = intTimes(left.ones, right.get)(group)
val part1 = intTimes(right.ones, left.get)(group)
val part2 = rng.times(left.get, right.get)
val nonUnit = rng.plus(part0, rng.plus(part1, part2))

AdjoinedUnit(ones, nonUnit)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class ApplicativeMonoid[T, M[_]](implicit app: Applicative[M], mon: Monoid[T])
}

/**
* Group, Ring, and Field ARE NOT AUTOMATIC. You have to check that the laws hold for your
* Group and Ring ARE NOT AUTOMATIC. You have to check that the laws hold for your
* Applicative. If your M[_] is a wrapper type (Option[_], Some[_], Try[_], Future[_], etc...)
* this generally works.
*/
Expand All @@ -149,7 +149,7 @@ class ApplicativeGroup[T, M[_]](implicit app: Applicative[M], grp: Group[T])
}

/**
* Group, Ring, and Field ARE NOT AUTOMATIC. You have to check that the laws hold for your
* Group and Ring ARE NOT AUTOMATIC. You have to check that the laws hold for your
* Applicative. If your M[_] is a wrapper type (Option[_], Some[_], Try[_], Future[_], etc...)
* this generally works.
*/
Expand All @@ -158,15 +158,3 @@ class ApplicativeRing[T, M[_]](implicit app: Applicative[M], ring: Ring[T])
lazy val one = app(ring.one)
def times(l: M[T], r: M[T]) = app.joinWith(l, r)(ring.times)
}

/**
* Group, Ring, and Field ARE NOT AUTOMATIC. You have to check that the laws hold for your
* Applicative. If your M[_] is a wrapper type (Option[_], Some[_], Try[_], Future[_], etc...)
* this generally works.
*/
class ApplicativeField[T, M[_]](implicit app: Applicative[M], fld: Field[T])
extends ApplicativeRing[T, M] with Field[M[T]] {
override def inverse(v: M[T]) = app.map(v)(fld.inverse)
override def div(l: M[T], r: M[T]) = app.joinWith(l, r)(fld.div)
}

115 changes: 0 additions & 115 deletions algebird-core/src/main/scala/com/twitter/algebird/Field.scala

This file was deleted.

66 changes: 43 additions & 23 deletions algebird-core/src/main/scala/com/twitter/algebird/Group.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ limitations under the License.
*/
package com.twitter.algebird

import algebra.{ Group => AGroup }
import algebra.ring.AdditiveGroup
import java.lang.{ Integer => JInt, Short => JShort, Long => JLong, Float => JFloat, Double => JDouble, Boolean => JBool }
import java.util.{ List => JList, Map => JMap }

Expand All @@ -28,10 +30,13 @@ import scala.math.Equiv
*/

@implicitNotFound(msg = "Cannot find Group type class for ${T}")
trait Group[@specialized(Int, Long, Float, Double) T] extends Monoid[T] {
// must override negate or minus (or both)
def negate(v: T): T = minus(zero, v)
def minus(l: T, r: T): T = plus(l, negate(r))
trait Group[@specialized(Int, Long, Float, Double) T] extends AGroup[T] with Monoid[T] with AdditiveGroup[T] {
/*
* This are from algebra.Group
*/
override def additive: AGroup[T] = this
override def remove(l: T, r: T): T = minus(l, r)
override def inverse(v: T): T = negate(v)
}

// For Java interop so they get the default methods
Expand Down Expand Up @@ -82,7 +87,20 @@ class ArrayGroup[T: ClassTag](implicit grp: Group[T])
}.toArray
}

object Group extends GeneratedGroupImplicits with ProductGroups {
class FromAlgebraGroup[T](m: AGroup[T]) extends FromAlgebraMonoid(m) with Group[T] {
override def negate(t: T): T = m.inverse(t)
override def minus(r: T, l: T): T = m.remove(r, l)
}

private[algebird] trait FromAlgebraGroupImplicit1 {
implicit def fromAlgebraAdditiveGroup[T](implicit m: AdditiveGroup[T]): Group[T] =
new FromAlgebraGroup(m.additive)
}
private[algebird] trait FromAlgebraGroupImplicit0 extends FromAlgebraGroupImplicit1 {
implicit def fromAlgebraGroup[T](implicit m: AGroup[T]): Group[T] = new FromAlgebraGroup(m)
}

object Group extends GeneratedGroupImplicits with ProductGroups with FromAlgebraGroupImplicit0 {
// This pattern is really useful for typeclasses
def negate[T](x: T)(implicit grp: Group[T]) = grp.negate(x)
def minus[T](l: T, r: T)(implicit grp: Group[T]) = grp.minus(l, r)
Expand All @@ -98,24 +116,26 @@ object Group extends GeneratedGroupImplicits with ProductGroups {
Monoid.intTimes(i, v)(grp)
}

implicit val nullGroup: Group[Null] = NullGroup
implicit val unitGroup: Group[Unit] = UnitGroup
implicit val boolGroup: Group[Boolean] = BooleanField
implicit val jboolGroup: Group[JBool] = JBoolField
implicit val intGroup: Group[Int] = IntRing
implicit val jintGroup: Group[JInt] = JIntRing
implicit val shortGroup: Group[Short] = ShortRing
implicit val jshortGroup: Group[JShort] = JShortRing
implicit val longGroup: Group[Long] = LongRing
implicit val bigIntGroup: Group[BigInt] = BigIntRing
implicit val bigDecimalGroup: Group[BigDecimal] = BigDecimalRing
implicit val jlongGroup: Group[JLong] = JLongRing
implicit val floatGroup: Group[Float] = FloatField
implicit val jfloatGroup: Group[JFloat] = JFloatField
implicit val doubleGroup: Group[Double] = DoubleField
implicit val jdoubleGroup: Group[JDouble] = JDoubleField
implicit def nullGroup: Group[Null] = NullGroup
implicit def unitGroup: Group[Unit] = UnitGroup
implicit def boolGroup: Group[Boolean] = BooleanRing
implicit def jboolGroup: Group[JBool] = JBoolRing
implicit def intGroup: Group[Int] = IntRing
implicit def jintGroup: Group[JInt] = JIntRing
implicit def shortGroup: Group[Short] = ShortRing
implicit def jshortGroup: Group[JShort] = JShortRing
implicit def longGroup: Group[Long] = LongRing
implicit def bigIntGroup: Group[BigInt] = BigIntRing
implicit def bigDecimalGroup: Group[BigDecimal] = implicitly[Ring[BigDecimal]]
implicit def jlongGroup: Group[JLong] = JLongRing
implicit def floatGroup: Group[Float] = FloatRing
implicit def jfloatGroup: Group[JFloat] = JFloatRing
implicit def doubleGroup: Group[Double] = DoubleRing
implicit def jdoubleGroup: Group[JDouble] = JDoubleRing
implicit def optionGroup[T: Group] = new OptionGroup[T]
implicit def indexedSeqGroup[T: Group]: Group[IndexedSeq[T]] = new IndexedSeqGroup[T]
implicit def mapGroup[K, V](implicit group: Group[V]) = new MapGroup[K, V]()(group)
implicit def scMapGroup[K, V](implicit group: Group[V]) = new ScMapGroup[K, V]()(group)
implicit def mapGroup[K, V](implicit group: Group[V]): Group[Map[K, V]] =
new MapGroup[K, V]()(group)
implicit def scMapGroup[K, V](implicit group: Group[V]): Group[scala.collection.Map[K, V]] =
new ScMapGroup[K, V]()(group)
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,34 +47,31 @@ object JLongRing extends Ring[JLong] {
override def times(x: JLong, y: JLong) = x * y
}

object JFloatField extends Field[JFloat] {
object JFloatRing extends Ring[JFloat] {
override val zero = JFloat.valueOf(0.0f)
override val one = JFloat.valueOf(1.0f)
override def plus(x: JFloat, y: JFloat) = x + y
override def negate(x: JFloat): JFloat = -x
override def minus(x: JFloat, y: JFloat) = x - y
override def times(x: JFloat, y: JFloat) = x * y
override def div(x: JFloat, y: JFloat) = { assertNotZero(y); x / y }
}

object JDoubleField extends Field[JDouble] {
object JDoubleRing extends Ring[JDouble] {
override val zero = JDouble.valueOf(0.0)
override val one = JDouble.valueOf(1.0)
override def plus(x: JDouble, y: JDouble) = x + y
override def negate(x: JDouble): JDouble = -x
override def minus(x: JDouble, y: JDouble) = x - y
override def times(x: JDouble, y: JDouble) = x * y
override def div(x: JDouble, y: JDouble) = { assertNotZero(y); x / y }
}

object JBoolField extends Field[JBool] {
object JBoolRing extends Ring[JBool] {
override val zero = JBool.FALSE
override val one = JBool.TRUE
override def plus(x: JBool, y: JBool) = JBool.valueOf(x.booleanValue ^ y.booleanValue)
override def negate(x: JBool) = x
override def minus(x: JBool, y: JBool) = plus(x, y)
override def times(x: JBool, y: JBool) = JBool.valueOf(x.booleanValue & y.booleanValue)
override def div(x: JBool, y: JBool) = { assertNotZero(y); x }
}

/**
Expand Down
Loading

0 comments on commit c1ede45

Please sign in to comment.