/*******************************************************************************
* Copyright (c) 2013 Imperial College London.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Raul Castro Fernandez - initial design and implementation
******************************************************************************/
package uk.ac.imperial.lsds.seep.api.largestateimpls;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
public class Matrix implements MatrixI, Serializable{
private static final long serialVersionUID = 1L;
private int colSize = 0;
// map the row tag with a row index
protected HashMap<Integer, Integer> rowIds = new HashMap<Integer, Integer>();
// the real rows
protected ArrayList<ArrayList<Component>> rows = new ArrayList<ArrayList<Component>>();
protected int rowSize = 0;
public int size(){
return rowSize;
}
public ArrayList<ArrayList<Component>> getRows(){
return rows;
}
/** BUILDER METHODS **/
public Matrix(){
this.colSize = 0;
}
public HashMap<Integer, Integer> getRowIds(){
return rowIds;
}
public Matrix(ArrayList<ArrayList<Component>> rows, int cols){
// Assign row ids
for(int i = 0; i<rows.size(); i++){
rowIds.put(i, i);
}
this.rows = rows;
this.colSize = cols;
}
/** OPERATIONS ON ROWS **/
@Override
public ArrayList<Component> getRowVectorWithTag(int rowTag) {
if(rowIds.get(rowTag) == null){
return null;
}
int rowIndex = rowIds.get(rowTag);
// ///\fixme{this should be safe higher in the stack}
// if(rows.get(rowIndex) == null){
// return null;
// }
return rows.get(rowIndex);
}
public void setRow(ArrayList<Component> component, int rowTag){
int idx;
if(rowIds.get(rowTag) != null){
// Update
idx = rowIds.get(rowTag);
rows.set(idx, component);
}
else{
// new
rows.add(component);
rowSize++;
// Update the rowIds with the new id for this row
rowIds.put(rowTag, rows.size()-1);
}
// Update cols
if (colSize < component.get(component.size()-1).col + 1){
colSize = component.get(component.size()-1).col + 1;
}
}
public synchronized void updateMatrixByIncreasingValue(int rowTag, int col, int value){
if(rowIds.get(rowTag) != null){
// If it exists, then update val in col
ArrayList<Component> row = getRowVectorWithTag(rowTag);
//int rowIdx = rows.indexOf(row);
int rowIdx = rowIds.get(rowTag);
if(row == null){
return;
}
// We go to the specific col to update
for(int i = 0; i < row.size(); i++){
// If the current col is equal or greater than col to update, insert col before this one
int currentElCol = row.get(i).col;
if(currentElCol > col){
int insertIdx = (i-1) < 0 ? 0 : i-1;
row.add(insertIdx, new Component(col, value));
break;
}
else if(currentElCol == col){
int current_value = row.get(i).value;
row.set(i, new Component(col, (current_value+value)));
break;
}
// else if the current col is lesser than col, and is the last element...
else if(currentElCol < col && row.size() == i+1){
// Insert at the end
row.add(new Component(col, value));
// This made the algo work.... shit
break;
}
}
// Finally insert the updated row
rows.set(rowIdx, row);
}
else{
// Non existent row, create a new one with the given value
ArrayList<Component> c = new ArrayList<Component>();
// System.out.println("Writing: row: "+c.size()+" col: "+col+" value: "+value);
c.add(new Component(col, value));
// Add to rows and update rowIds
rows.add(c);
rowSize++;
rowIds.put(rowTag, rows.size()-1);
}
// Update cols
ArrayList<Component> row = getRowVectorWithTag(rowTag);
if (colSize < row.get(row.size()-1).col + 1){
colSize = row.get(row.size()-1).col + 1;
}
}
/** Profiling decomposition **/
private ArrayList<Component> d(ArrayList<Component> row, int insertIdx, int col, int value){
long s = System.currentTimeMillis();
row.add(insertIdx, new Component(col, value));
long e = System.currentTimeMillis();
dtime += (e-s);
return row;
}
private ArrayList<Component> e(ArrayList<Component> row, int i, int col, int current_value, int value){
long s = System.currentTimeMillis();
row.set(i, new Component(col, (current_value+value)));
long e = System.currentTimeMillis();
etime += (e-s);
return row;
}
private ArrayList<Component> f(ArrayList<Component> row, int col, int value){
long s = System.currentTimeMillis();
row.add(new Component(col, value));
long e = System.currentTimeMillis();
ftime += (e-s);
return row;
}
private ArrayList<Component> c(ArrayList<Component> row, int col, int value){
long s = System.currentTimeMillis();
for(int i = 0; i < row.size(); i++){
// If the current col is equal or greater than col to update, insert col before this one
int currentElCol = row.get(i).col;
if(currentElCol > col){
int insertIdx = (i-1) < 0 ? 0 : i-1;
d(row, insertIdx, col, value);
break;
}
else if(currentElCol == col){
int current_value = row.get(i).value;
e(row, i, col, current_value, value);
break;
}
// else if the current col is lesser than col, and is the last element...
else if(currentElCol < col && row.size() == i+1){
// Insert at the end
f(row, col, value);
// This made the algo work.... shit
break;
}
}
long e = System.currentTimeMillis();
ctime += (e-s);
return row;
}
private void a(int rowTag, int col, int value){
long s = System.currentTimeMillis();
// If it exists, then update val in col
ArrayList<Component> row = getRowVectorWithTag(rowTag); // a1
long e1 = System.currentTimeMillis();
a1 += (e1-s);
int rowIdx = rowIds.get(rowTag);
long e2 = System.currentTimeMillis();
a2 += (e2-s);
// We go to the specific col to update
row = c(row, col, value);
// Finally insert the updated row
rows.set(rowIdx, row);
long e3 = System.currentTimeMillis();
a3 = (e3-s);
long e = System.currentTimeMillis();
atime += (e-s);
}
private void b(int rowTag, int col, int value){
long s = System.currentTimeMillis();
// Non existent row, create a new one with the given value
ArrayList<Component> c = new ArrayList<Component>();
c.add(new Component(col, value));
// Add to rows and update rowIds
rows.add(c);
rowSize++;
rowIds.put(rowTag, rows.size()-1);
long e = System.currentTimeMillis();
btime += (e-s);
}
public long totaltime = 0;
public long atime = 0;
public long a1 = 0;
public long a2 = 0;
public long a3 = 0;
public long btime = 0;
public long ctime = 0;
public long dtime = 0;
public long etime = 0;
public long ftime = 0;
public void _updateMatrixByReplacingValue(int rowTag, int col, int value){
long s = System.currentTimeMillis();
if(rowIds.get(rowTag) != null){
a(rowTag, col, value);
}
else{
b(rowTag, col, value);
}
long e = System.currentTimeMillis();
totaltime += (e-s);
}
public long reptime = 0;
public synchronized void updateMatrixByReplacingValue(int rowTag, int col, int value){
// System.out.println("surprise!");
//long s = System.currentTimeMillis();
if(rowIds.get(rowTag) != null){
// If it exists, then update val in col
ArrayList<Component> row = this.getRowVectorWithTag(rowTag);
//int rowIdx = rows.indexOf(row); // Looping through size
int rowIdx = rowIds.get(rowTag);
// We go to the specific col to update
if(row == null){
return;
}
for(int i = 0; i< row.size(); i++){
// If the current col is equal or greater than col to update, insert col before this one
int currentElCol = row.get(i).col;
if(currentElCol > col){
int insertIdx = (i-1) < 0 ? 0 : i-1;
row.add(insertIdx, new Component(col, value));
break;
}
else if(currentElCol == col){
row.set(i, new Component(col, value));
break;
}
// else if the current col is lesser than col, and is the last element...
else if(currentElCol < col && row.size() == i+1){
// Insert at the end
row.add(new Component(col, value));
break;
}
}
// Finally insert the updated row
rows.set(rowIdx, row);
}
else{
// Non existent row, create a new one with the given value
ArrayList<Component> c = new ArrayList<Component>();
c.add(new Component(col, value));
// Add to rows and update rowIds
rows.add(c);
rowSize++;
rowIds.put(rowTag, rows.size()-1);
}
// Update cols
ArrayList<Component> row = getRowVectorWithTag(rowTag);
if (colSize < row.get(row.size()-1).col + 1){
colSize = row.get(row.size()-1).col + 1;
}
//long e = System.currentTimeMillis();
//reptime += (e-s);
}
public void updateMatrix(ArrayList<Component> vector, int rowTag){
// If the row already existed
if(rowIds.get(rowTag) != null){
rows.set(rowIds.get(rowTag), vector);
}
// If its a new row
else{
rows.add(vector);
rowSize++;
rowIds.put(rowTag, rows.size()-1);
}
// Update cols
if (colSize < vector.get(vector.size()-1).col + 1){
colSize = vector.get(vector.size()-1).col + 1;
}
}
/** OPERATIONS OVER MATRICES **/
private ArrayList<ArrayList<Integer>> getZeroSquaredMatrix(int n){
ArrayList<ArrayList<Integer>> cMatrix = new ArrayList<ArrayList<Integer>>(n);
for(int i = 0; i<n; i++){
ArrayList<Integer> cRow = new ArrayList<Integer>();
for(int j = 0; j<n; j++){
cRow.add(0);
}
cMatrix.add(cRow);
}
return cMatrix;
}
//
public Matrix LILcoOccurrence(ArrayList<ArrayList<Component>> m) {
if(m.isEmpty()){
return null;
}
Matrix co = new Matrix();
// Loop through rows
for(int i = 0; i<m.size(); i++){
// Item selector, only picking non-zero elements, the relevant ones
for(Component item : m.get(i)){
// We iterate over the elements, also non-zero values always
for(Component iter : m.get(i)){
// Match, we want to increase the counter of co-occurrence for item-iter
// update for row i, col item, with value++
co.updateMatrixByIncreasingValue(item.col, iter.col, 1);
}
}
}
return co;
}
public long totalco = 0;
public long aco = 0;
public long bco = 0;
public long cco = 0;
public long dco = 0;
private Matrix dco(Matrix currentCO, Component item, Component iter, HashMap<Integer, Boolean> mem){
long s = System.currentTimeMillis();
int key = item.col*10+iter.col;
if(mem.get(key) == null){
currentCO.updateMatrixByReplacingValue(item.col, iter.col, 0);
mem.put(key, true);
}
currentCO.updateMatrixByIncreasingValue(item.col, iter.col, 1);
long e = System.currentTimeMillis();
dco += (e-s);
return currentCO;
}
private Matrix cco(ArrayList<ArrayList<Component>> m, Matrix currentCO, int itemId, HashMap<Integer, Boolean> mem, int i, Component item, ArrayList<Component> row, int j){
long s = System.currentTimeMillis();
// We iterate over the elements, also non-zero values always
//for(Component iter : row){
for(int k = j ; j<row.size(); j++){
Component iter = row.get(k);
// Match, we want to increase the counter of co-occurrence for item-iter
// update for row i, col item, with value++
if(item.col == itemId || iter.col == itemId){
currentCO = dco(currentCO, item, iter, mem);
break;
}
}
long e = System.currentTimeMillis();
cco += (e-s);
return currentCO;
}
private Matrix bco(ArrayList<ArrayList<Component>> m, Matrix currentCO, int itemId, HashMap<Integer, Boolean> mem, int i){
long s = System.currentTimeMillis();
// Item selector, only picking non-zero elements, the relevant ones
ArrayList<Component> row = m.get(i);
for(Component item : row){
int j = i;
// Constraint on the item id to modify
currentCO = cco(m, currentCO, itemId, mem, i, item, row, j);
}
long e = System.currentTimeMillis();
bco += (e-s);
return currentCO;
}
private Matrix aco(ArrayList<ArrayList<Component>> m, Matrix currentCO, int itemId){
long s = System.currentTimeMillis();
int rowSize = m.size();
HashMap<Integer, Boolean> mem = new HashMap<Integer, Boolean>();
// Loop through rows
for(int i = 0; i<rowSize; i++){
currentCO = bco(m, currentCO, itemId, mem, i);
}
long e = System.currentTimeMillis();
aco += (e-s);
return currentCO;
}
public Matrix _incLILcoOccurrence(ArrayList<ArrayList<Component>> m, Matrix currentCO, int itemId){
long s = System.currentTimeMillis();
if(m.isEmpty()){
return null;
}
aco(m, currentCO, itemId);
long e = System.currentTimeMillis();
totalco += (e-s);
return currentCO;
}
public long cotime = 0;
public int its = 0;
public Matrix incLILcoOccurrence(ArrayList<ArrayList<Component>> m, Matrix currentCO, int itemId){
//long s = System.currentTimeMillis();
//its++;
if(m.isEmpty()){
return null;
}
int rowSize = m.size();
HashMap<Integer, Boolean> mem = new HashMap<Integer, Boolean>();
// Loop through rows
for(int i = 0; i<rowSize; i++){
// Item selector, only picking non-zero elements, the relevant ones
for(Component item : m.get(i)){
// Constraint on the item id to modify
// We iterate over the elements, also non-zero values always
for(Component iter : m.get(i)){
// Match, we want to increase the counter of co-occurrence for item-iter
// update for row i, col item, with value++
if(item.col == itemId || iter.col == itemId){
int key = item.col*10+iter.col;
if(mem.get(key) == null){
currentCO.updateMatrixByReplacingValue(item.col, iter.col, 0);
mem.put(key, true);
}
currentCO.updateMatrixByIncreasingValue(item.col, iter.col, 1);
}
}
}
}
//long e = System.currentTimeMillis();
//cotime += (e-s);
return currentCO;
}
public Matrix incLILcoOccurrence2(ArrayList<ArrayList<Component>> m, Matrix currentCO, int itemId){
if(m.isEmpty()){
return null;
}
int rowSize = m.size();
HashMap<Integer, Boolean> mem = new HashMap<Integer, Boolean>();
// Loop through rows
for(int i = 0; i<rowSize; i++){
// Item selector, only picking non-zero elements, the relevant ones
ArrayList<Component> row = m.get(i);
for(Component item : row){
int j = i;
// Constraint on the item id to modify
// We iterate over the elements, also non-zero values always
//for(Component iter : row){
for(int k = j; j<row.size(); j++){
Component iter = row.get(k);
// Match, we want to increase the counter of co-occurrence for item-iter
// update for row i, col item, with value++
if(item.col == itemId || iter.col == itemId){
int key = item.col*10+iter.col;
if(mem.get(key) == null){
currentCO.updateMatrixByReplacingValue(item.col, iter.col, 0);
mem.put(key, true);
}
currentCO.updateMatrixByIncreasingValue(item.col, iter.col, 1);
}
}
}
}
return currentCO;
}
//TODO: implement the optimised method using accessIdx (to compute only the diagonal)
@Override
@Deprecated
public ArrayList<ArrayList<Integer>> coOccurrence(ArrayList<ArrayList<Integer>> m) {
if(m.isEmpty()){
return null;
}
int numItems = m.get(0).size();
// Build a zeroed co-occurrence matrix
ArrayList<ArrayList<Integer>> cMatrix = getZeroSquaredMatrix(numItems);
// loop through rows
for(int i = 0; i<m.size(); i++){
// Pick a given item
for(int j = 0; j<numItems; j++){
if(getValue(i, j, m) != 0){
// Check if the current item co-occurs with the rest of items
for(int k = 0; k<numItems; k++){
if(getValue(i, k, m) != 0){
int value = getValue(j, k, cMatrix);
ArrayList<Integer> rowToUpdate = cMatrix.get(j);
rowToUpdate.set(k, ++value);
cMatrix.set(j, rowToUpdate);
}
}
}
}
}
return cMatrix;
}
private int getValue(int row, int col, ArrayList<ArrayList<Integer>> m){
return m.get(row).get(col);
}
public ArrayList<Component> LILmultiplyVectorByDiagonalMatrix(ArrayList<Component> v, Matrix m){
if(v == null || m == null){
return null;
}
ArrayList<Component> r = new ArrayList<Component>();
// Every row in the matrix m
for(int i = 0; i<m.getRows().size(); i++){
// Pick the row
ArrayList<Component> toBeMultiplied = m.getRowVectorWithTag(i);
if(toBeMultiplied != null){
// Now, multiply that row by the vector and get 1 value.
int partialSum = 0;
// Every non zero component in the vector
for(Component cv : v){
// Multiplied by every non/zero component in the toBeMultiplied vector
for(Component cm : toBeMultiplied){
// If the col matches
if(cv.col == cm.col){
// System.out.println("Multiply: "+cv.col+" by "+cm.col);
// System.out.println("For a total value of : "+(cv.value * cm.value));
partialSum = partialSum + (cv.value * cm.value);
break;
}
}
}
if(partialSum != 0){
Component newComponent = new Component(i, partialSum);
r.add(newComponent);
}
}
}
return r;
}
@Deprecated
public static ArrayList<Integer> multipyVectorByDiagonalMatrix(ArrayList<Integer> vector, ArrayList<ArrayList<Integer>> m) {
int cols = vector.size();
// A value per item
ArrayList<Integer> rVector = new ArrayList<Integer>(cols);
for(ArrayList<Integer> row : m){
int v = 0;
for(int i = 0; i < cols; i++){
v += vector.get(i) * row.get(i);
}
rVector.add(v);
}
return rVector;
}
/** OPERATIONS TO SPLIT MATRICES **/
@Override
public Matrix[] splitByCol(Matrix m) {
// TODO Auto-generated method stub
return null;
}
@Override
public Matrix[] splitByRows(Matrix m) {
// TODO Auto-generated method stub
return null;
}
/** OPERATIONS RELATED TO MATRICES/VECTOR REPRESENTATIONS **/
public static ArrayList<Integer> representVectorAsBest(ArrayList<Component> v){
int estimatedColSize;
ArrayList<Integer> r = new ArrayList<Integer>();
if(!v.isEmpty()){
estimatedColSize = v.get(v.size()-1).col;
}
else{
return null;
}
estimatedColSize++; // Add additional column
for(int i = 0; i<estimatedColSize; i++){
r.add(0);
}
for(Component c : v){
//int idx = (c.col-1 < 0) ? 0 : c.col-1;
int idx = c.col;
r.set(idx, c.value);
}
return r;
}
@Override
public ArrayList<ArrayList<Integer>> getExpandedRepr(){
// Build a zeroed matrix
ArrayList<ArrayList<Integer>> xMatrix = new ArrayList<ArrayList<Integer>>(this.rows.size());
for(int j = 0; j<this.rows.size(); j++){
ArrayList<Integer> xRow = new ArrayList<Integer>(colSize);
for(int i = 0; i< colSize; i++){
xRow.add(0);
}
int insertIdx = rowIds.get(j);
xMatrix.add(insertIdx, xRow);
}
for(ArrayList<Component> row : rows){
int rowIdx = rows.indexOf(row);
ArrayList<Integer> pivot = xMatrix.get(rowIdx);
for(Component c : row){
pivot.set(c.col, c.value);
}
xMatrix.set(rowIdx, pivot);
}
return xMatrix;
}
public ArrayList<Integer> getExpandedVectorRepresentation(ArrayList<Component> vector){
// Create zeroed vector
ArrayList<Integer> toReturn = new ArrayList<Integer>();
for(int i = 0; i<colSize; i++){
toReturn.add(0);
}
for(Component c : vector){
toReturn.set(c.col, c.value);
}
return toReturn;
}
/** PRINT/OUTPUT METHODS **/
public void printVector(ArrayList<Component> vector){
// Create zeroed vector
ArrayList<Integer> toPrint = new ArrayList<Integer>();
for(int i = 0; i<colSize; i++){
toPrint.add(0);
}
for(Component c : vector){
toPrint.set(c.col, c.value);
}
for(Integer i : toPrint){
System.out.print(i+", ");
}
System.out.println("");
}
public void printIntegerVector(ArrayList<Integer> vector){
// One print per colum
for(int i = 0; i<vector.size(); i++){
System.out.print(vector.get(i)+", ");
}
System.out.println("");
}
public void printMatrix(){
// how many rows are there?
int rows = this.getRows().size();
for(int i = 0; i<rows; i++){
int rowIdx = rowIds.get(i);
ArrayList<Component> r = this.getRows().get(rowIdx);
printVector(r);
}
System.out.println();
}
public void printXMatrix(ArrayList<ArrayList<Integer>> x){
for(ArrayList<Integer> row : x){
for(Integer i : row){
System.out.print(i+", ");
}
System.out.println("");
}
}
public void printDimensions(){
System.out.println("DIM: "+rowSize+"x"+colSize);
}
public void printDimensionsReliably() {
System.out.println("DIM-rows: "+this.rows.size());
}
}
//@Deprecated
//public Matrix LILcoOccurrence2(ArrayList<ArrayList<Component>> m, Matrix co) {
// if(m.isEmpty()){
// return null;
// }
// // Loop through rows
// for(int i = 0; i<m.size(); i++){
// // Item selector, only picking non-zero elements, the relevant ones
// for(Component item : m.get(i)){
// // We iterate over the elements, also non-zero values always
// for(Component iter : m.get(i)){
// // Match, we want to increase the counter of co-occurrence for item-iter
// // update for row i, col item, with value++
// co.updateMatrixByIncreasingValue(item.col, iter.col, 1);
// }
// }
// }
// return co;
//}
//
//@Deprecated
//public Matrix LILcoOccurrence3_gitan(ArrayList<ArrayList<Component>> m, Matrix co, int row, int col) {
// if(m.isEmpty()){
// return null;
// }
// // Loop through rows
// for(int i = 0; i<m.size(); i++){
// // Item selector, only picking non-zero elements, the relevant ones
// for(Component item : m.get(i)){
// // We iterate over the elements, also non-zero values always
// for(Component iter : m.get(i)){
// // Match, we want to increase the counter of co-occurrence for item-iter
// // update for row i, col item, with value++
// if(item.col == row && iter.col == col){
// co.updateMatrixByIncreasingValue(item.col, iter.col, 1);
// }
// }
// }
// }
// return co;
//}