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 */ 017package org.apache.commons.math4.legacy.linear; 018 019import org.apache.commons.math4.legacy.core.Field; 020import org.apache.commons.math4.legacy.core.FieldElement; 021 022/** 023 * Sparse matrix implementation based on an open addressed map. 024 * 025 * <p> 026 * Caveat: This implementation assumes that, for any {@code x}, 027 * the equality {@code x * 0d == 0d} holds. But it is is not true for 028 * {@code NaN}. Moreover, zero entries will lose their sign. 029 * Some operations (that involve {@code NaN} and/or infinities) may 030 * thus give incorrect results. 031 * </p> 032 * @param <T> the type of the field elements 033 * @since 2.0 034 */ 035public class SparseFieldMatrix<T extends FieldElement<T>> extends AbstractFieldMatrix<T> { 036 037 /** Storage for (sparse) matrix elements. */ 038 private final OpenIntToFieldHashMap<T> entries; 039 /** Row dimension. */ 040 private final int rows; 041 /** Column dimension. */ 042 private final int columns; 043 044 /** 045 * Create a matrix with no data. 046 * 047 * @param field Field to which the elements belong. 048 */ 049 public SparseFieldMatrix(final Field<T> field) { 050 super(field); 051 rows = 0; 052 columns= 0; 053 entries = new OpenIntToFieldHashMap<>(field); 054 } 055 056 /** 057 * Create a new {@code SparseFieldMatrix<T>} with the supplied row and column 058 * dimensions. 059 * 060 * @param field Field to which the elements belong. 061 * @param rowDimension Number of rows in the new matrix. 062 * @param columnDimension Number of columns in the new matrix. 063 * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException 064 * if row or column dimension is not positive. 065 */ 066 public SparseFieldMatrix(final Field<T> field, 067 final int rowDimension, final int columnDimension) { 068 super(field, rowDimension, columnDimension); 069 this.rows = rowDimension; 070 this.columns = columnDimension; 071 entries = new OpenIntToFieldHashMap<>(field); 072 } 073 074 /** 075 * Copy constructor. 076 * 077 * @param other Instance to copy. 078 */ 079 public SparseFieldMatrix(SparseFieldMatrix<T> other) { 080 super(other.getField(), other.getRowDimension(), other.getColumnDimension()); 081 rows = other.getRowDimension(); 082 columns = other.getColumnDimension(); 083 entries = new OpenIntToFieldHashMap<>(other.entries); 084 } 085 086 /** 087 * Generic copy constructor. 088 * 089 * @param other Instance to copy. 090 */ 091 public SparseFieldMatrix(FieldMatrix<T> other){ 092 super(other.getField(), other.getRowDimension(), other.getColumnDimension()); 093 rows = other.getRowDimension(); 094 columns = other.getColumnDimension(); 095 entries = new OpenIntToFieldHashMap<>(getField()); 096 for (int i = 0; i < rows; i++) { 097 for (int j = 0; j < columns; j++) { 098 setEntry(i, j, other.getEntry(i, j)); 099 } 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}