001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.math3.linear;
019
020 import java.io.Serializable;
021
022 import org.apache.commons.math3.exception.DimensionMismatchException;
023 import org.apache.commons.math3.exception.NotStrictlyPositiveException;
024 import org.apache.commons.math3.exception.NumberIsTooLargeException;
025 import org.apache.commons.math3.exception.OutOfRangeException;
026 import org.apache.commons.math3.util.OpenIntToDoubleHashMap;
027
028 /**
029 * Sparse matrix implementation based on an open addressed map.
030 *
031 * @version $Id: OpenMapRealMatrix.java 1416643 2012-12-03 19:37:14Z tn $
032 * @since 2.0
033 * @deprecated As of version 3.1, this class is deprecated, for reasons exposed
034 * in this JIRA
035 * <a href="https://issues.apache.org/jira/browse/MATH-870">ticket</a>. This
036 * class will be removed in version 4.0.
037 *
038 */
039 @Deprecated
040 public class OpenMapRealMatrix extends AbstractRealMatrix
041 implements SparseRealMatrix, Serializable {
042 /** Serializable version identifier. */
043 private static final long serialVersionUID = -5962461716457143437L;
044 /** Number of rows of the matrix. */
045 private final int rows;
046 /** Number of columns of the matrix. */
047 private final int columns;
048 /** Storage for (sparse) matrix elements. */
049 private final OpenIntToDoubleHashMap entries;
050
051 /**
052 * Build a sparse matrix with the supplied row and column dimensions.
053 *
054 * @param rowDimension Number of rows of the matrix.
055 * @param columnDimension Number of columns of the matrix.
056 * @throws NotStrictlyPositiveException if row or column dimension is not
057 * positive.
058 * @throws NumberIsTooLargeException if the total number of entries of the
059 * matrix is larger than {@code Integer.MAX_VALUE}.
060 */
061 public OpenMapRealMatrix(int rowDimension, int columnDimension)
062 throws NotStrictlyPositiveException, NumberIsTooLargeException {
063 super(rowDimension, columnDimension);
064 long lRow = rowDimension;
065 long lCol = columnDimension;
066 if (lRow * lCol >= Integer.MAX_VALUE) {
067 throw new NumberIsTooLargeException(lRow * lCol, Integer.MAX_VALUE, false);
068 }
069 this.rows = rowDimension;
070 this.columns = columnDimension;
071 this.entries = new OpenIntToDoubleHashMap(0.0);
072 }
073
074 /**
075 * Build a matrix by copying another one.
076 *
077 * @param matrix matrix to copy.
078 */
079 public OpenMapRealMatrix(OpenMapRealMatrix matrix) {
080 this.rows = matrix.rows;
081 this.columns = matrix.columns;
082 this.entries = new OpenIntToDoubleHashMap(matrix.entries);
083 }
084
085 /** {@inheritDoc} */
086 @Override
087 public OpenMapRealMatrix copy() {
088 return new OpenMapRealMatrix(this);
089 }
090
091 /**
092 * {@inheritDoc}
093 *
094 * @throws NumberIsTooLargeException if the total number of entries of the
095 * matrix is larger than {@code Integer.MAX_VALUE}.
096 */
097 @Override
098 public OpenMapRealMatrix createMatrix(int rowDimension, int columnDimension)
099 throws NotStrictlyPositiveException, NumberIsTooLargeException {
100 return new OpenMapRealMatrix(rowDimension, columnDimension);
101 }
102
103 /** {@inheritDoc} */
104 @Override
105 public int getColumnDimension() {
106 return columns;
107 }
108
109 /**
110 * Compute the sum of this matrix and {@code m}.
111 *
112 * @param m Matrix to be added.
113 * @return {@code this} + {@code m}.
114 * @throws MatrixDimensionMismatchException if {@code m} is not the same
115 * size as {@code this}.
116 */
117 public OpenMapRealMatrix add(OpenMapRealMatrix m)
118 throws MatrixDimensionMismatchException {
119
120 MatrixUtils.checkAdditionCompatible(this, m);
121
122 final OpenMapRealMatrix out = new OpenMapRealMatrix(this);
123 for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) {
124 iterator.advance();
125 final int row = iterator.key() / columns;
126 final int col = iterator.key() - row * columns;
127 out.setEntry(row, col, getEntry(row, col) + iterator.value());
128 }
129
130 return out;
131
132 }
133
134 /** {@inheritDoc} */
135 @Override
136 public OpenMapRealMatrix subtract(final RealMatrix m)
137 throws MatrixDimensionMismatchException {
138 try {
139 return subtract((OpenMapRealMatrix) m);
140 } catch (ClassCastException cce) {
141 return (OpenMapRealMatrix) super.subtract(m);
142 }
143 }
144
145 /**
146 * Subtract {@code m} from this matrix.
147 *
148 * @param m Matrix to be subtracted.
149 * @return {@code this} - {@code m}.
150 * @throws MatrixDimensionMismatchException if {@code m} is not the same
151 * size as {@code this}.
152 */
153 public OpenMapRealMatrix subtract(OpenMapRealMatrix m)
154 throws MatrixDimensionMismatchException {
155 MatrixUtils.checkAdditionCompatible(this, m);
156
157 final OpenMapRealMatrix out = new OpenMapRealMatrix(this);
158 for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) {
159 iterator.advance();
160 final int row = iterator.key() / columns;
161 final int col = iterator.key() - row * columns;
162 out.setEntry(row, col, getEntry(row, col) - iterator.value());
163 }
164
165 return out;
166 }
167
168 /**
169 * {@inheritDoc}
170 *
171 * @throws NumberIsTooLargeException if {@code m} is an
172 * {@code OpenMapRealMatrix}, and the total number of entries of the product
173 * is larger than {@code Integer.MAX_VALUE}.
174 */
175 @Override
176 public RealMatrix multiply(final RealMatrix m)
177 throws DimensionMismatchException, NumberIsTooLargeException {
178 try {
179 return multiply((OpenMapRealMatrix) m);
180 } catch (ClassCastException cce) {
181
182 MatrixUtils.checkMultiplicationCompatible(this, m);
183
184 final int outCols = m.getColumnDimension();
185 final BlockRealMatrix out = new BlockRealMatrix(rows, outCols);
186 for (OpenIntToDoubleHashMap.Iterator iterator = entries.iterator(); iterator.hasNext();) {
187 iterator.advance();
188 final double value = iterator.value();
189 final int key = iterator.key();
190 final int i = key / columns;
191 final int k = key % columns;
192 for (int j = 0; j < outCols; ++j) {
193 out.addToEntry(i, j, value * m.getEntry(k, j));
194 }
195 }
196
197 return out;
198 }
199 }
200
201 /**
202 * Postmultiply this matrix by {@code m}.
203 *
204 * @param m Matrix to postmultiply by.
205 * @return {@code this} * {@code m}.
206 * @throws DimensionMismatchException if the number of rows of {@code m}
207 * differ from the number of columns of {@code this} matrix.
208 * @throws NumberIsTooLargeException if the total number of entries of the
209 * product is larger than {@code Integer.MAX_VALUE}.
210 */
211 public OpenMapRealMatrix multiply(OpenMapRealMatrix m)
212 throws DimensionMismatchException, NumberIsTooLargeException {
213 // Safety check.
214 MatrixUtils.checkMultiplicationCompatible(this, m);
215
216 final int outCols = m.getColumnDimension();
217 OpenMapRealMatrix out = new OpenMapRealMatrix(rows, outCols);
218 for (OpenIntToDoubleHashMap.Iterator iterator = entries.iterator(); iterator.hasNext();) {
219 iterator.advance();
220 final double value = iterator.value();
221 final int key = iterator.key();
222 final int i = key / columns;
223 final int k = key % columns;
224 for (int j = 0; j < outCols; ++j) {
225 final int rightKey = m.computeKey(k, j);
226 if (m.entries.containsKey(rightKey)) {
227 final int outKey = out.computeKey(i, j);
228 final double outValue =
229 out.entries.get(outKey) + value * m.entries.get(rightKey);
230 if (outValue == 0.0) {
231 out.entries.remove(outKey);
232 } else {
233 out.entries.put(outKey, outValue);
234 }
235 }
236 }
237 }
238
239 return out;
240 }
241
242 /** {@inheritDoc} */
243 @Override
244 public double getEntry(int row, int column) throws OutOfRangeException {
245 MatrixUtils.checkRowIndex(this, row);
246 MatrixUtils.checkColumnIndex(this, column);
247 return entries.get(computeKey(row, column));
248 }
249
250 /** {@inheritDoc} */
251 @Override
252 public int getRowDimension() {
253 return rows;
254 }
255
256 /** {@inheritDoc} */
257 @Override
258 public void setEntry(int row, int column, double value)
259 throws OutOfRangeException {
260 MatrixUtils.checkRowIndex(this, row);
261 MatrixUtils.checkColumnIndex(this, column);
262 if (value == 0.0) {
263 entries.remove(computeKey(row, column));
264 } else {
265 entries.put(computeKey(row, column), value);
266 }
267 }
268
269 /** {@inheritDoc} */
270 @Override
271 public void addToEntry(int row, int column, double increment)
272 throws OutOfRangeException {
273 MatrixUtils.checkRowIndex(this, row);
274 MatrixUtils.checkColumnIndex(this, column);
275 final int key = computeKey(row, column);
276 final double value = entries.get(key) + increment;
277 if (value == 0.0) {
278 entries.remove(key);
279 } else {
280 entries.put(key, value);
281 }
282 }
283
284 /** {@inheritDoc} */
285 @Override
286 public void multiplyEntry(int row, int column, double factor)
287 throws OutOfRangeException {
288 MatrixUtils.checkRowIndex(this, row);
289 MatrixUtils.checkColumnIndex(this, column);
290 final int key = computeKey(row, column);
291 final double value = entries.get(key) * factor;
292 if (value == 0.0) {
293 entries.remove(key);
294 } else {
295 entries.put(key, value);
296 }
297 }
298
299 /**
300 * Compute the key to access a matrix element
301 * @param row row index of the matrix element
302 * @param column column index of the matrix element
303 * @return key within the map to access the matrix element
304 */
305 private int computeKey(int row, int column) {
306 return row * columns + column;
307 }
308
309
310 }