/*
* File name: Matrix.java
* Author(s): Lukas König, free internet code.
* Java version: 6.0
* Generation date: 08 April 2010
*
* (c) This file is protected by Creative Commons by-nc-sa license. Any
* altered or further developed versions of this file have to meet the
* agreements stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.math.matrix;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import eas.miscellaneous.StaticMethods;
import eas.miscellaneous.datatypes.Integer2D;
import eas.startSetup.ParCollection;
import eas.startSetup.parameterDatatypes.ArrayListDouble;
/**
* @author Lukas König, Thomas Darimont
*
* Matrix multiplication from Thomas Darimont:
* http://www.tutorials.de/forum/java/164941-n-x-n-matrizenmultiplikation-aber-wie.html
*/
public class Matrix implements Serializable {
private static final long serialVersionUID = 1381109405948178031L;
/**
* Die Felder der Matrix.
*/
private double[][] matrix;
/**
* Zeilenüberschriften.
*/
private Integer2D[] zeilenUeberschr;
/**
* Spaltenüberschriften.
*/
private Integer2D[] spaltenUeberschr;
/* ************* Constructors ************* */
/**
* Generates matrix from text file.
*
* @param file The text file.
*/
public Matrix(final File file) {
List<String> dateiInhalt = StaticMethods.liesTextArray(file, null, true);
ArrayList<ArrayList<String>> geleseneMatrix = new ArrayList<ArrayList<String>>();
// Text aus Datei formatieren.
for (String s : dateiInhalt) {
String[] aufgeteilt = s.replace(" ", "").split("\\|");
ArrayList<String> zeile = new ArrayList<String>();
for (int i = 0; i < aufgeteilt.length; i++) {
zeile.add(aufgeteilt[i]);
}
geleseneMatrix.add(zeile);
}
// Matrix erzeugen.
int x = geleseneMatrix.get(1).size() - 3;
int y = geleseneMatrix.size() - 2;
this.matrix = new double[x][y];
this.zeilenUeberschr = new Integer2D[this.getRowCount()];
this.spaltenUeberschr = new Integer2D[this.getColumnCount()];
// Einträge.
for (int i = 0; i < this.getColumnCount(); i++) {
for (int j = 0; j < this.getRowCount(); j++) {
this.set(i, j, Double.parseDouble(geleseneMatrix.get(j + 2).get(i + 3)));
}
}
// Überschriften.
for (int i = 0; i < this.getColumnCount(); i++) {
this.spaltenUeberschr[i] = Integer2D.parseInteger2D(geleseneMatrix.get(1).get(i + 3));
}
for (int j = 0; j < this.getRowCount(); j++) {
this.zeilenUeberschr[j] = Integer2D.parseInteger2D(geleseneMatrix.get(j + 2).get(1));
}
}
/**
* Generates empty matrix of a certain size.
*
* @param x The number of columns.
* @param y The number of rows.
*/
public Matrix(final int x, final int y) {
this.matrix = new double[x][y];
this.zeilenUeberschr = new Integer2D[this.getRowCount()];
this.spaltenUeberschr = new Integer2D[this.getColumnCount()];
}
/**
* Generates matrix copying an existing matrix.
*
* @param mat The existing matrix.
*/
public Matrix(final double[][] mat) {
if (mat == null) {
throw new RuntimeException("Matrix darf nicht null sein.");
}
if (mat.length == 0) {
this.matrix = new double[0][0];
}
this.matrix = new double[mat.length][mat[0].length];
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat[0].length; j++) {
this.matrix[i][j] = mat[i][j];
}
}
this.zeilenUeberschr = new Integer2D[this.getRowCount()];
this.spaltenUeberschr = new Integer2D[this.getColumnCount()];
}
public Matrix(final Matrix matrix) {
this(matrix.matrix);
for (int i = 0; i < matrix.getColumnCount(); i++) {
this.spaltenUeberschr[i] = matrix.spaltenUeberschr[i];
}
for (int j = 0; j < matrix.getRowCount(); j++) {
this.zeilenUeberschr[j] = matrix.zeilenUeberschr[j];
}
}
/* ************* EO Constructors ************* */
public void storeMatrix(final File file, final ParCollection pars) {
String path = null;
if (file.getParent() != null) {
path = file.getParentFile().toString();
} else {
path = "";
}
StaticMethods.speichereTextDatei(
path,
file.getName(),
this.toStringFormatiert(),
pars);
}
public static Matrix rowSum(final Matrix mat) {
Matrix result = new Matrix(1, mat.getRowCount());
for (int j = 0; j < mat.getRowCount(); j++) {
for (int i = 0; i < mat.getColumnCount(); i++) {
result.set(0, j, result.get(0, j) + mat.get(i, j));
}
}
return result;
}
public static Matrix columnSum(final Matrix mat) {
Matrix result = new Matrix(mat.getColumnCount(), 1);
for (int j = 0; j < mat.getRowCount(); j++) {
for (int i = 0; i < mat.getColumnCount(); i++) {
result.set(i, 0, result.get(i, 0) + mat.get(i, j));
}
}
return result;
}
public String createMatlabString() {
String s = "";
int hoehe = this.getRowCount();
int breite = this.getColumnCount();
s += "[";
for (int i = 0; i < hoehe; i++) {
String semikolon = "";
if (i < hoehe - 1) {
semikolon = ";";
}
s += "[";
for (int j = 0; j < breite; j++) {
String komma = "";
if (j < breite - 1) {
komma = ",";
}
s += this.get(j, i) + komma;
}
s += "]" + semikolon;
}
s += "]";
return s;
}
public void revertRows() {
double[][] newMatrix = new double[this.matrix.length][this.matrix[0].length];
Integer2D[] newZeilen = new Integer2D[this.zeilenUeberschr.length];
for (int i = 0; i < newMatrix.length; i++) {
for (int j = 0; j < newMatrix[0].length; j++) {
newMatrix[newMatrix.length - i - 1][j] = this.matrix[i][j];
}
newZeilen[newMatrix.length - i - 1] = this.zeilenUeberschr[i];
}
this.zeilenUeberschr = newZeilen;
this.matrix = newMatrix;
}
public void revertColumns() {
double[][] newMatrix = new double[this.matrix.length][this.matrix[0].length];
Integer2D[] newSpalten = new Integer2D[this.spaltenUeberschr.length];
for (int i = 0; i < newMatrix.length; i++) {
for (int j = 0; j < newMatrix[0].length; j++) {
newMatrix[i][newMatrix[0].length - j - 1] = this.matrix[i][j];
newSpalten[newMatrix.length - j - 1] = this.spaltenUeberschr[j];
}
}
this.spaltenUeberschr = newSpalten;
this.matrix = newMatrix;
}
/**
* Performs a rounding operation on the values of all cells of the matrix.
*
* @param digits Number of digits after decimal point.
*/
public Matrix round(final int digits) {
if (this.matrix.length == 0) {
return this;
}
for (int i = 0; i < this.matrix.length; i++) {
for (int j = 0; j < this.matrix[0].length; j++) {
this.matrix[i][j] = Math.round(this.matrix[i][j]
* Math.pow(10, digits))
/ Math.pow(10, digits);
}
}
return this;
}
/**
* Matrix multiplication (by Thomas Darimont).
*
* @param other The matrix to multiply with.
*
* @return this x other.
*/
public void mult(final Matrix other) {
if (this.matrix[0].length != other.getColumnCount()) {
throw new IllegalArgumentException(
"Zeilenanzahl von andere muss der "
+ "Spaltenanzahl von this entsprechen");
}
double[][] c = new double[this.matrix.length][other.getRowCount()];
for (int i = 0; i < this.getColumnCount(); i++) {
for (int j = 0; j < other.getRowCount(); j++) {
for (int k = 0; k < this.getRowCount(); k++) {
c[i][j] += this.get(i, k) * other.get(k, j);
}
}
}
this.matrix = c;
}
/**
* Raise to a power.
*
* @param n The power to raise to.
*/
public void pow(final int n) {
if (this.getColumnCount() != this.getRowCount()) {
throw new RuntimeException("Potenzieren nur bei quadratischen"
+ "Matrizen möglich");
}
Matrix b = new Matrix(this.matrix);
if (n == 0) {
this.einheitsMatrix();
}
for (int i = 1; i < n; i++) {
this.mult(b);
}
}
/**
* Adds other to this; Caution: this gets overwritten by result.
*
* @param other The matrix to add to this.
*
* @return this + other.
*/
public Matrix add(final Matrix other) {
if (this.getColumnCount() != other.getColumnCount()
|| this.getRowCount() != other.getRowCount()) {
throw new RuntimeException("Wrong dimension in this vs. other.");
}
for (int i = 0; i < this.getColumnCount(); i++) {
for (int j = 0; j < this.getRowCount(); j++) {
this.set(i, j, this.get(i, j) + other.get(i, j));
}
}
return this;
}
/**
* Subtracts other from this; Caution: this gets overwritten by result.
*
* @param other The matrix to subtract from this.
*
* @return this - other.
*/
public Matrix sub(final Matrix other) {
if (this.getColumnCount() != other.getColumnCount()
|| this.getRowCount() != other.getRowCount()) {
throw new RuntimeException("Summand ist unterschiedlich dimensioniert.");
}
for (int i = 0; i < this.getColumnCount(); i++) {
for (int j = 0; j < this.getRowCount(); j++) {
this.set(i, j, this.get(i, j) - other.get(i, j));
}
}
return this;
}
/**
* Generates identity matrix.
*/
public Matrix einheitsMatrix() {
for (int i = 0; i < this.getRowCount(); i++) {
for (int j = 0; j < this.getColumnCount(); j++) {
if (i == j) {
this.set(j, i, 1);
} else {
this.set(j, i, 0);
}
}
}
return this;
}
@Override
public String toString() {
String s = "";
for (int i = 0; i < this.getRowCount(); i++) {
for (int j = 0; j < this.getColumnCount(); j++) {
s += this.get(j, i) + ",";
}
s = s.substring(0, s.length() - 1);
s += ";";
}
s = s.substring(0, s.length() - 1);
return s;
}
public String toStringFormatiert(){
String s = "\n";
int[] laengen = new int[this.getColumnCount()];
int zeilUebLaenge = 0;
// Breite der Spalten festlegen - Spaltenüberschriften durchsuchen.
for (int j = 0; j < this.spaltenUeberschr.length; j++) {
if ((this.spaltenUeberschr[j] + "").length() > laengen[j]) {
laengen[j] = (this.spaltenUeberschr[j] + "").length();
}
}
// Breite der Spalten festlegen - Übrige Zellen durchsuchen.
for (int i = 0; i < this.getRowCount(); i++) {
if ((this.zeilenUeberschr[i] + "").length() > zeilUebLaenge) {
zeilUebLaenge = (this.zeilenUeberschr[i] + "").length();
}
for (int j = 0; j < this.getColumnCount(); j++) {
if ((this.matrix[j][i] + "").length() > laengen[j]) {
laengen[j] = (this.matrix[j][i] + "").length();
}
}
}
// Linke obere Zelle.
s += " | ";
for (int k = 0; k < zeilUebLaenge; k++) {
s += " ";
}
// Obere Spalte.
s += " || ";
for (int j = 0; j < this.spaltenUeberschr.length; j++) {
s += this.spaltenUeberschr[j];
for (int k = 0; k < laengen[j]
- (this.spaltenUeberschr[j] + "").length(); k++) {
s += " ";
}
s += " | ";
}
s += "\n";
// Weitere Zellen.
for (int i = 0; i < this.getRowCount(); i++) {
s += " | ";
s += this.zeilenUeberschr[i];
for (int k = 0; k < zeilUebLaenge - (this.zeilenUeberschr[i] + "").length(); k++) {
s += " ";
}
s += " || ";
for (int j = 0; j < this.getColumnCount(); j++) {
s += this.matrix[j][i];
for (int k = 0; k < laengen[j]
- (this.matrix[j][i] + "").length(); k++) {
s += " ";
}
s += " | ";
}
s += "\n";
}
return s;
}
public String toPlainString() {
String s = "\n";
int[] laengen = new int[this.getColumnCount()];
// Breite der Spalten festlegen - Übrige Zellen durchsuchen.
for (int i = 0; i < this.getRowCount(); i++) {
for (int j = 0; j < this.getColumnCount(); j++) {
if ((this.matrix[j][i] + "").length() > laengen[j]) {
laengen[j] = (this.matrix[j][i] + "").length();
}
}
}
// Weitere Zellen.
for (int i = 0; i < this.getRowCount(); i++) {
for (int j = 0; j < this.getColumnCount(); j++) {
s += this.matrix[j][i];
for (int k = 0; k < laengen[j]
- (this.matrix[j][i] + "").length(); k++) {
s += " ";
}
s += "\t";
}
s += "\n";
}
return s;
}
public double get(final int i, final int j) {
return this.matrix[i][j];
}
public void set(final int i, final int j, final double wert) {
if (i >= 0 && i < this.getColumnCount()
&& j >= 0 && j < this.getRowCount()) {
this.matrix[i][j] = wert;
} else {
StaticMethods.logWarning(
"Matrix field ("
+ i
+ "/"
+ j
+ ") does not exist. Value \""
+ wert
+ "\" not set.",
null);
throw new RuntimeException();
}
}
public int getColumnCount() {
return this.matrix.length;
}
public int getRowCount() {
if (this.matrix.length == 0) {
return 0;
}
return this.matrix[0].length;
}
public Integer2D getRowTitle(final int j) {
return this.zeilenUeberschr[j];
}
public Integer2D getColumnTitle(final int i) {
return this.spaltenUeberschr[i];
}
public void setColumnTitle(final int i, final Integer2D wert) {
this.spaltenUeberschr[i] = wert;
}
public void setRowTitle(final int j, final Integer2D wert) {
this.zeilenUeberschr[j] = wert;
}
public Matrix transpone() {
Matrix mat = new Matrix(this.getRowCount(), this.getColumnCount());
for (int i = 0; i < this.getColumnCount(); i++) {
mat.setRowTitle(i, this.getColumnTitle(i));
for (int j = 0; j < this.getRowCount(); j++) {
mat.setColumnTitle(j, this.getRowTitle(j));
mat.set(j, i, this.get(i, j));
}
}
this.matrix = mat.matrix;
this.spaltenUeberschr = mat.spaltenUeberschr;
this.zeilenUeberschr = mat.zeilenUeberschr;
return this;
}
public Matrix erzeugeSpaltenMatrix(final int[] spalten) {
Matrix result = new Matrix(spalten.length, this.getRowCount());
for (int k = 0; k < spalten.length; k++) {
result.setColumnTitle(k, this.getColumnTitle(spalten[k]));
for (int j = 0; j < this.getRowCount(); j++) {
result.setRowTitle(j, this.getColumnTitle(j));
result.set(k, j, this.get(spalten[k], j));
}
}
return result;
}
public Matrix erzeugeZeilenMatrix(final int[] zeilen) {
Matrix result = new Matrix(this.getColumnCount(), zeilen.length);
for (int k = 0; k < zeilen.length; k++) {
result.setRowTitle(k, this.getRowTitle(zeilen[k]));
for (int j = 0; j < this.getColumnCount(); j++) {
result.setColumnTitle(j, this.getColumnTitle(j));
result.set(j, k, this.get(j, zeilen[k]));
}
}
return result;
}
private double getRandomValue() {
return rand.nextDouble() * (randomMaxValue - randomMinValue) + randomMinValue;
}
public Matrix randomize() {
for (int i = 0; i < this.getColumnCount(); i++) {
for (int j = 0; j < this.getRowCount(); j++) {
this.set(i, j, getRandomValue());
}
}
return this;
}
public double maxValue() {
double max = Double.NEGATIVE_INFINITY;
for (int i = 0; i < this.getColumnCount(); i++) {
for (int j = 0; j < this.getColumnCount(); j++) {
if (this.get(i, j) > max) {
max = this.get(i, j);
}
}
}
return max;
}
public double minValue() {
double min = Double.POSITIVE_INFINITY;
for (int i = 0; i < this.getColumnCount(); i++) {
for (int j = 0; j < this.getColumnCount(); j++) {
if (this.get(i, j) < min) {
min = this.get(i, j);
}
}
}
return min;
}
/**
* @param selNumberK Number of agents for selection tournaments.
* @param agentNumberN Number of agents in population.
*
* @return The special probability matrix according to Fig. 10 in
* ECTA2011 paper.
*/
public static Matrix erzeugeWkeitsMatrixSonder(final int selNumberK, final int agentNumberN) {
int k = selNumberK;
int n = agentNumberN;
Matrix wkeitsMatrix = new Matrix(k + 1, n + 1);
// Überschriften.
generateProbMatrixTitles(wkeitsMatrix, n, k);
// Werte erzeugen.
for (int i = 0; i < wkeitsMatrix.getColumnCount(); i++) {
for (int j = 0; j < wkeitsMatrix.getRowCount(); j++) {
if (wkeitsMatrix.getColumnTitle(i).gute > wkeitsMatrix.getRowTitle(j).gute
|| wkeitsMatrix.getColumnTitle(i).schlechte > wkeitsMatrix.getRowTitle(j).schlechte) {
wkeitsMatrix.set(i, j, 0);
} else {
if (i == k / 2) {
wkeitsMatrix.set(i, j, 1); //, rand.nextDouble());
} else {
wkeitsMatrix.set(i, j, 0.0001); //, rand.nextDouble());
}
}
}
}
// Werte normalisieren.
normalizeRowwise(wkeitsMatrix);
return wkeitsMatrix;
}
private static void generateProbMatrixTitles(
final Matrix wkeitsMatrix,
final int n,
final int k) {
for (int i = 0; i < wkeitsMatrix.getColumnCount(); i++) {
wkeitsMatrix.setColumnTitle(i, new Integer2D(i, k - i));
}
for (int j = 0; j < wkeitsMatrix.getRowCount(); j++) {
wkeitsMatrix.setRowTitle(j, new Integer2D(j, n - j));
}
}
/**
* Sum of all non-zero rows gets 1, relations are preserved rowwise.
*
* @param matrix The matrix to normalize.
*/
public static void normalizeRowwise(
final Matrix matrix) {
for (int j = 0; j < matrix.getRowCount(); j++) {
double summe = 0;
for (int i = 0; i < matrix.getColumnCount(); i++) {
summe += matrix.get(i, j);
}
if (summe != 0) {
for (int i = 0; i < matrix.getColumnCount(); i++) {
matrix.set(i, j, matrix.get(i, j) / summe);
}
}
}
}
/**
* Generates probability matrix with a polynomial preference for superior
* agents (cf. ECTA2011 paper).
* 0 Gute : 1/k (oder 0, falls unmöglich; dann Anpassung von k)
* 1 Guter: 2/k (oder 0, falls unmöglich; dann Anpassung von k)
* 2 Gute : 3/k (oder 0, falls unmöglich; dann Anpassung von k)
* ...
*
* @param selNumberK Number of agents for selection tournaments.
* @param agentNumberN Number of agents in population.
* @param exponent The polynomial exponent.
*
* @return Probability matrix.
*/
public static Matrix erzeugeWkeitsMatrixPolynomialGut(
final int selNumberK,
final int agentNumberN,
final double exponent) {
int k = selNumberK;
int n = agentNumberN;
Matrix wkeitsMatrix = new Matrix(k + 1, n + 1);
// Überschriften.
generateProbMatrixTitles(wkeitsMatrix, n, k);
// Werte erzeugen.
for (int i = 0; i < wkeitsMatrix.getColumnCount(); i++) {
for (int j = 0; j < wkeitsMatrix.getRowCount(); j++) {
if (wkeitsMatrix.getColumnTitle(i).gute > wkeitsMatrix.getRowTitle(j).gute
|| wkeitsMatrix.getColumnTitle(i).schlechte > wkeitsMatrix.getRowTitle(j).schlechte) {
wkeitsMatrix.set(i, j, 0);
} else {
wkeitsMatrix.set(i, j, Math.pow(wkeitsMatrix.getColumnTitle(i).gute + 1, exponent));
}
}
}
// Werte normalisieren.
normalizeRowwise(wkeitsMatrix);
return wkeitsMatrix;
}
/**
* Generates probability matrix with a polynomial preference for inferior
* agents (cf. ECTA2011 paper).
* 0 Schlechte : 1/k (oder 0, falls unmöglich; dann Anpassung von k)
* 1 Schlechter: 2/k (oder 0, falls unmöglich; dann Anpassung von k)
* 2 Schlechte : 3/k (oder 0, falls unmöglich; dann Anpassung von k)
* usw.
*
* @param selNumberK Number of agents for selection tournaments.
* @param agentNumberN Number of agents in population.
* @param exponent The polynomial exponent.
*
* @return Probability matrix.
*/
public static Matrix erzeugeWkeitsMatrixPolynomialSchlecht(
final int selNumberK,
final int agentNumberN,
final double exponent) {
int k = selNumberK;
int n = agentNumberN;
Matrix wkeitsMatrix = new Matrix(k + 1, n + 1);
// Überschriften.
generateProbMatrixTitles(wkeitsMatrix, n, k);
// Werte erzeugen.
for (int i = 0; i < wkeitsMatrix.getColumnCount(); i++) {
for (int j = 0; j < wkeitsMatrix.getRowCount(); j++) {
if (wkeitsMatrix.getColumnTitle(i).gute > wkeitsMatrix.getRowTitle(j).gute
|| wkeitsMatrix.getColumnTitle(i).schlechte > wkeitsMatrix.getRowTitle(j).schlechte) {
wkeitsMatrix.set(i, j, 0);
} else {
wkeitsMatrix.set(i, j, Math.pow(wkeitsMatrix.getColumnTitle(i).schlechte + 1, exponent));
}
}
}
// Werte normalisieren.
normalizeRowwise(wkeitsMatrix);
return wkeitsMatrix;
}
private static double getWkeit(
final Integer2D zeileGesMatrix,
final Integer2D spalteWkeitsMatrix,
final Matrix wkeitsMatrix) {
try {
return wkeitsMatrix.get(spalteWkeitsMatrix.gute, zeileGesMatrix.gute);
} catch (Exception e) {
return 0;
}
}
/**
* Generates a Markov transition matrix for a population of N agents,
* where the probabilities for the occurence of tournaments with
* l / (k - l) superior / inferior agents for every specific population state
* i / (n - i) is given in probabilityMatrixC. Selection with an explicit
* (fitness) preference for superior individuals can be modeled by shifting
* the fitness confidence factor c from 0 towards 1.
*
* @param agentNumberN Number of agents in population.
* @param probabilityMatrixC Probabilities for occurence of
* specific tournaments.
* @param cg Fitness confidence factor.
*
* @return The Markov transition matrix.
*/
public static Matrix generateTransitionMatrixKSelection(
final int agentNumberN,
final Matrix probabilityMatrixC,
final double cg) {
int n = agentNumberN;
int k = probabilityMatrixC.getColumnCount() - 1;
Matrix mat = new Matrix(n + 1, n + 1);
// Überschriften.
for (int i = 0; i < mat.getColumnCount(); i++) {
mat.setColumnTitle(i, new Integer2D(i, n - i));
}
for (int j = 0; j < mat.getRowCount(); j++) {
mat.setRowTitle(j, new Integer2D(j, n - j));
}
// Speichert die Summanden für die asymmetrische Wkeits-Verschiebung zugunsten der "Guten".
HashMap<Integer2D, Double> summanden = new HashMap<Integer2D, Double>();
// Übernimm Wkeitsmatrix in Gesamtmatrix.
for (int j = 0; j < mat.getRowCount(); j++) {
for (int i = Math.max(j - k + 1, 0); i < Math.min(j + k, mat.getColumnCount()); i++) {
if (i == j) {
mat.set(i, j, mat.get(i, j) + getWkeit(
mat.getRowTitle(j),
new Integer2D(0, k),
probabilityMatrixC));
mat.set(i, j, mat.get(i, j) + getWkeit(
mat.getRowTitle(j),
new Integer2D(k, 0),
probabilityMatrixC));
} else {
int gute;
double summand;
double l;
if (i < j) {
gute = j - i;
} else if (i > j) {
gute = k - (i - j);
} else {
// Dieser Fall kann nicht auftreten.
gute = -1;
summand = Double.NEGATIVE_INFINITY;
}
l = k - gute;
summand = l / k * cg;
Integer2D spalteWkeitsMatrix = new Integer2D(gute, k - gute);
double wkeit = getWkeit(
mat.getRowTitle(j),
spalteWkeitsMatrix,
probabilityMatrixC);
if (wkeit == 0) {
summand = 0;
}
// Achtung: Hier ist das Zweiertupel (x, y) die Koordinate [x][y] in der Wkeits-Matrix.
summanden.put(new Integer2D(i, j), summand);
mat.set(i, j, mat.get(i, j) + wkeit);
}
}
}
// Füge Wkeit für Konvertierung in Richtung "gut" bzw. "schlecht".
for (int j = 0; j < mat.getRowCount(); j++) {
double kk = k;
double l = kk; // Der Faktor für die Wkeit (=> gut / schlecht).
Double summand;
for (int i = 0; i < kk; i++) {
if (i != 0 && j + i >= 0 && j + i < mat.getColumnCount()) {
summand = summanden.get(new Integer2D(j + i, j));
if (summand == null) {
summand = 0.0;
}
mat.set(j + i, j, mat.get(j + i, j) * (l / kk + summand));
}
l--;
}
l = kk;
for (int i = 0; i < kk; i++) {
if (i != 0 && j - i >= 0 && j - i < mat.getColumnCount()) {
summand = summanden.get(new Integer2D(j - i, j));
if (summand == null) {
summand = 0.0;
}
mat.set(j - i, j, mat.get(j - i, j) * (l / kk - summand));
}
l--;
}
}
return mat;
}
/**
* Generates data for a complete convergence diagram using specific
* probability matrices C.
*
* @param n Population size.
* @param k Tournament size.
* @param iterations Iterations at calculation of inverse
* matrix (note that exact calculation
* as described in ECTA2011 paper is
* not implemented in Java but has been
* performed with MatLab).
* @param seed Random seed used for random matrix.
* @param confidenceFactorC The confidence factor in [0, 1].
* @param fileNameStore The file name to store convergence data.
* @param loadMatrixFromFileName File name from where to get the
* probability matrix in case
* probMatrixFromFile.
* @param optionProbabilityMatrix The number of the probability matrix
* type.
* @param exponent The exponent in cases
* probabilityMatrixPolynomialSuperior and
* probabilityMatrixPolynomialInferior.
*/
public static void generateConvergenceDiagram(
int n,
int k,
int iterations,
long seed,
double confidenceFactorC,
String fileNameStore,
String loadMatrixFromFileName,
int optionProbabilityMatrix,
double exponent) {
StaticMethods.logInfo("k = " + k, null);
StaticMethods.logInfo("n = " + n, null);
StaticMethods.logInfo("seed = " + seed, null);
StaticMethods.logInfo("iterations = " + iterations, null);
StaticMethods.logInfo("c (confidence factor) = " + confidenceFactorC, null);
StaticMethods.logInfo("Option: " + optionProbabilityMatrix, null);
if (optionProbabilityMatrix == 1 || optionProbabilityMatrix == 2) {
StaticMethods.logInfo("Exponent (only options 1 and 2): " + exponent, null);
} else {
StaticMethods.logInfo("(Exponent: " + exponent + " (not used))", null);
}
StaticMethods.logInfo("File name to get probability matrix: " + loadMatrixFromFileName, null);
StaticMethods.logInfo("File name to store data: " + fileNameStore, null);
Matrix mat = null;
if (optionProbabilityMatrix == probMatrixUniform) {
mat = Matrix.erzeugeWkeitsMatrixPolynomialGut(k, n, 0);
} else if (optionProbabilityMatrix == probMatrixPolynomialSuperior) {
mat = Matrix.erzeugeWkeitsMatrixPolynomialGut(k, n, exponent);
} else if (optionProbabilityMatrix == probMatrixPolynomialInferior) {
mat = Matrix.erzeugeWkeitsMatrixPolynomialSchlecht(k, n, exponent);
} else if (optionProbabilityMatrix == probMatrixSpecial) {
mat = Matrix.erzeugeWkeitsMatrixSonder(k, n);
} else if (optionProbabilityMatrix == probMatrixFromFile) {
mat = new Matrix(new File(loadMatrixFromFileName));
}
Matrix matGesamt = Matrix.generateTransitionMatrixKSelection(n, mat, confidenceFactorC);
Matrix matGesamt2 = Matrix.generateTransitionMatrixKSelection(n, mat, confidenceFactorC);
StaticMethods.log(StaticMethods.LOG_INFO, "\n\nProbabilities:\n" + mat, null, "plain", "plain");
StaticMethods.log(StaticMethods.LOG_INFO, "\n\nTransition matrix:\n" + matGesamt, null, "plain", "plain");
// I-Q erzeugen:
Matrix q = new Matrix(matGesamt);
int[] spalten = new int[q.getColumnCount() - 2];
int[] zeilen = new int[q.getRowCount() - 2];
for (int i = 1; i < q.getColumnCount() - 1; i++) {
spalten[i - 1] = i;
}
for (int j = 1; j < q.getRowCount() - 1; j++) {
zeilen[j - 1] = j;
}
q = q.erzeugeSpaltenMatrix(spalten).erzeugeZeilenMatrix(zeilen);
Matrix einheitMinusQ = new Matrix(q);
einheitMinusQ.einheitsMatrix();
einheitMinusQ.sub(q);
StaticMethods.log(StaticMethods.LOG_INFO, "\n\n(I-Q) - for Matlab:\n" + einheitMinusQ.createMatlabString(), null, "plain", "plain");
////
StaticMethods.log(StaticMethods.LOG_INFO, "\n\nSummed up probabilties (should all be 1.0):\n" + Matrix.rowSum(matGesamt).round(2), null, "plain", "plain");
ArrayList<String> werte = new ArrayList<String>();
String wert;
// System.out.println();
for (int i = 0; i < iterations; i++) {
// if (i % 10000 == 0) {
// System.out.println(" (" + i + ")");
// }
// if (i % 100 == 0) {
// System.out.print(".");
// }
wert = "";
for (int j = 0; j < matGesamt.getRowCount(); j++) {
wert += matGesamt.get(0, j) + "\t";
}
// wert = wert.replaceAll("\\.", ",");
werte.add(wert);
matGesamt.mult(matGesamt2);
}
// matGesamt.round(5);
StaticMethods.log(StaticMethods.LOG_INFO, "\n\nRaise to power of " + iterations + " (only columns 0 and n):\n" + matGesamt.erzeugeSpaltenMatrix(new int[] {0, n}), null, "plain", "plain");
StaticMethods.logInfo("Maximum in columns 1-" + (n - 1) + ": " + matGesamt.erzeugeSpaltenMatrix(new int[] {1, n - 1}).maxValue(), null);
if (fileNameStore != null) {
StaticMethods.speichereTextAusArray(".", fileNameStore, werte, null);
}
StaticMethods.log(
StaticMethods.LOG_INFO, "\nProbabilities for eventual superiority: "
+ matGesamt.erzeugeSpaltenMatrix(new int[] {n}).transpone().toPlainString(),
null,
"plain",
"");
}
public static final int probMatrixUniform = 0;
// Polynomial preference for selecting superior individuals.
public static final int probMatrixPolynomialSuperior = 1;
// Polynomial preference for selecting inferior individuals.
public static final int probMatrixPolynomialInferior = 2;
// Special matrix as in Fig. 10 from ECTA2011 paper.
public static final int probMatrixSpecial = 10;
public static final int probMatrixFromFile = 11;
/**
* Parses strings of the form:
*
* "0.0,1.2,2.9; 1.1,2.3,1.4; 2.2,3.3,-4.4; 5.4,-6.4,7.6"
* ==>
* 0.0 1.2 2.9
* 1.1 2.3 1.4
* 2.2 3.3 -4.4
* 5.4 -6.4 7.6
*
* @param matrix
* @return
*/
public static Matrix parseMatrix(final String matrix) {
String[] rows = matrix.replace(" ", "").replace("\n", "").split(";");
ArrayListDouble rowParsed;
ArrayListDouble[] matrixList = new ArrayListDouble[rows.length];
int maxColumns = 0;
int z = 0;
double[][] matrixArray;
for (String row : rows) {
rowParsed = ArrayListDouble.parseArrayListDouble(row);
if (rowParsed.size() > maxColumns) {
maxColumns = rowParsed.size();
}
matrixList[z] = rowParsed;
z++;
}
matrixArray = new double[maxColumns][rows.length];
for (int i = 0; i < matrixArray.length; i++) {
for (int j = 0; j < matrixArray[0].length; j++) {
matrixArray[i][j] = matrixList[j].get(i);
}
}
return new Matrix(matrixArray);
}
/**
* <code>This</code> is not changed.
*
* @return Another matrix that is the inverse (or pseudo-inverse) of <code>this</code>.
*/
public Matrix inverse() {
Jama.Matrix a = new Jama.Matrix(this.matrix);
Jama.Matrix i = a.inverse();
Matrix inv = new Matrix(i.getArray());
return inv;
}
public static void main(String[] args) {
Matrix mat = new Matrix(5, 5);
mat.randomize();
System.out.println(mat.toStringFormatiert());
mat.addRow(3, false);
mat.addColumn(3, true);
System.out.println(mat.toStringFormatiert());
System.exit(0);
int n = 30;
int k = 4;
long seed = System.currentTimeMillis();
Double cg = 0.2;
int iterations = 10000;
String fileNameProbMatrix = "./C_Matrix_only_3-1-Selection.txt";
String fileNameOutput = "./output.txt";
generateConvergenceDiagram(
n,
k,
iterations,
seed,
cg,
fileNameOutput,
fileNameProbMatrix,
probMatrixFromFile,
0);
}
/**
* Adds a zero row at the end of the matrix (headings are set null).
*/
public void addRow() {
this.addRow(this.getRowCount(), false);
}
/**
* Adds a zero row at the specified position (headings are set null).
* If the position is larger than the number of row, the matrix is filled
* with zero rows at the end to match.
*
* @param position The position to add a new row.
*/
public void addRow(int position, boolean fillWithRandomValues) {
if (position > this.getRowCount()) {
this.addRow(position - 1, fillWithRandomValues);
}
Matrix newMatrix = new Matrix(this.getColumnCount(), this.getRowCount() + 1);
int buffer = 0;
for (int j = 0; j < this.getRowCount(); j++) {
if (j >= position) {
buffer = 1;
}
for (int i = 0; i < this.getColumnCount(); i++) {
newMatrix.set(i, j + buffer, this.get(i, j));
}
}
if (fillWithRandomValues) {
for (int i = 0; i < this.getColumnCount(); i++) {
newMatrix.set(i, position, this.getRandomValue());
}
}
this.matrix = newMatrix.matrix;
this.spaltenUeberschr = newMatrix.spaltenUeberschr;
this.zeilenUeberschr = newMatrix.zeilenUeberschr;
}
private double randomMaxValue = 1;
private double randomMinValue = 1;
private Random rand = new Random();
public void setRandomParameters(double randMaxValue, double randMinValue, Random rand) {
this.rand = rand;
this.randomMaxValue = randMaxValue;
this.randomMinValue = randMinValue;
}
/**
* Adds a zero row at the end of the matrix (headings are set null).
*/
public void addColumn() {
this.addColumn(this.getColumnCount(), false);
}
/**
* Adds a zero row at the specified position (headings are set null).
* If the position is larger than the number of row, the matrix is filled
* with zero rows at the end to match.
*
* @param position The position to add a new row.
*/
public void addColumn(int position, boolean fillWithRandomValues) {
if (position > this.getColumnCount()) {
this.addColumn(position - 1, fillWithRandomValues);
}
Matrix newMatrix = new Matrix(this.getColumnCount() + 1, this.getRowCount());
int buffer = 0;
for (int i = 0; i < this.getColumnCount(); i++) {
if (i >= position) {
buffer = 1;
}
for (int j = 0; j < this.getRowCount(); j++) {
newMatrix.set(i + buffer, j, this.get(i, j));
}
}
if (fillWithRandomValues) {
for (int i = 0; i < this.getRowCount(); i++) {
newMatrix.set(position, i, this.getRandomValue());
}
}
this.matrix = newMatrix.matrix;
this.spaltenUeberschr = newMatrix.spaltenUeberschr;
this.zeilenUeberschr = newMatrix.zeilenUeberschr;
}
}