/*******************************************************************************
* Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt
******************************************************************************/
package com.opendoorlogistics.core.distances;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.opendoorlogistics.api.components.PredefinedTags;
import com.opendoorlogistics.api.distances.ODLCostMatrix;
import com.opendoorlogistics.api.geometry.LatLong;
import com.opendoorlogistics.api.tables.ODLColumnType;
import com.opendoorlogistics.api.tables.ODLTable;
import com.opendoorlogistics.api.tables.ODLTableReadOnly;
import com.opendoorlogistics.api.tables.TableQuery;
import com.opendoorlogistics.core.tables.memory.ODLTableDefinitionImpl;
import com.opendoorlogistics.core.tables.utils.TableUtils;
import com.opendoorlogistics.core.utils.Numbers;
import com.opendoorlogistics.core.utils.iterators.IteratorUtils;
import com.opendoorlogistics.core.utils.strings.StandardisedStringTreeMap;
public class ODLCostMatrixImpl extends ODLTableDefinitionImpl implements ODLTable,ODLCostMatrix {
final private List<String> ids;
protected final static String [] STANDARD_COST_FIELDNAMES = new String[] { PredefinedTags.TRAVEL_COST, PredefinedTags.DISTANCE, PredefinedTags.TIME };
final private double[][][] matrix;
final private int n;
final private int nSquared;
final private int nbCosts;
// final private int fromCol;
// final private int toCol;
// final private int costCol;
final private StandardisedStringTreeMap<Integer> idsToIndices = new StandardisedStringTreeMap<>(false);
public enum MatrixType {
SINGLE_COST, DISTANCE_TIME
}
@Override
public long getSizeInBytes() {
return nbCosts * n * n * 8;
}
public ODLCostMatrixImpl(Iterable<String> ids,String[]costFieldNames) {
setName(PredefinedTags.TRAVEL_COSTS);
nbCosts = costFieldNames.length;
// setup table definition
addColumn(-1, PredefinedTags.FROM_LOCATION, ODLColumnType.STRING, 0);
addColumn(-1, PredefinedTags.TO_LOCATION, ODLColumnType.STRING, 0);
for(int i =0 ; i<costFieldNames.length ; i++){
addColumn(-1, costFieldNames[i], ODLColumnType.DOUBLE, 0);
}
this.ids = IteratorUtils.toList(ids);
this.n = this.ids.size();
this.nSquared = n * n;
matrix = new double[costFieldNames.length][][];
for (int i = 0; i < costFieldNames.length; i++) {
matrix[i] = new double[n][];
for (int j = 0; j < n; j++) {
matrix[i][j] = new double[n];
}
}
// setup id lookup
for (int i = 0; i < n; i++) {
String s = this.ids.get(i);
if (idsToIndices.get(s) != null) {
throw new RuntimeException("Duplicate location id: " + s);
}
idsToIndices.put(s, i);
}
}
@Override
public int getRowCount() {
return nSquared;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
int from = rowIndex / n;
int to = rowIndex % n;
if (columnIndex == 0) {
return ids.get(from);
} else if (columnIndex == 1) {
return ids.get(to);
} else if (columnIndex > 1) {
return (double) matrix[columnIndex - 2][from][to];
}
return null;
}
@Override
public Object getValueById(long rowId, int columnIndex) {
int index = TableUtils.getLocalRowId(rowId);
return getValueAt(index, columnIndex);
}
@Override
public long getRowId(int rowIndex) {
return TableUtils.getGlobalId(getImmutableId(), rowIndex);
}
@Override
public boolean containsRowId(long rowId) {
int index = TableUtils.getLocalRowId(rowId);
return index < nSquared;
}
@Override
public long[] find(int col, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex >= 2) {
int from = rowIndex / n;
int to = rowIndex % n;
Double val = Numbers.toDouble(aValue);
float f;
if (val != null) {
f = (float) val.doubleValue();
} else {
f = 0;
}
matrix[columnIndex - 2][from][to] = f;
} else {
throw new UnsupportedOperationException();
}
}
public String getId(int i) {
return ids.get(i);
}
@Override
public double get(int fromIndex, int toIndex, int dim) {
return matrix[dim][fromIndex][toIndex];
}
//
// public void set(float val, String from, String to, int dim){
// set(val, idsToIndices.get(from), idsToIndices.get(to),dim);
// }
public void set(double val, int fromIndex, int toIndex, int dim) {
matrix[dim][fromIndex][toIndex] = val;
}
@Override
public void setValueById(Object aValue, long rowid, int columnIndex) {
int index = TableUtils.getLocalRowId(rowid);
setValueAt(aValue, index, columnIndex);
}
@Override
public int createEmptyRow(long rowId) {
throw new UnsupportedOperationException();
}
@Override
public void insertEmptyRow(int insertAtRowNb, long rowId) {
throw new UnsupportedOperationException();
}
@Override
public void deleteRow(int rowNumber) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return TableUtils.convertToString(this);
}
@Override
public long getRowFlags(long rowId) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void setRowFlags(long flags, long rowId) {
// TODO Auto-generated method stub
}
@Override
public int getNbCosts() {
return matrix.length;
}
@Override
public int getIndex(String id){
Integer ret = idsToIndices.get(id);
if(ret==null){
return -1;
}
return ret;
}
@Override
public int getNbFroms() {
return n;
}
@Override
public int getNbTos() {
return n;
}
// @Override
// public int getNbConnectedSubsets() {
// // TODO Auto-generated method stub
// return 0;
// }
//
// @Override
// public Iterable<String> getConnectedSubset(int i) {
// // TODO Auto-generated method stub
// return null;
// }
@Override
public boolean getIsConnected(int from, int to) {
for(int i=0 ; i < matrix.length ; i++){
if(matrix[i][from][to]==Double.POSITIVE_INFINITY || matrix[i][from][to]==Double.NaN || matrix[i][from][to]==Double.MAX_VALUE ){
return false;
}
}
return true;
}
@Override
public long getRowLastModifiedTimeMillsecs(long rowId) {
return 0;
}
@Override
public ODLTableReadOnly query(TableQuery query) {
return null;
}
public static ODLCostMatrixImpl createEmptyMatrix(List<Map.Entry<String, LatLong>> list) {
ArrayList<String> idList = new ArrayList<>();
for (Map.Entry<String, LatLong> entry : list) {
idList.add(entry.getKey());
}
ODLCostMatrixImpl output = new ODLCostMatrixImpl(idList,STANDARD_COST_FIELDNAMES);
return output;
}
@Override
public boolean isStillValid() {
return true;
}
@Override
public String getFromId(int fromIndex) {
return ids.get(fromIndex);
}
@Override
public String getToId(int toIndex) {
return ids.get(toIndex);
}
}