Mercurial > lasercutter
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/contrib/complex_numbers.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,293 @@ 1.4 +;; Complex numbers 1.5 + 1.6 +;; by Konrad Hinsen 1.7 +;; last updated May 4, 2009 1.8 + 1.9 +;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use 1.10 +;; and distribution terms for this software are covered by the Eclipse 1.11 +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.12 +;; which can be found in the file epl-v10.html at the root of this 1.13 +;; distribution. By using this software in any fashion, you are 1.14 +;; agreeing to be bound by the terms of this license. You must not 1.15 +;; remove this notice, or any other, from this software. 1.16 + 1.17 +(ns 1.18 + ^{:author "Konrad Hinsen" 1.19 + :doc "Complex numbers 1.20 + NOTE: This library is in evolution. Most math functions are 1.21 + not implemented yet."} 1.22 + clojure.contrib.complex-numbers 1.23 + (:refer-clojure :exclude (deftype)) 1.24 + (:use [clojure.contrib.types :only (deftype)] 1.25 + [clojure.contrib.generic :only (root-type)]) 1.26 + (:require [clojure.contrib.generic.arithmetic :as ga] 1.27 + [clojure.contrib.generic.comparison :as gc] 1.28 + [clojure.contrib.generic.math-functions :as gm])) 1.29 + 1.30 +; 1.31 +; Complex numbers are represented as struct maps. The real and imaginary 1.32 +; parts can be of any type for which arithmetic and maths functions 1.33 +; are defined. 1.34 +; 1.35 +(defstruct complex-struct :real :imag) 1.36 + 1.37 +; 1.38 +; The general complex number type 1.39 +; 1.40 +(deftype ::complex complex 1.41 + (fn [real imag] (struct complex-struct real imag)) 1.42 + (fn [c] (vals c))) 1.43 + 1.44 +(derive ::complex root-type) 1.45 + 1.46 +; 1.47 +; A specialized subtype for pure imaginary numbers. Introducing this type 1.48 +; reduces the number of operations by eliminating additions with and 1.49 +; multiplications by zero. 1.50 +; 1.51 +(deftype ::pure-imaginary imaginary 1.52 + (fn [imag] (struct complex-struct 0 imag)) 1.53 + (fn [c] (list (:imag c)))) 1.54 + 1.55 +(derive ::pure-imaginary ::complex) 1.56 + 1.57 +; 1.58 +; Extraction of real and imaginary parts 1.59 +; 1.60 +(def real (accessor complex-struct :real)) 1.61 +(def imag (accessor complex-struct :imag)) 1.62 + 1.63 +; 1.64 +; Equality and zero test 1.65 +; 1.66 +(defmethod gc/zero? ::complex 1.67 + [x] 1.68 + (let [[rx ix] (vals x)] 1.69 + (and (zero? rx) (zero? ix)))) 1.70 + 1.71 +(defmethod gc/= [::complex ::complex] 1.72 + [x y] 1.73 + (let [[rx ix] (vals x) 1.74 + [ry iy] (vals y)] 1.75 + (and (gc/= rx ry) (gc/= ix iy)))) 1.76 + 1.77 +(defmethod gc/= [::pure-imaginary ::pure-imaginary] 1.78 + [x y] 1.79 + (gc/= (imag x) (imag y))) 1.80 + 1.81 +(defmethod gc/= [::complex ::pure-imaginary] 1.82 + [x y] 1.83 + (let [[rx ix] (vals x)] 1.84 + (and (gc/zero? rx) (gc/= ix (imag y))))) 1.85 + 1.86 +(defmethod gc/= [::pure-imaginary ::complex] 1.87 + [x y] 1.88 + (let [[ry iy] (vals y)] 1.89 + (and (gc/zero? ry) (gc/= (imag x) iy)))) 1.90 + 1.91 +(defmethod gc/= [::complex root-type] 1.92 + [x y] 1.93 + (let [[rx ix] (vals x)] 1.94 + (and (gc/zero? ix) (gc/= rx y)))) 1.95 + 1.96 +(defmethod gc/= [root-type ::complex] 1.97 + [x y] 1.98 + (let [[ry iy] (vals y)] 1.99 + (and (gc/zero? iy) (gc/= x ry)))) 1.100 + 1.101 +(defmethod gc/= [::pure-imaginary root-type] 1.102 + [x y] 1.103 + (and (gc/zero? (imag x)) (gc/zero? y))) 1.104 + 1.105 +(defmethod gc/= [root-type ::pure-imaginary] 1.106 + [x y] 1.107 + (and (gc/zero? x) (gc/zero? (imag y)))) 1.108 + 1.109 +; 1.110 +; Addition 1.111 +; 1.112 +(defmethod ga/+ [::complex ::complex] 1.113 + [x y] 1.114 + (let [[rx ix] (vals x) 1.115 + [ry iy] (vals y)] 1.116 + (complex (ga/+ rx ry) (ga/+ ix iy)))) 1.117 + 1.118 +(defmethod ga/+ [::pure-imaginary ::pure-imaginary] 1.119 + [x y] 1.120 + (imaginary (ga/+ (imag x) (imag y)))) 1.121 + 1.122 +(defmethod ga/+ [::complex ::pure-imaginary] 1.123 + [x y] 1.124 + (let [[rx ix] (vals x)] 1.125 + (complex rx (ga/+ ix (imag y))))) 1.126 + 1.127 +(defmethod ga/+ [::pure-imaginary ::complex] 1.128 + [x y] 1.129 + (let [[ry iy] (vals y)] 1.130 + (complex ry (ga/+ (imag x) iy)))) 1.131 + 1.132 +(defmethod ga/+ [::complex root-type] 1.133 + [x y] 1.134 + (let [[rx ix] (vals x)] 1.135 + (complex (ga/+ rx y) ix))) 1.136 + 1.137 +(defmethod ga/+ [root-type ::complex] 1.138 + [x y] 1.139 + (let [[ry iy] (vals y)] 1.140 + (complex (ga/+ x ry) iy))) 1.141 + 1.142 +(defmethod ga/+ [::pure-imaginary root-type] 1.143 + [x y] 1.144 + (complex y (imag x))) 1.145 + 1.146 +(defmethod ga/+ [root-type ::pure-imaginary] 1.147 + [x y] 1.148 + (complex x (imag y))) 1.149 + 1.150 +; 1.151 +; Negation 1.152 +; 1.153 +(defmethod ga/- ::complex 1.154 + [x] 1.155 + (let [[rx ix] (vals x)] 1.156 + (complex (ga/- rx) (ga/- ix)))) 1.157 + 1.158 +(defmethod ga/- ::pure-imaginary 1.159 + [x] 1.160 + (imaginary (ga/- (imag x)))) 1.161 + 1.162 +; 1.163 +; Subtraction is automatically supplied by ga/-, optimized implementations 1.164 +; can be added later... 1.165 +; 1.166 + 1.167 +; 1.168 +; Multiplication 1.169 +; 1.170 +(defmethod ga/* [::complex ::complex] 1.171 + [x y] 1.172 + (let [[rx ix] (vals x) 1.173 + [ry iy] (vals y)] 1.174 + (complex (ga/- (ga/* rx ry) (ga/* ix iy)) 1.175 + (ga/+ (ga/* rx iy) (ga/* ix ry))))) 1.176 + 1.177 +(defmethod ga/* [::pure-imaginary ::pure-imaginary] 1.178 + [x y] 1.179 + (ga/- (ga/* (imag x) (imag y)))) 1.180 + 1.181 +(defmethod ga/* [::complex ::pure-imaginary] 1.182 + [x y] 1.183 + (let [[rx ix] (vals x) 1.184 + iy (imag y)] 1.185 + (complex (ga/- (ga/* ix iy)) 1.186 + (ga/* rx iy)))) 1.187 + 1.188 +(defmethod ga/* [::pure-imaginary ::complex] 1.189 + [x y] 1.190 + (let [ix (imag x) 1.191 + [ry iy] (vals y)] 1.192 + (complex (ga/- (ga/* ix iy)) 1.193 + (ga/* ix ry)))) 1.194 + 1.195 +(defmethod ga/* [::complex root-type] 1.196 + [x y] 1.197 + (let [[rx ix] (vals x)] 1.198 + (complex (ga/* rx y) (ga/* ix y)))) 1.199 + 1.200 +(defmethod ga/* [root-type ::complex] 1.201 + [x y] 1.202 + (let [[ry iy] (vals y)] 1.203 + (complex (ga/* x ry) (ga/* x iy)))) 1.204 + 1.205 +(defmethod ga/* [::pure-imaginary root-type] 1.206 + [x y] 1.207 + (imaginary (ga/* (imag x) y))) 1.208 + 1.209 +(defmethod ga/* [root-type ::pure-imaginary] 1.210 + [x y] 1.211 + (imaginary (ga/* x (imag y)))) 1.212 + 1.213 +; 1.214 +; Inversion 1.215 +; 1.216 +(ga/defmethod* ga / ::complex 1.217 + [x] 1.218 + (let [[rx ix] (vals x) 1.219 + den ((ga/qsym ga /) (ga/+ (ga/* rx rx) (ga/* ix ix)))] 1.220 + (complex (ga/* rx den) (ga/- (ga/* ix den))))) 1.221 + 1.222 +(ga/defmethod* ga / ::pure-imaginary 1.223 + [x] 1.224 + (imaginary (ga/- ((ga/qsym ga /) (imag x))))) 1.225 + 1.226 +; 1.227 +; Division is automatically supplied by ga//, optimized implementations 1.228 +; can be added later... 1.229 +; 1.230 + 1.231 +; 1.232 +; Conjugation 1.233 +; 1.234 +(defmethod gm/conjugate ::complex 1.235 + [x] 1.236 + (let [[r i] (vals x)] 1.237 + (complex r (ga/- i)))) 1.238 + 1.239 +(defmethod gm/conjugate ::pure-imaginary 1.240 + [x] 1.241 + (imaginary (ga/- (imag x)))) 1.242 + 1.243 +; 1.244 +; Absolute value 1.245 +; 1.246 +(defmethod gm/abs ::complex 1.247 + [x] 1.248 + (let [[r i] (vals x)] 1.249 + (gm/sqrt (ga/+ (ga/* r r) (ga/* i i))))) 1.250 + 1.251 +(defmethod gm/abs ::pure-imaginary 1.252 + [x] 1.253 + (gm/abs (imag x))) 1.254 + 1.255 +; 1.256 +; Square root 1.257 +; 1.258 +(let [one-half (/ 1 2) 1.259 + one-eighth (/ 1 8)] 1.260 + (defmethod gm/sqrt ::complex 1.261 + [x] 1.262 + (let [[r i] (vals x)] 1.263 + (if (and (gc/zero? r) (gc/zero? i)) 1.264 + 0 1.265 + (let [; The basic formula would say 1.266 + ; abs (gm/sqrt (ga/+ (ga/* r r) (ga/* i i))) 1.267 + ; p (gm/sqrt (ga/* one-half (ga/+ abs r))) 1.268 + ; but the slightly more complicated one below 1.269 + ; avoids overflow for large r or i. 1.270 + ar (gm/abs r) 1.271 + ai (gm/abs i) 1.272 + r8 (ga/* one-eighth ar) 1.273 + i8 (ga/* one-eighth ai) 1.274 + abs (gm/sqrt (ga/+ (ga/* r8 r8) (ga/* i8 i8))) 1.275 + p (ga/* 2 (gm/sqrt (ga/+ abs r8))) 1.276 + q ((ga/qsym ga /) ai (ga/* 2 p)) 1.277 + s (gm/sgn i)] 1.278 + (if (gc/< r 0) 1.279 + (complex q (ga/* s p)) 1.280 + (complex p (ga/* s q)))))))) 1.281 + 1.282 +; 1.283 +; Exponential function 1.284 +; 1.285 +(defmethod gm/exp ::complex 1.286 + [x] 1.287 + (let [[r i] (vals x) 1.288 + exp-r (gm/exp r) 1.289 + cos-i (gm/cos i) 1.290 + sin-i (gm/sin i)] 1.291 + (complex (ga/* exp-r cos-i) (ga/* exp-r sin-i)))) 1.292 + 1.293 +(defmethod gm/exp ::pure-imaginary 1.294 + [x] 1.295 + (let [i (imag x)] 1.296 + (complex (gm/cos i) (gm/sin i))))