/* ===========================================================
* TradeManager : An application to trade strategies for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2011-2011, by Simon Allen and Contributors.
*
* Project Info: org.trade
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Oracle, Inc.
* in the United States and other countries.]
*
* (C) Copyright 2011-2011, by Simon Allen and Contributors.
*
* Original Author: Simon Allen;
* Contributor(s): -;
*
* Changes
* -------
*
*/
package org.trade.core.util;
import java.util.Enumeration;
import java.util.Hashtable;
/**
*
* @author Simon Allen
*/
public final class MatrixFunctions {
private static int listingForm = 0;
public MatrixFunctions() {
}
/**
* Method solve.
*
* @param userDataVector
* Hashtable<Long,Pair>
* @param polyOrder
* Integer
* @return double[]
*/
public static synchronized double[] solve(Pair[] pairs, Integer polyOrder) {
int size = pairs.length;
if (size > 1) {
return getCalculatedCoeffients(pairs, polyOrder);
}
return null;
}
/**
* Method updateXYPairs.
*
* @param userDataVector
* Hashtable<Long,Pair>
* @param terms
* double[]
* @return boolean
*/
public static synchronized boolean updateXYPairs(Hashtable<Long, Pair> userDataVector, double[] terms) {
boolean updated = false;
for (Enumeration<Pair> enumPairs = userDataVector.elements(); enumPairs.hasMoreElements();) {
Pair pair = enumPairs.nextElement();
double y = fx(pair.x, terms);
pair.y = y;
updated = true;
}
return updated;
}
/**
* Method getCorrelationCoefficient.
*
* @param data
* Pair[]
* @param terms
* double[]
* @return double
*/
public static synchronized double getCorrelationCoefficient(Pair[] data, double[] terms) {
double r = 0;
int n = data.length;
double sx = 0, sx2 = 0, sy = 0, sy2 = 0, sxy = 0;
double x, y;
for (Pair pr : data) {
x = fx(pr.x, terms);
y = pr.y;
sx += x;
sy += y;
sxy += x * y;
sx2 += x * x;
sy2 += y * y;
}
double div = Math.sqrt((sx2 - ((sx * sx) / n)) * (sy2 - ((sy * sy) / n)));
if (div != 0) {
r = Math.pow((sxy - ((sx * sy) / n)) / div, 2);
}
return r;
}
/**
* Method getStandardError.
*
* @param data
* Pair[]
* @param terms
* double[]
* @return double
*/
public static synchronized double getStandardError(Pair[] data, double[] terms) {
double r = 0;
int n = data.length;
if (n > 2) {
double a = 0;
for (Pair pr : data) {
a += Math.pow((fx(pr.x, terms) - pr.y), 2);
}
r = Math.sqrt(a / (n - 2));
}
return r;
}
/**
* Method getCalculatedCoeffients.
*
* @param data
* Pair[]
* @param p
* int
* @return double[]
*/
public static synchronized double[] getCalculatedCoeffients(Pair[] data, int p) {
p += 1;
int n = data.length;
int r, c;
int rs = (2 * p) - 1;
//
// by request: read each datum only once
// not the most efficient processing method
// but required if the data set is huge
//
// create square matrix with added RH column
double[][] m = new double[p][p + 1];
// create array of precalculated matrix data
double[] mpc = new double[rs];
mpc[0] = n;
for (Pair pr : data) {
// process precalculation array
for (r = 1; r < rs; r++) {
mpc[r] += Math.pow(pr.x, r);
}
// process RH column cells
m[0][p] += pr.y;
for (r = 1; r < p; r++) {
m[r][p] += Math.pow(pr.x, r) * pr.y;
}
}
// populate square matrix section
for (r = 0; r < p; r++) {
for (c = 0; c < p; c++) {
m[r][c] = mpc[r + c];
}
}
// parent.show_mat(m);
// reduce matrix
gj_echelonize(m);
// parent.show_mat(m);
// extract rh column
double[] result = new double[p];
for (int j = 0; j < p; j++) {
result[j] = m[j][p];
}
return result;
}
/**
* Method fx.
*
* @param x
* double
* @param terms
* double[]
* @return double
*/
public static synchronized double fx(double x, double[] terms) {
double a = 0;
int e = 0;
for (double i : terms) {
a += i * Math.pow(x, e);
e++;
}
return a;
}
/**
* Method gj_divide.
*
* @param A
* double[][]
* @param i
* int
* @param j
* int
* @param m
* int
*/
private static synchronized void gj_divide(double[][] A, int i, int j, int m) {
for (int q = j + 1; q < m; q++) {
A[i][q] /= A[i][j];
}
A[i][j] = 1;
}
/**
* Method gj_eliminate.
*
* @param A
* double[][]
* @param i
* int
* @param j
* int
* @param n
* int
* @param m
* int
*/
private static synchronized void gj_eliminate(double[][] A, int i, int j, int n, int m) {
for (int k = 0; k < n; k++) {
if ((k != i) && (A[k][j] != 0)) {
for (int q = j + 1; q < m; q++) {
A[k][q] -= A[k][j] * A[i][q];
}
A[k][j] = 0;
}
}
}
/**
* Method gj_echelonize.
*
* @param A
* double[][]
*/
private static synchronized void gj_echelonize(double[][] A) {
int n = A.length;
int m = A[0].length;
int i = 0;
int j = 0;
int k;
double temp[];
while ((i < n) && (j < m)) {
// look for non-zero entries in col j at or below row i
k = i;
while ((k < n) && (A[k][j] == 0)) {
k++;
}
// if an entry is found at row k
if (k < n) {
// if k is not i, then swap row i with row k
if (k != i) {
temp = A[i];
A[i] = A[k];
A[k] = temp;
}
// if A[i][j] is != 1, divide row i by A[i][j]
if (A[i][j] != 1) {
gj_divide(A, i, j, m);
}
// eliminate all other non-zero entries
gj_eliminate(A, i, j, n, m);
i++;
}
j++;
}
}
/**
* Method toPrint.
*
* @param polyOrder
* int
* @param result_cc
* double
* @param result_se
* double
* @param terms
* double[]
* @param dataPoints
* int
* @return String
*/
public static synchronized String toPrint(int polyOrder, double correlationCoeff, double standardDeviation,
double[] terms, int dataPoints) {
String styleTag[] = { "", "pow", "Math.pow" };
int n = dataPoints;
String text = "Degree " + polyOrder + ", " + n + " x,y pairs. ";
text += "Corr. coeff. (r^2) = " + formatNum(correlationCoeff, false) + ". ";
text += "SE = " + formatNum(standardDeviation, false) + "\n\n";
text += (listingForm > 0) ? "double f(double x) {\n return" : "f(x) =";
for (int i = 0; i <= polyOrder; i++) {
double a = terms[i];
if (i > 0) {
if (listingForm > 0) {
text += " ";
}
text += " +";
}
text += formatNum(a, true);
if (i == 1) {
text += " * x";
}
if (i > 1) {
if (listingForm > 0) {
text += (" * " + styleTag[listingForm] + "(x," + i + ")");
} else {
text += (" * x^" + i);
}
}
if (i < polyOrder) {
text += "\n";
}
}
if (listingForm > 0) {
text += ";\n}";
}
if (polyOrder > (n - 1)) {
text += "\n\nWarning: Polynomial degree exceeds data size - 1.";
}
return text;
}
/**
* Method formatNum.
*
* @param n
* double
* @param wide
* boolean
* @return String
*/
private static synchronized String formatNum(double n, boolean wide) {
String w = (wide) ? "21" : "";
return String.format("%" + w + ".12e", n);
}
}