sascha@2695: package de.intevation.flys.artifacts.model; sascha@2695: sascha@3059: import de.intevation.flys.artifacts.math.Linear; sascha@3059: sascha@2695: import gnu.trove.TDoubleArrayList; sascha@2695: sascha@2695: import java.io.Serializable; sascha@2695: sascha@2785: import org.apache.log4j.Logger; sascha@2785: sascha@2695: public class Parameters sascha@2695: implements Serializable sascha@2695: { sascha@2785: private static Logger log = Logger.getLogger(Parameters.class); sascha@2785: sascha@3217: public interface Visitor { sascha@3217: sascha@3217: void visit(double [] row); sascha@3217: sascha@3217: } // interface Visitor sascha@3217: sascha@3059: public static final double EPSILON = 1e-4; sascha@3059: sascha@2695: protected String [] columnNames; sascha@2695: protected TDoubleArrayList [] columns; sascha@2695: sascha@2695: public Parameters() { sascha@2695: } sascha@2695: sascha@2695: public Parameters(String [] columnNames) { sascha@2695: if (columnNames == null || columnNames.length < 1) { sascha@2695: throw new IllegalArgumentException("columnNames too short."); sascha@2695: } sascha@2695: this.columnNames = columnNames; sascha@2695: columns = new TDoubleArrayList[columnNames.length]; sascha@2695: for (int i = 0; i < columns.length; ++i) { sascha@2695: columns[i] = new TDoubleArrayList(); sascha@2695: } sascha@2695: } sascha@2695: sascha@2695: public int columnIndex(String name) { sascha@2695: for (int i = 0; i < columnNames.length; ++i) { sascha@2993: if (columnNames[i].equals(name)) { sascha@2695: return i; sascha@2695: } sascha@2695: } sascha@3057: if (log.isDebugEnabled()) { sascha@3057: log.debug("columnIndex: " + name + " not found in columnNames"); sascha@3057: } sascha@2695: return -1; sascha@2695: } sascha@2695: sascha@2729: public int newRow() { sascha@2695: sascha@2695: int N = columns[0].size(); sascha@2695: sascha@2695: for (int i = 0; i < columns.length; ++i) { sascha@2695: columns[i].add(Double.NaN); sascha@2695: } sascha@2695: sascha@2729: return N; sascha@2695: } sascha@2695: sascha@3010: public double get(int row, int index) { sascha@3010: return columns[index].getQuick(row); sascha@2695: } sascha@2695: sascha@2695: public double get(int i, String columnName) { sascha@2695: int index = columnIndex(columnName); sascha@2695: return index >= 0 sascha@2695: ? columns[index].getQuick(i) sascha@2695: : Double.NaN; sascha@2695: } sascha@2695: sascha@3010: public void set(int row, int index, double value) { sascha@3010: columns[index].setQuick(row, value); sascha@3010: } sascha@3010: sascha@2729: public void set(int i, String columnName, double value) { sascha@2729: int idx = columnIndex(columnName); sascha@2729: if (idx >= 0) { sascha@2785: columns[idx].setQuick(i, value); sascha@2729: } sascha@2729: } sascha@2729: sascha@3011: public boolean set(int row, int [] indices, double [] values) { sascha@3011: boolean invalid = false; sascha@3011: for (int i = 0; i < indices.length; ++i) { sascha@3011: double v = values[i]; sascha@3011: if (Double.isNaN(v)) { sascha@3011: invalid = true; sascha@3011: } sascha@3011: else { sascha@3011: columns[indices[i]].setQuick(row, v); sascha@3011: } sascha@3011: } sascha@3011: return invalid; sascha@3011: } sascha@3011: sascha@2695: public int size() { sascha@2695: return columns[0].size(); sascha@2695: } sascha@2695: sascha@2695: public int getNumberColumns() { sascha@2695: return columnNames.length; sascha@2695: } sascha@2695: sascha@2695: public String [] getColumnNames() { sascha@2695: return columnNames; sascha@2695: } sascha@2695: sascha@2695: public void removeNaNs() { sascha@2695: W.removeNaNs(columns); sascha@2695: } sascha@2744: sascha@2744: public int [] columnIndices(String [] columns) { sascha@2744: int [] indices = new int[columns.length]; sascha@2744: for (int i = 0; i < columns.length; ++i) { sascha@2744: indices[i] = columnIndex(columns[i]); sascha@2744: } sascha@2744: return indices; sascha@2744: } sascha@2744: sascha@3392: public double getValue(int row, String column) { sascha@3392: int idx = columnIndex(column); sascha@3392: return idx >= 0 sascha@3392: ? columns[idx].getQuick(row) sascha@3392: : Double.NaN; sascha@3392: } sascha@3392: ingo@3105: public double [] get(int row, String [] columns) { ingo@3105: return get(row, columns, new double[columns.length]); ingo@3105: } ingo@3105: ingo@3105: public double [] get(int row, String [] columns, double [] values) { ingo@3105: for (int i = 0; i < columns.length; ++i) { ingo@3105: int idx = columnIndex(columns[i]); ingo@3105: values[i] = idx < 0 ingo@3105: ? Double.NaN ingo@3105: : this.columns[idx].getQuick(row); ingo@3105: } ingo@3105: ingo@3105: return values; ingo@3105: } ingo@3105: sascha@2744: public void get(int row, int [] columnIndices, double [] values) { sascha@2744: for (int i = 0; i < columnIndices.length; ++i) { sascha@2744: int index = columnIndices[i]; sascha@2744: values[i] = index >= 0 && index < columns.length sascha@2744: ? columns[index].getQuick(row) sascha@2744: : Double.NaN; sascha@2744: } sascha@2744: } sascha@3027: sascha@3027: public int binarySearch(String columnName, double value) { sascha@3027: return binarySearch(columnIndex(columnName), value); sascha@3027: } sascha@3027: christian@3056: /** christian@3056: * Performes a binary search in the column identified by its christian@3056: * index. christian@3056: * @return Index of found element or negative insertion point (shifted by one) christian@3056: */ sascha@3027: public int binarySearch(int columnIndex, double value) { sascha@3027: TDoubleArrayList column = columns[columnIndex]; sascha@3027: return column.binarySearch(value); sascha@3027: } sascha@3027: sascha@3027: public int binarySearch(String columnName, double value, double epsilon) { sascha@3027: return binarySearch(columnIndex(columnName), value, epsilon); sascha@3027: } sascha@3027: sascha@3027: public int binarySearch(int columnIndex, double value, double epsilon) { sascha@3057: if (epsilon < 0d) epsilon = -epsilon; sascha@3027: double vl = value - epsilon; sascha@3027: double vh = value + epsilon; sascha@3027: sascha@3027: TDoubleArrayList column = columns[columnIndex]; sascha@3027: int lo = 0, hi = column.size()-1; raimund@3126: while (hi >= lo) { raimund@3126: int mid = (lo + hi) >> 1; sascha@3027: double v = column.getQuick(mid); raimund@3126: if (v < vl) lo = mid + 1; raimund@3126: else if (v > vh) hi = mid - 1; sascha@3057: else return mid; sascha@3027: } sascha@3027: sascha@3059: return -(lo + 1); sascha@3059: } sascha@3059: sascha@3059: public double [] interpolate(int columnIndex, double key) { sascha@3059: return interpolate(columnIndex, key, new double[columns.length]); sascha@3059: } sascha@3059: sascha@3059: public double [] interpolate(String columnName, double key) { sascha@3059: return interpolate( sascha@3059: columnIndex(columnName), key, new double[columns.length]); sascha@3059: } sascha@3059: sascha@3059: public double [] interpolate( sascha@3059: String columnName, sascha@3076: double key, sascha@3059: double [] values sascha@3059: ) { sascha@3059: return interpolate(columnIndex(columnName), key, values); sascha@3059: } sascha@3059: sascha@3061: public double [] interpolate( sascha@3076: int columnIndex, sascha@3076: double key, sascha@3061: double [] values sascha@3061: ) { sascha@3059: int row = binarySearch(columnIndex, key, EPSILON); sascha@3059: christian@3081: if (row >= 0) { // direct hit sascha@3059: for (int i = 0; i < values.length; ++i) { sascha@3059: values[i] = columns[i].getQuick(row); sascha@3059: } sascha@3059: } sascha@3059: else { sascha@3059: row = -row - 1; sascha@3059: if (row < 1 || row >= size()) { sascha@3059: return null; sascha@3059: } sascha@3059: double v1 = columns[columnIndex].getQuick(row-1); sascha@3059: double v2 = columns[columnIndex].getQuick(row); sascha@3059: double factor = Linear.factor(key, v1, v2); sascha@3059: for (int i = 0; i < values.length; ++i) { sascha@3059: values[i] = Linear.weight( sascha@3059: factor, sascha@3059: columns[i].getQuick(row-1), sascha@3059: columns[i].getQuick(row)); sascha@3059: } sascha@3059: } sascha@3059: return values; sascha@3027: } sascha@3027: sascha@3061: sascha@3061: public double [] interpolate( sascha@3076: String keyName, sascha@3076: double key, sascha@3061: String [] columnNames sascha@3061: ) { sascha@3061: int keyIndex = columnIndex(keyName); sascha@3061: return keyIndex < 0 sascha@3061: ? null sascha@3061: : interpolate(keyIndex, key, columnNames); sascha@3061: } sascha@3061: sascha@3061: public double [] interpolate( sascha@3061: int keyIndex, sascha@3061: double key, sascha@3061: String [] columnNames sascha@3061: ) { sascha@3061: int row = binarySearch(keyIndex, key, EPSILON); sascha@3061: sascha@3061: if (row >= 0) { // direct match sascha@3061: double [] values = new double[columnNames.length]; sascha@3061: for (int i = 0; i < values.length; ++i) { sascha@3061: int ci = columnIndex(columnNames[i]); sascha@3061: values[i] = ci < 0 sascha@3061: ? Double.NaN sascha@3061: : columns[ci].getQuick(row); sascha@3061: } sascha@3061: return values; sascha@3061: } sascha@3061: sascha@3061: row = -row - 1; christian@3081: if (row < 1 || row >= size()) { sascha@3082: log.debug("interpolate: row is out of bounds"); sascha@3061: return null; sascha@3061: } sascha@3061: sascha@3061: double v1 = columns[keyIndex].getQuick(row-1); sascha@3061: double v2 = columns[keyIndex].getQuick(row); sascha@3061: double factor = Linear.factor(key, v1, v2); sascha@3061: sascha@3061: double [] values = new double[columnNames.length]; sascha@3061: sascha@3061: for (int i = 0; i < values.length; ++i) { sascha@3061: int ci = columnIndex(columnNames[i]); sascha@3061: values[i] = ci < 0 sascha@3061: ? Double.NaN sascha@3061: : Linear.weight( sascha@3061: factor, sascha@3061: columns[ci].getQuick(row-1), sascha@3061: columns[ci].getQuick(row)); sascha@3061: } sascha@3061: sascha@3061: return values; sascha@3061: } sascha@3061: sascha@3027: public boolean isSorted(String columnName) { sascha@3027: return isSorted(columnIndex(columnName)); sascha@3027: } sascha@3027: sascha@3027: public boolean isSorted(int columnIndex) { sascha@3027: TDoubleArrayList column = columns[columnIndex]; sascha@3027: for (int i = 1, N = column.size(); i < N; ++i) { sascha@3027: if (column.getQuick(i-1) > column.getQuick(i)) { sascha@3027: return false; sascha@3027: } sascha@3027: } sascha@3027: return true; sascha@3027: } sascha@3217: sascha@3217: public void visit(Visitor visitor) { sascha@3217: visit(visitor, new double[columns.length]); sascha@3217: } sascha@3217: sascha@3217: public void visit(Visitor visitor, double [] data) { sascha@3217: for (int i = 0, R = size(); i < R; ++i) { sascha@3217: for (int j = 0; j < data.length; ++j) { sascha@3217: data[j] = columns[j].getQuick(i); sascha@3217: } sascha@3217: visitor.visit(data); sascha@3217: } sascha@3217: } sascha@2695: } sascha@2695: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :