View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.numerics.math;
39  
40  import static org.apache.commons.math3.util.FastMath.atan2;
41  import static org.apache.commons.math3.util.FastMath.cosh;
42  import static org.apache.commons.math3.util.FastMath.hypot;
43  import static org.apache.commons.math3.util.FastMath.sinh;
44  
45  import org.apache.commons.math3.util.FastMath;
46  
47  /**
48   * ComplexNumber class.
49   *
50   * @author Timothy D. Fenn
51   * @since 1.0
52   */
53  public class ComplexNumber {
54  
55    private double re;
56    private double im;
57  
58    /**
59     * Constructor for ComplexNumber.
60     */
61    public ComplexNumber() {
62    }
63  
64    /**
65     * Constructor for ComplexNumber.
66     *
67     * @param real a double.
68     * @param imag a double.
69     */
70    public ComplexNumber(double real, double imag) {
71      re = real;
72      im = imag;
73    }
74  
75    /**
76     * Static version of phaseShift.
77     *
78     * @param a a {@link ComplexNumber} object.
79     * @param s a double.
80     * @return a {@link ComplexNumber} object.
81     */
82    public static ComplexNumber phaseShift(ComplexNumber a, double s) {
83      ComplexNumber sc = new ComplexNumber(FastMath.cos(s), FastMath.sin(s));
84      return a.times(sc);
85    }
86  
87    /**
88     * abs
89     *
90     * @return a double.
91     */
92    public double abs() {
93      return hypot(re, im);
94    }
95  
96    /**
97     * Return a new Complex object whose value is the conjugate of this.
98     *
99     * @return a {@link ComplexNumber} object.
100    */
101   public ComplexNumber conjugate() {
102     return new ComplexNumber(re, -im);
103   }
104 
105   /**
106    * conjugateIP
107    */
108   public void conjugateIP() {
109     this.im = -this.im;
110   }
111 
112   /**
113    * copy
114    *
115    * @param b a {@link ComplexNumber} object.
116    */
117   public void copy(ComplexNumber b) {
118     ComplexNumber a = this;
119     a.re = b.re;
120     a.im = b.im;
121   }
122 
123   /**
124    * Return a new Complex object whose value is the complex cosine of this.
125    *
126    * @return a {@link ComplexNumber} object.
127    */
128   public ComplexNumber cos() {
129     return new ComplexNumber(FastMath.cos(re) * cosh(im), -FastMath.sin(re) * sinh(im));
130   }
131 
132   /**
133    * Return a / b.
134    *
135    * @param b a {@link ComplexNumber} object.
136    * @return a {@link ComplexNumber} object.
137    */
138   public ComplexNumber divides(ComplexNumber b) {
139     ComplexNumber a = this;
140     return a.times(b.reciprocal());
141   }
142 
143   /**
144    * Return a new Complex object whose value is the complex exponential of this.
145    *
146    * @return a {@link ComplexNumber} object.
147    */
148   public ComplexNumber exp() {
149     return new ComplexNumber(
150         FastMath.exp(re) * FastMath.cos(im), FastMath.exp(re) * FastMath.sin(im));
151   }
152 
153   /**
154    * im
155    *
156    * @return a double.
157    */
158   public double im() {
159     return im;
160   }
161 
162   /**
163    * im
164    *
165    * @param im a double.
166    */
167   public void im(double im) {
168     this.im = im;
169   }
170 
171   /**
172    * Return a new Complex object whose value is (this - b).
173    *
174    * @param b a {@link ComplexNumber} object.
175    * @return a {@link ComplexNumber} object.
176    */
177   public ComplexNumber minus(ComplexNumber b) {
178     ComplexNumber a = this;
179     var real = a.re - b.re;
180     var imag = a.im - b.im;
181     return new ComplexNumber(real, imag);
182   }
183 
184   /**
185    * minusIP
186    *
187    * @param b a {@link ComplexNumber} object.
188    */
189   public void minusIP(ComplexNumber b) {
190     ComplexNumber a = this;
191     a.re -= b.re;
192     a.im -= b.im;
193   }
194 
195   /**
196    * phase
197    *
198    * @return a double.
199    */
200   public double phase() {
201     return atan2(im, re);
202   }
203 
204   /**
205    * phaseShift
206    *
207    * @param s a double.
208    * @return a {@link ComplexNumber} object.
209    */
210   public ComplexNumber phaseShift(double s) {
211     ComplexNumber sc = new ComplexNumber(FastMath.cos(s), FastMath.sin(s));
212     return this.times(sc);
213   }
214 
215   /**
216    * phaseShiftIP
217    *
218    * @param s a double.
219    */
220   public void phaseShiftIP(double s) {
221     ComplexNumber a = this;
222     var sr = FastMath.cos(s);
223     var si = FastMath.sin(s);
224     var real = a.re * sr - a.im * si;
225     var imag = a.re * si + a.im * sr;
226     a.re = real;
227     a.im = imag;
228   }
229 
230   /**
231    * Return a new Complex object whose value is (this + b).
232    *
233    * @param b a {@link ComplexNumber} object.
234    * @return a {@link ComplexNumber} object.
235    */
236   public ComplexNumber plus(ComplexNumber b) {
237     ComplexNumber a = this;
238     var real = a.re + b.re;
239     var imag = a.im + b.im;
240     return new ComplexNumber(real, imag);
241   }
242 
243   /**
244    * plusIP
245    *
246    * @param b a {@link ComplexNumber} object.
247    */
248   public void plusIP(ComplexNumber b) {
249     ComplexNumber a = this;
250     a.re += b.re;
251     a.im += b.im;
252   }
253 
254   /**
255    * re
256    *
257    * @return a double.
258    */
259   public double re() {
260     return re;
261   }
262 
263   /**
264    * re
265    *
266    * @param re a double.
267    */
268   public void re(double re) {
269     this.re = re;
270   }
271 
272   /**
273    * Return a new Complex object whose value is the reciprocal of this.
274    *
275    * @return a {@link ComplexNumber} object.
276    */
277   public ComplexNumber reciprocal() {
278     var scale = re * re + im * im;
279     var iScale = 1.0 / scale;
280     return new ComplexNumber(re * iScale, -im * iScale);
281   }
282 
283   /**
284    * reciprocalIP
285    */
286   public void reciprocalIP() {
287     var scale = re * re + im * im;
288     var iScale = 1.0 / scale;
289     re *= iScale;
290     im *= -iScale;
291   }
292 
293   /**
294    * Return a new Complex object whose value is the complex sine of this.
295    *
296    * @return a {@link ComplexNumber} object.
297    */
298   public ComplexNumber sin() {
299     return new ComplexNumber(FastMath.sin(re) * cosh(im), FastMath.cos(re) * sinh(im));
300   }
301 
302   /**
303    * Return a new Complex object whose value is the complex tangent of this.
304    *
305    * @return a {@link ComplexNumber} object.
306    */
307   public ComplexNumber tan() {
308     return sin().divides(cos());
309   }
310 
311   /**
312    * Return a new Complex object whose value is (this * b).
313    *
314    * @param b a {@link ComplexNumber} object.
315    * @return a {@link ComplexNumber} object.
316    */
317   public ComplexNumber times(ComplexNumber b) {
318     ComplexNumber a = this;
319     var real = a.re * b.re - a.im * b.im;
320     var imag = a.re * b.im + a.im * b.re;
321     return new ComplexNumber(real, imag);
322   }
323 
324   /**
325    * Return a new object whose value is (this * alpha).
326    *
327    * @param alpha a double.
328    * @return a {@link ComplexNumber} object.
329    */
330   public ComplexNumber times(double alpha) {
331     return new ComplexNumber(alpha * re, alpha * im);
332   }
333 
334   /**
335    * timesIP
336    *
337    * @param b a {@link ComplexNumber} object.
338    */
339   public void timesIP(ComplexNumber b) {
340     ComplexNumber a = this;
341     var real = a.re * b.re - a.im * b.im;
342     var imag = a.re * b.im + a.im * b.re;
343     a.re = real;
344     a.im = imag;
345   }
346 
347   /**
348    * timesIP
349    *
350    * @param alpha a double.
351    */
352   public void timesIP(double alpha) {
353     ComplexNumber a = this;
354     a.re *= alpha;
355     a.im *= alpha;
356   }
357 
358   /**
359    * {@inheritDoc}
360    */
361   @Override
362   public String toString() {
363     if (im == 0) {
364       return re + "";
365     }
366     if (re == 0) {
367       return im + "i";
368     }
369     if (im < 0) {
370       return re + " - " + (-im) + "i";
371     }
372     return re + " + " + im + "i";
373   }
374 }