Input/Output Ausgleichen chemischer Reaktionsgleichungen mit dem Gauß-Algorithmus

Daviddiviad

Mitglied
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:

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 :)
 

Daviddiviad

Mitglied
Das ist mir klar, aber wenn ich die Gleichungen auf dem Papier, oder sogar im Kopf lösen kann, muss ja ein Fehler im Programm vorliegen.

Trotzdem Danke :D
 

Oben