1   package org.djutils.math.polynomialroots;
2   
3   import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4   import static org.junit.jupiter.api.Assertions.assertEquals;
5   
6   import org.djutils.math.complex.Complex;
7   import org.junit.jupiter.api.Test;
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  public class TestPolynomialRoots2
19  {
20  
21      
22  
23  
24  
25      @Test
26      public void quadraticTest()
27      {
28          double[] paramValues = new double[] {0, 1, 2, 3, 4, Math.PI, -Math.E, 0.0001, 10000};
29          for (double a : paramValues)
30          {
31              for (double b : paramValues)
32              {
33                  for (double c : paramValues)
34                  {
35                      
36                      Complex[] roots = PolynomialRoots2.quadraticRoots(a, b, c);
37                      int expectedNumber = a != 0 ? 2 : b != 0 ? 1 : 0;
38                      assertEquals(expectedNumber, roots.length, "number of roots");
39                      
40                      
41                      for (Complex root : roots)
42                      {
43                          
44                          Complex result = root.times(root).times(a).plus(root.times(b)).plus(c);
45                          double margin = Math.max(root.norm() / 1e6, 1E-300);
46                          assertEquals(0, result.re, margin, "root is a root of the equation; re");
47                          assertEquals(0, result.im, margin, "root is a root of the equation; im");
48                      }
49                      
50                      Complex[] alternate = PolynomialRoots2.cubicRootsDurandKerner(0, a, b, c);
51                      assertArrayEquals(roots, alternate, "cubic solver returns same results as quadratic solver if a is 0");
52                  }
53              }
54          }
55          double q1 = 3 * Math.sqrt(Double.MAX_VALUE);
56          Complex[] roots = PolynomialRoots2.quadraticRoots(q1, 1);
57          assertEquals(2, roots.length, "two roots");
58          assertEquals(0, roots[0].re, 0.0001, "first root is 0: re");
59          assertEquals(0, roots[0].im, 0.0001, "first root is 0: im");
60          
61          assertEquals(-q1, roots[1].re, q1 / 1e7, "second root is 0: re");
62          assertEquals(0, roots[1].im, 0.0001, "second root is 0: im");
63      }
64  
65      
66  
67  
68      @Test
69      public void cubicTestDurandKerner()
70      {
71          double[] paramValues = new double[] {0, 1, 2, 3, 4, Math.PI, -Math.E, 0.001, 1000};
72          for (double a : paramValues)
73          {
74              for (double b : paramValues)
75              {
76                  for (double c : paramValues)
77                  {
78                      for (double d : paramValues)
79                      {
80                          
81                          Complex[] roots = PolynomialRoots2.cubicRootsDurandKerner(a, b, c, d);
82                          int expectedNumber = a != 0 ? 3 : b != 0 ? 2 : c != 0 ? 1 : 0;
83                          assertEquals(expectedNumber, roots.length, "number of roots");
84                          
85                          
86                          for (Complex root : roots)
87                          {
88                              
89                              Complex result = root.times(root).times(root).times(a).plus(root.times(root).times(b))
90                                      .plus(root.times(c)).plus(d);
91                              double margin = Math.max(root.norm() / 1e6, 1E-300);
92                              assertEquals(0, result.re, margin, "root is a root of the equation; re");
93                              assertEquals(0, result.im, margin, "root is a root of the equation; im");
94                          }
95                          
96                      }
97                  }
98              }
99          }
100     }
101 
102     
103 
104 
105     @Test
106     public void quarticTestDurandKerner()
107     {
108         double[] paramValues = new double[] {0, 1, 2, 3, 4, Math.PI, -Math.E, 0.01, 100};
109         for (double a : paramValues)
110         {
111             for (double b : paramValues)
112             {
113                 for (double c : paramValues)
114                 {
115                     for (double d : paramValues)
116                     {
117                         for (double e : paramValues)
118                         {
119                             
120                             Complex[] roots = PolynomialRoots2.quarticRootsDurandKerner(a, b, c, d, e);
121                             int expectedNumber = a != 0 ? 4 : b != 0 ? 3 : c != 0 ? 2 : d != 0 ? 1 : 0;
122                             assertEquals(expectedNumber, roots.length, "number of roots");
123                             
124                             
125                             for (Complex root : roots)
126                             {
127                                 
128                                 
129                                 Complex result = root.times(root).times(root).times(root).times(a)
130                                         .plus(root.times(root).times(root).times(b)).plus(root.times(root).times(c))
131                                         .plus(root.times(d)).plus(e);
132                                 double margin = Math.max(root.norm() / 2e5, 1E-300);
133                                 assertEquals(0, result.re, margin, a + " x^4 + " + b + " x^3 + " + c + " x^2 + " + d + " x + " + e
134                                                 + " = 0 : root is a root of the equation; re");
135                                 assertEquals(0, result.im, margin, a + " x^4 + " + b + " x^3 + " + c + " x^2 + " + d + " x + " + e
136                                                 + " = 0 : root is a root of the equation; im");
137                             }
138                             
139                         }
140                     }
141                 }
142             }
143         }
144     }
145 
146     
147 
148 
149     @Test
150     public void cubicTestAberthEhrlich()
151     {
152         double[] paramValues = new double[] {0, 1, 2, 3, 4, Math.PI, -Math.E, 0.001, 1000};
153         for (double a : paramValues)
154         {
155             for (double b : paramValues)
156             {
157                 for (double c : paramValues)
158                 {
159                     for (double d : paramValues)
160                     {
161                         
162                         Complex[] roots = PolynomialRoots2.cubicRootsAberthEhrlich(a, b, c, d);
163                         int expectedNumber = a != 0 ? 3 : b != 0 ? 2 : c != 0 ? 1 : 0;
164                         assertEquals(expectedNumber, roots.length, "number of roots");
165                         
166                         
167                         for (Complex root : roots)
168                         {
169                             
170                             Complex result = root.times(root).times(root).times(a).plus(root.times(root).times(b))
171                                     .plus(root.times(c)).plus(d);
172                             double margin = Math.max(root.norm() / 1e6, 1E-300);
173                             assertEquals(0, result.re, margin, "root is a root of the equation; re");
174                             assertEquals(0, result.im, margin, "root is a root of the equation; im");
175                         }
176                         
177                     }
178                 }
179             }
180         }
181     }
182 
183     
184 
185 
186     @Test
187     public void quarticTestAberthEhrlich()
188     {
189         double[] paramValues = new double[] {0, 1, 2, 3, 4, Math.PI, -Math.E, 0.01, 100};
190         for (double a : paramValues)
191         {
192             for (double b : paramValues)
193             {
194                 for (double c : paramValues)
195                 {
196                     for (double d : paramValues)
197                     {
198                         for (double e : paramValues)
199                         {
200                             
201                             Complex[] roots = PolynomialRoots2.quarticRootsAberthEhrlich(a, b, c, d, e);
202                             int expectedNumber = a != 0 ? 4 : b != 0 ? 3 : c != 0 ? 2 : d != 0 ? 1 : 0;
203                             assertEquals(expectedNumber, roots.length, "number of roots");
204                             
205                             
206                             for (Complex root : roots)
207                             {
208                                 
209                                 
210                                 Complex result = root.times(root).times(root).times(root).times(a)
211                                         .plus(root.times(root).times(root).times(b)).plus(root.times(root).times(c))
212                                         .plus(root.times(d)).plus(e);
213                                 double margin = Math.max(root.norm() / 2e5, 1E-300);
214                                 assertEquals(0, result.re, margin, a + " x^4 + " + b + " x^3 + " + c + " x^2 + " + d + " x + " + e
215                                                 + " = 0 : root is a root of the equation; re");
216                                 assertEquals(0, result.im, margin, a + " x^4 + " + b + " x^3 + " + c + " x^2 + " + d + " x + " + e
217                                                 + " = 0 : root is a root of the equation; im");
218                             }
219                             
220                         }
221                     }
222                 }
223             }
224         }
225     }
226 
227     
228 
229 
230 
231     public void cubicTestNewtonFactor()
232     {
233         double[] paramValues = new double[] {0, 1, 2, 3, 4, Math.PI, -Math.E, 0.001, 1000};
234         for (double a : paramValues)
235         {
236             for (double b : paramValues)
237             {
238                 for (double c : paramValues)
239                 {
240                     for (double d : paramValues)
241                     {
242                         
243                         Complex[] roots = PolynomialRoots2.cubicRootsNewtonFactor(a, b, c, d);
244                         int expectedNumber = a != 0 ? 3 : b != 0 ? 2 : c != 0 ? 1 : 0;
245                         assertEquals(expectedNumber, roots.length, "number of roots");
246                         
247                         
248                         for (Complex root : roots)
249                         {
250                             
251                             Complex result = root.times(root).times(root).times(a).plus(root.times(root).times(b))
252                                     .plus(root.times(c)).plus(d);
253                             double margin = Math.max(root.norm() / 1e4, 1E-3);
254                             String eq = a + " x^3 + " + b + " x^2 + " + c + " x + " + d + " = 0";
255                             assertEquals(0, result.re, margin, eq + ", root=" + root + ", result=" + result + "; re");
256                             assertEquals(0, result.im, margin, eq + ", root=" + root + ", result=" + result + "; im");
257                         }
258                         
259                     }
260                 }
261             }
262         }
263     }
264 
265 }