View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.linear;
23  
24  import org.hipparchus.Field;
25  import org.hipparchus.FieldElement;
26  import org.hipparchus.exception.MathIllegalArgumentException;
27  import org.hipparchus.util.OpenIntToFieldHashMap;
28  
29  /**
30   * Sparse matrix implementation based on an open addressed map.
31   *
32   * <p>
33   *  Caveat: This implementation assumes that, for any {@code x},
34   *  the equality {@code x * 0d == 0d} holds. But it is is not true for
35   *  {@code NaN}. Moreover, zero entries will lose their sign.
36   *  Some operations (that involve {@code NaN} and/or infinities) may
37   *  thus give incorrect results.
38   * </p>
39   * @param <T> the type of the field elements
40   */
41  public class SparseFieldMatrix<T extends FieldElement<T>> extends AbstractFieldMatrix<T> {
42  
43      /** Storage for (sparse) matrix elements. */
44      private final OpenIntToFieldHashMap<T> entries;
45      /** Row dimension. */
46      private final int rows;
47      /** Column dimension. */
48      private final int columns;
49  
50      /**
51       * Create a matrix with no data.
52       *
53       * @param field Field to which the elements belong.
54       */
55      public SparseFieldMatrix(final Field<T> field) {
56          super(field);
57          rows = 0;
58          columns= 0;
59          entries = new OpenIntToFieldHashMap<>(field);
60      }
61  
62      /**
63       * Create a new {@link SparseFieldMatrix} with the supplied row and column
64       * dimensions.
65       *
66       * @param field Field to which the elements belong.
67       * @param rowDimension Number of rows in the new matrix.
68       * @param columnDimension Number of columns in the new matrix.
69       * @throws org.hipparchus.exception.MathIllegalArgumentException
70       * if row or column dimension is not positive.
71       */
72      public SparseFieldMatrix(final Field<T> field,
73                               final int rowDimension, final int columnDimension) {
74          super(field, rowDimension, columnDimension);
75          this.rows = rowDimension;
76          this.columns = columnDimension;
77          entries = new OpenIntToFieldHashMap<>(field);
78      }
79  
80      /**
81       * Copy constructor.
82       *
83       * @param other Instance to copy.
84       */
85      public SparseFieldMatrix(SparseFieldMatrix<T> other) {
86          super(other.getField(), other.getRowDimension(), other.getColumnDimension());
87          rows = other.getRowDimension();
88          columns = other.getColumnDimension();
89          entries = new OpenIntToFieldHashMap<>(other.entries);
90      }
91  
92      /**
93       * Generic copy constructor.
94       *
95       * @param other Instance to copy.
96       */
97      public SparseFieldMatrix(FieldMatrix<T> other){
98          super(other.getField(), other.getRowDimension(), other.getColumnDimension());
99          rows = other.getRowDimension();
100         columns = other.getColumnDimension();
101         entries = new OpenIntToFieldHashMap<>(getField());
102         for (int i = 0; i < rows; i++) {
103             for (int j = 0; j < columns; j++) {
104                 setEntry(i, j, other.getEntry(i, j));
105             }
106         }
107     }
108 
109     /** {@inheritDoc} */
110     @Override
111     public void addToEntry(int row, int column, T increment) {
112         checkRowIndex(row);
113         checkColumnIndex(column);
114         final int key = computeKey(row, column);
115         final T value = entries.get(key).add(increment);
116         if (getField().getZero().equals(value)) {
117             entries.remove(key);
118         } else {
119             entries.put(key, value);
120         }
121     }
122 
123     /** {@inheritDoc} */
124     @Override
125     public FieldMatrix<T> copy() {
126         return new SparseFieldMatrix<T>(this);
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public FieldMatrix<T> createMatrix(int rowDimension, int columnDimension) {
132         return new SparseFieldMatrix<T>(getField(), rowDimension, columnDimension);
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public int getColumnDimension() {
138         return columns;
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     public T getEntry(int row, int column) {
144         checkRowIndex(row);
145         checkColumnIndex(column);
146         return entries.get(computeKey(row, column));
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public int getRowDimension() {
152         return rows;
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     public void multiplyEntry(int row, int column, T factor) {
158         checkRowIndex(row);
159         checkColumnIndex(column);
160         final int key = computeKey(row, column);
161         final T value = entries.get(key).multiply(factor);
162         if (getField().getZero().equals(value)) {
163             entries.remove(key);
164         } else {
165             entries.put(key, value);
166         }
167 
168     }
169 
170     /** {@inheritDoc} */
171     @Override
172     public void setEntry(int row, int column, T value) {
173         checkRowIndex(row);
174         checkColumnIndex(column);
175         if (getField().getZero().equals(value)) {
176             entries.remove(computeKey(row, column));
177         } else {
178             entries.put(computeKey(row, column), value);
179         }
180     }
181 
182     /**
183      * {@inheritDoc}
184      *
185      * @throws MathIllegalArgumentException if {@code m} is an
186      * {@code OpenMapRealMatrix}, and the total number of entries of the product
187      * is larger than {@code Integer.MAX_VALUE}.
188      */
189     @Override
190     public FieldMatrix<T> multiplyTransposed(final FieldMatrix<T> m)
191         throws MathIllegalArgumentException {
192 
193         MatrixUtils.checkSameColumnDimension(this, m);
194 
195         final int outCols = m.getRowDimension();
196         final FieldMatrix<T> out = m.createMatrix(rows, outCols);
197         for (OpenIntToFieldHashMap<T>.Iterator iterator = entries.iterator(); iterator.hasNext();) {
198             iterator.advance();
199             final T   value    = iterator.value();
200             final int key      = iterator.key();
201             final int i        = key / columns;
202             final int k        = key % columns;
203             for (int j = 0; j < outCols; ++j) {
204                 out.addToEntry(i, j, value.multiply(m.getEntry(j, k)));
205             }
206         }
207 
208         return out;
209 
210     }
211 
212     /**
213      * {@inheritDoc}
214      *
215      * @throws MathIllegalArgumentException if {@code m} is an
216      * {@code OpenMapRealMatrix}, and the total number of entries of the product
217      * is larger than {@code Integer.MAX_VALUE}.
218      */
219     @Override
220     public FieldMatrix<T> transposeMultiply(final FieldMatrix<T> m)
221         throws MathIllegalArgumentException {
222 
223         MatrixUtils.checkSameRowDimension(this, m);
224 
225         final int outCols = m.getColumnDimension();
226         final FieldMatrix<T> out = m.createMatrix(columns, outCols);
227         for (OpenIntToFieldHashMap<T>.Iterator iterator = entries.iterator(); iterator.hasNext();) {
228             iterator.advance();
229             final T   value = iterator.value();
230             final int key   = iterator.key();
231             final int k     = key / columns;
232             final int i     = key % columns;
233             for (int j = 0; j < outCols; ++j) {
234                 out.addToEntry(i, j, value.multiply(m.getEntry(k, j)));
235             }
236         }
237 
238         return out;
239 
240     }
241 
242     /**
243      * Compute the key to access a matrix element.
244      *
245      * @param row Row index of the matrix element.
246      * @param column Column index of the matrix element.
247      * @return the key within the map to access the matrix element.
248      */
249     private int computeKey(int row, int column) {
250         return row * columns + column;
251     }
252 }