blob: e6c8a7bdcbef855e742f9d39f87c2cbbc03fdfde [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.sysds.runtime.util.UtilFunctions;
import java.util.stream.IntStream;
/**
* Dense Large Row Blocks have multiple 1D arrays (blocks), which contain complete rows.
* Except the last block all blocks have the same size (size refers to the number of rows contained and space allocated).
*/
public abstract class DenseBlockLDRB extends DenseBlock
{
private static final long serialVersionUID = -7519435549328146356L;
protected int _blen;
protected DenseBlockLDRB(int[] dims) {
super(dims);
}
/**
* Create the internal array to store the blocks. Does not create
* storage space for a block yet, call allocate block for that.
*
* @param numBlocks the number of blocks to create
*/
protected abstract void allocateBlocks(int numBlocks);
@Override
public int blockSize() {
return _blen;
}
@Override
public int blockSize(int bix) {
return Math.min(_blen, _rlen - bix * _blen);
}
@Override
public void reset(int rlen, int[] odims, double v) {
long dataLength = (long) rlen * odims[0];
int newBlockSize = Math.min(rlen, Integer.MAX_VALUE / odims[0]);
int numBlocks = UtilFunctions.toInt(Math.ceil((double) rlen / newBlockSize));
if (_blen == newBlockSize && dataLength <= capacity()) {
IntStream.range(0, numBlocks)
.forEach((bi) -> {
int toIndex = (int)Math.min(newBlockSize, dataLength - bi * newBlockSize) * _odims[0];
fillBlock(bi, 0, toIndex, v);
});
} else {
int lastBlockSize = (newBlockSize == rlen ? newBlockSize : rlen % newBlockSize) * odims[0];
allocateBlocks(numBlocks);
IntStream.range(0, numBlocks)
.forEach((i) -> {
int length = (i == numBlocks - 1 ? lastBlockSize : newBlockSize * _odims[0]);
allocateBlock(i, length);
if (v != 0)
fillBlock(i, 0, length, v);
});
}
_blen = newBlockSize;
_rlen = rlen;
_odims = odims;
}
@Override
public int pos(int[] ix) {
int pos = pos(ix[0]);
pos += ix[ix.length - 1];
for(int i = 1; i < ix.length - 1; i++)
pos += ix[i] * _odims[i];
return pos;
}
@Override
public boolean isContiguous(int rl, int ru) {
return index(rl) == index(ru);
}
@Override
public int size(int bix) {
return blockSize(bix) * _odims[0];
}
@Override
public int index(int r) {
return r / blockSize();
}
@Override
public int pos(int r) {
return (r % blockSize()) * _odims[0];
}
@Override
public int pos(int r, int c) {
return (r % blockSize()) * _odims[0] + c;
}
@Override
public long countNonZeros() {
long nnz = 0;
for (int i = 0; i < numBlocks() - 1; i++) {
nnz += computeNnz(i, 0, blockSize() * _odims[0]);
}
return nnz + computeNnz(numBlocks() - 1, 0, blockSize(numBlocks() - 1) * _odims[0]);
}
@Override
public int countNonZeros(int r) {
return (int) computeNnz(index(r), pos(r), _odims[0]);
}
@Override
public long countNonZeros(int rl, int ru, int cl, int cu) {
long nnz = 0;
boolean allColumns = cl == 0 && cu == _odims[0];
int rb = pos(rl);
int re = blockSize() * _odims[0];
// loop over rows of blocks, and call computeNnz for the specified columns
for (int bi = index(rl); bi <= index(ru - 1); bi++) {
// loop complete block if not last one
if (bi == index(ru - 1)) {
re = pos(ru - 1) + _odims[0];
}
if (allColumns) {
nnz += computeNnz(bi, rb, re - rb);
} else {
for (int ri = rb; ri < re; ri += _odims[0]) {
nnz += computeNnz(bi, ri + cl, cu - cl);
}
}
rb = 0;
}
return nnz;
}
@Override
public DenseBlock set(double v) {
for (int i = 0; i < numBlocks() - 1; i++) {
fillBlock(i, 0, blockSize() * _odims[0], v);
}
fillBlock(numBlocks() - 1, 0, blockSize(numBlocks() - 1) * _odims[0], v);
return this;
}
@Override
public DenseBlock set(int rl, int ru, int cl, int cu, double v) {
boolean allColumns = cl == 0 && cu == _odims[0];
int rb = pos(rl);
int re = blockSize() * _odims[0];
for (int bi = index(rl); bi <= index(ru - 1); bi++) {
if (bi == index(ru - 1)) {
re = pos(ru - 1) + _odims[0];
}
if (allColumns) {
fillBlock(bi, rb, re, v);
}
else {
for (int ri = rb; ri < re; ri += _odims[0]) {
fillBlock(bi, ri + cl, ri + cu, v);
}
}
rb = 0;
}
return this;
}
@Override
public DenseBlock set(int r, double[] v) {
int bix = index(r);
int offset = pos(r);
IntStream.range(0, _odims[0])
.forEach((i) -> setInternal(bix, offset + i, v[i]));
return this;
}
@Override
public DenseBlock set(DenseBlock db) {
// ToDo: Optimize if dense block types match
// ToDo: Performance
for (int ri = 0; ri < _rlen; ri += blockSize()) {
int bix = ri / blockSize();
double[] other = db.valuesAt(bix);
IntStream.range(0, blockSize(bix) * _odims[0])
.forEach((i) -> setInternal(bix, i, other[i]));
}
return this;
}
}