Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use standard algebra types #523

Merged
merged 15 commits into from
Dec 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just make this an implicit class?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would have to be an inner class of a trait to get the priority right. I think it is just clearer to manually handle it personally.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Also, I think having one of the implicit classes extend the other would get ugly when both were defined in traits. This encoding seems pretty straightforward to me.

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