1/31 Categories as type classes in the Scala Algebra System Raphal - - PowerPoint PPT Presentation

1 31 categories as type classes in the scala algebra
SMART_READER_LITE
LIVE PREVIEW

1/31 Categories as type classes in the Scala Algebra System Raphal - - PowerPoint PPT Presentation

1/31 Categories as type classes in the Scala Algebra System Raphal Jolly Databeans CASC 2013 Berlin Outline 2/31 * The Scala Algebra System * Categorical view of computer algebra * Bounded


slide-1
SLIDE 1

1/31 Categories as type classes in the Scala Algebra System Raphaël Jolly Databeans CASC 2013 Berlin

slide-2
SLIDE 2

Outline 2/31 * The Scala Algebra System * Categorical view of computer algebra * Bounded polymorphism * Type classes

slide-3
SLIDE 3

The Scala Algebra System (ScAS) 3/31 * polynomial arithmetic over various base rings (integer, rational, complex, modular) * rational and algebraic functions * ring modules/algebras * polynomial GCD * Gröbner bases

slide-4
SLIDE 4

Trade-off 4/31 * type-safe * generic * mathematical syntax * efficient ?

slide-5
SLIDE 5

Milestones 5/31 * 2003 : jscl-meditor * 2004 : jscl was chosen as symbolic engine of GeoGebra * 2007 : encounter with JAS and parametric polymorphism (Java 2.5) * 2008 : port to Scala -> ScAS * 2012 : ScAS 2.0 (type classes) * 2013 : scripting support in Scala 2.11

slide-6
SLIDE 6

Categorical view of computer algebra 6/31 1.arithmetic operations between elements are restricted based on their 2.domains must support abstraction by means of 3.categories must support multiple inheritance 4.(optional) categories may support default definition of

  • perations
slide-7
SLIDE 7

Categorical view of computer algebra 7/31 * Axiom [Davenport:1992] * Gauss [Gruntz:1994] * JAS [Kredel:2006] * DoCon [Mechveliani:2001] * Mathemagix [VanDerHoeven:2002]

slide-8
SLIDE 8

Bounded polymorphism 8/31 trait Ring[T <: Ring.Element[T]] { def zero: T ... }

  • bject Ring {

trait Element[T <: Element[T]] { val factory: Ring[T] def +(that: T): T def unary_-: T ... } }

slide-9
SLIDE 9

9/31

  • bject BigInteger extends Ring[BigInteger] {

def apply(i: Int): BigInteger = apply(java.math.BigInteger.valueOf(i)) def apply(value: java.math.BigInteger) = new BigInteger(value) def zero = apply(0) } class BigInteger(val value: java.math.BigInteger) extends Ring.Element[BigInteger] { val factory = BigInteger def +(that: BigInteger) = factory( this.value.add(that.value)) def unary_- = factory(value.negate())

  • verride def toString = value.toString

} BigInteger(1) + BigInteger(1) // 2

slide-10
SLIDE 10

10/31 class Polynomial[C <: Ring.Element[C]](val ring: Ring[C], val variable: String) extends Ring[ Polynomial.Element[C]] { def generator = new Polynomial.Element(...)(this) }

  • bject Polynomial {

def apply[C <: Ring.Element[C]](ring: Ring[C], variable: String) = new Polynomial(ring, variable) class Element[C <: Ring.Element[C]](val value: Repr[C])( val factory: Polynomial[C]) extends Ring.Element[ Element[C]] } val r = Polynomial(BigInteger, "x") val x = r.generator x + x // 2*x

slide-11
SLIDE 11

Basic Types : BigInteger 11/31

Ring.Ele m e nt[T < : Ring.Ele m e nt[T]] < < inte rfa ce > > Ring[T < : Ring.Ele m e nt[T]] < < inte rfa ce > > BigInte ge r < < re a lize > > BigInte ge r < < re a lize > >

slide-12
SLIDE 12

Basic Types : BigInteger, Polynomial 12/31

Polynom ia l.Ele m e nt[C < : Ring.Ele m e nt[C]] Polynom ia l[C < : Ring.Ele m e nt[C]] Ring.Ele m e nt[T < : Ring.Ele m e nt[T]] < < inte rfa ce > > Ring[T < : Ring.Ele m e nt[T]] < < inte rfa ce > > < < re a lize > > < < re a lize > > BigInte ge r < < re a lize > > BigInte ge r < < re a lize > >

slide-13
SLIDE 13

Type classes 13/31

trait Ring[T] { outer => def zero: T def plus(x: T, y: T): T implicit def mkOps(value: T): Ring.Ops[T] = new Ring.Ops[T] { val lhs = value val factory = outer } }

  • bject Ring {

trait ExtraImplicits { implicit def infixRingOps[T: Ring](lhs: T) = implicitly[Ring[T]].mkOps(lhs) } trait Ops[T] { val lhs: T val factory: Ring[T] def +(rhs: T) = factory.plus(lhs, rhs) } }

slide-14
SLIDE 14

14/31 type BigInteger = java.math.BigInteger

  • bject BigInteger extends Ring[BigInteger] {

def apply(i: Int) = java.math.BigInteger.valueOf(i) def zero = apply(0) def plus(x: BigInteger, y: BigInteger) = x.add(y) } trait ExtraImplicits { implicit val ZZ = BigInteger }

  • bject Implicits extends ExtraImplicits

with Ring.ExtraImplicits import Implicits.{ZZ, infixRingOps} BigInteger(1) + BigInteger(1) // 2

slide-15
SLIDE 15

15/31 class Polynomial[C: Ring](val variable: String) extends Ring[Repr[C]] { val ring = implicitly[Ring[C]] def generator: Repr[C] = ... }

  • bject Polynomial {

def apply[C: Ring](variable: String) = new Polynomial(variable) } import Implicits.{ZZ, infixRingOps} implicit val r = Polynomial[BigInteger]("x") val x = r.generator x + x // 2*x

slide-16
SLIDE 16

Basic Types : BigInteger 16/31

Ring[T] < < inte rfa ce > > BigInte ge r < < re a lize > > ja va .m a th::BigInte ge r

slide-17
SLIDE 17

Basic Types : BigInteger, Polynomial 17/31

BigInte ge r Ring[T] < < inte rfa ce > > < < re a lize > > ja va .m a th::BigInte ge r Polynom ia l[C: Ring] < < re a lize > > Re pr[C]

slide-18
SLIDE 18

Category hierarchy of ScAS 18/31

Monoid Ring Se m iGroup Se t UFD Abe lia nGroup NotQuite Group Euclide a nDom a in Fie ld Group Module Equiv / Orde ring Alge bra Ove rRing Alge bra Ve ctorSpa ce Boole a nAlge bra < < vie w> > Sta rRing

slide-19
SLIDE 19

Type classes : pros 19/31 * avoid the dependent type problem : type system makes no distinction between types of elements from e.g. ModInteger(2) and ModInteger(3) but only one implicit value is allowed for the associated domain * reuse of existing types : allows unboxed primitive types => generic numeric-symbolic implementations * makes domain subclassing easier : SolvablePolynomial <: Polynomial RealAlgebraicNumber <: AlgebraicNumber PolynomialWithSubresGCD <: Polynomial

slide-20
SLIDE 20

Type classes : cons 20/31 * does not play well with coercions BigInteger(1) + 1 => BigInteger(1) + BigInteger(1) x + 1 => x + r(1) * Need an idea to solve this

slide-21
SLIDE 21

Hybrid abstraction scheme 21/31

  • bject Ring {

trait ExtraImplicits { implicit def infixRingOps[T: Ring](lhs: T) = implicitly[Ring[T]].mkOps(lhs) } trait Ops[T] { val lhs: T val factory: Ring[T] def +(rhs: T) = factory.plus(lhs, rhs) } }

slide-22
SLIDE 22

Hybrid abstraction scheme 21/31

  • bject Ring {

trait ExtraImplicits { implicit def infixRingOps[T: Ring](lhs: T) = implicitly[Ring[T]].mkOps(lhs) } trait Ops[T] { val lhs: T val factory: Ring[T] def +(rhs: T) = factory.plus(lhs, rhs) } trait Element[T <: Element[T]] extends Ops[T] { this: T => val lhs = this } }

slide-23
SLIDE 23

Hybrid abstraction scheme 22/31

BigInte ge r Ring[T] < < inte rfa ce > > < < re a lize > > ja va .m a th::BigInte ge r Polynom ia l[C: Ring] < < re a lize > > Re pr[C]

slide-24
SLIDE 24

Hybrid abstraction scheme 22/31

Ring.Ele m e nt[T] < < inte rfa ce > > Ring[T] < < inte rfa ce > > Polynom ia l.Ele m e nt[C] Polynom ia l[C: Ring] < < re a lize > > < < re a lize > > BigInte ge r < < re a lize > > ja va .m a th::BigInte ge r

slide-25
SLIDE 25

Type classes in computer algebra 23/31 * introduced in Haskell [Oliveira:2010] * first mentionned as possible abstractions for computer algebra structures [Weber:1993] [Santas:1995] * DoCon : actually uses them * Scala : a code example in the language documentation explicitly involves abstract algebraic constructs * Mathemagix uses a concept of categories that is completely equivalent to type classes

slide-26
SLIDE 26

DoCon : computer algebra in Haskell 24/31 class CommutativeRing a => GCDRing a where gcd : a -> a -> a canAssoc : a -> a instance GCDRing Integer where canAssoc n = if n < 0 then -n else n gcd n 0 = n gcd n m = gcd m (mod n m) data Fraction a = a :/ a ... instance GCDRing a => AdditiveSemigroup (Fraction a) where (x :/ y) + (x' :/ y') = ... usual way to sum fractions instance GCDRing a => Field (Fraction a) where ...

slide-27
SLIDE 27

25/31

abstract class SemiGroup[A] { def add(x: A, y: A): A } abstract class Monoid[A] extends SemiGroup[A] { def unit: A }

  • bject ImplicitTest extends App {

implicit object StringMonoid extends Monoid[String] { def add(x: String, y: String): String = x concat y def unit: String = "" } implicit object IntMonoid extends Monoid[Int] { def add(x: Int, y: Int): Int = x + y def unit: Int = 0 } def sum[A](xs: List[A])(implicit m: Monoid[A]): A = if (xs.isEmpty) m.unit else m.add(xs.head, sum(xs.tail)) println(sum(List(1, 2, 3))) // 6 println(sum(List("a", "b", "c"))) // abc }

http://docs.scala-lang.org/tutorials/tour/implicit- parameters.html

slide-28
SLIDE 28

Categories in the Scala standard library 26/31

Ordering Numeric PartialOrdering Equiv Integral Fractional

slide-29
SLIDE 29

Categories in Spire 27/31

AdditiveMonoid AdditiveGroup AdditiveAbGroup Monoid Group AbGroup SemiGroup MultiplicativeSemiGroup MultiplicativeMonoid MultiplicativeGroup MultiplicativeAbGroup Rig Ring Module RightModule VectorSpace NormedVectorSpace InnerProductSpace EuclideanRing Field RingAlgebra ZAlgebra FieldAlgebra Numeric Eq Order Integral Fractional AdditiveSemiGroup SemiRing Rng

slide-30
SLIDE 30

Operation 28/31

x + y ZZ infixRingOps( )( ).+( )

  • ptimized away by Spire macro

ZZ.mkOps( ) .+ ( ) ZZ.plus ( , ) specialized ; inlined by JIT x + y

slide-31
SLIDE 31

Spire is Fast 29/31

spire direct 38.9 36.9 30.1 29.9 19.3 13.4 10.6 10.5 scala spire nspec gcd mean

gcd mean 5 10 15 20 25 30 35 40 45 s cala s pire ns pec s pire direct

http://typelevel.org/blog/2013/07/07/generic-numeric- programming.html

slide-32
SLIDE 32

ScAS : polypower benchmark 30/31

n 20 4.4 4.2 24 11.6 10.9 28 27.6 26.4 32 59.1 54.6 ModInteger ModInt

20 24 28 32 10 20 30 40 50 60 70 ModInteger ModInt

slide-33
SLIDE 33

31/31 Thank you ! http://github.com/rjolly/scas