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    *      http://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  package org.apache.commons.math4.legacy.linear;
18  
19  import org.apache.commons.math4.legacy.core.Field;
20  import org.apache.commons.math4.legacy.core.FieldElement;
21  
22  /**
23   * Sparse matrix implementation based on an open addressed map.
24   *
25   * <p>
26   *  Caveat: This implementation assumes that, for any {@code x},
27   *  the equality {@code x * 0d == 0d} holds. But it is is not true for
28   *  {@code NaN}. Moreover, zero entries will lose their sign.
29   *  Some operations (that involve {@code NaN} and/or infinities) may
30   *  thus give incorrect results.
31   * </p>
32   * @param <T> the type of the field elements
33   * @since 2.0
34   */
35  public class SparseFieldMatrix<T extends FieldElement<T>> extends AbstractFieldMatrix<T> {
36  
37      /** Storage for (sparse) matrix elements. */
38      private final OpenIntToFieldHashMap<T> entries;
39      /** Row dimension. */
40      private final int rows;
41      /** Column dimension. */
42      private final int columns;
43  
44      /**
45       * Create a matrix with no data.
46       *
47       * @param field Field to which the elements belong.
48       */
49      public SparseFieldMatrix(final Field<T> field) {
50          super(field);
51          rows = 0;
52          columns= 0;
53          entries = new OpenIntToFieldHashMap<>(field);
54      }
55  
56      /**
57       * Create a new {@code SparseFieldMatrix<T>} with the supplied row and column
58       * dimensions.
59       *
60       * @param field Field to which the elements belong.
61       * @param rowDimension Number of rows in the new matrix.
62       * @param columnDimension Number of columns in the new matrix.
63       * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException
64       * if row or column dimension is not positive.
65       */
66      public SparseFieldMatrix(final Field<T> field,
67                               final int rowDimension, final int columnDimension) {
68          super(field, rowDimension, columnDimension);
69          this.rows = rowDimension;
70          this.columns = columnDimension;
71          entries = new OpenIntToFieldHashMap<>(field);
72      }
73  
74      /**
75       * Copy constructor.
76       *
77       * @param other Instance to copy.
78       */
79      public SparseFieldMatrix(SparseFieldMatrix<T> other) {
80          super(other.getField(), other.getRowDimension(), other.getColumnDimension());
81          rows = other.getRowDimension();
82          columns = other.getColumnDimension();
83          entries = new OpenIntToFieldHashMap<>(other.entries);
84      }
85  
86      /**
87       * Generic copy constructor.
88       *
89       * @param other Instance to copy.
90       */
91      public SparseFieldMatrix(FieldMatrix<T> other){
92          super(other.getField(), other.getRowDimension(), other.getColumnDimension());
93          rows = other.getRowDimension();
94          columns = other.getColumnDimension();
95          entries = new OpenIntToFieldHashMap<>(getField());
96          for (int i = 0; i < rows; i++) {
97              for (int j = 0; j < columns; j++) {
98                  setEntry(i, j, other.getEntry(i, j));
99              }
100         }
101     }
102 
103     /** {@inheritDoc} */
104     @Override
105     public void addToEntry(int row, int column, T increment) {
106         checkRowIndex(row);
107         checkColumnIndex(column);
108         final int key = computeKey(row, column);
109         final T value = entries.get(key).add(increment);
110         if (getField().getZero().equals(value)) {
111             entries.remove(key);
112         } else {
113             entries.put(key, value);
114         }
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public FieldMatrix<T> copy() {
120         return new SparseFieldMatrix<>(this);
121     }
122 
123     /** {@inheritDoc} */
124     @Override
125     public FieldMatrix<T> createMatrix(int rowDimension, int columnDimension) {
126         return new SparseFieldMatrix<>(getField(), rowDimension, columnDimension);
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public int getColumnDimension() {
132         return columns;
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public T getEntry(int row, int column) {
138         checkRowIndex(row);
139         checkColumnIndex(column);
140         return entries.get(computeKey(row, column));
141     }
142 
143     /** {@inheritDoc} */
144     @Override
145     public int getRowDimension() {
146         return rows;
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public void multiplyEntry(int row, int column, T factor) {
152         checkRowIndex(row);
153         checkColumnIndex(column);
154         final int key = computeKey(row, column);
155         final T value = entries.get(key).multiply(factor);
156         if (getField().getZero().equals(value)) {
157             entries.remove(key);
158         } else {
159             entries.put(key, value);
160         }
161     }
162 
163     /** {@inheritDoc} */
164     @Override
165     public void setEntry(int row, int column, T value) {
166         checkRowIndex(row);
167         checkColumnIndex(column);
168         if (getField().getZero().equals(value)) {
169             entries.remove(computeKey(row, column));
170         } else {
171             entries.put(computeKey(row, column), value);
172         }
173     }
174 
175     /**
176      * Compute the key to access a matrix element.
177      *
178      * @param row Row index of the matrix element.
179      * @param column Column index of the matrix element.
180      * @return the key within the map to access the matrix element.
181      */
182     private int computeKey(int row, int column) {
183         return row * columns + column;
184     }
185 }