v2 / vlib / math / complex / complex.v
376 lines · 325 sloc · 10.02 KB · 219ac050fee2ee98b2b4d32735e58d8068a55fda
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4
5module complex
6
7import math
8
9pub struct Complex {
10pub mut:
11 re f64
12 im f64
13}
14
15// complex returns a complex struct with the given `real` and `imaginary` values
16pub fn complex(real f64, imaginary f64) Complex {
17 return Complex{real, imaginary}
18}
19
20// To String method
21pub fn (c Complex) str() string {
22 mut out := '${c.re:.6f}'
23 out += if c.im >= 0 { '+${c.im:.6f}' } else { '${c.im:.6f}' }
24 out += 'i'
25 return out
26}
27
28// Complex Modulus value
29// mod() and abs() return the same
30pub fn (c Complex) abs() f64 {
31 return math.hypot(c.re, c.im)
32}
33
34// mod returns the modulus value of `c`
35pub fn (c Complex) mod() f64 {
36 return c.abs()
37}
38
39// Complex Angle
40pub fn (c Complex) angle() f64 {
41 return math.atan2(c.im, c.re)
42}
43
44// Complex Addition c1 + c2
45pub fn (c1 Complex) + (c2 Complex) Complex {
46 return Complex{c1.re + c2.re, c1.im + c2.im}
47}
48
49// Complex Substraction c1 - c2
50pub fn (c1 Complex) - (c2 Complex) Complex {
51 return Complex{c1.re - c2.re, c1.im - c2.im}
52}
53
54// Complex Multiplication c1 * c2
55pub fn (c1 Complex) * (c2 Complex) Complex {
56 return Complex{(c1.re * c2.re) + ((c1.im * c2.im) * -1), (c1.re * c2.im) + (c1.im * c2.re)}
57}
58
59// Complex Division c1 / c2
60pub fn (c1 Complex) / (c2 Complex) Complex {
61 denom := (c2.re * c2.re) + (c2.im * c2.im)
62 return Complex{((c1.re * c2.re) + ((c1.im * -c2.im) * -1)) / denom, ((c1.re * -c2.im) +
63 (c1.im * c2.re)) / denom}
64}
65
66// Complex Addition c1.add(c2)
67pub fn (c1 Complex) add(c2 Complex) Complex {
68 return c1 + c2
69}
70
71// Complex Subtraction c1.subtract(c2)
72pub fn (c1 Complex) subtract(c2 Complex) Complex {
73 return c1 - c2
74}
75
76// Complex Multiplication c1.multiply(c2)
77pub fn (c1 Complex) multiply(c2 Complex) Complex {
78 return Complex{(c1.re * c2.re) + ((c1.im * c2.im) * -1), (c1.re * c2.im) + (c1.im * c2.re)}
79}
80
81// Complex Division c1.divide(c2)
82pub fn (c1 Complex) divide(c2 Complex) Complex {
83 denom := (c2.re * c2.re) + (c2.im * c2.im)
84 return Complex{((c1.re * c2.re) + ((c1.im * -c2.im) * -1)) / denom, ((c1.re * -c2.im) +
85 (c1.im * c2.re)) / denom}
86}
87
88// Complex Conjugate
89pub fn (c Complex) conjugate() Complex {
90 return Complex{c.re, -c.im}
91}
92
93// Complex Additive Inverse
94// Based on
95// http://tutorial.math.lamar.edu/Extras/ComplexPrimer/Arithmetic.aspx
96pub fn (c Complex) addinv() Complex {
97 return Complex{-c.re, -c.im}
98}
99
100// Complex Multiplicative Inverse
101// Based on
102// http://tutorial.math.lamar.edu/Extras/ComplexPrimer/Arithmetic.aspx
103pub fn (c Complex) mulinv() Complex {
104 return Complex{c.re / (c.re * c.re + c.im * c.im), -c.im / (c.re * c.re + c.im * c.im)}
105}
106
107// Complex Power
108// Based on
109// https://www.khanacademy.org/math/precalculus/imaginary-and-complex-numbers/multiplying-and-dividing-complex-numbers-in-polar-form/a/complex-number-polar-form-review
110pub fn (c Complex) pow(n f64) Complex {
111 r := math.pow(c.abs(), n)
112 angle := c.angle()
113 return Complex{r * math.cos(n * angle), r * math.sin(n * angle)}
114}
115
116// Complex nth root
117pub fn (c Complex) root(n f64) Complex {
118 return c.pow(1.0 / n)
119}
120
121// Complex Exponential
122// Using Euler's Identity
123// Based on
124// https://www.math.wisc.edu/~angenent/Free-Lecture-Notes/freecomplexnumbers.pdf
125pub fn (c Complex) exp() Complex {
126 a := math.exp(c.re)
127 return Complex{a * math.cos(c.im), a * math.sin(c.im)}
128}
129
130// Complex Natural Logarithm
131// Based on
132// http://www.chemistrylearning.com/logarithm-of-complex-number/
133pub fn (c Complex) ln() Complex {
134 return Complex{math.log(c.abs()), c.angle()}
135}
136
137// Complex Log Base Complex
138// Based on
139// http://www.milefoot.com/math/complex/summaryops.htm
140pub fn (c Complex) log(base Complex) Complex {
141 return c.ln().divide(base.ln())
142}
143
144// Complex Argument
145// Based on
146// http://mathworld.wolfram.com/ComplexArgument.html
147pub fn (c Complex) arg() f64 {
148 return math.atan2(c.im, c.re)
149}
150
151// Complex raised to Complex Power
152// Based on
153// http://mathworld.wolfram.com/ComplexExponentiation.html
154pub fn (c Complex) cpow(p Complex) Complex {
155 a := c.arg()
156 b := math.pow(c.re, 2) + math.pow(c.im, 2)
157 d := p.re * a + (1.0 / 2) * p.im * math.log(b)
158 t1 := math.pow(b, p.re / 2) * math.exp(-p.im * a)
159 return Complex{t1 * math.cos(d), t1 * math.sin(d)}
160}
161
162// Complex Sin
163// Based on
164// http://www.milefoot.com/math/complex/functionsofi.htm
165pub fn (c Complex) sin() Complex {
166 return Complex{math.sin(c.re) * math.cosh(c.im), math.cos(c.re) * math.sinh(c.im)}
167}
168
169// Complex Cosine
170// Based on
171// http://www.milefoot.com/math/complex/functionsofi.htm
172pub fn (c Complex) cos() Complex {
173 return Complex{math.cos(c.re) * math.cosh(c.im), -(math.sin(c.re) * math.sinh(c.im))}
174}
175
176// Complex Tangent
177// Based on
178// http://www.milefoot.com/math/complex/functionsofi.htm
179pub fn (c Complex) tan() Complex {
180 return c.sin().divide(c.cos())
181}
182
183// Complex Cotangent
184// Based on
185// http://www.suitcaseofdreams.net/Trigonometric_Functions.htm
186pub fn (c Complex) cot() Complex {
187 return c.cos().divide(c.sin())
188}
189
190// Complex Secant
191// Based on
192// http://www.suitcaseofdreams.net/Trigonometric_Functions.htm
193pub fn (c Complex) sec() Complex {
194 return complex(1, 0).divide(c.cos())
195}
196
197// Complex Cosecant
198// Based on
199// http://www.suitcaseofdreams.net/Trigonometric_Functions.htm
200pub fn (c Complex) csc() Complex {
201 return complex(1, 0).divide(c.sin())
202}
203
204// Complex Arc Sin / Sin Inverse
205// Based on
206// http://www.milefoot.com/math/complex/summaryops.htm
207pub fn (c Complex) asin() Complex {
208 return complex(0, -1).multiply(complex(0, 1).multiply(c).add(complex(1, 0).subtract(c.pow(2)).root(2)).ln())
209}
210
211// Complex Arc Consine / Consine Inverse
212// Based on
213// http://www.milefoot.com/math/complex/summaryops.htm
214pub fn (c Complex) acos() Complex {
215 return complex(0, -1).multiply(c.add(complex(0, 1).multiply(complex(1, 0).subtract(c.pow(2)).root(2))).ln())
216}
217
218// Complex Arc Tangent / Tangent Inverse
219// Based on
220// http://www.milefoot.com/math/complex/summaryops.htm
221pub fn (c Complex) atan() Complex {
222 i := complex(0, 1)
223 return complex(0, 1.0 / 2).multiply(i.add(c).divide(i.subtract(c)).ln())
224}
225
226// Complex Arc Cotangent / Cotangent Inverse
227// Based on
228// http://www.suitcaseofdreams.net/Inverse_Functions.htm
229pub fn (c Complex) acot() Complex {
230 return complex(1, 0).divide(c).atan()
231}
232
233// Complex Arc Secant / Secant Inverse
234// Based on
235// http://www.suitcaseofdreams.net/Inverse_Functions.htm
236pub fn (c Complex) asec() Complex {
237 return complex(1, 0).divide(c).acos()
238}
239
240// Complex Arc Cosecant / Cosecant Inverse
241// Based on
242// http://www.suitcaseofdreams.net/Inverse_Functions.htm
243pub fn (c Complex) acsc() Complex {
244 return complex(1, 0).divide(c).asin()
245}
246
247// Complex Hyperbolic Sin
248// Based on
249// http://www.milefoot.com/math/complex/functionsofi.htm
250pub fn (c Complex) sinh() Complex {
251 return Complex{math.cos(c.im) * math.sinh(c.re), math.sin(c.im) * math.cosh(c.re)}
252}
253
254// Complex Hyperbolic Cosine
255// Based on
256// http://www.milefoot.com/math/complex/functionsofi.htm
257pub fn (c Complex) cosh() Complex {
258 return Complex{math.cos(c.im) * math.cosh(c.re), math.sin(c.im) * math.sinh(c.re)}
259}
260
261// Complex Hyperbolic Tangent
262// Based on
263// http://www.milefoot.com/math/complex/functionsofi.htm
264pub fn (c Complex) tanh() Complex {
265 return c.sinh().divide(c.cosh())
266}
267
268// Complex Hyperbolic Cotangent
269// Based on
270// http://www.suitcaseofdreams.net/Hyperbolic_Functions.htm
271pub fn (c Complex) coth() Complex {
272 return c.cosh().divide(c.sinh())
273}
274
275// Complex Hyperbolic Secant
276// Based on
277// http://www.suitcaseofdreams.net/Hyperbolic_Functions.htm
278pub fn (c Complex) sech() Complex {
279 return complex(1, 0).divide(c.cosh())
280}
281
282// Complex Hyperbolic Cosecant
283// Based on
284// http://www.suitcaseofdreams.net/Hyperbolic_Functions.htm
285pub fn (c Complex) csch() Complex {
286 return complex(1, 0).divide(c.sinh())
287}
288
289// Complex Hyperbolic Arc Sin / Sin Inverse
290// Based on
291// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
292pub fn (c Complex) asinh() Complex {
293 return c.add(c.pow(2).add(complex(1, 0)).root(2)).ln()
294}
295
296// Complex Hyperbolic Arc Consine / Consine Inverse
297// Based on
298// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
299pub fn (c Complex) acosh() Complex {
300 if c.re > 1 {
301 return c.add(c.pow(2).subtract(complex(1, 0)).root(2)).ln()
302 } else {
303 one := complex(1, 0)
304 return c.add(c.add(one).root(2).multiply(c.subtract(one).root(2))).ln()
305 }
306}
307
308// Complex Hyperbolic Arc Tangent / Tangent Inverse
309// Based on
310// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
311pub fn (c Complex) atanh() Complex {
312 one := complex(1, 0)
313 if c.re < 1 {
314 return complex(1.0 / 2, 0).multiply(one.add(c).divide(one.subtract(c)).ln())
315 } else {
316 return complex(1.0 / 2, 0).multiply(one.add(c).ln().subtract(one.subtract(c).ln()))
317 }
318}
319
320// Complex Hyperbolic Arc Cotangent / Cotangent Inverse
321// Based on
322// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
323pub fn (c Complex) acoth() Complex {
324 one := complex(1, 0)
325 if c.re < 0 || c.re > 1 {
326 return complex(1.0 / 2, 0).multiply(c.add(one).divide(c.subtract(one)).ln())
327 } else {
328 div := one.divide(c)
329 return complex(1.0 / 2, 0).multiply(one.add(div).ln().subtract(one.subtract(div).ln()))
330 }
331}
332
333// Complex Hyperbolic Arc Secant / Secant Inverse
334// Based on
335// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
336// For certain scenarios, Result mismatch in crossverification with Wolfram Alpha - analysis pending
337// pub fn (c Complex) asech() Complex {
338// one := complex(1,0)
339// if(c.re < -1.0) {
340// return one.subtract(
341// one.subtract(
342// c.pow(2)
343// )
344// .root(2)
345// )
346// .divide(c)
347// .ln()
348// }
349// else {
350// return one.add(
351// one.subtract(
352// c.pow(2)
353// )
354// .root(2)
355// )
356// .divide(c)
357// .ln()
358// }
359// }
360
361// Complex Hyperbolic Arc Cosecant / Cosecant Inverse
362// Based on
363// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
364pub fn (c Complex) acsch() Complex {
365 one := complex(1, 0)
366 if c.re < 0 {
367 return one.subtract(one.add(c.pow(2)).root(2)).divide(c).ln()
368 } else {
369 return one.add(one.add(c.pow(2)).root(2)).divide(c).ln()
370 }
371}
372
373// Complex Equals
374pub fn (c1 Complex) equals(c2 Complex) bool {
375 return c1.re.eq_epsilon(c2.re) && c1.im.eq_epsilon(c2.im)
376}
377