Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Numeric Programming with Spire

Numeric Programming with Spire

Numeric programming is a notoriously difficult topic. For number crunching, e.g. solving systems of linear equations, we need raw performance. However, using floating-point numbers may lead to inaccurate results. On top of that, as functional programmers, we'd really like to abstract over concrete number types, which is where abstract algebra comes into play. This interplay between abstract and concrete, and the fact that everything needs to run on finite hardware, is what makes good library support necessary for writing fast & correct programs. Spire is such a library in the Typelevel Scala ecosystem. This talk will be an introduction to Spire, showcasing the "number tower", real-ish numbers and how to obey the law.

A1216674d5c9747bcdcc716872439137?s=128

Lars Hupel

June 25, 2016
Tweet

More Decks by Lars Hupel

Other Decks in Programming

Transcript

  1. Numeric Programming with Spire Lars Hupel June 25th, 2016

  2. None
  3. What is Spire? “ Spire is a numeric library for

    Scala which is intended to be generic, fast, and precise. ” 3
  4. What’s in Spire? ▶ algebraic tower ▶ number types ▶

    numeric algorithms ▶ pretty syntax ▶ optimization macros ▶ laws 4
  5. Why Spire? 5

  6. Semigroup trait Semigroup[A] { def append(x: A, y: A): A

    } 6
  7. Semigroup trait Semigroup[A] { def append(x: A, y: A): A

    } Law: Associativity append(x, append(y, z)) == append(append(x, y), z) 6
  8. Monoids trait Monoid[A] { def append(x: A, y: A): A

    def zero: A } Law: Neutral element append(x, zero) == x 7
  9. Monoidal structures Lots of things are monoids. ▶ Int, BigInt,

    ... 8
  10. Monoidal structures Lots of things are monoids. ▶ Int, BigInt,

    ... ▶ List[T] 8
  11. Monoidal structures Lots of things are monoids. ▶ Int, BigInt,

    ... ▶ List[T] ▶ Map[K, V] 8
  12. Monoidal structures Lots of things are monoids. ▶ Int, BigInt,

    ... ▶ List[T] ▶ Map[K, V] ▶ ... 8
  13. Demo

  14. Algebraic hierarchy Semigroup Monoid Group 10

  15. Algebraic hierarchy Semigroup Monoid Group AddSemigroup AddMonoid AddGroup 10

  16. Algebraic hierarchy Semigroup Monoid Group AddSemigroup AddMonoid AddGroup MulSemigroup MulMonoid

    MulGroup 10
  17. Algebraic hierarchy AddSemigroup AddMonoid AddGroup MulSemigroup MulMonoid MulGroup Semiring 10

  18. Algebraic hierarchy AddSemigroup AddMonoid AddGroup MulSemigroup MulMonoid MulGroup Semiring AddAbGroup

    MulAbGroup Rig Rng Ring Field 10
  19. Law Checking // Float and Double fail these tests checkAll(”Int”,

    RingLaws[Int].euclideanRing) checkAll(”Long”, RingLaws[Long].euclideanRing) checkAll(”BigInt”, RingLaws[BigInt].euclideanRing) checkAll(”BigInteger”, RingLaws[BigInteger].euclideanRing) checkAll(”Rational”, RingLaws[Rational].field) checkAll(”Real”, RingLaws[Real].field) 11
  20. Numbers ▶ machine floats are fast, but imprecise ▶ good

    tradeoff for many purposes, but not all! ▶ there is no “one size fits all” number type 12
  21. Rational numbers n d ∈ Q where n, d ∈

    Z Properties ▶ closed under addition, multiplication, ... ▶ decidable comparison 13
  22. Demo

  23. Real numbers We can’t represent all real numbers on a

    computer ... 15
  24. Real numbers We can’t represent all real numbers on a

    computer ... ... but we can get arbitrarily close 15
  25. Real numbers, approximated trait Real { def approximate(precision: Int): Rational

    } 16
  26. Real numbers, approximated trait Real { self => def approximate(precision:

    Int): Rational def +(that: Real): Real = new Real { def approximate(precision: Int) = { val r1 = self.approximate(precision + 2) val r2 = that.approximate(precision + 2) r1 + r2 } } } 16
  27. Real numbers, approximated trait Real { def approximate(precision: Int): Rational

    def +(that: Real): Real = new Real { // ... } } object Real { def apply(f: Int => Rational) = // ... def fromRational(rat: Rational) = apply(_ => rat) } 16
  28. Irrational numbers val pi: Real = Real(16) * atan(Real(Rational(1, 5)))

    - Real(4) * atan(Real(Rational(1, 239))) 17
  29. Demo

  30. Error bounds ▶ often, inputs are not accurate ▶ e.g.

    measurements (temperature, work, time, ...) ▶ What to do with error bounds? 19
  31. Interval arithmetic case class Interval[A](lower: A, upper: A) 20

  32. Interval arithmetic case class Interval[A](lower: A, upper: A) { def

    +(that: Interval[A])(implicit ev: AddSemigroup[A]) = Interval(this.lower + that.lower, this.upper + that.upper) } 20
  33. Interval arithmetic case class Interval[A](lower: A, upper: A) { def

    +(that: Interval[A])(implicit ev: AddSemigroup[A]) = Interval(this.lower + that.lower, this.upper + that.upper) } Spire generalizes this even further: ▶ open/closed intervals ▶ bounded/unbounded intervals 20
  34. Demo

  35. Polynomials f(x) = ∑ i ai · xi 22

  36. Demo

  37. Q & A  larsrh  larsr h