Created
August 1, 2012 02:01
-
-
Save propensive/3222735 to your computer and use it in GitHub Desktop.
Quaternions in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Algebra { | |
// Build up increasingly complex algebras | |
trait Magma[T] { | |
def add(x : T, y : T) : T | |
} | |
trait Monoid[T] extends Magma[T] { | |
def zero : T | |
} | |
trait Group[T] extends Monoid[T] { | |
def negation(x : T) : T | |
} | |
trait Ring[T] extends Group[T] { | |
def one : T | |
def multiply(x : T, y : T) : T | |
} | |
trait Field[T] extends Ring[T] { | |
def divide(x : T, y : T) : T | |
def inverse(x : T) : T = divide(one, x) | |
// This is required later... | |
def conjugate(x : T) : T = x | |
} | |
// Specify how doubles form a field | |
implicit object DoubleField extends Field[Double] { | |
def add(x : Double, y : Double) = x+y | |
def negation(x : Double) = -x | |
def zero = 0 | |
def one = 1 | |
def multiply(x : Double, y : Double) = x*y | |
def divide(x : Double, y : Double) = x/y | |
} | |
// Define complex numbers over a type T (e.g. Double) | |
object Complex { | |
def apply[T : Field](re : T, im : T) = new Complex[T](re, im) | |
def unapply[T : Field](re : T, im : T) = Some((re, im)) | |
} | |
class Complex[T](val re : T, val im : T)(implicit base : Field[T]) { | |
import base._ | |
def +(that : Complex[T]) : Complex[T] = | |
Complex[T](add(re, that.re), add(im, that.im)) | |
def -(that : Complex[T]) : Complex[T] = | |
Complex[T](add(re, negation(that.re)), add(im, negation(that.im))) | |
// Note this definition of multiplication isn't the most obvious one | |
def *(that : Complex[T]) : Complex[T] = | |
Complex[T](add(multiply(re, that.re), negation(multiply(im, base.conjugate(that.im)))), | |
add(multiply(that.im, re), multiply(im, base.conjugate(that.re)))) | |
def /(that : Complex[T]) : Complex[T] = | |
Complex[T](divide(add(multiply(re, that.re), multiply(im, that.im)), add(multiply(that.re, that.re), multiply(that.im, that.im))), divide(add(multiply(im, that.re), negation(multiply(that.im, re))), add(multiply(that.re, that.re), multiply(that.im, that.im)))) | |
def negate : Complex[T] = Complex[T](negation(re), negation(im)) | |
// Note the "real" part | |
def conjugate : Complex[T] = Complex[T](base.conjugate(re), negation(im)) | |
override def toString = "("+re.toString+" + "+im.toString+"i)" | |
} | |
// Specify how complex numbers over any type T form a field | |
implicit def complexIsField[T](implicit base : Field[T]) = new Field[Complex[T]] { | |
def add(x : Complex[T], y : Complex[T]) = x + y | |
def zero : Complex[T] = Complex[T](base.zero, base.zero) | |
def negation(x : Complex[T]) = x.negate | |
def one : Complex[T] = Complex[T](base.one, base.zero) | |
def multiply(x : Complex[T], y : Complex[T]) = x*y | |
def divide(x : Complex[T], y : Complex[T]) = x/y | |
override def conjugate(x : Complex[T]) = x.conjugate | |
} | |
// The magic bit | |
case class Quaternion[T : Field](x : T, i : T, j : T, k : T) | |
extends Complex[Complex[T]](Complex[T](x, i), Complex[T](j, k)) | |
implicit def doubleToQuaternion(d : Double) = Quaternion(d, 0.0, 0.0, 0.0) | |
val h = Quaternion(1.0, 0.0, 0.0, 0.0) // == 1.0 | |
val i = Quaternion(0.0, 1.0, 0.0, 0.0) | |
val j = Quaternion(0.0, 0.0, 1.0, 0.0) | |
val k = Quaternion(0.0, 0.0, 0.0, 1.0) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment