blob: d1b0c8a91b9aa9dcad5a7a927edfaf583da20b03 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sysds.runtime.data;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.sysds.common.Types;
import org.apache.sysds.runtime.util.UtilFunctions;
import org.apache.sysds.utils.MemoryEstimates;
import java.util.Arrays;
import java.util.HashMap;
public class DenseBlockFP64DEDUP extends DenseBlockDRB
{
private static final long serialVersionUID = -4012376952006079198L;
private double[][] _data;
//TODO: implement estimator for nr of distinct
private int _distinct = 0;
public void setDistinct(int d){
_distinct = d;
}
protected DenseBlockFP64DEDUP(int[] dims) {
super(dims);
reset(_rlen, _odims, 0);
}
public int getNrDistinctRows(){
return _distinct;
}
@Override
protected void allocateBlock(int bix, int length) {
_data[bix] = new double[length];
}
@Override
public void reset(int rlen, int[] odims, double v) {
if(rlen > _rlen)
_data = new double[rlen][];
else{
if(_data == null)
_data = new double[rlen][];
if(v == 0.0){
for(int i = 0; i < rlen; i++)
_data[i] = null;
}
else {
for(int i = 0; i < rlen; i++) {
if(odims[0] > _odims[0] ||_data[i] == null )
allocateBlock(i, odims[0]);
Arrays.fill(_data[i], 0, odims[0], v);
}
}
}
_rlen = rlen;
_odims = odims;
}
@Override
public void resetNoFill(int rlen, int[] odims) {
if(_data == null || rlen > _rlen){
_data = new double[rlen][];
}
_rlen = rlen;
_odims = odims;
}
@Override
public boolean isNumeric() {
return true;
}
@Override
public boolean isNumeric(Types.ValueType vt) {
return Types.ValueType.FP64 == vt;
}
@Override
public long capacity() {
return (_data != null) ? ((long) _data.length)*_odims[0] : -1;
}
@Override
public long countNonZeros() {
long nnz = 0;
HashMap<double[], Long> cache = new HashMap<>();
for (int i = 0; i < _rlen; i++) {
double[] row = this._data[i];
if(row == null)
continue;
Long count = cache.getOrDefault(row, null);
if(count == null){
count = Long.valueOf(countNonZeros(i));
cache.put(row, count);
}
nnz += count;
}
this._distinct = cache.size();
return nnz;
}
@Override
public int countNonZeros(int r) {
return _data[r] == null ? 0 : UtilFunctions.computeNnz(_data[r], 0, _odims[0]);
}
@Override
public long countNonZeros(int rl, int ru, int ol, int ou) {
long nnz = 0;
HashMap<double[], Long> cache = new HashMap<>();
for (int i = rl; i < ru; i++) {
double[] row = this._data[i];
if(row == null)
continue;
Long count = cache.getOrDefault(row, null);
if(count == null){
count = Long.valueOf(UtilFunctions.computeNnz(_data[i], ol, ou));
cache.put(row, count);
}
nnz += count;
}
return nnz;
}
@Override
protected long computeNnz(int bix, int start, int length) {
int nnz = 0;
int row_start = (int) Math.floor(start / _odims[0]);
int col_start = start % _odims[0];
for (int i = 0; i < length; i++) {
if(_data[row_start] == null){
i += _odims[0] - 1 - col_start;
col_start = 0;
row_start += 1;
continue;
}
nnz += _data[row_start][col_start] != 0 ? 1 : 0;
col_start += 1;
if(col_start == _odims[0]) {
col_start = 0;
row_start += 1;
}
}
return nnz;
}
@Override
public int pos(int r){
return 0;
}
@Override
public int pos(int r, int c){
return c;
}
@Override
public int pos(int[] ix){
int pos = ix[ix.length - 1];
for(int i = 1; i < ix.length - 1; i++)
pos += ix[i] * _odims[i];
return pos;
}
@Override
public int blockSize(int bix) {
return 1;
}
@Override
public boolean isContiguous() {
return false;
}
@Override
public boolean isContiguous(int rl, int ru){
return rl == ru;
}
@Override
public double[] values(int r) {
return valuesAt(r);
}
@Override
public double[] valuesAt(int bix) {
return _data[bix] == null ? new double[_odims[0]] : _data[bix];
}
@Override
public int index(int r) {
return r;
}
@Override
public int numBlocks(){
return _data.length;
}
@Override
public int size(int bix) {
return _odims[0];
}
@Override
public void incr(int r, int c) {
incr(r,c,1.0);
}
@Override
public void incr(int r, int c, double delta) {
if(_data[r] == null)
allocateBlock(r, _odims[0]);
_data[r][c] += delta;
}
@Override
protected void fillBlock(int bix, int fromIndex, int toIndex, double v) {
if(_data[bix] == null)
allocateBlock(bix, _odims[0]);
Arrays.fill(_data[bix], fromIndex, toIndex, v);
}
@Override
protected void setInternal(int bix, int ix, double v) {
set(bix, ix, v);
}
@Override
public DenseBlock set(int r, int c, double v) {
if(_data[r] == null)
_data[r] = new double[_odims[0]];
_data[r][c] = v;
return this;
}
@Override
public DenseBlock set(int r, double[] v) {
if(v.length == _odims[0])
_data[r] = v;
else
throw new RuntimeException("set Denseblock called with an array length [" + v.length +"], array to overwrite is of length [" + _odims[0] + "]");
return this;
}
@Override
public DenseBlock set(DenseBlock db) {
throw new NotImplementedException();
}
@Override
public DenseBlock set(int rl, int ru, int ol, int ou, DenseBlock db) {
if( !(db instanceof DenseBlockFP64DEDUP))
throw new NotImplementedException();
HashMap<double[], double[]> cache = new HashMap<>();
int len = ou - ol;
for(int i=rl, ix1 = 0; i<ru; i++, ix1++){
double[] row = db.values(ix1);
double[] newRow = cache.get(row);
if (newRow == null) {
newRow = new double[len];
System.arraycopy(row, 0, newRow, 0, len);
cache.put(row, newRow);
}
set(i, newRow);
}
return this;
}
@Override
public DenseBlock set(int[] ix, double v) {
return set(ix[0], pos(ix), v);
}
@Override
public DenseBlock set(int[] ix, long v) {
return set(ix[0], pos(ix), v);
}
@Override
public DenseBlock set(int[] ix, String v) {
return set(ix[0], pos(ix), Double.parseDouble(v));
}
@Override
public double get(int r, int c) {
if(_data[r] == null)
return 0.0;
else
return _data[r][c];
}
@Override
public double get(int[] ix) {
return get(ix[0], pos(ix));
}
@Override
public String getString(int[] ix) {
return String.valueOf(get(ix[0], pos(ix)));
}
@Override
public long getLong(int[] ix) {
return UtilFunctions.toLong(get(ix[0], pos(ix)));
}
public long estimateMemory(){
if( (double)_rlen * _odims[0] > Long.MAX_VALUE )
return Long.MAX_VALUE;
return estimateMemory(_rlen, _odims[0], _distinct);
}
public static long estimateMemory(int rows, int cols, int duplicates){
return estimateMemory((long) rows, (long)cols, (long) duplicates);
}
public static long estimateMemory(long rows, long cols, long duplicates){
return ((long) (DenseBlock.estimateMemory(rows, cols)))
+ ((long) MemoryEstimates.doubleArrayCost(cols)*duplicates)
+ ((long) MemoryEstimates.objectArrayCost(rows));
}
}