annotate src/clojure/contrib/complex_numbers.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 ;; Complex numbers
rlm@10 2
rlm@10 3 ;; by Konrad Hinsen
rlm@10 4 ;; last updated May 4, 2009
rlm@10 5
rlm@10 6 ;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use
rlm@10 7 ;; and distribution terms for this software are covered by the Eclipse
rlm@10 8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 9 ;; which can be found in the file epl-v10.html at the root of this
rlm@10 10 ;; distribution. By using this software in any fashion, you are
rlm@10 11 ;; agreeing to be bound by the terms of this license. You must not
rlm@10 12 ;; remove this notice, or any other, from this software.
rlm@10 13
rlm@10 14 (ns
rlm@10 15 ^{:author "Konrad Hinsen"
rlm@10 16 :doc "Complex numbers
rlm@10 17 NOTE: This library is in evolution. Most math functions are
rlm@10 18 not implemented yet."}
rlm@10 19 clojure.contrib.complex-numbers
rlm@10 20 (:refer-clojure :exclude (deftype))
rlm@10 21 (:use [clojure.contrib.types :only (deftype)]
rlm@10 22 [clojure.contrib.generic :only (root-type)])
rlm@10 23 (:require [clojure.contrib.generic.arithmetic :as ga]
rlm@10 24 [clojure.contrib.generic.comparison :as gc]
rlm@10 25 [clojure.contrib.generic.math-functions :as gm]))
rlm@10 26
rlm@10 27 ;
rlm@10 28 ; Complex numbers are represented as struct maps. The real and imaginary
rlm@10 29 ; parts can be of any type for which arithmetic and maths functions
rlm@10 30 ; are defined.
rlm@10 31 ;
rlm@10 32 (defstruct complex-struct :real :imag)
rlm@10 33
rlm@10 34 ;
rlm@10 35 ; The general complex number type
rlm@10 36 ;
rlm@10 37 (deftype ::complex complex
rlm@10 38 (fn [real imag] (struct complex-struct real imag))
rlm@10 39 (fn [c] (vals c)))
rlm@10 40
rlm@10 41 (derive ::complex root-type)
rlm@10 42
rlm@10 43 ;
rlm@10 44 ; A specialized subtype for pure imaginary numbers. Introducing this type
rlm@10 45 ; reduces the number of operations by eliminating additions with and
rlm@10 46 ; multiplications by zero.
rlm@10 47 ;
rlm@10 48 (deftype ::pure-imaginary imaginary
rlm@10 49 (fn [imag] (struct complex-struct 0 imag))
rlm@10 50 (fn [c] (list (:imag c))))
rlm@10 51
rlm@10 52 (derive ::pure-imaginary ::complex)
rlm@10 53
rlm@10 54 ;
rlm@10 55 ; Extraction of real and imaginary parts
rlm@10 56 ;
rlm@10 57 (def real (accessor complex-struct :real))
rlm@10 58 (def imag (accessor complex-struct :imag))
rlm@10 59
rlm@10 60 ;
rlm@10 61 ; Equality and zero test
rlm@10 62 ;
rlm@10 63 (defmethod gc/zero? ::complex
rlm@10 64 [x]
rlm@10 65 (let [[rx ix] (vals x)]
rlm@10 66 (and (zero? rx) (zero? ix))))
rlm@10 67
rlm@10 68 (defmethod gc/= [::complex ::complex]
rlm@10 69 [x y]
rlm@10 70 (let [[rx ix] (vals x)
rlm@10 71 [ry iy] (vals y)]
rlm@10 72 (and (gc/= rx ry) (gc/= ix iy))))
rlm@10 73
rlm@10 74 (defmethod gc/= [::pure-imaginary ::pure-imaginary]
rlm@10 75 [x y]
rlm@10 76 (gc/= (imag x) (imag y)))
rlm@10 77
rlm@10 78 (defmethod gc/= [::complex ::pure-imaginary]
rlm@10 79 [x y]
rlm@10 80 (let [[rx ix] (vals x)]
rlm@10 81 (and (gc/zero? rx) (gc/= ix (imag y)))))
rlm@10 82
rlm@10 83 (defmethod gc/= [::pure-imaginary ::complex]
rlm@10 84 [x y]
rlm@10 85 (let [[ry iy] (vals y)]
rlm@10 86 (and (gc/zero? ry) (gc/= (imag x) iy))))
rlm@10 87
rlm@10 88 (defmethod gc/= [::complex root-type]
rlm@10 89 [x y]
rlm@10 90 (let [[rx ix] (vals x)]
rlm@10 91 (and (gc/zero? ix) (gc/= rx y))))
rlm@10 92
rlm@10 93 (defmethod gc/= [root-type ::complex]
rlm@10 94 [x y]
rlm@10 95 (let [[ry iy] (vals y)]
rlm@10 96 (and (gc/zero? iy) (gc/= x ry))))
rlm@10 97
rlm@10 98 (defmethod gc/= [::pure-imaginary root-type]
rlm@10 99 [x y]
rlm@10 100 (and (gc/zero? (imag x)) (gc/zero? y)))
rlm@10 101
rlm@10 102 (defmethod gc/= [root-type ::pure-imaginary]
rlm@10 103 [x y]
rlm@10 104 (and (gc/zero? x) (gc/zero? (imag y))))
rlm@10 105
rlm@10 106 ;
rlm@10 107 ; Addition
rlm@10 108 ;
rlm@10 109 (defmethod ga/+ [::complex ::complex]
rlm@10 110 [x y]
rlm@10 111 (let [[rx ix] (vals x)
rlm@10 112 [ry iy] (vals y)]
rlm@10 113 (complex (ga/+ rx ry) (ga/+ ix iy))))
rlm@10 114
rlm@10 115 (defmethod ga/+ [::pure-imaginary ::pure-imaginary]
rlm@10 116 [x y]
rlm@10 117 (imaginary (ga/+ (imag x) (imag y))))
rlm@10 118
rlm@10 119 (defmethod ga/+ [::complex ::pure-imaginary]
rlm@10 120 [x y]
rlm@10 121 (let [[rx ix] (vals x)]
rlm@10 122 (complex rx (ga/+ ix (imag y)))))
rlm@10 123
rlm@10 124 (defmethod ga/+ [::pure-imaginary ::complex]
rlm@10 125 [x y]
rlm@10 126 (let [[ry iy] (vals y)]
rlm@10 127 (complex ry (ga/+ (imag x) iy))))
rlm@10 128
rlm@10 129 (defmethod ga/+ [::complex root-type]
rlm@10 130 [x y]
rlm@10 131 (let [[rx ix] (vals x)]
rlm@10 132 (complex (ga/+ rx y) ix)))
rlm@10 133
rlm@10 134 (defmethod ga/+ [root-type ::complex]
rlm@10 135 [x y]
rlm@10 136 (let [[ry iy] (vals y)]
rlm@10 137 (complex (ga/+ x ry) iy)))
rlm@10 138
rlm@10 139 (defmethod ga/+ [::pure-imaginary root-type]
rlm@10 140 [x y]
rlm@10 141 (complex y (imag x)))
rlm@10 142
rlm@10 143 (defmethod ga/+ [root-type ::pure-imaginary]
rlm@10 144 [x y]
rlm@10 145 (complex x (imag y)))
rlm@10 146
rlm@10 147 ;
rlm@10 148 ; Negation
rlm@10 149 ;
rlm@10 150 (defmethod ga/- ::complex
rlm@10 151 [x]
rlm@10 152 (let [[rx ix] (vals x)]
rlm@10 153 (complex (ga/- rx) (ga/- ix))))
rlm@10 154
rlm@10 155 (defmethod ga/- ::pure-imaginary
rlm@10 156 [x]
rlm@10 157 (imaginary (ga/- (imag x))))
rlm@10 158
rlm@10 159 ;
rlm@10 160 ; Subtraction is automatically supplied by ga/-, optimized implementations
rlm@10 161 ; can be added later...
rlm@10 162 ;
rlm@10 163
rlm@10 164 ;
rlm@10 165 ; Multiplication
rlm@10 166 ;
rlm@10 167 (defmethod ga/* [::complex ::complex]
rlm@10 168 [x y]
rlm@10 169 (let [[rx ix] (vals x)
rlm@10 170 [ry iy] (vals y)]
rlm@10 171 (complex (ga/- (ga/* rx ry) (ga/* ix iy))
rlm@10 172 (ga/+ (ga/* rx iy) (ga/* ix ry)))))
rlm@10 173
rlm@10 174 (defmethod ga/* [::pure-imaginary ::pure-imaginary]
rlm@10 175 [x y]
rlm@10 176 (ga/- (ga/* (imag x) (imag y))))
rlm@10 177
rlm@10 178 (defmethod ga/* [::complex ::pure-imaginary]
rlm@10 179 [x y]
rlm@10 180 (let [[rx ix] (vals x)
rlm@10 181 iy (imag y)]
rlm@10 182 (complex (ga/- (ga/* ix iy))
rlm@10 183 (ga/* rx iy))))
rlm@10 184
rlm@10 185 (defmethod ga/* [::pure-imaginary ::complex]
rlm@10 186 [x y]
rlm@10 187 (let [ix (imag x)
rlm@10 188 [ry iy] (vals y)]
rlm@10 189 (complex (ga/- (ga/* ix iy))
rlm@10 190 (ga/* ix ry))))
rlm@10 191
rlm@10 192 (defmethod ga/* [::complex root-type]
rlm@10 193 [x y]
rlm@10 194 (let [[rx ix] (vals x)]
rlm@10 195 (complex (ga/* rx y) (ga/* ix y))))
rlm@10 196
rlm@10 197 (defmethod ga/* [root-type ::complex]
rlm@10 198 [x y]
rlm@10 199 (let [[ry iy] (vals y)]
rlm@10 200 (complex (ga/* x ry) (ga/* x iy))))
rlm@10 201
rlm@10 202 (defmethod ga/* [::pure-imaginary root-type]
rlm@10 203 [x y]
rlm@10 204 (imaginary (ga/* (imag x) y)))
rlm@10 205
rlm@10 206 (defmethod ga/* [root-type ::pure-imaginary]
rlm@10 207 [x y]
rlm@10 208 (imaginary (ga/* x (imag y))))
rlm@10 209
rlm@10 210 ;
rlm@10 211 ; Inversion
rlm@10 212 ;
rlm@10 213 (ga/defmethod* ga / ::complex
rlm@10 214 [x]
rlm@10 215 (let [[rx ix] (vals x)
rlm@10 216 den ((ga/qsym ga /) (ga/+ (ga/* rx rx) (ga/* ix ix)))]
rlm@10 217 (complex (ga/* rx den) (ga/- (ga/* ix den)))))
rlm@10 218
rlm@10 219 (ga/defmethod* ga / ::pure-imaginary
rlm@10 220 [x]
rlm@10 221 (imaginary (ga/- ((ga/qsym ga /) (imag x)))))
rlm@10 222
rlm@10 223 ;
rlm@10 224 ; Division is automatically supplied by ga//, optimized implementations
rlm@10 225 ; can be added later...
rlm@10 226 ;
rlm@10 227
rlm@10 228 ;
rlm@10 229 ; Conjugation
rlm@10 230 ;
rlm@10 231 (defmethod gm/conjugate ::complex
rlm@10 232 [x]
rlm@10 233 (let [[r i] (vals x)]
rlm@10 234 (complex r (ga/- i))))
rlm@10 235
rlm@10 236 (defmethod gm/conjugate ::pure-imaginary
rlm@10 237 [x]
rlm@10 238 (imaginary (ga/- (imag x))))
rlm@10 239
rlm@10 240 ;
rlm@10 241 ; Absolute value
rlm@10 242 ;
rlm@10 243 (defmethod gm/abs ::complex
rlm@10 244 [x]
rlm@10 245 (let [[r i] (vals x)]
rlm@10 246 (gm/sqrt (ga/+ (ga/* r r) (ga/* i i)))))
rlm@10 247
rlm@10 248 (defmethod gm/abs ::pure-imaginary
rlm@10 249 [x]
rlm@10 250 (gm/abs (imag x)))
rlm@10 251
rlm@10 252 ;
rlm@10 253 ; Square root
rlm@10 254 ;
rlm@10 255 (let [one-half (/ 1 2)
rlm@10 256 one-eighth (/ 1 8)]
rlm@10 257 (defmethod gm/sqrt ::complex
rlm@10 258 [x]
rlm@10 259 (let [[r i] (vals x)]
rlm@10 260 (if (and (gc/zero? r) (gc/zero? i))
rlm@10 261 0
rlm@10 262 (let [; The basic formula would say
rlm@10 263 ; abs (gm/sqrt (ga/+ (ga/* r r) (ga/* i i)))
rlm@10 264 ; p (gm/sqrt (ga/* one-half (ga/+ abs r)))
rlm@10 265 ; but the slightly more complicated one below
rlm@10 266 ; avoids overflow for large r or i.
rlm@10 267 ar (gm/abs r)
rlm@10 268 ai (gm/abs i)
rlm@10 269 r8 (ga/* one-eighth ar)
rlm@10 270 i8 (ga/* one-eighth ai)
rlm@10 271 abs (gm/sqrt (ga/+ (ga/* r8 r8) (ga/* i8 i8)))
rlm@10 272 p (ga/* 2 (gm/sqrt (ga/+ abs r8)))
rlm@10 273 q ((ga/qsym ga /) ai (ga/* 2 p))
rlm@10 274 s (gm/sgn i)]
rlm@10 275 (if (gc/< r 0)
rlm@10 276 (complex q (ga/* s p))
rlm@10 277 (complex p (ga/* s q))))))))
rlm@10 278
rlm@10 279 ;
rlm@10 280 ; Exponential function
rlm@10 281 ;
rlm@10 282 (defmethod gm/exp ::complex
rlm@10 283 [x]
rlm@10 284 (let [[r i] (vals x)
rlm@10 285 exp-r (gm/exp r)
rlm@10 286 cos-i (gm/cos i)
rlm@10 287 sin-i (gm/sin i)]
rlm@10 288 (complex (ga/* exp-r cos-i) (ga/* exp-r sin-i))))
rlm@10 289
rlm@10 290 (defmethod gm/exp ::pure-imaginary
rlm@10 291 [x]
rlm@10 292 (let [i (imag x)]
rlm@10 293 (complex (gm/cos i) (gm/sin i))))