Skip to content
Math and statistics utilities
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
cubic
format/shared/src
project
quartic
stats/shared/src
tolerance/shared/src
types
utils
.gitignore
.travis.yml
LICENSE
README.md
build.sbt

README.md

math-utils

Build Status codecov

Math, stats, and miscellaneous numeric and type-related utilities:

  • format: format numbers to a given number of significant figures
  • stats: collect+display statistics about collections of numeric elements
  • tolerance: "fuzzy-equality" for Doubles
  • types: misc type- and type-class-utilities (auto-derived Orderings and Monoids, a scala-js runtime-predicate, etc.)
  • utils: misc numeric utilities (binomial coefficients, interpolation, etc.)
  • cubic/quartic: solve cubic/quartic equations in terms of Spire type-classes

format

  Maven Central: org.hammerlab.math:::format:1.1.1

Format numbers to a given number of significant figures:

import hammerlab.math.sigfigs._
implicit val sf: SigFigs = 3

import cats.syntax.show._

1.2345.show
// 1.23

123.45.show
// 123

123456.0.show
// 123456; same length as "1.23e5", so don't bother abbreviating to scientific notation

1234567.0.show
// 1.23e6

0.0000123456.show
// 1.23e-5

stats

  Maven Central: org.hammerlab.math:::stats:1.3.3

org.hammerlab.stats.Stats has APIs for ingesting numeric elements and outputting nicely formatted statistics about them; modeled after Apache commons-math DescriptiveStatistics:

// Context for displaying ints, longs, and doubles
import cats.syntax.show._
import cats.instances.int.catsStdShowForInt
import cats.instances.long.catsStdShowForLong
import hammerlab.math.sigfigs._
implicit val sf: SigFigs = 2

// Stats are displayed on multiple lines
import hammerlab.lines._
import hammerlab.indent.spaces

// Simulate some doubles to collect statistics about
import util.Random._; setSeed(123)
val samples = Array.fill(100)(nextGaussian)

import hammerlab.stats._

// Create and display a Stats:
val stats = Stats(samples)
stats.showLines
// N: 100, μ/σ: -0.02/1, med/mad: -0.038/0.71
//  elems: -1.4 0.63 0.23 0.28 0.18 -0.37 1.4 0.36 -0.21 1 … -0.4 -1.6 -0.11 -1.1 -0.39 1.5 -0.17 1.6 0.25 -0.25
// sorted: -3.1 -2.2 -1.9 -1.9 -1.7 -1.6 -1.4 -1.4 -1.4 -1.4 … 1.3 1.4 1.4 1.5 1.5 1.5 1.6 1.7 1.8 2.8
//   .01:	-3.1
//   .05:	-1.7
//   .10:	-1.4
//   .25:	-0.75
//   .50:	-0.038
//   .75:	0.67
//   .90:	1.3
//   .95:	1.5
//   .99:	2.7

As a bonus, it can ingest numbers in histogram-style / run-length-encoded format, supporting Long values as well for computations involving element counts from RDDs:

// Create a Stats from a histogram:   
Stats.fromHist(
  List(
    1  10000000000L,
    2   1000000000L,
    1          100L,
    2   1000000000L
  )
)
.showLines
// N: 12000000100, μ/σ: 1.2/0.37, med/mad: 1/0
//  elems: 1×10000000000 2×1000000000 1×100 2×1000000000
// sorted: 1×10000000100 2×2000000000
//   .75:	1
//   .90:	2

tolerance

  Maven Central: org.hammerlab.math:::tolerance:1.0.1

Fuzzy-equality for Doubles:

import hammerlab.math.tolerance._

// let things be "equal" that are within 1% of one another
implicit val ε: E = 1e-2
2.0  === 2.02  //  true
2.02 === 2.04  //  true
2.0  === 2.03  // false!

hammerlab/test-utils Suite interfaces come with a (configurable) 1e-6 fuzz-factor for Double comparisons

types

  Maven Central: org.hammerlab:::types:1.5.0

either/or

Shorthands for Either and "or" (cats.Ior) subclasses:

import hammerlab.either._
import hammerlab.or._

collection

CanBuildFrom instances for Arrays and Vectors:

import hammerlab.collection._

monoid

cats.Monoid derivations for products and coproducts:

import hammerlab.monoid._
case class Samples(num: Int, sum: Long)

Samples(10, 1000) |+| Samples(20, 2000)
// Samples(30, 3000)

option

Some Option-related helpers:

Opt

Wrapper class for Option that implicitly wraps values in a Some where necessary:

import hammerlab.option._

// remove default-argument boilerplate
def foo(n: Opt[Int] = 111) = { ??? }

// remove call-site boilerplate
foo(333)

// degrade gracefully to regular Option
foo(Some(222))
foo(None)

? operator

Create a Some iff a predicate is true:

(20 > 10) ? "abc"
// Some(abc)

(20 < 10) ? "abc"
// None

scalajs

Predicates for specializing behavior on the JVM vs JS:

import hammerlab.scalajs._
js (111)(222)  // 111 in JS, 222 in JVM
JS (111)(222)  // same
222 js_? 111   // same 

jvm(111)(222)  // 111 in JVM, 222 in JS
JVM(111)(222)  // same
222 jvm_? 111  // same

str

Name (alias Str) type that is implicitly-constructible from a String or Symbol:

import hammerlab.str._
val a: Str = "abc"
val b: Str = 'def

utils

  Maven Central: org.hammerlab.math:::utils:2.4.0

Miscellaneous numeric utilities

import hammerlab.math._

min

Overloads of math.min that take an Int and a Long and return an `Int

HyperGeometric Distribution

hammerlab.math.utils.HypergeometricDistribution is an implementation of a hypergeometric distribution, modeled after org.apache.commons.math3.distribution.HypergeometricDistribution, but supporting 8-byte Long parameters.

div

Up-rounding integer-division:

div(20 , 10)  // 2
div(21L, 10)  // 3

Steps

geometricSteps(100, 15)
// SortedSet(0, 1, 2, 3, 4, 5, 6, 8, 11, 17, 24, 34, 49, 70, 100)

roundNumbers(100)
// SortedSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100)

cubic, quartic

  Maven Central: org.hammerlab.math:::cubic:1.0.0   Maven Central: org.hammerlab.math:::quartic:1.0.0

Solve cubics with Double coefficients (and Complex[Double] roots):

import cubic.complex._
import spire.implicits._

val dbl = Cubic.doubleComplex[Double]

// Solutions to x³ + 2x² + 3x + 4 = 0:
dbl(1, 2, 3, 4)
// List(
//   -0.175 + 1.547i,
//   -1.651 - 4.457e-16i,
//   -0.175 - 1.54i
// )

// x³ + 3x² + 3x + 1 = 0:
dbl.monic(3, 3, 1)
List(
  -1.0 - 0.0i,
  -1.0 + 0.0i,
  -1.0 + 0.0i
)

// x³ + 4x + 6 = 0:
dbl.depressed(4, 6)
// List(
//   0.567 + 2.228i,
//   -1.135 + -6.594e-16i,
//   0.567 + -2.228i
// )

// Solve cubics with BigDecimal coefficients (and Complex[BigDecimal] roots):

val bigdbl = Cubic.doubleComplex[BigDecimal]

bigdbl(1, 2, 3, 4)
List(
  -0.17468540428030620349438212279655060000000000000000000000000000000000000 + 1.546868887231396634770605370742269000000000000000000000000000000000000000i, 
  -1.650629191439388248503394865883312800000000000000000000000000000000000000000000000000 + -3.43495611274383380622701277675890600000000000000000000000E-16i,
  -0.17468540428030587574830256705833460000000000000000000000000000000000000 + -1.546868887231396291274994096359002000000000000000000000000000000000000000i
)

Quartics work similarly:

import quartic.complex._

// Solve quartics with Double coefficients
val dbl = Quartic.doubleComplex[Double]

// Solve quartics with BigDouble coefficients
val bigdbl = Quartic.doubleComplex[BigDecimal]

dbl(a, b, c, d, e)
dbl.monic(b, c, d, e)
dbl.depressed(p, q, r)
You can’t perform that action at this time.