/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package amgframework; import amgframework.SparseMatrix.*; import java.util.Enumeration; import java.util.Iterator; /** * * @author mrupp */ public class FlexSparseMatrix implements SparseMatrix { FlexSparseMatrix(boolean _bNeedsValues) { bNeedsValues = _bNeedsValues; } void resize(int rows, int _cols) { rowStart = new int[rows]; rowEnd = new int[rows]; rowMax = new int[rows]; for (int i = 0; i < rows; i++) rowStart[i] = -1; m_numCols = _cols; if (bNeedsValues) values = new double[rows]; cols = new int[rows]; maxValues = 0; } @Override public int num_rows() { return rowStart.length; } @Override public int num_cols() { return m_numCols; } void copyToNewSize(int newSize) { double v[] = new double[newSize]; int c[] = new int[newSize]; int j = 0; for (int r = 0; r < num_rows(); r++) { if (rowStart[r] == -1) continue; int start = j; for (int k = rowStart[r]; k < rowEnd[r]; k++, j++) { if (bNeedsValues) v[j] = values[k]; c[j] = cols[k]; } rowStart[r] = start; rowEnd[r] = rowMax[r] = j; } fragmented = 0; maxValues = j; if (bNeedsValues) values = v; cols = c; } void defragment() { copyToNewSize(nnz); } void assureValuesSize(int s) { if (s < cols.length) return; int newSize = nnz * 2; if (newSize < s) newSize = s; copyToNewSize(newSize); } public boolean has_connection(int r, int c) { return get_index(r, c, false) != -1; } private int get_index_internal(int row, int col) { assert (rowStart[row] != -1); int l = rowStart[row], r = rowEnd[row], mid = 0; while (l < r) { mid = (l + r) / 2; if (cols[mid] < col) l = mid + 1; else { if (cols[mid] > col) r = mid - 1; else return mid; } } mid = (l + r) / 2; if (mid < rowStart[row]) return rowStart[row]; else if (mid == rowEnd[row] || col <= cols[mid]) return mid; else return mid + 1; } int get_index(int r, int c, boolean bCreate) { if (rowStart[r] == -1) { if (!bCreate) return -1; assureValuesSize(maxValues + 1); rowStart[r] = maxValues; rowEnd[r] = maxValues + 1; rowMax[r] = maxValues + 1; if (bNeedsValues) values[maxValues] = 0.0; cols[maxValues] = c; maxValues++; nnz++; return maxValues - 1; } /* for(int i=rowStart[r]; i<rowEnd[r]; i++) if(cols[i] == c) return i;*/ int index = get_index_internal(r, c); if (index < rowEnd[r] && index < maxValues && cols[index] == c) return index; assert (index == rowEnd[r] || cols[index] > c); if (rowEnd[r] == rowMax[r]) { int newSize = (rowEnd[r] - rowStart[r]) * 2; if (maxValues + newSize > cols.length) { assureValuesSize(maxValues + newSize); index = get_index_internal(r, c); } fragmented += rowEnd[r] - rowStart[r]; index = index - rowStart[r] + maxValues; int j = rowEnd[r] - rowStart[r] + maxValues; for (int i = rowEnd[r] - 1; i >= rowStart[r]; i--, j--) { if (j == index) j--; if (bNeedsValues) values[j] = values[i]; cols[j] = cols[i]; } rowEnd[r] = maxValues + rowEnd[r] - rowStart[r] + 1; rowStart[r] = maxValues; rowMax[r] = maxValues + newSize; maxValues += newSize; } else { for (int i = rowEnd[r] - 1; i >= index; i--) { if (bNeedsValues) values[i + 1] = values[i]; cols[i + 1] = cols[i]; } rowEnd[r]++; } if (bNeedsValues) values[index] = 0.0; cols[index] = c; assert (index >= rowStart[r] && index < rowEnd[r]); nnz++; return index; } void set(int r, int c, double v) { int j = get_index(r, c, true); if (bNeedsValues) values[j] = v; } public double get(int r, int c) { int j = get_index(r, c, false); if (j == -1) return 0.0; else if(bNeedsValues) return values[j]; else return 1.0; } public void set_connection(int r, int c) { get_index(r, c, true); } @Override public Iterator<IConnection> begin_row(int r) { return new rowIterator(this, r); } FlexSparseMatrix mult(FlexSparseMatrix A) { return FlexSparseMatrix.Mult(this, A); } private static FlexSparseMatrix Mult(FlexSparseMatrix A, FlexSparseMatrix B) { FlexSparseMatrix R = new FlexSparseMatrix(true); R.resize(A.num_rows(), B.num_cols()); assert (A.num_cols() == B.num_rows()); for (int i = 0; i < A.num_rows(); i++) { for (IConnection itAik : A.row(i)) { double Aik = itAik.value(); if (Aik == 0.0) continue; int k = itAik.index(); for (IConnection itBkj : B.row(k)) { double Bkj = itBkj.value(); if (Bkj == 0.0) continue; int j = itBkj.index(); int index = R.get_index(i, j, true); R.values[index] += Aik * Bkj; } } } R.defragment(); return R; } FlexSparseMatrix mult(FlexSparseMatrix B, FlexSparseMatrix C) { return FlexSparseMatrix.Mult(this, B, C); } private static FlexSparseMatrix Mult(FlexSparseMatrix A, FlexSparseMatrix B, FlexSparseMatrix C) { FlexSparseMatrix R = new FlexSparseMatrix(true); R.resize(A.num_rows(), C.num_cols()); assert (A.num_cols() == B.num_rows() && B.num_cols() == C.num_rows()); for (int i = 0; i < A.num_rows(); i++) { for (IConnection itAik : A.row(i)) { double Aik = itAik.value(); if (Aik == 0.0) continue; int k = itAik.index(); for (IConnection itBkj : B.row(k)) { double Bkj = itBkj.value(); if (Bkj == 0.0) continue; int j = itBkj.index(); for (IConnection itCjl : C.row(j)) { double Cjl = itCjl.value(); if (Cjl == 0.0) { continue; } int l = itCjl.index(); int index = R.get_index(i, l, true); R.values[index] += Aik * Bkj * Cjl; } } } } R.defragment(); return R; } class connection implements IConnection { FlexSparseMatrix A; connection(FlexSparseMatrix _A, int _i, double _v) { A = _A; i = _i; v = _v; } void set(double d) { A.values[i] = d; } void add(double d) { A.values[i] += d; } void sub(double d) { A.values[i] -= d; } @Override public double value() { return v; } @Override public int index() { return i; } int i; double v; } class rowIterator implements Iterator<IConnection> { FlexSparseMatrix A; int row; int end; int i; rowIterator(FlexSparseMatrix _A, int r) { A = _A; i = A.rowStart[r]; if (i == -1) end = -2; else end = A.rowEnd[r]; } rowIterator(FlexSparseMatrix _A, int r, int c) { A = _A; i = A.get_index(r, c, true); } @Override public boolean hasNext() { return i < end; } @Override public IConnection next() { if (A.bNeedsValues) return new connection(A, A.cols[i], A.values[i++]); else return new connection(A, A.cols[i++], 1.0); } @Override public void remove() { throw new UnsupportedOperationException("Not supported yet."); } } @Override public Row row(int r) { return new Row(this, r); } public int num_connections() { return nnz; } public int num_connections(int r) { if (rowStart[r] == -1) return 0; return rowEnd[r] - rowStart[r]; } public void print_statistic() { System.out.println("Matrix " + num_rows() + "x" + num_cols() + ". NNZ: " + nnz + ". Cols Length: " + cols.length + ". MaxValues=" + maxValues + ". Fragmented: " + fragmented + " values surplus: " + (maxValues - nnz)); } @Override public void print() { for (int r = 0; r < num_rows(); r++) for (IConnection c : row(r)) System.out.println("A(" + r + ", " + c.index() + ") = " + c.value()); } FlexSparseMatrix transpose() { FlexSparseMatrix A = new FlexSparseMatrix(bNeedsValues); /*A.resize(num_cols(), num_rows()); for(int r=0; r<num_rows(); r++) for(IConnection c : row(r)) A.set(c.index(), r, c.value()); A.defragment();*/ A.rowStart = new int[num_cols()]; A.rowMax = new int[num_cols()]; A.rowEnd = new int[num_cols()]; if (bNeedsValues) A.values = new double[nnz]; A.cols = new int[nnz]; A.nnz = nnz; A.maxValues = maxValues; A.fragmented = 0; A.m_numCols = num_rows(); int r, c; for (r = 0; r < num_rows(); r++) for (IConnection con : row(r)) A.rowMax[con.index()]++; A.rowEnd[0] = A.rowMax[0]; A.rowMax[0] = 0; for (c = 1; c < num_cols(); c++) { A.rowStart[c] = A.rowEnd[c - 1]; A.rowEnd[c] = A.rowStart[c] + A.rowMax[c]; A.rowMax[c] = A.rowStart[c]; } // ????? for (r = 0; r < num_rows(); r++) { for (IConnection con : row(r)) { c = con.index(); A.cols[A.rowMax[c]] = r; if (bNeedsValues) A.values[A.rowMax[c]] = con.value(); A.rowMax[c]++; } } // todo: sort rows return A; } @Override public double row_mult(Vector b, int r) { if(rowStart[r] == -1) return 0.0; double s = 0; /*for (IConnection con : row(r)) s += b.get(con.index()) * con.value();*/ for(int i=rowStart[r]; i<rowEnd[r]; i++) s += b.get(cols[i]) * values[i]; return s; } public boolean is_equal(SparseMatrix A) { for (int r = 0; r < num_rows(); r++) for (IConnection con : row(r)) if (con.value() != A.get(r, con.index())) return false; return true; } private int rowStart[]; private int rowEnd[]; private int rowMax[]; private int cols[]; int fragmented = 0; int nnz = 0; boolean bNeedsValues; private double[] values; int maxValues; private int m_numCols; }