//Copyright (C) 2011 Zeno Gantner, Chris Newell // //This file is part of MyMediaLite. // //MyMediaLite is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by //the Free Software Foundation, either version 3 of the License, or //(at your option) any later version. // //MyMediaLite is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. // //You should have received a copy of the GNU General Public License //along with MyMediaLite. If not, see <http://www.gnu.org/licenses/>. package org.mymedialite.datatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * A symmetric sparse matrix; consumes less memory. * * Be careful when accessing the matrix via the NonEmptyRows property: this contains * only the entries with x > y, but not their symmetric counterparts. * @version 2.03 */ public class SymmetricSparseMatrix<T> extends SparseMatrix<T> { private T d; /** * Create a symmetric sparse matrix with a given dimension. * @param dimension the dimension (number of rows/columns) * @param d the default value for elements, or null */ public SymmetricSparseMatrix(int dimension, T d) { super(dimension, dimension, null); this.d = d; } /** * Access the elements of the sparse matrix. * @param x the row ID * @param y the column ID */ public T get(int x, int y) { // Ensure x <= y if (x > y) { int tmp = x; x = y; y = tmp; } T result; if (x < row_list.size()) { result = row_list.get(x).get(y); if(result != null) { return result; } } return d; } public void set(int x, int y, T value) { // Ensure x <= y if (x > y) { int tmp = x; x = y; y = tmp; } if (x >= row_list.size()) for (int i = row_list.size(); i <= x; i++) row_list.add(new HashMap<Integer, T>()); row_list.get(x).put(y, value); } /** * Always true because the data type is symmetric. * @return Always true because the data type is symmetric */ public boolean isSymmetric() { return true; } /** * */ public IMatrix<T> createMatrix(int num_rows, int num_columns) { if (num_rows != num_columns) throw new IllegalArgumentException("Symmetric matrices must have the same number of rows and columns."); return new SymmetricSparseMatrix<T>(num_rows, null); } /** * */ public List<Pair<Integer, Integer>> nonEmptyEntryIDs() { List<Pair<Integer, Integer>> return_list = new ArrayList<Pair<Integer, Integer>>(); for (int row_id : nonEmptyRows().keySet()) { HashMap<Integer, T> row = row_list.get(row_id); for (int col_id : row.keySet()) { return_list.add(new Pair<Integer, Integer>(row_id, col_id)); if (row_id != col_id) return_list.add(new Pair<Integer, Integer>(col_id, row_id)); } } return return_list; } /** * */ public int numberOfNonEmptyEntries() { int counter = 0; for (int i = 0; i < row_list.size(); i++) { counter += 2 * row_list.get(i).size(); // Adjust for diagonal elements if (row_list.get(i).containsKey(i)) counter--; } return counter; } }