/*
* Datei: MatrixVarianten.java
* Autor(en): Lukas König, free internet code.
* Java-Version: 6.0
* Erstellt: 08.04.2010
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* 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.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import eas.math.MiscMath;
import eas.miscellaneous.datatypes.DoppComp;
import eas.miscellaneous.datatypes.Integer2D;
/**
* @author Lukas König, Thomas Darimont (Internet).
*
* http://www.tutorials.de/forum/java/
* 164941-n-x-n-matrizenmultiplikation-aber-wie.html
*/
public class MatrixVarianten implements Serializable {
private static final long serialVersionUID = -4504318010909128688L;
/**
* Die Felder der Matrix.
*/
private double[][] matrix;
/**
* Zeilenüberschriften.
*/
private Integer2D[] zeilenUeberschr;
/**
* Spalten�berschriften.
*/
private Integer2D[] spaltenUeberschr;
/**
* Konstruktor.
*
* @param x Die Anzahl der Spalten.
* @param y Die Anzahl der Zeilen.
*/
public MatrixVarianten(final int x, final int y) {
this.matrix = new double[x][y];
this.zeilenUeberschr = new Integer2D[this.getAnzZeilen()];
this.spaltenUeberschr = new Integer2D[this.getAnzSpalten()];
}
/**
* Konstruktor.
*
* @param mat Die Initialmatrix.
*/
public MatrixVarianten(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.getAnzZeilen()];
this.spaltenUeberschr = new Integer2D[this.getAnzSpalten()];
}
public MatrixVarianten(final MatrixVarianten matrix) {
this(matrix.matrix);
for (int i = 0; i < matrix.getAnzSpalten(); i++) {
this.spaltenUeberschr[i] = matrix.spaltenUeberschr[i];
}
for (int j = 0; j < matrix.getAnzZeilen(); j++) {
this.zeilenUeberschr[j] = matrix.zeilenUeberschr[j];
}
}
/**
* Berechnet die Wahrscheinlichkeit, dass sich zwei unterschiedliche
* aus einer Population treffen.
*
* @param vert Die Verteilung guter und schlechter in der Population.
* @param schlechteGuete Die Güte der schlechten Roboter
* (0 - unbeweglich, 1 - gleich wie gute).
*
* @return Die Wahrscheinlichkeit.
*/
private double wkeitUnterschiedlich(
final Integer2D vert, final double schlechteGuete) {
double gute = vert.gute;
double schlechte = vert.schlechte;
// Schlechte sind so gut wie gute (1).
if (schlechteGuete > 0.5) {
return 2 * gute * schlechte / (gute + schlechte)
/ (gute + schlechte - 1);
} else { // Schlechte sind schlecht (unbeweglich; 0).
if (Math.abs(gute) < 0.001) {
return 0;
} else {
return schlechte / (gute + schlechte - 1);
}
}
}
/**
* Erzeugt einen Reproduktionsgraphen für die angegebene Populationsgröße
* für eine homogene Markow-Kette.
*
* Dabei wird zwischen guten und schlechten Individuen unterschieden, die
* sich gleichverteilt zufällig paarweise treffen.
*
* @param popGr Die Populationsgröße.
* @param schlechteGuete Die Güte der schlechten Roboter
* (0 - unbeweglich, 1 - gleich wie gute).
*
* @return Die Wahrscheinlichkeitmatrix.
*/
public static MatrixVarianten erzeugeRepGraphFein(
final int popGr,
final double schlechteGuete) {
LinkedList<Integer2D> zustaende = new LinkedList<Integer2D>();
MatrixVarianten mat;
for (int i = 0; i <= popGr; i++) {
zustaende.add(new Integer2D(i, popGr - i));
}
Collections.sort(zustaende, new DoppComp());
mat = new MatrixVarianten(zustaende.size(), zustaende.size());
for (int i = 0; i < zustaende.size(); i++) {
mat.setSpaltenUeberschr(i, zustaende.get(i));
mat.setZeilenUeberschr(i, zustaende.get(i));
}
for (int i = 0; i < mat.getAnzZeilen(); i++) {
for (int j = 0; j < mat.getAnzSpalten(); j++) {
// X / Y => X+1 / Y-1
if (mat.getSpaltenUeberschr(j).gute
- mat.getZeilenUeberschr(i).gute == 1) {
mat.set(i, j, mat.wkeitUnterschiedlich(mat
.getZeilenUeberschr(i), schlechteGuete) / 2);
}
// X / Y => X-1 / Y+1
if (mat.getSpaltenUeberschr(j).gute
- mat.getZeilenUeberschr(i).gute == -1) {
mat.set(i, j, mat.wkeitUnterschiedlich(mat
.getZeilenUeberschr(i), schlechteGuete) / 2);
}
// X / Y => X / Y
if (mat.getSpaltenUeberschr(j).gute
- mat.getZeilenUeberschr(i).gute == 0) {
mat.set(i, j, 1 - mat.wkeitUnterschiedlich(mat
.getZeilenUeberschr(i), schlechteGuete));
}
}
}
mat.transpone();
return mat;
}
/**
* Erzeugt einen Rekombinationsgraphen als
* Markow-Wahrscheinlichkeits-Matrix.
*
* @param startX Die Anzahl der guten Startroboter.
* @param startY Die Anzahl der schlechten Startroboter.
*
* @return Die Wahrscheinlichkeitsmatrix.
*/
public static MatrixVarianten erzeugeRepGraph(final int startX, final int startY) {
HashSet<Integer2D> zustaende = new HashSet<Integer2D>();
LinkedList<Integer2D> hinzu = new LinkedList<Integer2D>();
LinkedList<Integer2D> zustListe;
MatrixVarianten mat;
hinzu.add(new Integer2D(startX, startY));
while (!zustaende.containsAll(hinzu)) {
zustaende.addAll(hinzu);
hinzu.clear();
for (Integer2D p : zustaende) {
if (p.gute >= p.schlechte) {
for (int i = -p.schlechte; i <= p.schlechte; i += 1) {
hinzu.add(new Integer2D(p.gute + i, p.schlechte - i));
}
} else {
for (int i = -p.gute; i <= p.gute; i += 1) {
hinzu.add(new Integer2D(p.gute + i, p.schlechte - i));
}
}
}
}
zustListe = new LinkedList<Integer2D>(zustaende);
Collections.sort(zustListe, new DoppComp());
mat = new MatrixVarianten(zustListe.size(), zustListe.size());
for (int i = 0; i < zustListe.size(); i++) {
mat.setSpaltenUeberschr(i, zustListe.get(i));
mat.setZeilenUeberschr(i, zustListe.get(i));
}
// Matrix f�llen.
// Deterministische Zeilen:
for (int i = 0; i < mat.getAnzZeilen(); i++) {
if (mat.getZeilenUeberschr(i).gute == 0
|| mat.getZeilenUeberschr(i).schlechte == 0) {
for (int j = 0; j < mat.getAnzSpalten(); j++) {
if (mat.getSpaltenUeberschr(j).equals(
mat.getZeilenUeberschr(i))) {
mat.set(i, j, 1);
} else {
mat.set(i, j, 0);
}
}
}
}
// Probabilistische Zeilen:
for (int i = 0; i < mat.getAnzZeilen(); i++) {
if (mat.getZeilenUeberschr(i).gute >= mat.getZeilenUeberschr(i).schlechte) {
for (int k = 0; k <= mat.getZeilenUeberschr(i).schlechte; k++) {
for (int j = 0; j < mat.getAnzSpalten(); j++) {
if (mat.getSpaltenUeberschr(j).gute == mat
.getZeilenUeberschr(i).gute
- mat.getZeilenUeberschr(i).schlechte + 2 * k
&& mat.getSpaltenUeberschr(j).schlechte == 2
* mat.getZeilenUeberschr(i).schlechte - 2 * k) {
double wert = MiscMath.binomialCoefficient(mat
.getZeilenUeberschr(i).schlechte, k)
/ Math.pow(2, mat.getZeilenUeberschr(i).schlechte);
mat.set(i, j, wert);
}
}
}
} else {
for (int k = 0; k <= mat.getZeilenUeberschr(i).gute; k++) {
for (int j = 0; j < mat.getAnzSpalten(); j++) {
if (mat.getSpaltenUeberschr(j).gute == 2
* mat.getZeilenUeberschr(i).gute - 2 * k
&& mat.getSpaltenUeberschr(j).schlechte == mat
.getZeilenUeberschr(i).schlechte
- mat.getZeilenUeberschr(i).gute + 2 * k) {
double wert = MiscMath.binomialCoefficient(mat
.getZeilenUeberschr(i).gute, k)
/ Math.pow(2, mat.getZeilenUeberschr(i).gute);
mat.set(i, j, wert);
}
}
}
}
}
mat.transpone();
return mat;
}
/**
* @param i Spalte.
* @param j Zeile.
*
* @return Das Feld [i,j].
*/
public double get(final int i, final int j) {
return this.matrix[i][j];
}
/**
* @param i Die Zeile.
* @param j Die Spalte.
* @param wert Der zu setzende Wert.
*/
public void set(final int i, final int j, final double wert) {
this.matrix[i][j] = wert;
}
/**
* @return Spaltenanzahl der Matrix.
*/
public int getAnzSpalten() {
return this.matrix.length;
}
/**
* @return Zeilenanzahl der Matrix.
*/
public int getAnzZeilen() {
if (this.matrix.length == 0) {
return 0;
}
return this.matrix[0].length;
}
/**
* Gibt die j-te Zeilen�berschrift zur�ck.
*
* @param j Nummer der �berschrift.
*
* @return Die �berschrift mit der angegebenen Nummer.
*/
public Integer2D getZeilenUeberschr(final int j) {
return this.zeilenUeberschr[j];
}
/**
* Gibt die i-te Spaltenn�berschrift zur�ck.
*
* @param i Nummer der �berschrift.
*
* @return Die �berschrift mit der angegebenen Nummer.
*/
public Integer2D getSpaltenUeberschr(final int i) {
return this.spaltenUeberschr[i];
}
/**
* Setzt die i-te �berschrift auf einen Wert.
*
* @param i Nummer der �berschrift.
*
* @param wert Der Wert, auf den die �berschrift gesetzt werden soll.
*/
public void setSpaltenUeberschr(final int i, final Integer2D wert) {
this.spaltenUeberschr[i] = wert;
}
/**
* Setzt die j-te �berschrift auf einen Wert.
*
* @param j Nummer der �berschrift.
*
* @param wert Der Wert, auf den die �berschrift gesetzt werden soll.
*/
public void setZeilenUeberschr(final int j, final Integer2D wert) {
this.zeilenUeberschr[j] = wert;
}
public void transpone() {
MatrixVarianten mat = new MatrixVarianten(this.getAnzZeilen(), this.getAnzSpalten());
for (int i = 0; i < this.getAnzSpalten(); i++) {
mat.setZeilenUeberschr(i, this.getSpaltenUeberschr(i));
for (int j = 0; j < this.getAnzZeilen(); j++) {
mat.setSpaltenUeberschr(j, this.getZeilenUeberschr(j));
mat.set(j, i, this.get(i, j));
}
}
this.matrix = mat.matrix;
this.spaltenUeberschr = mat.spaltenUeberschr;
this.zeilenUeberschr = mat.zeilenUeberschr;
}
/**
* @param selAnzahlK Anzahl der Agenten für die Selektion.
* @param agentenAnzahlN Anzahl der Agenten in der Population.
*
* @return Wahrscheinlichkeitsmatrix.
*/
public static Matrix erzeugeWkeitsMatrixStandard1(final int selAnzahlK, final int agentenAnzahlN) {
int k = selAnzahlK;
int n = agentenAnzahlN;
Matrix wkeitsMatrix = new Matrix(k + 1, n + 1);
// Ãœberschriften.
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));
}
// 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, 1);
}
}
}
// Werte normalisieren.
for (int j = 0; j < wkeitsMatrix.getRowCount(); j++) {
double summe = 0;
for (int i = 0; i < wkeitsMatrix.getColumnCount(); i++) {
summe += wkeitsMatrix.get(i, j);
}
for (int i = 0; i < wkeitsMatrix.getColumnCount(); i++) {
wkeitsMatrix.set(i, j, wkeitsMatrix.get(i, j) / summe);
}
}
return wkeitsMatrix;
}
}