package sim.util.matrix; public abstract class Matrix { public int m; public int n; public abstract Vector times(Vector B); public abstract Vector times(Vector B, Vector C); public abstract Vector transposeTimes(Vector B); public abstract Vector transposeTimes(Vector B, Vector C); public abstract DiagonalMatrix getDiagonalMatrix(); public static Vector solveBiConjugateGradient(BorderedDiagonalIdentityMatrix A, Vector b, Vector x, int maxit, double stop_tol, boolean useILU) { double b_norm = Math.sqrt(b.dot(b)); if (b_norm == 0) { x = b.copyInto(x); return x; } Vector r = new Vector(b.m); Vector r_tilde = new Vector(b.m); Vector z = new Vector(b.m); Vector z_tilde = new Vector(b.m); Vector p = new Vector(b.m); Vector p_tilde = new Vector(b.m); Vector q = new Vector(b.m); Vector q_tilde = new Vector(b.m); double rho = 0; double rho_prev = 0; double beta; double alpha; Vector tmp = new Vector(b.m); r = b.minus(A.times(x, tmp), r); r_tilde = b.minus(A.transposeTimes(x, tmp), r_tilde); int i = 1; while (i <= maxit) { double[] pivots = A.getPivots(); if (useILU) { z = A.DILUSolve(r, pivots); z_tilde = A.DILUTransposeSolve(r_tilde, pivots); } else { r.copyInto(z); r_tilde.copyInto(z_tilde); } rho_prev = rho; rho = z.dot(r_tilde); if (rho == 0) { throw new RuntimeException("BiConjugate Gradient failed to converge - rho is 0"); } if (i == 1) { z.copyInto(p); z_tilde.copyInto(p_tilde); } else { beta = rho / rho_prev; p = z.plus(p.times(beta, tmp), p); p_tilde = z_tilde.plus(p_tilde.times(beta, tmp), p_tilde); } q = A.times(p, q); q_tilde = A.transposeTimes(p_tilde, q_tilde); if (p_tilde.dot(q) == 0) throw new RuntimeException("P dot Q is 0"); alpha = rho/(p_tilde.dot(q)); x = x.plus(p.times(alpha, tmp), x); r = r.minus(q.times(alpha, tmp), r); r_tilde = r_tilde.minus(q_tilde.times(alpha, tmp), r_tilde); double r_norm = Math.sqrt(r.dot(r)); if (r_norm <= stop_tol * b_norm) break; i++; } if (i > maxit) throw new RuntimeException("BiConjugate Gradient failed to converge - max iterations exceeded"); return x; } public static Vector solveBiConjugateGradient(Matrix J, DiagonalMatrix W, DiagonalMatrix M, sim.util.matrix.Vector b, sim.util.matrix.Vector x, int maxit, double stop_tol) { double b_norm = Math.sqrt(b.dot(b)); if (b_norm == 0) { x = b.copyInto(x); return x; } Vector r = new Vector(b.m); Vector r_tilde = new Vector(b.m); Vector z = new Vector(b.m); Vector z_tilde = new Vector(b.m); Vector p = new Vector(b.m); Vector p_tilde = new Vector(b.m); Vector q = new Vector(b.m); Vector q_tilde = new Vector(b.m); double rho = 0; double rho_prev = 0; double beta; double alpha; Vector tmpJ = new Vector(J.m); Vector tmpJt = new Vector(J.n); Vector tmpW = new Vector(W.m); Vector tmpb = new Vector(b.m); Vector tmpx = new Vector(x.m); r = b.minus(J.times(W.times(J.transposeTimes(x, tmpJt), tmpW), tmpJ), r); r.copyInto(r_tilde); int i = 1; while (i <= maxit) { M.solve(r, z); M.solve(r_tilde, z_tilde); rho_prev = rho; rho = z.dot(r_tilde); if (rho == 0) throw new RuntimeException("BiConjugate Gradient failed to converge - rho is 0"); if (i == 1) { z.copyInto(p); z_tilde.copyInto(p_tilde); } else { beta = rho / rho_prev; p = z.plus(p.times(beta, tmpb), p); p_tilde = z_tilde.plus(p_tilde.times(beta, tmpb), p_tilde); } q = J.times(W.times(J.transposeTimes(p, tmpJt), tmpW), q); q_tilde = J.times(W.times(J.transposeTimes(p_tilde, tmpJt), tmpW), q_tilde); alpha = rho/(p_tilde.dot(q)); x = x.plus(p.times(alpha, tmpx), x); r = r.minus(q.times(alpha, tmpx), r); r_tilde = r_tilde.minus(q_tilde.times(alpha, tmpx), r_tilde); double r_norm = Math.sqrt(r.dot(r)); if (r_norm <= stop_tol * b_norm) break; i++; } if (i > maxit) throw new RuntimeException("BiConjugate Gradient failed to converge - max iterations exceeded"); return x; } }