Hey Leute,
ich versuche schon seit längerem ein Programm rund um die Chemie zu schreiben. Nun bin ich zum Teil des automatischen Ausgleichen von Reaktionsgleichungen gekommen. Dies versuche ich mit dem Gauß Algorithmus umzusetzen. Einen Parser für die Reaktionsgleichung habe ich schon, es funktioniert auch bei einigen Gleichungen sehr gut, bei anderen kommt der Algorithmus jedoch auf keine Lösung und spuckt "0" aus.
Code:
Die Element Klasse ist eine Enumeration aller chemischen Elemente.
Nun habe ich folgende Fragen:
- Liegt es am Gauß-Algorithmus das diese Fehler auftreten? (Diesen habe ich aus dem Internet)
- Mache ich etwas falsch beim umstellen der Wertigkeiten in die Matrix?
Wenn ihr irgendwelche Ideen habt, wie ich so einen auto-Ausgleicher auch anders umsetzen kann, würde ich mich sehr darüber freuen.
- David
ich versuche schon seit längerem ein Programm rund um die Chemie zu schreiben. Nun bin ich zum Teil des automatischen Ausgleichen von Reaktionsgleichungen gekommen. Dies versuche ich mit dem Gauß Algorithmus umzusetzen. Einen Parser für die Reaktionsgleichung habe ich schon, es funktioniert auch bei einigen Gleichungen sehr gut, bei anderen kommt der Algorithmus jedoch auf keine Lösung und spuckt "0" aus.
Code:
Java:
package ct.test;
public class GaussianElimination {
private static final double EPSILON = 1e-10;
// Gaussian elimination with partial pivoting
public static double[] lsolve(double[][] A, double[] b) {
int N = b.length;
for (int p = 0; p < N; p++) {
// find pivot row and swap
int max = p;
for (int i = p + 1; i < N; i++) {
if (Math.abs(A[i][p]) > Math.abs(A[max][p])) {
max = i;
}
}
double[] temp = A[p]; A[p] = A[max]; A[max] = temp;
double t = b[p]; b[p] = b[max]; b[max] = t;
// singular or nearly singular
if (Math.abs(A[p][p]) <= EPSILON) {
throw new RuntimeException("Matrix is singular or nearly singular");
}
// pivot within A and b
for (int i = p + 1; i < N; i++) {
double alpha = A[i][p] / A[p][p];
b[i] -= alpha * b[p];
for (int j = p; j < N; j++) {
A[i][j] -= alpha * A[p][j];
}
}
}
// back substitution
double[] x = new double[N];
for (int i = N - 1; i >= 0; i--) {
double sum = 0.0;
for (int j = i + 1; j < N; j++) {
sum += A[i][j] * x[j];
}
x[i] = (b[i] - sum) / A[i][i];
}
return x;
}
public void recompensateEquation (ReactionEquation e) {
// e.getAllBonds() Alle Verbinungen/Reaktanten in der Gleichung (Ag, HNO3, AgNO3, NO, H2O)
// e.getElementsInEquation() Alle Elemente die an der Verbindung teil haben. (Ag, H, N, O)
try {
double[] b = new double[e.getAllBonds().length - 1];
for (int i = 0; i < e.getElementsInEquation().length; i++) { //Hier lege ich sozusagen eine Variable fest, nämlich auf 1.
//Das ist die des Reaktanten Silber, der dann den Koeffizienten 1 hat.
b[i] = e.getAllBonds()[0].getIndexOfElement(e.getElementsInEquation()[i]);
}
/*b hat nun die Indices der Elemente, welche an der Verbindung teilhaben, in sich (1, 0, 0, 0) = 1 SILVER, 0 HYDROGEN, O NITROGEN, 0 OXYGEN*/
// double[][] matrix = new double[][]{{0, 1, 0, 0},
// {1, 0, 0, 2}, //Die Matrix einmal dargestellt
// {1, 1, 1, 0},
// {3, 3, 1, 1}};
double[][] matrix = new double[e.getElementsInEquation().length][e.getAllBonds().length - 1];
for (int i = 0; i < e.getElementsInEquation().length; i++) { /**0, 1, 2, 3 (Die Elemente in der Reaktion)**/
for (int j = 1; j < e.getAllBonds().length; j++) { /**2, 3, 4, 5 (Die Indices der Reaktion, welche noch nicht vergeben sind**/
matrix[i][j - 1] = e.getAllBonds()[j].getIndexOfElement(e.getElementsInEquation()[i]);
}
}
double[] rs = lsolve(matrix, b);
double multiplier = (1 / getLowest(rs)); //Hochrechnen auf ganze Zahlen
e.getAllBonds()[0].setCoefficient(toRoundetInt(1 * multiplier)); //Koeffitienten setzen.
for (int i = 0; i < rs.length; i++) {
e.getAllBonds()[i + 1].setCoefficient(toRoundetInt(rs[i] * multiplier));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static int toRoundetInt(double data) {
double roundet = Math.abs(data);
return (int) roundet;
}
public static void main(String[] args) {
//Einmal diese Gleichung als Beispiel:
System.out.println(new ReactionEquation("Ag + HNO3 > AgNO3 + NO + H2O").compensate().toString());
}
private static double getLowest (double[] data) {
double lowest = 0.0;
double old;
old = data[data.length - 1];
for (int i = 0; i < data.length; i++) {
if (data[i] < old) lowest = data[i];
old = data[i];
}
return lowest;
}
}
Die Element Klasse ist eine Enumeration aller chemischen Elemente.
Nun habe ich folgende Fragen:
- Liegt es am Gauß-Algorithmus das diese Fehler auftreten? (Diesen habe ich aus dem Internet)
- Mache ich etwas falsch beim umstellen der Wertigkeiten in die Matrix?
Wenn ihr irgendwelche Ideen habt, wie ich so einen auto-Ausgleicher auch anders umsetzen kann, würde ich mich sehr darüber freuen.
- David