OSDN Git Service

Merge branch 'master' of git.sourceforge.jp:/gitroot/karinto/karinto
[karinto/karinto.git] / Karinto / PointList.cs
1 /*\r
2  *      Karinto Library Project\r
3  *\r
4  *      This software is distributed under a zlib-style license.\r
5  *      See license.txt for more information.\r
6  */\r
7 \r
8 using System;\r
9 using System.Collections.Generic;\r
10 using System.Data;\r
11 \r
12 namespace Karinto\r
13 {\r
14     public class PointList : List<Point>, ICloneable\r
15     {\r
16         #region properties\r
17         /// <summary>\r
18         ///     最初の点\r
19         /// </summary>\r
20         public Point First\r
21         {\r
22             get { return this[0]; }\r
23         }\r
24 \r
25         /// <summary>\r
26         ///     最後の点\r
27         /// </summary>\r
28         public Point Last\r
29         {\r
30             get { return this[this.Count - 1]; }\r
31         }\r
32 \r
33         /// <summary>\r
34         ///     Xの配列\r
35         /// </summary>\r
36         public double[] XArray\r
37         {\r
38             get\r
39             {\r
40                 double[] array = new double[this.Count];\r
41                 for (int i = 0; i < this.Count; ++i) { array[i] = this[i].X; }\r
42                 return array;\r
43             }\r
44             set\r
45             {\r
46                 if (value.Length != this.Count)\r
47                 {\r
48                     throw new ArgumentException("The input array is too short or long.");\r
49                 }\r
50                 for (int i = 0; i < value.Length; ++i) { this[i].X = value[i]; }\r
51             }\r
52         }\r
53 \r
54         /// <summary>\r
55         ///     Yの配列\r
56         /// </summary>\r
57         public double[] YArray\r
58         {\r
59             get\r
60             {\r
61                 double[] array = new double[this.Count];\r
62                 for (int i = 0; i < this.Count; ++i) { array[i] = this[i].Y; }\r
63                 return array;\r
64             }\r
65             set\r
66             {\r
67                 if (value.Length != this.Count)\r
68                 {\r
69                     throw new ArgumentException("The input array is too short or long.");\r
70                 }\r
71                 for (int i = 0; i < value.Length; ++i) { this[i].Y = value[i]; }\r
72             }\r
73         }\r
74 \r
75         /// <summary>\r
76         ///     Xの最小値\r
77         /// </summary>\r
78         public double XMin\r
79         {\r
80             get\r
81             {\r
82                 double min = XArray[0];\r
83                 foreach (Point p in this) { if (min > p.X) min = p.X; }\r
84                 return min;\r
85             }\r
86         }\r
87 \r
88         /// <summary>\r
89         ///     Xの最大値\r
90         /// </summary>\r
91         public double XMax\r
92         {\r
93             get\r
94             {\r
95                 double max = XArray[0];\r
96                 foreach (Point p in this) { if (max < p.X) max = p.X; }\r
97                 return max;\r
98             }\r
99         }\r
100 \r
101         /// <summary>\r
102         ///     Yの最小値\r
103         /// </summary>\r
104         public double YMin\r
105         {\r
106             get\r
107             {\r
108                 double min = YArray[0];\r
109                 foreach (Point p in this) { if (min > p.Y) min = p.Y; }\r
110                 return min;\r
111             }\r
112         }\r
113 \r
114         /// <summary>\r
115         ///     Yの最大値\r
116         /// </summary>\r
117         public double YMax\r
118         {\r
119             get\r
120             {\r
121                 double max = YArray[0];\r
122                 foreach (Point p in this) { if (max < p.Y) max = p.Y; }\r
123                 return max;\r
124             }\r
125         }\r
126 \r
127         /// <summary>\r
128         ///     Xの平均\r
129         /// </summary>\r
130         public double XAverage\r
131         {\r
132             get\r
133             {\r
134                 double sum = 0.0;\r
135                 foreach (Point p in this) { sum += p.X; }\r
136                 return sum / this.Count;\r
137             }\r
138         }\r
139 \r
140         /// <summary>\r
141         ///     Yの平均\r
142         /// </summary>\r
143         public double YAverage\r
144         {\r
145             get\r
146             {\r
147                 double sum = 0.0;\r
148                 foreach (Point p in this) { sum += p.Y; }\r
149                 return sum / this.Count;\r
150             }\r
151         }\r
152 \r
153         /// <summary>\r
154         ///     Xの分散\r
155         /// </summary>\r
156         public double XVariance\r
157         {\r
158             get\r
159             {\r
160                 double avg = this.XAverage;\r
161                 double var = 0.0;\r
162                 foreach (Point d in this)\r
163                 {\r
164                     double dif = (d.X - avg);\r
165                     var += dif * dif;\r
166                 }\r
167                 return var / this.Count;\r
168             }\r
169         }\r
170 \r
171         /// <summary>\r
172         ///     Yの分散\r
173         /// </summary>\r
174         public double YVariance\r
175         {\r
176             get\r
177             {\r
178                 double avg = this.YAverage;\r
179                 double var = 0.0;\r
180                 foreach (Point d in this)\r
181                 {\r
182                     double dif = (d.Y - avg);\r
183                     var += dif * dif;\r
184                 }\r
185                 return var / this.Count;\r
186             }\r
187         }\r
188 \r
189         /// <summary>\r
190         ///     共分散\r
191         /// </summary>\r
192         public double Covariance\r
193         {\r
194             get\r
195             {\r
196                 double avgX = this.XAverage;\r
197                 double avgY = this.YAverage;\r
198                 double var = 0.0;\r
199                 foreach (Point d in this)\r
200                 {\r
201                     var += (d.X - avgX) * (d.Y - avgY);\r
202                 }\r
203                 return var / this.Count;\r
204             }\r
205         }\r
206 \r
207         /// <summary>\r
208         ///     R2乗値\r
209         /// </summary>\r
210         public double R2\r
211         {\r
212             get\r
213             {\r
214                 double cov = Covariance;\r
215                 double var = XVariance * YVariance;\r
216 \r
217                 if (Math.Abs(cov) < Double.Epsilon && Math.Abs(var) < Double.Epsilon)\r
218                 {\r
219                     return 1.0; // とりあえず実質1点のみの場合は1 数学的には不定の方が正しい?\r
220                 }\r
221                 return cov * cov / var;\r
222             }\r
223         }\r
224 \r
225         /// <summary>\r
226         ///     Xの値域\r
227         /// </summary>\r
228         public Range XRange\r
229         {\r
230             get\r
231             {\r
232                 return new Range(XMin, XMax);\r
233             }\r
234         }\r
235 \r
236         /// <summary>\r
237         ///     Yの値域\r
238         /// </summary>\r
239         public Range YRange\r
240         {\r
241             get\r
242             {\r
243                 return new Range(YMin, YMax);\r
244             }\r
245         }\r
246         \r
247         /// <summary>\r
248         ///     広義単調増加か否か\r
249         /// </summary>\r
250         public bool MonotonicallyIncreasing\r
251         {\r
252             get\r
253             {\r
254                 PointList sorted = (PointList)Clone();\r
255                 sorted.SortByX();\r
256                 double yPrev = sorted.First.Y;\r
257                 for (int i = 1; i < Count; ++i)\r
258                 {\r
259                     double yCur = this[i].Y;\r
260                     if (yCur < yPrev) return false;\r
261                     yPrev = yCur;\r
262                 }\r
263                 return true;\r
264             }\r
265         }\r
266 \r
267         /// <summary>\r
268         ///     広義単調減少か否か\r
269         /// </summary>\r
270         public bool MonotonicallyDecreasing\r
271         {\r
272             get\r
273             {\r
274                 PointList sorted = (PointList)Clone();\r
275                 sorted.SortByX();\r
276                 double yPrev = sorted.First.Y;\r
277                 for (int i = 1; i < Count; ++i)\r
278                 {\r
279                     double yCur = this[i].Y;\r
280                     if (yCur > yPrev) return false;\r
281                     yPrev = yCur;\r
282                 }\r
283                 return true;\r
284             }\r
285         }\r
286         #endregion\r
287 \r
288         #region constructors\r
289 \r
290         public PointList() : base() { }\r
291 \r
292         public PointList(PointList points)\r
293             : base(points.Count)\r
294         {\r
295             foreach (Point p in points) { this.Add(new Point(p)); }\r
296         }\r
297 \r
298         public PointList(Point[] points)\r
299             : base(points.Length)\r
300         {\r
301             foreach (Point p in points) { this.Add(new Point(p)); }\r
302         }\r
303 \r
304         public PointList(double[] xArray, double[] yArray)\r
305             : base(xArray.Length)\r
306         {\r
307             if (xArray.Length != yArray.Length)\r
308             {\r
309                 throw new ArgumentException("xArray and yArray must be same length");\r
310             }\r
311             for (int i = 0; i < xArray.Length; ++i)\r
312             {\r
313                 this.Add(xArray[i], yArray[i]);\r
314             }\r
315         }\r
316 \r
317         public PointList(FilePath path)\r
318         {\r
319             CsvReader<Point> reader = new CsvReader<Point>();\r
320             List<Point> points = reader.Read(path);\r
321             foreach (Point p in points) { this.Add(new Point(p)); }\r
322         }\r
323         #endregion\r
324 \r
325         #region public methods\r
326         /// <summary>\r
327         ///     点を追加\r
328         /// </summary>\r
329         /// <param name="x">点のx値</param>\r
330         /// <param name="y">点のy値</param>\r
331         public void Add(double x, double y)\r
332         {\r
333             this.Add(new Point(x, y));\r
334         }\r
335 \r
336         public Object Clone()\r
337         {\r
338             return (Object)new PointList(this);\r
339         }\r
340 \r
341         /// <summary>\r
342         ///     Xの値で昇順に並び変える\r
343         /// </summary>\r
344         public void SortByX()\r
345         {\r
346             Sort(Point.XComparer);\r
347         }\r
348 \r
349         /// <summary>\r
350         ///     Yの値で昇順に並び変える\r
351         /// </summary>\r
352         public void SortByY()\r
353         {\r
354             Sort(Point.YComparer);\r
355         }\r
356 \r
357         /// <summary>\r
358         ///     点列の各要素を定数倍する\r
359         /// </summary>\r
360         /// <param name="scale">x,yそれぞれに掛ける係数からなる点</param>\r
361         public void Stretch(Point scale)\r
362         {\r
363             for (int i = 0; i < Count; ++i)\r
364             {\r
365                 this[i] = this[i].Stretch(scale);\r
366             }\r
367         }\r
368 \r
369         public void SwapXY()\r
370         {\r
371             for (int i = 0; i < Count; ++i)\r
372             {\r
373                 this[i].SwapXY();\r
374             }\r
375         }\r
376 \r
377         public DataTable ToDataTable()\r
378         {\r
379             DataTable table = new Xml.Data.PointListDataTable();\r
380             for (int i = 0; i < Count; ++i)\r
381             {\r
382                 Xml.Data.PointListRow row = table.NewRow() as Xml.Data.PointListRow;\r
383                 row.X = this[i].X;\r
384                 row.Y = this[i].Y;\r
385                 table.Rows.Add(row);\r
386             }\r
387             return table;\r
388         }\r
389 \r
390         #endregion\r
391     }\r
392 }\r