// 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.data; import it.unimi.dsi.fastutil.doubles.DoubleArrayList; import it.unimi.dsi.fastutil.doubles.DoubleCollection; import it.unimi.dsi.fastutil.doubles.DoubleIterator; import it.unimi.dsi.fastutil.doubles.DoubleList; import it.unimi.dsi.fastutil.doubles.DoubleListIterator; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntCollection; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; import javax.management.openmbean.InvalidKeyException; /** * Data structure for storing ratings * Small memory overhead for added flexibility. * This data structure supports incremental updates. * @version 2.03 */ public class Ratings extends DataSet implements IRatings { protected DoubleList values = new DoubleArrayList(); protected double minRating = Double.MAX_VALUE; protected double maxRating = Double.MIN_NORMAL; private IntList countByUser; private IntArrayList countByItem; public DoubleList values() { return values; } @Override public double get(int index) { return values.getDouble(index); } @Override public double set(int index, double rating) { return values.set(index, rating); } @Override public double minRating() { return minRating; } @Override public double maxRating() { return maxRating; } @Override public IntList countByUser() { if (countByUser == null) buildByUserCounts(); return countByUser; } public void buildByUserCounts() { countByUser = new IntArrayList(maxUserID + 1); countByUser.size(maxUserID + 1); for (int index = 0; index < size(); index++) { int userId = users.getInt(index); Integer count = countByUser.get(userId); if (count != null) countByUser.set(userId, count + 1); else countByUser.set(userId, 1); } } @Override public IntList countByItem() { if (countByItem == null || countByItem.size() < maxItemID + 1) buildByItemCounts(); return countByItem; } public void buildByItemCounts() { countByItem = new IntArrayList(maxItemID + 1); for (int index = 0; index < size(); index++) { int itemId = items.getInt(index); Integer count = countByItem.get(itemId); if (count != null) countByItem.set(itemId, count + 1); else countByItem.set(itemId, 1); } } @Override public double average() { double sum = 0; for (int index = 0; index < size(); index++) sum += get(index); double average = sum / size(); return average; } @Override public double get(int user_id, int item_id) { for (int index = 0; index < values.size(); index++) if (users.getInt(index) == user_id && items.getInt(index) == item_id) return values.getDouble(index); throw new InvalidKeyException("rating " + user_id + ", " + item_id + " not found."); } @Override public Double tryGet(int user_id, int item_id) { for (int index = 0; index < values.size(); index++) if (users.getInt(index) == user_id && items.getInt(index) == item_id) return values.get(index); return null; } @Override public double get(int user_id, int item_id, IntCollection indexes) { for (int index : indexes) if (users.getInt(index) == user_id && items.getInt(index) == item_id) return values.getDouble(index); throw new InvalidKeyException("rating " + user_id + ", " + item_id + " not found."); } @Override public Double tryGet(int user_id, int item_id, IntCollection indexes) { for (int index : indexes) if (users.getInt(index) == user_id && items.getInt(index) == item_id) return values.get(index); return null; } @Override public Integer tryGetIndex(int user_id, int item_id) { for (int i = 0; i < size(); i++) if (users.getInt(i) == user_id && items.getInt(i) == item_id) return i; return null; } @Override public void add(int user_id, int item_id, float rating) { add(user_id, item_id, (double) rating); byUser = null; } @Override public void add(int user_id, int item_id, byte rating) { add(user_id, item_id, (double) rating); byUser = null; } @Override public void add(int user_id, int item_id, double rating) { users.add(user_id); items.add(item_id); values.add(rating); int pos = users.size() - 1; if (user_id > maxUserID) maxUserID = user_id; if (item_id > maxItemID) maxItemID = item_id; if (rating < minRating) minRating = rating; if (rating > maxRating) maxRating = rating; // Update index data structures if necessary. if (byUser != null) { for (int u = byUser.size(); u <= user_id; u++) byUser.add(new IntArrayList()); byUser.get(user_id).add(pos); } if (byItem != null) { for (int i = byItem.size(); i <= item_id; i++) byItem.add(new IntArrayList()); byItem.get(item_id).add(pos); } } public void removeAt(int index) { users.remove(index); items.remove(index); values.removeDouble(index); } @Override public void removeUser(int user_id) { for (int index = 0; index < size(); index++) if (users.getInt(index) == user_id) { users.remove(index); items.remove(index); values.remove(index); } if (maxUserID == user_id) maxUserID--; } @Override public void removeItem(int item_id) { for (int index = 0; index < size(); index++) if (items.getInt(index) == item_id) { users.remove(index); items.remove(index); values.remove(index); } if (maxItemID == item_id) maxItemID--; } public boolean isReadOnly() { return true; } // @Override // public Integer tryGetIndex(int user_id, int item_id, IntCollection indexes) { // for (int i : indexes) // if (users.getInt(i) == user_id && items.getInt(i) == item_id) // return i; // return null; // } // // /** Override an existing value if it exists. */ // public void addOrUpdate(int user_id, int item_id, double rating) { // for (int index = 0; index < values.size(); index++) // if (users.getInt(index) == user_id && items.getInt(index) == item_id) { // values.set(index, rating); // return; // } // add(user_id, item_id, rating); // } // // @Override // public boolean add(Double e) { // throw new UnsupportedOperationException(); // } // // @Override // public void add(int index, Double element) { // throw new UnsupportedOperationException(); // } // @Override // public boolean addAll(Collection<? extends Double> c) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean addAll(int index, Collection<? extends Double> c) { // throw new UnsupportedOperationException(); // } // // @Override // public void clear() { // throw new UnsupportedOperationException(); // } // // @Override // public boolean contains(Object o) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean containsAll(Collection<?> c) { // throw new UnsupportedOperationException(); // } // // @Override // public int indexOf(Object o) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean isEmpty() { // throw new UnsupportedOperationException(); // } // // @Override // public int lastIndexOf(Object o) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean remove(Object o) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean removeAll(Collection<?> c) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean retainAll(Collection<?> c) { // throw new UnsupportedOperationException(); // } // // @Override // public Double set(int index, Double element) { // throw new UnsupportedOperationException(); // } // // @Override // public Object[] toArray() { // throw new UnsupportedOperationException(); // } // // @Override // public <T> T[] toArray(T[] a) { // throw new UnsupportedOperationException(); // } // // @Override // public int compareTo(List<? extends Double> o) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean addAll(DoubleCollection arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean contains(double arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean containsAll(DoubleCollection arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean rem(double arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean removeAll(DoubleCollection arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean retainAll(DoubleCollection arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public double[] toArray(double[] arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public double[] toDoubleArray() { // throw new UnsupportedOperationException(); // } // // @Override // public double[] toDoubleArray(double[] arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean add(double arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public void add(int arg0, double arg1) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean addAll(DoubleList arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean addAll(int arg0, DoubleCollection arg1) { // throw new UnsupportedOperationException(); // } // // @Override // public boolean addAll(int arg0, DoubleList arg1) { // throw new UnsupportedOperationException(); // } // // @Override // public void addElements(int arg0, double[] arg1) { // throw new UnsupportedOperationException(); // } // // @Override // public void addElements(int arg0, double[] arg1, int arg2, int arg3) { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleList doubleSubList(int arg0, int arg1) { // throw new UnsupportedOperationException(); // } // // @Override // public void getElements(int arg0, double[] arg1, int arg2, int arg3) { // throw new UnsupportedOperationException(); // } // // @Override // public int indexOf(double arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public int lastIndexOf(double arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public double removeDouble(int arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public void removeElements(int arg0, int arg1) { // throw new UnsupportedOperationException(); // } // // @Override // public void size(int arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleList subList(int arg0, int arg1) { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleListIterator doubleListIterator() { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleListIterator doubleListIterator(int arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleListIterator iterator() { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleListIterator listIterator() { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleListIterator listIterator(int arg0) { // throw new UnsupportedOperationException(); // } // // @Override // public DoubleIterator doubleIterator() { // throw new UnsupportedOperationException(); // } }