From f396f2e65eb0ca5f12c9fcb29774c69de94a2a71 Mon Sep 17 00:00:00 2001 From: Ilia Gyrdymov Date: Fri, 7 Jun 2024 00:48:51 +0300 Subject: [PATCH] Speed up Vector.filled (#177) --- CHANGELOG.md | 4 +++ .../vector_initializing/float32x4_filled.dart | 25 +++++++++++++++++++ lib/src/vector/float32x4_vector.dart | 14 ++++++++--- lib/src/vector/float64x2_vector.g.dart | 14 ++++++++--- pubspec.yaml | 2 +- ...filled_constructor_test_group_factory.dart | 12 +++++++++ 6 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 benchmark/vector/float32/vector_initializing/float32x4_filled.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 0421f38e..9c336ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 13.12.4 +- `Vector.filled`: + - factory-constructor speed-up + ## 13.12.3 - `Vector.fromList`: - factory-constructor speed-up diff --git a/benchmark/vector/float32/vector_initializing/float32x4_filled.dart b/benchmark/vector/float32/vector_initializing/float32x4_filled.dart new file mode 100644 index 00000000..c050da1c --- /dev/null +++ b/benchmark/vector/float32/vector_initializing/float32x4_filled.dart @@ -0,0 +1,25 @@ +// Approx. 0.23 second (MacBook Pro 2019), Dart version: 2.16.0 + +import 'package:benchmark_harness/benchmark_harness.dart'; +import 'package:ml_linalg/vector.dart'; + +const amountOfElements = 10000000; + +class Float32x4VectorFilledBenchmark extends BenchmarkBase { + Float32x4VectorFilledBenchmark() + : super('Vector initialization (filled), ' + '$amountOfElements elements'); + + static void main() { + Float32x4VectorFilledBenchmark().report(); + } + + @override + void run() { + Vector.filled(amountOfElements, 10000); + } +} + +void main() { + Float32x4VectorFilledBenchmark.main(); +} diff --git a/lib/src/vector/float32x4_vector.dart b/lib/src/vector/float32x4_vector.dart index 4cd26874..6a170c0d 100644 --- a/lib/src/vector/float32x4_vector.dart +++ b/lib/src/vector/float32x4_vector.dart @@ -69,12 +69,18 @@ class Float32x4Vector with IterableMixin implements Vector { Float32x4Vector.filled( this.length, num value, this._cache, this._simdHelper) { + if (length < 0) { + throw ArgumentError('Length cannot be negative'); + } + _numOfBuckets = _getNumOfBuckets(length, _bucketSize); - final byteData = ByteData(_numOfBuckets * _bytesPerSimdElement); - _buffer = byteData.buffer; + final list = Float32x4List(_numOfBuckets); + _buffer = list.buffer; - for (var i = 0; i < length; i++) { - byteData.setFloat32(_bytesPerElement * i, value.toDouble(), Endian.host); + final simdValue = Float32x4.splat(value.toDouble()); + + for (var i = 0; i < _numOfBuckets; i++) { + list[i] = simdValue; } } diff --git a/lib/src/vector/float64x2_vector.g.dart b/lib/src/vector/float64x2_vector.g.dart index 0aebc49f..b235e825 100644 --- a/lib/src/vector/float64x2_vector.g.dart +++ b/lib/src/vector/float64x2_vector.g.dart @@ -72,12 +72,18 @@ class Float64x2Vector with IterableMixin implements Vector { Float64x2Vector.filled( this.length, num value, this._cache, this._simdHelper) { + if (length < 0) { + throw ArgumentError('Length cannot be negative'); + } + _numOfBuckets = _getNumOfBuckets(length, _bucketSize); - final byteData = ByteData(_numOfBuckets * _bytesPerSimdElement); - _buffer = byteData.buffer; + final list = Float64x2List(_numOfBuckets); + _buffer = list.buffer; - for (var i = 0; i < length; i++) { - byteData.setFloat64(_bytesPerElement * i, value.toDouble(), Endian.host); + final simdValue = Float64x2.splat(value.toDouble()); + + for (var i = 0; i < _numOfBuckets; i++) { + list[i] = simdValue; } } diff --git a/pubspec.yaml b/pubspec.yaml index 5c63533f..00fc69bb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: ml_linalg description: SIMD-based linear algebra and statistics, efficient manipulation with numeric data -version: 13.12.3 +version: 13.12.4 homepage: https://github.com/gyrdym/ml_linalg environment: diff --git a/test/vector/constructors/filled_constructor/vector_filled_constructor_test_group_factory.dart b/test/vector/constructors/filled_constructor/vector_filled_constructor_test_group_factory.dart index 786ea88c..d7949c26 100644 --- a/test/vector/constructors/filled_constructor/vector_filled_constructor_test_group_factory.dart +++ b/test/vector/constructors/filled_constructor/vector_filled_constructor_test_group_factory.dart @@ -14,5 +14,17 @@ void vectorFilledConstructorTestGroupFactory(DType dtype) => expect(vector.length, equals(10)); expect(vector.dtype, dtype); }); + + test( + 'should provide correct size of vectors when summing up, length is 5', + () { + final vector1 = Vector.filled(5, 2.0, dtype: dtype); + final vector2 = Vector.filled(5, 3.0, dtype: dtype); + final vector = vector1 + vector2; + + expect(vector, equals([5.0, 5.0, 5.0, 5.0, 5.0])); + expect(vector.length, equals(5)); + expect(vector.dtype, dtype); + }); }); });