001 /* 002 * Copyright (C) 2008-2010 by Holger Arndt 003 * 004 * This file is part of the Universal Java Matrix Package (UJMP). 005 * See the NOTICE file distributed with this work for additional 006 * information regarding copyright ownership and licensing. 007 * 008 * UJMP is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation; either version 2 011 * of the License, or (at your option) any later version. 012 * 013 * UJMP is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public 019 * License along with UJMP; if not, write to the 020 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 021 * Boston, MA 02110-1301 USA 022 */ 023 024 package org.ujmp.core.timeseries; 025 026 import java.util.ArrayList; 027 import java.util.HashMap; 028 import java.util.Iterator; 029 import java.util.List; 030 import java.util.Map; 031 import java.util.SortedMap; 032 import java.util.TreeMap; 033 034 import org.ujmp.core.Matrix; 035 import org.ujmp.core.collections.SortedListSet; 036 import org.ujmp.core.doublematrix.stub.AbstractDenseDoubleMatrix2D; 037 import org.ujmp.core.exceptions.MatrixException; 038 039 public class TimeSeriesMatrix extends AbstractDenseDoubleMatrix2D { 040 private static final long serialVersionUID = 4326920011599023858L; 041 042 public enum Interpolation { 043 NONE, STEPS, LINEAR 044 }; 045 046 private Interpolation defaultInterpolation = Interpolation.NONE; 047 048 private final Map<Integer, Interpolation> seriesInterpolations = new HashMap<Integer, Interpolation>(); 049 050 private final List<SortedMap<Long, Double>> series = new ArrayList<SortedMap<Long, Double>>(); 051 052 private final SortedListSet<Long> timestampsListSet = new SortedListSet<Long>(); 053 054 private long[] size = new long[2]; 055 056 public void addEvent(long timestamp, Matrix value) { 057 if (value.getRowCount() != 1) { 058 throw new MatrixException("matrix cannot have more than one row"); 059 } 060 for (int id = 0; id < value.getColumnCount(); id++) { 061 addEvent(timestamp, id + 1, value.getAsDouble(0, id)); 062 } 063 } 064 065 public Interpolation getInterpolation(int seriesId) { 066 Interpolation i = seriesInterpolations.get(seriesId); 067 if (i == null) { 068 return defaultInterpolation; 069 } else { 070 return i; 071 } 072 } 073 074 public Interpolation getDefaultInterpolation() { 075 return defaultInterpolation; 076 } 077 078 public void setDefaultInterpolation(Interpolation defaultInterpolation) { 079 this.defaultInterpolation = defaultInterpolation; 080 } 081 082 /** 083 * Adds the events of a new Matrix to the time series. The first column of 084 * the matrix must contain the timestamps. 085 * 086 * @param events 087 * matrix with events to add 088 */ 089 public void addEvents(Matrix events) { 090 int seriesCount = getSeriesCount(); 091 for (int r = 0; r < events.getRowCount(); r++) { 092 long timestamp = events.getAsLong(r, 0); 093 for (int c = 1; c < events.getColumnCount(); c++) { 094 double value = events.getAsDouble(r, c); 095 addEvent(timestamp, seriesCount + c - 1, value); 096 } 097 } 098 } 099 100 public void addEvent(long timestamp, int column, double value) { 101 int seriesId = column - 1; 102 while (series.size() <= seriesId) { 103 series.add(new TreeMap<Long, Double>()); 104 } 105 SortedMap<Long, Double> map = series.get(seriesId); 106 map.put(timestamp, value); 107 timestampsListSet.add(timestamp); 108 } 109 110 public int getEventCount() { 111 return timestampsListSet.size(); 112 } 113 114 public int getSeriesCount() { 115 return series.size(); 116 } 117 118 public List<Long> getTimestamps() { 119 return timestampsListSet; 120 } 121 122 public long[] getSize() { 123 size[ROW] = getEventCount(); 124 size[COLUMN] = getSeriesCount() + 1; 125 return size; 126 } 127 128 public long getRowCount() { 129 return getEventCount(); 130 } 131 132 public long getColumnCount() { 133 return getSeriesCount() + 1; 134 } 135 136 public double getDouble(long row, long column) { 137 return getDouble((int) row, (int) column); 138 } 139 140 public double getDouble(int row, int column) { 141 142 if (row < 0 || column >= getColumnCount() || row >= getRowCount()) { 143 return Double.NaN; 144 } 145 146 int seriesId = column - 1; 147 long timestamp = timestampsListSet.get(row); 148 if (column == 0) { 149 return timestamp; 150 } else { 151 SortedMap<Long, Double> map = series.get(seriesId); 152 switch (getInterpolation(seriesId)) { 153 case NONE: 154 Double v = map.get(timestamp); 155 if (v == null) { 156 return Double.NaN; 157 } else { 158 return v; 159 } 160 161 case STEPS: 162 Iterator<Long> it = map.keySet().iterator(); 163 double value = 0.0; 164 while (it.hasNext()) { 165 long t = it.next(); 166 if (t > timestamp) { 167 break; 168 } else { 169 value = map.get(t); 170 } 171 } 172 return value; 173 174 default: 175 throw new MatrixException("Interpolation method not (yet) supported: " 176 + getInterpolation(seriesId)); 177 } 178 } 179 } 180 181 public void setDouble(double value, long row, long column) { 182 throw new MatrixException("please use addEvent() for making changes"); 183 } 184 185 public void setDouble(double value, int row, int column) { 186 throw new MatrixException("please use addEvent() for making changes"); 187 } 188 189 public void setInterpolation(int column, Interpolation interpolation) { 190 int seriesId = column - 1; 191 seriesInterpolations.put(seriesId, interpolation); 192 } 193 194 public long getRowForTime(long time) { 195 long rows = getRowCount(); 196 for (long r = 0; r < rows; r++) { 197 long t = getAsLong(r, 0); 198 if (t == time) { 199 return r; 200 } 201 } 202 return -1; 203 } 204 205 public double getAsDoubleForTime(long time, long column) { 206 long row = getRowForTime(time); 207 if (row < 0 || column >= getColumnCount()) { 208 return Double.NaN; 209 } 210 return getAsDouble(row, column); 211 } 212 213 public long getTimestamp(long row) { 214 if (row < 0 | row >= timestampsListSet.size()) { 215 return 0; 216 } else { 217 return timestampsListSet.get((int) row); 218 } 219 } 220 221 public long getMinTimestamp() { 222 if (timestampsListSet.isEmpty()) { 223 return 0; 224 } else { 225 return timestampsListSet.first(); 226 } 227 } 228 229 public long getMaxTimestamp() { 230 if (timestampsListSet.isEmpty()) { 231 return 0; 232 } else { 233 return timestampsListSet.last(); 234 } 235 } 236 237 }