svn path=/branches/mono-1-1-9/mcs/; revision=50438
[mono.git] / mcs / class / System.Drawing / Test / DrawingTest / Exocortex.DSP / src / ComplexStats.cs
1 /*\r
2  * BSD Licence:\r
3  * Copyright (c) 2001, 2002 Ben Houston [ ben@exocortex.org ]\r
4  * Exocortex Technologies [ www.exocortex.org ]\r
5  * All rights reserved.\r
6  *\r
7  * Redistribution and use in source and binary forms, with or without \r
8  * modification, are permitted provided that the following conditions are met:\r
9  *\r
10  * 1. Redistributions of source code must retain the above copyright notice, \r
11  * this list of conditions and the following disclaimer.\r
12  * 2. Redistributions in binary form must reproduce the above copyright \r
13  * notice, this list of conditions and the following disclaimer in the \r
14  * documentation and/or other materials provided with the distribution.\r
15  * 3. Neither the name of the <ORGANIZATION> nor the names of its contributors\r
16  * may be used to endorse or promote products derived from this software\r
17  * without specific prior written permission.\r
18  *\r
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR\r
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \r
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\r
29  * DAMAGE.\r
30  */\r
31 \r
32 using System;\r
33 using System.Diagnostics;\r
34 \r
35 namespace Exocortex.DSP\r
36 {\r
37         // Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org\r
38         // Version: May 4, 2002\r
39         \r
40         /// <summary>\r
41         /// <p>A set of statistical utilities for complex number arrays</p>\r
42         /// </summary>\r
43         public class ComplexStats\r
44         {\r
45                 //---------------------------------------------------------------------------------------------\r
46 \r
47                 private ComplexStats() {\r
48                 }\r
49 \r
50                 //---------------------------------------------------------------------------------------------\r
51                 //--------------------------------------------------------------------------------------------\r
52 \r
53                 /// <summary>\r
54                 /// Calculate the sum\r
55                 /// </summary>\r
56                 /// <param name="data"></param>\r
57                 /// <returns></returns>\r
58                 static public  ComplexF         Sum( ComplexF[] data ) {\r
59                         Debug.Assert( data != null );\r
60                         return  SumRecursion( data, 0, data.Length );\r
61                 }\r
62                 static private ComplexF         SumRecursion( ComplexF[] data, int start, int end ) {\r
63                         Debug.Assert( 0 <= start, "start = " + start );\r
64                         Debug.Assert( start < end, "start = " + start + " and end = " + end );\r
65                         Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );\r
66                         if( ( end - start ) <= 1000 ) {\r
67                                 ComplexF sum = ComplexF.Zero;\r
68                                 for( int i = start; i < end; i ++ ) {\r
69                                         sum += data[ i ];\r
70                                 \r
71                                 }\r
72                                 return  sum;\r
73                         }\r
74                         else {\r
75                                 int middle = ( start + end ) >> 1;\r
76                                 return  SumRecursion( data, start, middle ) + SumRecursion( data, middle, end );\r
77                         }\r
78                 }\r
79 \r
80                 /// <summary>\r
81                 /// Calculate the sum\r
82                 /// </summary>\r
83                 /// <param name="data"></param>\r
84                 /// <returns></returns>\r
85                 static public  Complex          Sum( Complex[] data ) {\r
86                         Debug.Assert( data != null );\r
87                         return  SumRecursion( data, 0, data.Length );\r
88                 }\r
89                 static private Complex          SumRecursion( Complex[] data, int start, int end ) {\r
90                         Debug.Assert( 0 <= start, "start = " + start );\r
91                         Debug.Assert( start < end, "start = " + start + " and end = " + end );\r
92                         Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );\r
93                         if( ( end - start ) <= 1000 ) {\r
94                                 Complex sum = Complex.Zero;\r
95                                 for( int i = start; i < end; i ++ ) {\r
96                                         sum += data[ i ];\r
97                                 \r
98                                 }\r
99                                 return  sum;\r
100                         }\r
101                         else {\r
102                                 int middle = ( start + end ) >> 1;\r
103                                 return  SumRecursion( data, start, middle ) + SumRecursion( data, middle, end );\r
104                         }\r
105                 }\r
106 \r
107                 //--------------------------------------------------------------------------------------------\r
108                 //--------------------------------------------------------------------------------------------\r
109 \r
110                 /// <summary>\r
111                 /// Calculate the sum of squares\r
112                 /// </summary>\r
113                 /// <param name="data"></param>\r
114                 /// <returns></returns>\r
115                 static public ComplexF          SumOfSquares( ComplexF[] data ) {\r
116                         Debug.Assert( data != null );\r
117                         return  SumOfSquaresRecursion( data, 0, data.Length );\r
118                 }\r
119                 static private ComplexF         SumOfSquaresRecursion( ComplexF[] data, int start, int end ) {\r
120                         Debug.Assert( 0 <= start, "start = " + start );\r
121                         Debug.Assert( start < end, "start = " + start + " and end = " + end );\r
122                         Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );\r
123                         if( ( end - start ) <= 1000 ) {\r
124                                 ComplexF sumOfSquares = ComplexF.Zero;\r
125                                 for( int i = start; i < end; i ++ ) {\r
126                                         sumOfSquares += data[ i ] * data[ i ];\r
127                                 \r
128                                 }\r
129                                 return  sumOfSquares;\r
130                         }\r
131                         else {\r
132                                 int middle = ( start + end ) >> 1;\r
133                                 return  SumOfSquaresRecursion( data, start, middle ) + SumOfSquaresRecursion( data, middle, end );\r
134                         }\r
135                 }\r
136 \r
137                 /// <summary>\r
138                 /// Calculate the sum of squares\r
139                 /// </summary>\r
140                 /// <param name="data"></param>\r
141                 /// <returns></returns>\r
142                 static public Complex           SumOfSquares( Complex[] data ) {\r
143                         Debug.Assert( data != null );\r
144                         return  SumOfSquaresRecursion( data, 0, data.Length );\r
145                 }\r
146                 static private Complex          SumOfSquaresRecursion( Complex[] data, int start, int end ) {\r
147                         Debug.Assert( 0 <= start, "start = " + start );\r
148                         Debug.Assert( start < end, "start = " + start + " and end = " + end );\r
149                         Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );\r
150                         if( ( end - start ) <= 1000 ) {\r
151                                 Complex sumOfSquares = Complex.Zero;\r
152                                 for( int i = start; i < end; i ++ ) {\r
153                                         sumOfSquares += data[ i ] * data[ i ];\r
154                                 \r
155                                 }\r
156                                 return  sumOfSquares;\r
157                         }\r
158                         else {\r
159                                 int middle = ( start + end ) >> 1;\r
160                                 return  SumOfSquaresRecursion( data, start, middle ) + SumOfSquaresRecursion( data, middle, end );\r
161                         }\r
162                 }\r
163 \r
164                 //--------------------------------------------------------------------------------------------\r
165                 //--------------------------------------------------------------------------------------------\r
166 \r
167                 /// <summary>\r
168                 /// Calculate the mean (average)\r
169                 /// </summary>\r
170                 /// <param name="data"></param>\r
171                 /// <returns></returns>\r
172                 static public ComplexF          Mean( ComplexF[] data ) {\r
173                         return  ComplexStats.Sum( data ) / data.Length;\r
174                 }\r
175 \r
176                 /// <summary>\r
177                 /// Calculate the mean (average)\r
178                 /// </summary>\r
179                 /// <param name="data"></param>\r
180                 /// <returns></returns>\r
181                 static public Complex           Mean( Complex[] data ) {\r
182                         return  ComplexStats.Sum( data ) / data.Length;\r
183                 }\r
184 \r
185                 /// <summary>\r
186                 /// Calculate the variance\r
187                 /// </summary>\r
188                 /// <param name="data"></param>\r
189                 /// <returns></returns>\r
190                 static public ComplexF  Variance( ComplexF[] data ) {\r
191                         Debug.Assert( data != null );\r
192                         if( data.Length == 0 ) {\r
193                                 throw new DivideByZeroException( "length of data is zero" );\r
194                         }\r
195                         return  ComplexStats.SumOfSquares( data ) / data.Length - ComplexStats.Sum( data );\r
196                 }\r
197                 /// <summary>\r
198                 /// Calculate the variance \r
199                 /// </summary>\r
200                 /// <param name="data"></param>\r
201                 /// <returns></returns>\r
202                 static public Complex   Variance( Complex[] data ) {\r
203                         Debug.Assert( data != null );\r
204                         if( data.Length == 0 ) {\r
205                                 throw new DivideByZeroException( "length of data is zero" );\r
206                         }\r
207                         return  ComplexStats.SumOfSquares( data ) / data.Length - ComplexStats.Sum( data );\r
208                 }\r
209 \r
210                 /// <summary>\r
211                 /// Calculate the standard deviation\r
212                 /// </summary>\r
213                 /// <param name="data"></param>\r
214                 /// <returns></returns>\r
215                 static public ComplexF  StdDev( ComplexF[] data ) {\r
216                         Debug.Assert( data != null );\r
217                         if( data.Length == 0 ) {\r
218                                 throw new DivideByZeroException( "length of data is zero" );\r
219                         }\r
220                         return  ComplexMath.Sqrt( ComplexStats.Variance( data ) );\r
221                 }\r
222                 /// <summary>\r
223                 /// Calculate the standard deviation \r
224                 /// </summary>\r
225                 /// <param name="data"></param>\r
226                 /// <returns></returns>\r
227                 static public Complex   StdDev( Complex[] data ) {\r
228                         Debug.Assert( data != null );\r
229                         if( data.Length == 0 ) {\r
230                                 throw new DivideByZeroException( "length of data is zero" );\r
231                         }\r
232                         return  ComplexMath.Sqrt( ComplexStats.Variance( data ) );\r
233                 }\r
234 \r
235                 //--------------------------------------------------------------------------------------------\r
236                 //--------------------------------------------------------------------------------------------\r
237 \r
238                 /// <summary>\r
239                 /// Calculate the root mean squared (RMS) error between two sets of data.\r
240                 /// </summary>\r
241                 /// <param name="alpha"></param>\r
242                 /// <param name="beta"></param>\r
243                 /// <returns></returns>\r
244                 static public float     RMSError( ComplexF[] alpha, ComplexF[] beta ) {\r
245                         Debug.Assert( alpha != null );\r
246                         Debug.Assert( beta != null );\r
247                         Debug.Assert( beta.Length == alpha.Length );\r
248 \r
249                         return (float) Math.Sqrt( SumOfSquaredErrorRecursion( alpha, beta, 0, alpha.Length ) );\r
250                 }\r
251                 static private float    SumOfSquaredErrorRecursion( ComplexF[] alpha, ComplexF[] beta, int start, int end ) {\r
252                         Debug.Assert( 0 <= start, "start = " + start );\r
253                         Debug.Assert( start < end, "start = " + start + " and end = " + end );\r
254                         Debug.Assert( end <= alpha.Length, "end = " + end + " and alpha.Length = " + alpha.Length );\r
255                         Debug.Assert( beta.Length == alpha.Length );\r
256                         if( ( end - start ) <= 1000 ) {\r
257                                 float sumOfSquaredError = 0;\r
258                                 for( int i = start; i < end; i ++ ) {\r
259                                         ComplexF delta = beta[ i ] - alpha[ i ];\r
260                                         sumOfSquaredError += ( delta.Re * delta.Re ) + ( delta.Im * delta.Im );\r
261                                 \r
262                                 }\r
263                                 return  sumOfSquaredError;\r
264                         }\r
265                         else {\r
266                                 int middle = ( start + end ) >> 1;\r
267                                 return  SumOfSquaredErrorRecursion( alpha, beta, start, middle ) + SumOfSquaredErrorRecursion( alpha, beta, middle, end );\r
268                         }\r
269                 }\r
270 \r
271                 /// <summary>\r
272                 /// Calculate the root mean squared (RMS) error between two sets of data.\r
273                 /// </summary>\r
274                 /// <param name="alpha"></param>\r
275                 /// <param name="beta"></param>\r
276                 /// <returns></returns>\r
277                 static public double    RMSError( Complex[] alpha, Complex[] beta ) {\r
278                         Debug.Assert( alpha != null );\r
279                         Debug.Assert( beta != null );\r
280                         Debug.Assert( beta.Length == alpha.Length );\r
281 \r
282                         return Math.Sqrt( SumOfSquaredErrorRecursion( alpha, beta, 0, alpha.Length ) );\r
283                 }\r
284                 static private double   SumOfSquaredErrorRecursion( Complex[] alpha, Complex[] beta, int start, int end ) {\r
285                         Debug.Assert( 0 <= start, "start = " + start );\r
286                         Debug.Assert( start < end, "start = " + start + " and end = " + end );\r
287                         Debug.Assert( end <= alpha.Length, "end = " + end + " and alpha.Length = " + alpha.Length );\r
288                         Debug.Assert( beta.Length == alpha.Length );\r
289                         if( ( end - start ) <= 1000 ) {\r
290                                 double sumOfSquaredError = 0;\r
291                                 for( int i = start; i < end; i ++ ) {\r
292                                         Complex delta = beta[ i ] - alpha[ i ];\r
293                                         sumOfSquaredError += ( delta.Re * delta.Re ) + ( delta.Im * delta.Im );\r
294                                 \r
295                                 }\r
296                                 return  sumOfSquaredError;\r
297                         }\r
298                         else {\r
299                                 int middle = ( start + end ) >> 1;\r
300                                 return  SumOfSquaredErrorRecursion( alpha, beta, start, middle ) + SumOfSquaredErrorRecursion( alpha, beta, middle, end );\r
301                         }\r
302                 }\r
303 \r
304 \r
305         }\r
306 }\r