Skip to content

Commit

Permalink
Matrix constructors speed up
Browse files Browse the repository at this point in the history
  • Loading branch information
gyrdym committed Nov 18, 2019
1 parent 22b9960 commit 55ea6eb
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 109 deletions.
6 changes: 3 additions & 3 deletions benchmark/main.dart
@@ -1,7 +1,7 @@
import 'matrix/float32/matrix_initializing/float32_matrix_from_columns.dart';
import 'matrix/float32/matrix_initializing/float32_from_flattened.dart';
import 'matrix/float32/matrix_initializing/float32_from_list.dart';
import 'matrix/float32/matrix_initializing/float32_from_rows.dart';
import 'matrix/float32/matrix_initializing/float32_matrix_from_flattened.dart';
import 'matrix/float32/matrix_initializing/float32_matrix_from_list.dart';
import 'matrix/float32/matrix_initializing/float32_matrix_from_rows.dart';
import 'vector/float32/vector_initializing/float32x4_from_list.dart';
import 'vector/float32/vector_initializing/float32x4_random_filled.dart';
import 'vector/float32/vector_operations/float32x4_vector_abs.dart';
Expand Down
@@ -1,4 +1,4 @@
// Approx. 1.6 second (MacBook Air mid 2017), Dart VM version: 2.5.0
// Approx. 2.5 second (MacBook Air mid 2017), Dart VM version: 2.5.0

import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:ml_linalg/dtype.dart';
Expand Down
@@ -1,4 +1,4 @@
// Approx. 4.5 seconds (MacBook Air mid 2017), Dart VM version: 2.5.0
// Approx. 5 seconds (MacBook Air mid 2017), Dart VM version: 2.5.0

import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:ml_linalg/dtype.dart';
Expand All @@ -10,7 +10,7 @@ const numOfColumns = 1000;

class Float32MatrixFromFlattenedBenchmark extends BenchmarkBase {
Float32MatrixFromFlattenedBenchmark() :
super('Matrix initialization, from flattened list');
super('Matrix initialization (fromFlattenedList)');

List<double> _source;

Expand All @@ -26,7 +26,7 @@ class Float32MatrixFromFlattenedBenchmark extends BenchmarkBase {

@override
void setup() {
_source = Vector.randomFilled(numOfRows * numOfColumns)
_source = Vector.randomFilled(numOfRows * numOfColumns, min: -1000, max: 1000)
.toList(growable: false);
}
}
Expand Down
@@ -1,4 +1,4 @@
// Approx. 0.9 second (MacBook Air mid 2017), Dart VM version: 2.5.0
// Approx. 1 second (MacBook Air mid 2017), Dart VM version: 2.5.0

import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:ml_linalg/dtype.dart';
Expand All @@ -10,12 +10,12 @@ const numOfColumns = 1000;

class Float32MatrixFromListBenchmark extends BenchmarkBase {
Float32MatrixFromListBenchmark() :
super('Matrix initialization, from list');
super('Matrix initialization (fromList)');

final _source = List.filled(numOfRows,
Vector
.randomFilled(numOfColumns, min: -10000, max: 10000)
.toList(),
.toList(growable: false),
);

static void main() {
Expand Down
Expand Up @@ -10,7 +10,7 @@ const numOfColumns = 1000;

class Float32MatrixFromRowsBenchmark extends BenchmarkBase {
Float32MatrixFromRowsBenchmark() :
super('Matrix initialization, from rows');
super('Matrix initialization (fromRows)');

final _source =
List<Vector>.filled(numOfColumns,
Expand Down
73 changes: 34 additions & 39 deletions lib/src/matrix/data_manager/float32_matrix_data_manager.dart
Expand Up @@ -20,15 +20,11 @@ class Float32MatrixDataManager implements MatrixDataManager {
_colsCache = List<Vector>(getLengthOfFirstOrZero(source)),
_data = ByteData(source.length *
getLengthOfFirstOrZero(source) * _bytesPerElement) {
var i = 0;
var j = 0;
final dataAsList = _data.buffer.asFloat32List();
for (final row in source) {
for (final value in row) {
dataAsList[i * columnsNum + j++] = value;
for (int i = 0, j = 0; i < source.length; i++) {
for (int j = 0; j < source[i].length; j++) {
dataAsList[i * columnsNum + j] = source[i][j];
}
i++;
j = 0;
}
}

Expand All @@ -41,14 +37,20 @@ class Float32MatrixDataManager implements MatrixDataManager {
_colsCache = List<Vector>(getLengthOfFirstOrZero(source)),
_data = ByteData(source.length *
getLengthOfFirstOrZero(source) * _bytesPerElement) {
var i = 0;
var j = 0;
final dataAsList = _data.buffer.asFloat32List();
for (final row in source) {
for (final value in row) {
for (int i = 0, j = 0; i < source.length; i++) {
final row = source[i];
if (row.dtype != dtype) {
throw Exception('Expected vector type: `$dtype`, '
'but given: ${row.dtype}');
}
if (row.length != columnsNum) {
throw Exception('Expected vector length: `$columnsNum`, '
'but given: ${row.length}');
}
for (final value in source[i]) {
dataAsList[i * columnsNum + j++] = value;
}
i++;
j = 0;
}
}
Expand All @@ -65,8 +67,14 @@ class Float32MatrixDataManager implements MatrixDataManager {
final dataAsList = _data.buffer.asFloat32List();
for (int i = 0, j = 0; i < source.length; i++) {
final column = source[i];
// we use for..in here because `column` provides efficient
// Float32List.iterator
if (column.dtype != dtype) {
throw Exception('Expected vector type: `$dtype`, '
'but given: ${column.dtype}');
}
if (column.length != rowsNum) {
throw Exception('Expected vector length: `$rowsNum`, '
'but given: ${column.length}');
}
for (final value in column) {
dataAsList[j++ * columnsNum + i] = value;
}
Expand Down Expand Up @@ -112,7 +120,10 @@ class Float32MatrixDataManager implements MatrixDataManager {
_rowsCache = List<Vector>(size),
_colsCache = List<Vector>(size),
_data = ByteData(size * size * _bytesPerElement) {
_updateByteDataForDiagonalMatrix((i) => scalar);
for (int i = 0; i < size; i++) {
_data.setFloat32((i * columnsNum + i) * _bytesPerElement, scalar,
Endian.host);
}
}

@override
Expand Down Expand Up @@ -142,23 +153,17 @@ class Float32MatrixDataManager implements MatrixDataManager {
bool get hasData => rowsNum > 0 && columnsNum > 0;

@override
List<double> getValues(int indexFrom, int count) {
Vector getRow(int index) {
if (!hasData) {
throw Exception('Matrix is empty');
}
final indexFrom = index * columnsNum;
if (indexFrom >= rowsNum * columnsNum) {
throw RangeError.range(indexFrom, 0, rowsNum * columnsNum);
}
return _data.buffer.asFloat32List(indexFrom * _bytesPerElement, count);
}

@override
Vector getRow(int index) {
if (!hasData) {
throw Exception('Matrix is empty');
}
_rowsCache[index] ??= Vector.fromList(getValues(index * columnsNum,
columnsNum), dtype: dtype);
final values = _data.buffer.asFloat32List(
indexFrom * _bytesPerElement, columnsNum);
_rowsCache[index] ??= Vector.fromList(values, dtype: dtype);
return _rowsCache[index];
}

Expand All @@ -169,22 +174,12 @@ class Float32MatrixDataManager implements MatrixDataManager {
}
if (_colsCache[index] == null) {
final result = List<double>(rowsNum);
for (final i in rowIndices) {
//@TODO: find a more efficient way to get the single value
result[i] = getValues(i * columnsNum + index, 1).first;
for (int i = 0; i < result.length; i++) {
result[i] = _data.getFloat32(
(i * columnsNum + index) * _bytesPerElement, Endian.host);
}
_colsCache[index] = Vector.fromList(result, dtype: dtype);
}
return _colsCache[index];
}

void _updateByteDataForDiagonalMatrix(double generateValue(int i)) {
for (int i = 0; i < rowsNum; i++) {
for (int j = 0; j < columnsNum; j++) {
final value = i == j ? generateValue(i) : 0.0;
_data.setFloat32((i * columnsNum + j) * _bytesPerElement, value,
Endian.host);
}
}
}
}
82 changes: 40 additions & 42 deletions lib/src/matrix/data_manager/float64_matrix_data_manager.dart
Expand Up @@ -22,15 +22,11 @@ class Float64MatrixDataManager implements MatrixDataManager {
_colsCache = List<Vector>(getLengthOfFirstOrZero(source)),
_data = ByteData(source.length *
getLengthOfFirstOrZero(source) * _bytesPerElement) {
var i = 0;
var j = 0;
final dataAsList = _data.buffer.asFloat64List();
for (final row in source) {
for (final value in row) {
dataAsList[i * columnsNum + j++] = value;
for (int i = 0, j = 0; i < source.length; i++) {
for (int j = 0; j < source[i].length; j++) {
dataAsList[i * columnsNum + j] = source[i][j];
}
i++;
j = 0;
}
}

Expand All @@ -43,14 +39,20 @@ class Float64MatrixDataManager implements MatrixDataManager {
_colsCache = List<Vector>(getLengthOfFirstOrZero(source)),
_data = ByteData(source.length *
getLengthOfFirstOrZero(source) * _bytesPerElement) {
var i = 0;
var j = 0;
final dataAsList = _data.buffer.asFloat64List();
for (final row in source) {
for (final value in row) {
for (int i = 0, j = 0; i < source.length; i++) {
final row = source[i];
if (row.dtype != dtype) {
throw Exception('Expected vector type: `$dtype`, '
'but given: ${row.dtype}');
}
if (row.length != columnsNum) {
throw Exception('Expected vector length: `$columnsNum`, '
'but given: ${row.length}');
}
for (final value in source[i]) {
dataAsList[i * columnsNum + j++] = value;
}
i++;
j = 0;
}
}
Expand All @@ -64,14 +66,20 @@ class Float64MatrixDataManager implements MatrixDataManager {
_colsCache = source,
_data = ByteData(source.length *
getLengthOfFirstOrZero(source) * _bytesPerElement) {
var i = 0;
var j = 0;
final dataAsList = _data.buffer.asFloat64List();
for (final column in source) {
for (int i = 0, j = 0; i < source.length; i++) {
final column = source[i];
if (column.dtype != dtype) {
throw Exception('Expected vector type: `$dtype`, '
'but given: ${column.dtype}');
}
if (column.length != rowsNum) {
throw Exception('Expected vector length: `$rowsNum`, '
'but given: ${column.length}');
}
for (final value in column) {
dataAsList[j++ * columnsNum + i] = value;
}
i++;
j = 0;
}
}
Expand Down Expand Up @@ -100,7 +108,10 @@ class Float64MatrixDataManager implements MatrixDataManager {
_rowsCache = List<Vector>(source.length),
_colsCache = List<Vector>(source.length),
_data = ByteData(source.length * source.length * _bytesPerElement) {
_updateByteDataForDiagonalMatrix((i) => source[i]);
for (int i = 0; i < rowsNum; i++) {
_data.setFloat64((i * columnsNum + i) * _bytesPerElement, source[i],
Endian.host);
}
}

Float64MatrixDataManager.scalar(double scalar, int size) :
Expand All @@ -111,7 +122,10 @@ class Float64MatrixDataManager implements MatrixDataManager {
_rowsCache = List<Vector>(size),
_colsCache = List<Vector>(size),
_data = ByteData(size * size * _bytesPerElement) {
_updateByteDataForDiagonalMatrix((i) => scalar);
for (int i = 0; i < size; i++) {
_data.setFloat64((i * columnsNum + i) * _bytesPerElement, scalar,
Endian.host);
}
}

@override
Expand Down Expand Up @@ -141,23 +155,17 @@ class Float64MatrixDataManager implements MatrixDataManager {
bool get hasData => rowsNum > 0 && columnsNum > 0;

@override
List<double> getValues(int indexFrom, int count) {
Vector getRow(int index) {
if (!hasData) {
throw Exception('Matrix is empty');
}
final indexFrom = index * columnsNum;
if (indexFrom >= rowsNum * columnsNum) {
throw RangeError.range(indexFrom, 0, rowsNum * columnsNum);
}
return _data.buffer.asFloat64List(indexFrom * _bytesPerElement, count);
}

@override
Vector getRow(int index) {
if (!hasData) {
throw Exception('Matrix is empty');
}
_rowsCache[index] ??= Vector.fromList(getValues(index * columnsNum,
columnsNum), dtype: dtype);
final values = _data.buffer.asFloat64List(
indexFrom * _bytesPerElement, columnsNum);
_rowsCache[index] ??= Vector.fromList(values, dtype: dtype);
return _rowsCache[index];
}

Expand All @@ -168,22 +176,12 @@ class Float64MatrixDataManager implements MatrixDataManager {
}
if (_colsCache[index] == null) {
final result = List<double>(rowsNum);
for (final i in rowIndices) {
//@TODO: find a more efficient way to get the single value
result[i] = getValues(i * columnsNum + index, 1).first;
for (int i = 0; i < result.length; i++) {
result[i] = _data.getFloat64(
(i * columnsNum + index) * _bytesPerElement, Endian.host);
}
_colsCache[index] = Vector.fromList(result, dtype: dtype);
}
return _colsCache[index];
}

void _updateByteDataForDiagonalMatrix(double generateValue(int i)) {
for (int i = 0; i < rowsNum; i++) {
for (int j = 0; j < columnsNum; j++) {
final value = i == j ? generateValue(i) : 0.0;
_data.setFloat64((i * columnsNum + j) * _bytesPerElement, value,
Endian.host);
}
}
}
}
1 change: 0 additions & 1 deletion lib/src/matrix/data_manager/matrix_data_manager.dart
Expand Up @@ -11,5 +11,4 @@ abstract class MatrixDataManager {
bool get hasData;
Vector getColumn(int index);
Vector getRow(int index);
List<double> getValues(int index, int length);
}
6 changes: 1 addition & 5 deletions lib/src/vector/float32x4_vector.dart
Expand Up @@ -60,11 +60,7 @@ class Float32x4Vector with IterableMixin<double> implements Vector {
Float32x4Vector.zero(this.length, this._cacheManager, this._simdHelper) :
_numOfBuckets = _getNumOfBuckets(length, _bucketSize),
_buffer = ByteData(_getNumOfBuckets(length, _bucketSize) *
_bytesPerSimdElement).buffer {
for (int i = 0; i < length; i++) {
_buffer.asByteData().setFloat32(_bytesPerElement * i, 0.0, Endian.host);
}
}
_bytesPerSimdElement).buffer;

Float32x4Vector.fromSimdList(Float32x4List data, this.length,
this._cacheManager, this._simdHelper) :
Expand Down
6 changes: 1 addition & 5 deletions lib/src/vector/float64x2_vector.dart
Expand Up @@ -62,11 +62,7 @@ class Float64x2Vector with IterableMixin<double> implements Vector {
Float64x2Vector.zero(this.length, this._cacheManager, this._simdHelper) :
_numOfBuckets = _getNumOfBuckets(length, _bucketSize),
_buffer = ByteData(_getNumOfBuckets(length, _bucketSize) *
_bytesPerSimdElement).buffer {
for (int i = 0; i < length; i++) {
_buffer.asByteData().setFloat64(_bytesPerElement * i, 0.0, Endian.host);
}
}
_bytesPerSimdElement).buffer;

Float64x2Vector.fromSimdList(Float64x2List data, this.length,
this._cacheManager, this._simdHelper) :
Expand Down
Expand Up @@ -11,8 +11,8 @@ void matrixFromColumnsConstructorTestGroupFactory(DType dtype) =>
test('should create an instance with predefined vectors as matrix '
'columns', () {
final actual = Matrix.fromColumns([
Vector.fromList([1.0, 2.0, 3.0, 4.0, 5.0]),
Vector.fromList([6.0, 7.0, 8.0, 9.0, 0.0]),
Vector.fromList([1.0, 2.0, 3.0, 4.0, 5.0], dtype: dtype),
Vector.fromList([6.0, 7.0, 8.0, 9.0, 0.0], dtype: dtype),
], dtype: dtype);

final expected = [
Expand Down

0 comments on commit 55ea6eb

Please sign in to comment.