/src/org/mymedialite/datatype/SparseMatrix.java

http://github.com/jcnewell/MyMediaLiteJava · Java · 193 lines · 102 code · 25 blank · 66 comment · 23 complexity · 7aa2e4b609a7455a1d732a309b3e281e MD5 · raw file

  1. // Copyright (C) 2010, 2011 Zeno Gantner
  2. // Copyright (C) 2011 Chris Newell
  3. //
  4. // This file is part of MyMediaLite.
  5. //
  6. // MyMediaLite is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // MyMediaLite is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with MyMediaLite. If not, see <http://www.gnu.org/licenses/>.
  18. package org.mymedialite.datatype;
  19. import java.util.*;
  20. /**
  21. * Class for storing sparse matrices.
  22. * The data is stored in row-major mode.
  23. * Indexes are zero-based.
  24. * T the matrix element type, must have a default constructor/value
  25. * @version 2.03
  26. */
  27. public class SparseMatrix<T> implements IMatrix<T> {
  28. private int numberOfColumns;
  29. /**
  30. * List that stores the rows of the matrix.
  31. */
  32. // TODO Consider fastutil
  33. protected List<HashMap<Integer, T>> row_list = new ArrayList<HashMap<Integer, T>>();
  34. /**
  35. * The default values for elements.
  36. */
  37. private T d = null;
  38. /**
  39. * Create a sparse matrix with a given number of rows.
  40. * @param num_rows the number of rows
  41. * @param num_cols the number of columns
  42. */
  43. public SparseMatrix(int num_rows, int num_cols) {
  44. this(num_rows, num_cols, null);
  45. }
  46. /**
  47. * Create a sparse matrix with a given number of rows.
  48. * @param num_rows the number of rows
  49. * @param num_cols the number of columns
  50. * @param d the default value for elements
  51. */
  52. public SparseMatrix(int num_rows, int num_cols, T d) {
  53. for (int i = 0; i < num_rows; i++) {
  54. row_list.add(new HashMap<Integer, T>());
  55. }
  56. this.numberOfColumns = num_cols;
  57. this.d = d;
  58. }
  59. @Override
  60. public IMatrix<T> createMatrix(int num_rows, int num_columns) {
  61. return new SparseMatrix<T>(num_rows, num_columns, null);
  62. }
  63. @Override
  64. public boolean isSymmetric() {
  65. if (numberOfRows() != numberOfColumns()) return false;
  66. for (int i = 0; i < row_list.size(); i++)
  67. for (int j : row_list.get(i).keySet()) {
  68. if (i > j)
  69. continue; // check every pair only once
  70. if (! get(i, j).equals(get(j, i)))
  71. return false;
  72. }
  73. return true;
  74. }
  75. @Override
  76. public int numberOfRows() {
  77. return row_list.size();
  78. }
  79. @Override
  80. public int numberOfColumns() {
  81. return numberOfColumns;
  82. }
  83. @Override
  84. public IMatrix<T> transpose() {
  85. SparseMatrix<T> transpose = new SparseMatrix<T>(numberOfColumns(), numberOfRows());
  86. for (Pair<Integer, Integer> p : nonEmptyEntryIDs()) {
  87. transpose.set(p.second, p.first, get(p.first, p.second));
  88. }
  89. return transpose;
  90. }
  91. /**
  92. * Get a row of the matrix.
  93. * @param x the row ID
  94. */
  95. public HashMap<Integer, T> get(int x) {
  96. if (x >= row_list.size())
  97. return new HashMap<Integer, T>();
  98. else
  99. return row_list.get(x);
  100. }
  101. /**
  102. * Access the elements of the sparse matrix.
  103. * @param x the row ID
  104. * @param y the column ID
  105. */
  106. @Override
  107. public T get(int x, int y) {
  108. T result;
  109. if (x < row_list.size()) {
  110. result = row_list.get(x).get(y);
  111. if(result != null) {
  112. return result;
  113. }
  114. }
  115. return d;
  116. }
  117. @Override
  118. public void set(int x, int y, T value) {
  119. if (x >= row_list.size())
  120. for (int i = row_list.size(); i <= x; i++) row_list.add(new HashMap<Integer, T>());
  121. row_list.get(x).put(y, value);
  122. }
  123. /**
  124. * The non-empty rows of the matrix (the ones that contain at least one non-zero entry),
  125. * with their IDs
  126. * .
  127. */
  128. public HashMap<Integer, HashMap<Integer, T>> nonEmptyRows() {
  129. HashMap<Integer, HashMap<Integer, T>> return_list = new HashMap<Integer, HashMap<Integer, T>>();
  130. for(int i=0; i < row_list.size(); i++) {
  131. HashMap<Integer, T> row = get(i);
  132. if(row.size() > 0)
  133. return_list.put(i, row);
  134. }
  135. return return_list;
  136. }
  137. /**
  138. * The row and column IDs of non-empty entries in the matrix.
  139. * @return The row and column IDs of non-empty entries in the matrix
  140. */
  141. public List<Pair<Integer, Integer>> nonEmptyEntryIDs() {
  142. List <Pair<Integer, Integer>> return_list = new ArrayList<Pair<Integer, Integer>>();
  143. for (Map.Entry<Integer, HashMap<Integer, T>> id_row : nonEmptyRows().entrySet())
  144. for (Integer col_id : id_row.getValue().keySet())
  145. return_list.add(new Pair<Integer, Integer>(id_row.getKey(), col_id));
  146. return return_list;
  147. }
  148. /**
  149. * The number of non-empty entries in the matrix.
  150. * @return The number of non-empty entries in the matrix
  151. */
  152. public int numberOfNonEmptyEntries() {
  153. int counter = 0;
  154. for (HashMap<Integer, T> row : row_list)
  155. counter += row.size();
  156. return counter;
  157. }
  158. @Override
  159. public void grow(int num_rows, int num_cols) {
  160. // If necessary, grow rows
  161. if (num_rows > numberOfRows())
  162. for (int i = row_list.size(); i < num_rows; i++)
  163. row_list.add(new HashMap<Integer, T>());
  164. // If necessary, grow columns
  165. if (num_cols > numberOfColumns)
  166. numberOfColumns = num_cols;
  167. }
  168. }