cat_engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/cat_engine.gemspec +30 -0
- data/lib/cat_engine.rb +11 -0
- data/lib/cat_engine/bank.rb +57 -0
- data/lib/cat_engine/config.rb +12 -0
- data/lib/cat_engine/engine.rb +34 -0
- data/lib/cat_engine/flat_engine.rb +40 -0
- data/lib/cat_engine/question.rb +83 -0
- data/lib/cat_engine/rails.rb +7 -0
- data/lib/cat_engine/response.rb +50 -0
- data/lib/cat_engine/version.rb +3 -0
- data/lib/tasks/cat_engine_tasks.rake +9 -0
- data/vendor/cat_engine/CATEngine3.cs +2123 -0
- data/vendor/cat_engine/IEngine.cs +65 -0
- data/vendor/cat_engine/ShellWrapper.cs +44 -0
- data/vendor/cat_engine/Util.cs +825 -0
- metadata +169 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
namespace CORE.Engines
|
3
|
+
{
|
4
|
+
using System;
|
5
|
+
using System.Xml;
|
6
|
+
|
7
|
+
public interface IEngine
|
8
|
+
{
|
9
|
+
|
10
|
+
XmlDocument getCurrentItem();
|
11
|
+
XmlDocument getPreviousItem();
|
12
|
+
XmlDocument getNextItem();
|
13
|
+
XmlDocument getForm();
|
14
|
+
|
15
|
+
|
16
|
+
void updateNode(XmlNode node);
|
17
|
+
bool loadItems(XmlDocument doc, XmlDocument FormParams, bool WithHeader);
|
18
|
+
|
19
|
+
void decrementPosition();
|
20
|
+
void incrementPosition();
|
21
|
+
void rollbackPosition();
|
22
|
+
|
23
|
+
bool finished
|
24
|
+
{
|
25
|
+
get;
|
26
|
+
}
|
27
|
+
bool IsCompleted
|
28
|
+
{
|
29
|
+
get;
|
30
|
+
}
|
31
|
+
bool IsResume
|
32
|
+
{
|
33
|
+
get;
|
34
|
+
}
|
35
|
+
int currentPosition
|
36
|
+
{
|
37
|
+
get;
|
38
|
+
set;
|
39
|
+
}
|
40
|
+
int previousPosition
|
41
|
+
{
|
42
|
+
get;
|
43
|
+
set;
|
44
|
+
}
|
45
|
+
|
46
|
+
int TotalItems
|
47
|
+
{
|
48
|
+
get;
|
49
|
+
}
|
50
|
+
|
51
|
+
string message
|
52
|
+
{
|
53
|
+
get;
|
54
|
+
set;
|
55
|
+
}
|
56
|
+
|
57
|
+
string paramPROC
|
58
|
+
{
|
59
|
+
get;
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
}
|
64
|
+
|
65
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
namespace CORE.Engines
|
2
|
+
{
|
3
|
+
using System;
|
4
|
+
using System.Xml;
|
5
|
+
|
6
|
+
public class ShellWrapper
|
7
|
+
{
|
8
|
+
static void Main(string[] args)
|
9
|
+
{
|
10
|
+
// get form id from command line args
|
11
|
+
string formID = args[0];
|
12
|
+
|
13
|
+
XmlDocument doc = new XmlDocument();
|
14
|
+
doc.Load("forms/" + formID + ".xml");
|
15
|
+
|
16
|
+
XmlDocument formParams = new XmlDocument();
|
17
|
+
formParams.Load("parameters/" + formID + ".xml");
|
18
|
+
|
19
|
+
CATEngine3 e = new CATEngine3();
|
20
|
+
e.loadItems(doc, formParams, true);
|
21
|
+
|
22
|
+
// get answers from command line args if they exist
|
23
|
+
string responseID = "";
|
24
|
+
for(int i = 1; i < args.Length; i++) {
|
25
|
+
responseID = args[i];
|
26
|
+
XmlDocument nextItem = e.getNextItem();
|
27
|
+
XmlElement item = (XmlElement)nextItem.GetElementsByTagName("Item")[0];
|
28
|
+
item.SetAttribute("ItemResponseOID", responseID);
|
29
|
+
// item.Attributes["Response"].Value = responseID;
|
30
|
+
// item.Attributes["ResponseTime"].Value = "10";
|
31
|
+
e.updateNode(item);
|
32
|
+
}
|
33
|
+
|
34
|
+
if(e.finished) {
|
35
|
+
double theta = e.ThetaHistory[e.ThetaHistory.Length - 1];
|
36
|
+
double stdError = e.StdErrorHistory[e.StdErrorHistory.Length - 1];
|
37
|
+
Console.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Results Theta=\"" + theta + "\" StdError=\"" + stdError + "\" />");
|
38
|
+
|
39
|
+
} else {
|
40
|
+
e.getCurrentItem().Save(Console.Out);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1,825 @@
|
|
1
|
+
namespace CORE.Engines
|
2
|
+
{
|
3
|
+
using System;
|
4
|
+
using System.Collections;
|
5
|
+
using System.Collections.Generic;
|
6
|
+
using System.IO;
|
7
|
+
using System.Linq;
|
8
|
+
using System.Text;
|
9
|
+
|
10
|
+
|
11
|
+
/// <summary>
|
12
|
+
/// A set of general utilities.
|
13
|
+
/// </summary>
|
14
|
+
public class Util
|
15
|
+
{
|
16
|
+
/// <summary>
|
17
|
+
/// Enumerator for the dimension type. These are dimension names for a matrix.
|
18
|
+
/// </summary>
|
19
|
+
public enum DimensionType
|
20
|
+
{
|
21
|
+
/// <summary>Dimension 0</summary>
|
22
|
+
Row,
|
23
|
+
/// <summary>Dimension 1</summary>
|
24
|
+
Column,
|
25
|
+
/// <summary>Dimension 2</summary>
|
26
|
+
Depth
|
27
|
+
};
|
28
|
+
|
29
|
+
/// <summary>
|
30
|
+
/// Reads a two-dimensional table of numbers from a text file.
|
31
|
+
/// </summary>
|
32
|
+
/// <param name="SourceFilename">The source filename.</param>
|
33
|
+
/// <param name="Delimiter">The delimiter separating the numeric values.</param>
|
34
|
+
/// <returns>A two-dimensional array of numbers (double data type).</returns>
|
35
|
+
/// <remarks>Assumes carriage return/line feed at the end of every row.
|
36
|
+
/// Assumes no delimiter at the end of every row.</remarks>
|
37
|
+
public static double[][] Read2DNumericTable(string SourceFilename, string Delimiter)
|
38
|
+
{
|
39
|
+
double[][] data;
|
40
|
+
FileInfo SourceFile;
|
41
|
+
StreamReader Reader;
|
42
|
+
ArrayList ar1d;
|
43
|
+
ArrayList ar2d;
|
44
|
+
int start;
|
45
|
+
int end;
|
46
|
+
|
47
|
+
ar2d = new ArrayList();
|
48
|
+
SourceFile = new FileInfo(SourceFilename);
|
49
|
+
Reader = SourceFile.OpenText();
|
50
|
+
string TextLine;
|
51
|
+
do {
|
52
|
+
TextLine = Reader.ReadLine();
|
53
|
+
if ( TextLine != null ) {
|
54
|
+
TextLine = TextLine.Trim();
|
55
|
+
ar1d = new ArrayList();
|
56
|
+
start = 0;
|
57
|
+
end = 0;
|
58
|
+
while ( end != -1 ) {
|
59
|
+
end = TextLine.IndexOf(Delimiter, start);
|
60
|
+
if ( start != end ) {
|
61
|
+
//if start == end then delimiter is the next character so skip it
|
62
|
+
if ( end == -1 && TextLine.Length != 0 ) {
|
63
|
+
//Last number in the line with no delimiter at the end
|
64
|
+
ar1d.Add(Convert.ToDouble(TextLine.Substring(start).Trim()));
|
65
|
+
}
|
66
|
+
else {
|
67
|
+
ar1d.Add(Convert.ToDouble(TextLine.Substring(start, (end - start)).Trim()));
|
68
|
+
}
|
69
|
+
}
|
70
|
+
start = end + 1;
|
71
|
+
}
|
72
|
+
ar2d.Add(ar1d.ToArray(typeof(double)));
|
73
|
+
}
|
74
|
+
} while ( TextLine != null );
|
75
|
+
|
76
|
+
data = (double[][])ar2d.ToArray(typeof(double[]));
|
77
|
+
Reader.Close();
|
78
|
+
|
79
|
+
return data;
|
80
|
+
}
|
81
|
+
|
82
|
+
/// <summary>
|
83
|
+
/// Reads a list of numbers from a text file
|
84
|
+
/// </summary>
|
85
|
+
/// <param name="SourceFilename">The source filename.</param>
|
86
|
+
/// <returns>An array of numbers (double data type)</returns>
|
87
|
+
/// <remarks>Assumes carriage return/line feed at the end of every line, with one number per line.
|
88
|
+
/// Lines that cannot be evaluated to valid numbers are skipped.</remarks>
|
89
|
+
public static double[] ReadNumericList(string SourceFilename)
|
90
|
+
{
|
91
|
+
double result;
|
92
|
+
|
93
|
+
List<double> liList = new List<double>();
|
94
|
+
FileInfo SourceFile = new FileInfo(SourceFilename);
|
95
|
+
StreamReader Reader = SourceFile.OpenText();
|
96
|
+
string TextLine;
|
97
|
+
|
98
|
+
do {
|
99
|
+
TextLine = Reader.ReadLine();
|
100
|
+
if (TextLine != null) {
|
101
|
+
TextLine = TextLine.Trim();
|
102
|
+
if (double.TryParse(TextLine, out result)) {
|
103
|
+
liList.Add(result);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
} while (TextLine != null);
|
107
|
+
|
108
|
+
Reader.Close();
|
109
|
+
|
110
|
+
return liList.ToArray();
|
111
|
+
}
|
112
|
+
|
113
|
+
|
114
|
+
#region WriteNumericArrayToFile (overloaded)
|
115
|
+
|
116
|
+
/// <summary>
|
117
|
+
/// Writes a two-dimensional table of numbers to a text file.
|
118
|
+
/// </summary>
|
119
|
+
/// <param name="TargetFilename">The target filename.</param>
|
120
|
+
/// <param name="AppendToFile">If set to <c>true</c> append to the end of the file.</param>
|
121
|
+
/// <param name="Delimiter">The delimiter separating the numeric values.</param>
|
122
|
+
/// <param name="data">The data to be written.</param>
|
123
|
+
/// <remarks>Data is a 2D jagged array.</remarks>
|
124
|
+
public static void WriteNumericArrayToFile(string TargetFilename, bool AppendToFile, string Delimiter, double[][] data)
|
125
|
+
{
|
126
|
+
StreamWriter Writer;
|
127
|
+
int i;
|
128
|
+
int j;
|
129
|
+
|
130
|
+
Writer = new StreamWriter(TargetFilename, AppendToFile);
|
131
|
+
StringBuilder TextLine;
|
132
|
+
for ( i = 0; i < data.Length; i++ ) {
|
133
|
+
TextLine = new StringBuilder();
|
134
|
+
for ( j = 0; j < data[i].Length; j++ ) {
|
135
|
+
TextLine.Append(data[i][j]);
|
136
|
+
//no delimiter at the end
|
137
|
+
if ( j != data[i].Length - 1 ) {
|
138
|
+
TextLine.Append(Delimiter);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
Writer.WriteLine(TextLine.ToString());
|
142
|
+
}
|
143
|
+
Writer.Close();
|
144
|
+
}
|
145
|
+
|
146
|
+
/// <summary>
|
147
|
+
/// Writes a two-dimensional table of numbers to a text file.
|
148
|
+
/// </summary>
|
149
|
+
/// <param name="TargetFilename">The target filename.</param>
|
150
|
+
/// <param name="AppendToFile">If set to <c>true</c> append to the end of the file.</param>
|
151
|
+
/// <param name="Delimiter">The delimiter separating the numeric values.</param>
|
152
|
+
/// <param name="data">The data to be written.</param>
|
153
|
+
/// <remarks>Data is a 2D rectangular array.</remarks>
|
154
|
+
public static void WriteNumericArrayToFile(string TargetFilename, bool AppendToFile, string Delimiter, double[,] data)
|
155
|
+
{
|
156
|
+
StreamWriter Writer;
|
157
|
+
int i;
|
158
|
+
int j;
|
159
|
+
|
160
|
+
Writer = new StreamWriter(TargetFilename, AppendToFile);
|
161
|
+
StringBuilder TextLine;
|
162
|
+
for ( i = 0; i < data.GetLength(0); i++ ) {
|
163
|
+
TextLine = new StringBuilder();
|
164
|
+
for ( j = 0; j < data.GetLength(1); j++ ) {
|
165
|
+
TextLine.Append(data[i, j]);
|
166
|
+
//no delimiter at the end
|
167
|
+
if ( j != data.GetLength(1) - 1 ) {
|
168
|
+
TextLine.Append(Delimiter);
|
169
|
+
}
|
170
|
+
}
|
171
|
+
Writer.WriteLine(TextLine.ToString());
|
172
|
+
}
|
173
|
+
Writer.Close();
|
174
|
+
}
|
175
|
+
|
176
|
+
/// <summary>
|
177
|
+
/// Writes an array of numbers to a text file.
|
178
|
+
/// </summary>
|
179
|
+
/// <param name="TargetFilename">The target filename.</param>
|
180
|
+
/// <param name="AppendToFile">If set to <c>true</c> append to the end of the file.</param>
|
181
|
+
/// <param name="Delimiter">The delimiter separating the numeric values.</param>
|
182
|
+
/// <param name="data">The data to be written.</param>
|
183
|
+
/// <remarks>Data is a 1D array.</remarks>
|
184
|
+
public static void WriteNumericArrayToFile(string TargetFilename, bool AppendToFile, string Delimiter, double[] data)
|
185
|
+
{
|
186
|
+
StreamWriter Writer;
|
187
|
+
int i;
|
188
|
+
|
189
|
+
Writer = new StreamWriter(TargetFilename, AppendToFile);
|
190
|
+
StringBuilder TextLine;
|
191
|
+
TextLine = new StringBuilder();
|
192
|
+
for ( i = 0; i < data.Length; i++ ) {
|
193
|
+
TextLine.Append(data[i]);
|
194
|
+
//no delimiter at the end
|
195
|
+
if ( i != data.Length - 1 ) {
|
196
|
+
TextLine.Append(Delimiter);
|
197
|
+
}
|
198
|
+
}
|
199
|
+
Writer.WriteLine(TextLine.ToString());
|
200
|
+
Writer.Close();
|
201
|
+
}
|
202
|
+
|
203
|
+
/// <summary>
|
204
|
+
/// Writes a two-dimensional table of numbers to a text file.
|
205
|
+
/// </summary>
|
206
|
+
/// <param name="TargetFilename">The target filename.</param>
|
207
|
+
/// <param name="AppendToFile">If set to <c>true</c> append to the end of the file.</param>
|
208
|
+
/// <param name="Delimiter">The delimiter separating the numeric values.</param>
|
209
|
+
/// <param name="data">The data to be written.</param>
|
210
|
+
/// <remarks>Data is a 2D jagged array.</remarks>
|
211
|
+
public static void WriteNumericArrayToFile(string TargetFilename, bool AppendToFile, string Delimiter, int[][] data)
|
212
|
+
{
|
213
|
+
StreamWriter Writer;
|
214
|
+
int i;
|
215
|
+
int j;
|
216
|
+
|
217
|
+
Writer = new StreamWriter(TargetFilename, AppendToFile);
|
218
|
+
StringBuilder TextLine;
|
219
|
+
for ( i = 0; i < data.Length; i++ ) {
|
220
|
+
TextLine = new StringBuilder();
|
221
|
+
for ( j = 0; j < data[i].Length; j++ ) {
|
222
|
+
TextLine.Append(data[i][j]);
|
223
|
+
//no delimiter at the end
|
224
|
+
if ( j != data[i].Length - 1 ) {
|
225
|
+
TextLine.Append(Delimiter);
|
226
|
+
}
|
227
|
+
}
|
228
|
+
Writer.WriteLine(TextLine.ToString());
|
229
|
+
}
|
230
|
+
Writer.Close();
|
231
|
+
}
|
232
|
+
|
233
|
+
/// <summary>
|
234
|
+
/// Writes a two-dimensional table of numbers to a text file.
|
235
|
+
/// </summary>
|
236
|
+
/// <param name="TargetFilename">The target filename.</param>
|
237
|
+
/// <param name="AppendToFile">If set to <c>true</c> append to the end of the file.</param>
|
238
|
+
/// <param name="Delimiter">The delimiter separating the numeric values.</param>
|
239
|
+
/// <param name="data">The data to be written.</param>
|
240
|
+
/// <remarks>Data is a 2D rectangular array.</remarks>
|
241
|
+
public static void WriteNumericArrayToFile(string TargetFilename, bool AppendToFile, string Delimiter, int[,] data)
|
242
|
+
{
|
243
|
+
StreamWriter Writer;
|
244
|
+
int i;
|
245
|
+
int j;
|
246
|
+
|
247
|
+
Writer = new StreamWriter(TargetFilename, AppendToFile);
|
248
|
+
StringBuilder TextLine;
|
249
|
+
for ( i = 0; i < data.GetLength(0); i++ ) {
|
250
|
+
TextLine = new StringBuilder();
|
251
|
+
for ( j = 0; j < data.GetLength(1); j++ ) {
|
252
|
+
TextLine.Append(data[i, j]);
|
253
|
+
//no delimiter at the end
|
254
|
+
if ( j != data.GetLength(1) - 1 ) {
|
255
|
+
TextLine.Append(Delimiter);
|
256
|
+
}
|
257
|
+
}
|
258
|
+
Writer.WriteLine(TextLine.ToString());
|
259
|
+
}
|
260
|
+
Writer.Close();
|
261
|
+
}
|
262
|
+
|
263
|
+
/// <summary>
|
264
|
+
/// Writes an array of numbers to a text file.
|
265
|
+
/// </summary>
|
266
|
+
/// <param name="TargetFilename">The target filename.</param>
|
267
|
+
/// <param name="AppendToFile">If set to <c>true</c> append to the end of the file.</param>
|
268
|
+
/// <param name="Delimiter">The delimiter separating the numeric values.</param>
|
269
|
+
/// <param name="data">The data to be written.</param>
|
270
|
+
/// <remarks>Data is a 1D array.</remarks>
|
271
|
+
public static void WriteNumericArrayToFile(string TargetFilename, bool AppendToFile, string Delimiter, int[] data)
|
272
|
+
{
|
273
|
+
StreamWriter Writer;
|
274
|
+
int i;
|
275
|
+
|
276
|
+
Writer = new StreamWriter(TargetFilename, AppendToFile);
|
277
|
+
StringBuilder TextLine;
|
278
|
+
TextLine = new StringBuilder();
|
279
|
+
for ( i = 0; i < data.Length; i++ ) {
|
280
|
+
TextLine.Append(data[i]);
|
281
|
+
//no delimiter at the end
|
282
|
+
if ( i != data.Length - 1 ) {
|
283
|
+
TextLine.Append(Delimiter);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
Writer.WriteLine(TextLine.ToString());
|
287
|
+
Writer.Close();
|
288
|
+
}
|
289
|
+
|
290
|
+
#endregion
|
291
|
+
|
292
|
+
/// <summary>
|
293
|
+
/// Writes a text string to a file.
|
294
|
+
/// </summary>
|
295
|
+
/// <param name="TargetFilename">The target filename.</param>
|
296
|
+
/// <param name="AppendToFile">if set to <c>true</c> append to the end of the file.</param>
|
297
|
+
/// <param name="data">The text to write to the file.</param>
|
298
|
+
public static void WriteStringToFile(string TargetFilename, bool AppendToFile, string data)
|
299
|
+
{
|
300
|
+
StreamWriter Writer;
|
301
|
+
|
302
|
+
Writer = new StreamWriter(TargetFilename, AppendToFile);
|
303
|
+
Writer.WriteLine(data);
|
304
|
+
Writer.Close();
|
305
|
+
}
|
306
|
+
|
307
|
+
/// <summary>
|
308
|
+
/// Sets the normal distribution.
|
309
|
+
/// </summary>
|
310
|
+
/// <param name="DataArray">The input data array.</param>
|
311
|
+
/// <param name="Mean">The mean around which to set the distribution.</param>
|
312
|
+
/// <param name="StdDev">The standard deviation to use for the distribution.</param>
|
313
|
+
/// <returns>
|
314
|
+
/// An array with the normal distribution points around the given mean and standard deviation for the data array given.
|
315
|
+
/// If the mean is null then 0.0 is used. If the standard deviation is null or zero then 1.0 is used.
|
316
|
+
/// </returns>
|
317
|
+
public static double[] SetNormalDistribution(double[] DataArray, double Mean, double StdDev)
|
318
|
+
{
|
319
|
+
if ( DataArray == null ) {
|
320
|
+
return null;
|
321
|
+
}
|
322
|
+
if ( Mean.Equals(null) ) {
|
323
|
+
Mean = 0.0;
|
324
|
+
}
|
325
|
+
if ( StdDev.Equals(null) ) {
|
326
|
+
StdDev = 1.0;
|
327
|
+
}
|
328
|
+
else if ( StdDev <= 0.0 ) {
|
329
|
+
StdDev = 1.0;
|
330
|
+
}
|
331
|
+
ArrayList ar1d = new ArrayList();
|
332
|
+
double tmp;
|
333
|
+
for ( int i = 0; i < DataArray.Length; i++ ) {
|
334
|
+
tmp = (DataArray[i] - Mean) / StdDev;
|
335
|
+
ar1d.Add(1 / Math.Sqrt(2 * Math.PI) * Math.Exp(-0.5 * tmp * tmp));
|
336
|
+
}
|
337
|
+
return (double[])ar1d.ToArray(typeof(double));
|
338
|
+
}
|
339
|
+
|
340
|
+
#region MatrixMultiply (overloaded)
|
341
|
+
|
342
|
+
/// <summary>
|
343
|
+
/// Multiplies two matricies, item by item.
|
344
|
+
/// </summary>
|
345
|
+
/// <param name="a">The first matrix, 1D.</param>
|
346
|
+
/// <param name="b">The second matrix, 2D.</param>
|
347
|
+
/// <returns>The product of two matricies. Result will be the same size as the 2D matrix.</returns>
|
348
|
+
/// <remarks>
|
349
|
+
/// Each product is a(row) * b(row,col) with dimensions of b. "row" must be equal for both a and b,
|
350
|
+
/// or null value is returned.
|
351
|
+
/// </remarks>
|
352
|
+
public static double[,] MatrixMultiply(double[] a, double[,] b)
|
353
|
+
{
|
354
|
+
if ( a.Length != b.GetLength(0) ) {
|
355
|
+
return null;
|
356
|
+
}
|
357
|
+
double[,] Product = new double[b.GetLength(0), b.GetLength(1)];
|
358
|
+
|
359
|
+
for ( int row = 0; row < b.GetLength(0); row++ ) {
|
360
|
+
for ( int col = 0; col < b.GetLength(1); col++ ) {
|
361
|
+
Product[row, col] = b[row, col] * a[row];
|
362
|
+
}
|
363
|
+
}
|
364
|
+
return Product;
|
365
|
+
}
|
366
|
+
|
367
|
+
/// <summary>
|
368
|
+
/// Multiplies two matricies, item by item.
|
369
|
+
/// </summary>
|
370
|
+
/// <param name="a">The first matrix, 1D.</param>
|
371
|
+
/// <param name="b">The second matrix, 2D.</param>
|
372
|
+
/// <returns>The product of two matricies. Result will be the same size as the 2D matrix.</returns>
|
373
|
+
/// <remarks>
|
374
|
+
/// Each product is a(row) * b(row,col) with dimensions of b. "row" must be equal for both a and b,
|
375
|
+
/// or null value is returned.
|
376
|
+
/// </remarks>
|
377
|
+
public static double[,] MatrixMultiply(int[] a, double[,] b)
|
378
|
+
{
|
379
|
+
if ( a.Length != b.GetLength(0) ) {
|
380
|
+
return null;
|
381
|
+
}
|
382
|
+
double[,] Product = new double[b.GetLength(0), b.GetLength(1)];
|
383
|
+
|
384
|
+
for ( int row = 0; row < b.GetLength(0); row++ ) {
|
385
|
+
for ( int col = 0; col < b.GetLength(1); col++ ) {
|
386
|
+
Product[row, col] = b[row, col] * a[row];
|
387
|
+
}
|
388
|
+
}
|
389
|
+
return Product;
|
390
|
+
}
|
391
|
+
|
392
|
+
/// <summary>
|
393
|
+
/// Multiplies two matricies, item by item.
|
394
|
+
/// </summary>
|
395
|
+
/// <param name="a">The first matrix, 1D.</param>
|
396
|
+
/// <param name="b">The second matrix, 2D.</param>
|
397
|
+
/// <returns>The product of two matricies. Result will be the same size as the 2D matrix.</returns>
|
398
|
+
/// <remarks>
|
399
|
+
/// Each product is a(row) * b(row,col) with dimensions of b. "row" must be equal for both a and b,
|
400
|
+
/// or null value is returned.
|
401
|
+
/// </remarks>
|
402
|
+
public static double[,] MatrixMultiply(double[] a, int[,] b)
|
403
|
+
{
|
404
|
+
if ( a.Length != b.GetLength(0) ) {
|
405
|
+
return null;
|
406
|
+
}
|
407
|
+
double[,] Product = new double[b.GetLength(0), b.GetLength(1)];
|
408
|
+
|
409
|
+
for ( int row = 0; row < b.GetLength(0); row++ ) {
|
410
|
+
for ( int col = 0; col < b.GetLength(1); col++ ) {
|
411
|
+
Product[row, col] = b[row, col] * a[row];
|
412
|
+
}
|
413
|
+
}
|
414
|
+
return Product;
|
415
|
+
}
|
416
|
+
|
417
|
+
/// <summary>
|
418
|
+
/// Multiplies two matricies, item by item.
|
419
|
+
/// </summary>
|
420
|
+
/// <param name="a">The first matrix, 2D.</param>
|
421
|
+
/// <param name="b">The second matrix, 1D.</param>
|
422
|
+
/// <returns>The product of two matricies. Result will be the same size as the 2D matrix.</returns>
|
423
|
+
/// <remarks>
|
424
|
+
/// Each product is a(row,col) * b(row) with dimensions of a. "row" must be equal for both a and b,
|
425
|
+
/// or null value is returned.
|
426
|
+
/// </remarks>
|
427
|
+
public static double[,] MatrixMultiply(double[,] a, double[] b)
|
428
|
+
{
|
429
|
+
if ( b.Length != a.GetLength(0) ) {
|
430
|
+
return null;
|
431
|
+
}
|
432
|
+
double[,] Product = new double[a.GetLength(0), a.GetLength(1)];
|
433
|
+
|
434
|
+
for ( int row = 0; row < a.GetLength(0); row++ ) {
|
435
|
+
for ( int col = 0; col < a.GetLength(1); col++ ) {
|
436
|
+
Product[row, col] = a[row, col] * b[row];
|
437
|
+
}
|
438
|
+
}
|
439
|
+
return Product;
|
440
|
+
}
|
441
|
+
|
442
|
+
/// <summary>
|
443
|
+
/// Multiplies two matricies, item by item.
|
444
|
+
/// </summary>
|
445
|
+
/// <param name="a">The first matrix, 2D.</param>
|
446
|
+
/// <param name="b">The second matrix, 1D.</param>
|
447
|
+
/// <returns>The product of two matricies. Result will be the same size as the 2D matrix.</returns>
|
448
|
+
/// <remarks>
|
449
|
+
/// Each product is a(row,col) * b(row) with dimensions of a. "row" must be equal for both a and b,
|
450
|
+
/// or null value is returned.
|
451
|
+
/// </remarks>
|
452
|
+
public static double[,] MatrixMultiply(int[,] a, double[] b)
|
453
|
+
{
|
454
|
+
if ( b.Length != a.GetLength(0) ) {
|
455
|
+
return null;
|
456
|
+
}
|
457
|
+
double[,] Product = new double[a.GetLength(0), a.GetLength(1)];
|
458
|
+
|
459
|
+
for ( int row = 0; row < a.GetLength(0); row++ ) {
|
460
|
+
for ( int col = 0; col < a.GetLength(1); col++ ) {
|
461
|
+
Product[row, col] = a[row, col] * b[row];
|
462
|
+
}
|
463
|
+
}
|
464
|
+
return Product;
|
465
|
+
}
|
466
|
+
|
467
|
+
/// <summary>
|
468
|
+
/// Multiplies two matricies, item by item.
|
469
|
+
/// </summary>
|
470
|
+
/// <param name="a">The first matrix, 2D.</param>
|
471
|
+
/// <param name="b">The second matrix, 1D.</param>
|
472
|
+
/// <returns>The product of two matricies. Result will be the same size as the 2D matrix.</returns>
|
473
|
+
/// <remarks>
|
474
|
+
/// Each product is a(row,col) * b(row) with dimensions of a. "row" must be equal for both a and b,
|
475
|
+
/// or null value is returned.
|
476
|
+
/// </remarks>
|
477
|
+
public static double[,] MatrixMultiply(double[,] a, int[] b)
|
478
|
+
{
|
479
|
+
if ( b.Length != a.GetLength(0) ) {
|
480
|
+
return null;
|
481
|
+
}
|
482
|
+
double[,] Product = new double[a.GetLength(0), a.GetLength(1)];
|
483
|
+
|
484
|
+
for ( int row = 0; row < a.GetLength(0); row++ ) {
|
485
|
+
for ( int col = 0; col < a.GetLength(1); col++ ) {
|
486
|
+
Product[row, col] = a[row, col] * b[row];
|
487
|
+
}
|
488
|
+
}
|
489
|
+
return Product;
|
490
|
+
}
|
491
|
+
|
492
|
+
/// <summary>
|
493
|
+
/// Multiplies two matricies, item by item.
|
494
|
+
/// </summary>
|
495
|
+
/// <param name="a">The first matrix, 1D.</param>
|
496
|
+
/// <param name="b">The second matrix, 1D.</param>
|
497
|
+
/// <returns>The product of two matricies. Result will be a 1D matrix.</returns>
|
498
|
+
/// <remarks>
|
499
|
+
/// Each product is a(row) * b(row) with dimensions of a. a and b must be the same size
|
500
|
+
/// or null is returned.</remarks>
|
501
|
+
public static double[] MatrixMultiply(double[] a, double[] b)
|
502
|
+
{
|
503
|
+
if ( a.Length != b.Length ) {
|
504
|
+
return null;
|
505
|
+
}
|
506
|
+
double[] Product = new double[a.Length];
|
507
|
+
|
508
|
+
for ( int row = 0; row < a.Length; row++ ) {
|
509
|
+
Product[row] = a[row] * b[row];
|
510
|
+
}
|
511
|
+
return Product;
|
512
|
+
}
|
513
|
+
|
514
|
+
/// <summary>
|
515
|
+
/// Multiplies two matricies, item by item.
|
516
|
+
/// </summary>
|
517
|
+
/// <param name="a">The first matrix, 1D.</param>
|
518
|
+
/// <param name="b">The second matrix, 1D.</param>
|
519
|
+
/// <returns>The product of two matricies. Result will be a 1D matrix.</returns>
|
520
|
+
/// <remarks>
|
521
|
+
/// Each product is a(row) * b(row) with dimensions of a. a and b must be the same size
|
522
|
+
/// or null is returned.</remarks>
|
523
|
+
public static double[] MatrixMultiply(int[] a, double[] b)
|
524
|
+
{
|
525
|
+
if ( a.Length != b.Length ) {
|
526
|
+
return null;
|
527
|
+
}
|
528
|
+
double[] Product = new double[a.Length];
|
529
|
+
|
530
|
+
for ( int row = 0; row < a.Length; row++ ) {
|
531
|
+
Product[row] = a[row] * b[row];
|
532
|
+
}
|
533
|
+
return Product;
|
534
|
+
}
|
535
|
+
|
536
|
+
/// <summary>
|
537
|
+
/// Multiplies two matricies, item by item.
|
538
|
+
/// </summary>
|
539
|
+
/// <param name="a">The first matrix, 1D.</param>
|
540
|
+
/// <param name="b">The second matrix, 1D.</param>
|
541
|
+
/// <returns>The product of two matricies. Result will be a 1D matrix.</returns>
|
542
|
+
/// <remarks>
|
543
|
+
/// Each product is a(row) * b(row) with dimensions of a. a and b must be the same size
|
544
|
+
/// or null is returned.</remarks>
|
545
|
+
public static double[] MatrixMultiply(double[] a, int[] b)
|
546
|
+
{
|
547
|
+
if ( a.Length != b.Length ) {
|
548
|
+
return null;
|
549
|
+
}
|
550
|
+
double[] Product = new double[a.Length];
|
551
|
+
|
552
|
+
for ( int row = 0; row < a.Length; row++ ) {
|
553
|
+
Product[row] = a[row] * b[row];
|
554
|
+
}
|
555
|
+
return Product;
|
556
|
+
}
|
557
|
+
|
558
|
+
#endregion
|
559
|
+
|
560
|
+
/// <summary>
|
561
|
+
/// Reduces a 2D matrix to 1D by summing each column or row.
|
562
|
+
/// </summary>
|
563
|
+
/// <param name="a">The matrix.</param>
|
564
|
+
/// <param name="ByDim">Dimension to sum by.</param>
|
565
|
+
/// <returns>1D matrix with summed values, having same length as the dimension to sum by.</returns>
|
566
|
+
public static double[] MatrixReduceBySum(double[,] a, DimensionType ByDim)
|
567
|
+
{
|
568
|
+
double[] sum;
|
569
|
+
int row;
|
570
|
+
int col;
|
571
|
+
if ( ByDim == DimensionType.Row ) {
|
572
|
+
sum = new double[a.GetLength(0)];
|
573
|
+
for ( row = 0; row < a.GetLength(0); row++ ) {
|
574
|
+
for ( col = 0; col < a.GetLength(1); col++ ) {
|
575
|
+
sum[row] = sum[row] + a[row, col];
|
576
|
+
}
|
577
|
+
}
|
578
|
+
}
|
579
|
+
else {
|
580
|
+
sum = new double[a.GetLength(1)];
|
581
|
+
for ( col = 0; col < a.GetLength(1); col++ ) {
|
582
|
+
for ( row = 0; row < a.GetLength(0); row++ ) {
|
583
|
+
sum[col] = sum[col] + a[row, col];
|
584
|
+
}
|
585
|
+
}
|
586
|
+
}
|
587
|
+
return sum;
|
588
|
+
}
|
589
|
+
|
590
|
+
#region ArraySum (overloaded)
|
591
|
+
|
592
|
+
/// <summary>
|
593
|
+
/// Sums all elements of a 1D array.
|
594
|
+
/// </summary>
|
595
|
+
/// <param name="a">The array to sum.</param>
|
596
|
+
/// <returns>The sum of all elements in the array.</returns>
|
597
|
+
public static double ArraySum(double[] a)
|
598
|
+
{
|
599
|
+
double info = 0;
|
600
|
+
for ( int i = 0; i < a.Length; i++ ) {
|
601
|
+
info = info + a[i];
|
602
|
+
}
|
603
|
+
return info;
|
604
|
+
}
|
605
|
+
|
606
|
+
/// <summary>
|
607
|
+
/// Sums all elements of a 1D array.
|
608
|
+
/// </summary>
|
609
|
+
/// <param name="a">The array to sum.</param>
|
610
|
+
/// <returns>The sum of all elements in the array.</returns>
|
611
|
+
public static double ArraySum(int[] a)
|
612
|
+
{
|
613
|
+
int info = 0;
|
614
|
+
for ( int i = 0; i < a.Length; i++ ) {
|
615
|
+
info = info + a[i];
|
616
|
+
}
|
617
|
+
return (double)info;
|
618
|
+
}
|
619
|
+
|
620
|
+
#endregion
|
621
|
+
|
622
|
+
/// <summary>
|
623
|
+
/// Slices one dimension from a 3D matrix.
|
624
|
+
/// </summary>
|
625
|
+
/// <param name="a">The 3D matrix.</param>
|
626
|
+
/// <param name="ByDim">The dimension to slice.</param>
|
627
|
+
/// <param name="x">Index of the first dimension to hold constant.</param>
|
628
|
+
/// <param name="DimX">The first constant dimension.</param>
|
629
|
+
/// <param name="y">Index of the second dimension to hold constant.</param>
|
630
|
+
/// <param name="DimY">The second constant dimension.</param>
|
631
|
+
/// <returns>A one dimensional array from the 3D matrix.</returns>
|
632
|
+
public static double[] MatrixSlice1D(double[, ,] a, DimensionType ByDim, int x, DimensionType DimX, int y, DimensionType DimY)
|
633
|
+
{
|
634
|
+
int ArraySize = a.GetLength((int)ByDim);
|
635
|
+
double[] ar1d = new double[ArraySize];
|
636
|
+
switch ( ByDim ) {
|
637
|
+
case DimensionType.Row:
|
638
|
+
for ( int i = 0; i < ArraySize; i++ ) {
|
639
|
+
if ( DimX == DimensionType.Column ) {
|
640
|
+
ar1d[i] = a[i, x, y];
|
641
|
+
}
|
642
|
+
else {
|
643
|
+
ar1d[i] = a[i, y, x];
|
644
|
+
}
|
645
|
+
}
|
646
|
+
break;
|
647
|
+
case DimensionType.Column:
|
648
|
+
for ( int i = 0; i < ArraySize; i++ ) {
|
649
|
+
if ( DimX == DimensionType.Row ) {
|
650
|
+
ar1d[i] = a[x, i, y];
|
651
|
+
}
|
652
|
+
else {
|
653
|
+
ar1d[i] = a[y, i, x];
|
654
|
+
}
|
655
|
+
}
|
656
|
+
break;
|
657
|
+
case DimensionType.Depth:
|
658
|
+
for ( int i = 0; i < ArraySize; i++ ) {
|
659
|
+
if ( DimX == DimensionType.Row ) {
|
660
|
+
ar1d[i] = a[x, y, i];
|
661
|
+
}
|
662
|
+
else {
|
663
|
+
ar1d[i] = a[y, x, i];
|
664
|
+
}
|
665
|
+
}
|
666
|
+
break;
|
667
|
+
}
|
668
|
+
return ar1d;
|
669
|
+
}
|
670
|
+
|
671
|
+
/// <summary>
|
672
|
+
/// Calculate averages across categories. Mimics the "tapply" method in R. Assumes that <c>categories</c> and <c>items</c>
|
673
|
+
/// are in the proper order with respect to each other.
|
674
|
+
/// </summary>
|
675
|
+
/// <param name="categories"><c>List</c> of categories of items.</param>
|
676
|
+
/// <param name="items"><c>List</c> of items.</param>
|
677
|
+
/// <returns><c>SortedList</c> of categories with their averages.</returns>
|
678
|
+
public static SortedList<int, double> CategoryAverages (List<int> categories, List<double> items)
|
679
|
+
{
|
680
|
+
if (items.Count != categories.Count) {
|
681
|
+
throw new ApplicationException("CategoryAverages: item/category count mismatch. ");
|
682
|
+
}
|
683
|
+
|
684
|
+
SortedList<int, List<double>> slCat = new SortedList<int, List<double>>();
|
685
|
+
|
686
|
+
for (int i=0; i<items.Count; i++) {
|
687
|
+
if (!(slCat.ContainsKey(categories[i]))) {
|
688
|
+
List<double> Items = new List<double>();
|
689
|
+
Items.Add(items[i]);
|
690
|
+
slCat.Add(categories[i], Items);
|
691
|
+
}
|
692
|
+
else {
|
693
|
+
slCat[categories[i]].Add(items[i]);
|
694
|
+
}
|
695
|
+
}
|
696
|
+
|
697
|
+
SortedList<int,double> averages = new SortedList<int,double>();
|
698
|
+
|
699
|
+
foreach (int i in slCat.Keys) {
|
700
|
+
averages[i] = slCat[i].AsQueryable().Average();
|
701
|
+
}
|
702
|
+
|
703
|
+
return averages;
|
704
|
+
}
|
705
|
+
|
706
|
+
/// <summary>
|
707
|
+
/// Utility for random number selection. This can use the C# random number generator
|
708
|
+
/// or use an input list (used for QA to ensure the same random number sequence).
|
709
|
+
/// </summary>
|
710
|
+
public class RandomNumber
|
711
|
+
{
|
712
|
+
private static int _Index;
|
713
|
+
private static int _ListCount;
|
714
|
+
private static double[] _NumberList;
|
715
|
+
private static Random _RandomNumber;
|
716
|
+
private static bool _UseList;
|
717
|
+
|
718
|
+
/// <summary>
|
719
|
+
/// Private constructor
|
720
|
+
/// </summary>
|
721
|
+
private RandomNumber ()
|
722
|
+
{
|
723
|
+
Init();
|
724
|
+
}
|
725
|
+
|
726
|
+
public static void Init ()
|
727
|
+
{
|
728
|
+
_UseList = false;
|
729
|
+
_RandomNumber = new Random(unchecked((int)DateTime.Now.Ticks));
|
730
|
+
}
|
731
|
+
|
732
|
+
/// <summary>
|
733
|
+
/// Initialize the generator to use a predetermined list of random numbers.
|
734
|
+
/// </summary>
|
735
|
+
/// <param name="randomNumberList">The list of predetermined random numbers, type <c>double</c>,
|
736
|
+
/// with values from zero to one.</param>
|
737
|
+
public static void Init (double[] randomNumberList) {
|
738
|
+
|
739
|
+
if (randomNumberList.Count() == 0) {
|
740
|
+
throw new ApplicationException("QArandom error: input list is empty");
|
741
|
+
}
|
742
|
+
|
743
|
+
_UseList = true;
|
744
|
+
_NumberList = randomNumberList;
|
745
|
+
_ListCount = _NumberList.Count();
|
746
|
+
_Index = -1;
|
747
|
+
}
|
748
|
+
|
749
|
+
/// <summary>
|
750
|
+
/// Get the next random number.
|
751
|
+
/// </summary>
|
752
|
+
/// <returns>A <c>double</c> between zero and one.</returns>
|
753
|
+
public static double NextDouble()
|
754
|
+
{
|
755
|
+
if (_UseList) {
|
756
|
+
if (_Index == _ListCount-1) {
|
757
|
+
//If at the end of the list go back to the beginning
|
758
|
+
_Index = 0;
|
759
|
+
}
|
760
|
+
else {
|
761
|
+
_Index++;
|
762
|
+
}
|
763
|
+
return _NumberList[_Index];
|
764
|
+
}
|
765
|
+
else {
|
766
|
+
if (_RandomNumber == null) {
|
767
|
+
Init();
|
768
|
+
}
|
769
|
+
return _RandomNumber.NextDouble();
|
770
|
+
}
|
771
|
+
}
|
772
|
+
|
773
|
+
/// <summary>
|
774
|
+
/// Get the next random number and scale it to the integer <c>maxValue</c>.
|
775
|
+
/// </summary>
|
776
|
+
/// <param name="maxValue">The maximum <c>integer</c> value to return</param>
|
777
|
+
/// <returns>A random <c>integer</c> between zero and <c>maxValue</c>.</returns>
|
778
|
+
public static int Next(int maxValue)
|
779
|
+
{
|
780
|
+
if (_UseList) {
|
781
|
+
if (_Index == _ListCount-1) {
|
782
|
+
//If at the end of the list go back to the beginning
|
783
|
+
_Index = 0;
|
784
|
+
}
|
785
|
+
else {
|
786
|
+
_Index++;
|
787
|
+
}
|
788
|
+
return (int)Math.Round(_NumberList[_Index] * maxValue);
|
789
|
+
}
|
790
|
+
else {
|
791
|
+
if (_RandomNumber == null) {
|
792
|
+
Init();
|
793
|
+
}
|
794
|
+
return _RandomNumber.Next(maxValue);
|
795
|
+
}
|
796
|
+
}
|
797
|
+
|
798
|
+
}
|
799
|
+
|
800
|
+
|
801
|
+
/// <summary>
|
802
|
+
/// A comparer for a list of double-int key-value pairs. This is required to allow sorting of this type of list.
|
803
|
+
/// </summary>
|
804
|
+
public class KVPDoubleIntComparer : IComparer<KeyValuePair<double,int>>
|
805
|
+
{
|
806
|
+
public int Compare ( KeyValuePair<double, int> kvp1, KeyValuePair<double, int> kvp2 )
|
807
|
+
{
|
808
|
+
//Check for equalities: use the same method as the R programming language
|
809
|
+
if ((kvp1.Key == kvp2.Key) && (kvp1.Value != kvp2.Value)) {
|
810
|
+
if (kvp1.Value > kvp2.Value) {
|
811
|
+
return 1;
|
812
|
+
}
|
813
|
+
else {
|
814
|
+
return -1;
|
815
|
+
}
|
816
|
+
}
|
817
|
+
else {
|
818
|
+
return (kvp1.Key.CompareTo(kvp2.Key));
|
819
|
+
}
|
820
|
+
}
|
821
|
+
}
|
822
|
+
|
823
|
+
}
|
824
|
+
|
825
|
+
}
|