diff --git a/.travis.yml b/.travis.yml index e962e095..852d8c84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: dart dart: -- "2.1.0" +- "2.2.0" dart_task: - test: --platform vm - dartanalyzer: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 93d9101b..e4ba5b4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 6.0.0 +- prefix `ML` removed from entities' names +- Float32x4Vector: equality operator override added +- Matrix: `uniqueRows` method added + ## 5.5.1 - MLMatrix: fixed bug in `setColumn` method when rows cache was not cleared diff --git a/README.md b/README.md index e4ba415d..f0421089 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,13 @@ computation architecture. Actually, the main purpose of the library - connect su the pure math. So, the library contains a high performance SIMD vector class, based on [Float32x4](https://api.dartlang.org/stable/2.1.0/dart-typed_data/Float32x4-class.html) - [Float32x4Vector](https://github.com/gyrdym/linalg/blob/master/lib/src/vector/float32x4/float32x4_vector.dart). -Most of operations in the vector are performed in four "threads". This kind of concurrency is reached by special +Most of operations in the vector class are performed in four "threads". This kind of concurrency is reached by special 128-bit processor registers, which are used directly by program code. For better understanding of the topic please read the [article](https://www.dartlang.org/articles/dart-vm/simd). It is also possible to implement [Float64x2](https://api.dartlang.org/stable/2.1.0/dart-typed_data/Float64x2-class.html)-based -version of the vector using existing codebase, but so far there is no need to do so. - The class [Float32x4Vector] is hidden from the library's user. You can create an [Float32x4Vector] instance -via [MLVector] factory (see examples below). +version of vector using existing codebase, but so far there is no need to do so. + The class [Float32x4Vector](https://github.com/gyrdym/linalg/blob/master/lib/src/vector/float32x4/float32x4_vector.dart) +is hidden from the library's users. You can create a [Float32x4Vector](https://github.com/gyrdym/linalg/blob/master/lib/src/vector/float32x4/float32x4_vector.dart) +instance via [Vector](https://github.com/gyrdym/ml_linalg/blob/master/lib/vector.dart) factory (see examples below). #### Vector operations examples At the present moment most common vector operations are implemented: @@ -70,8 +71,8 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); - final vector2 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1 + vector2; print(result.toList()); // [3.0, 5.0, 7.0, 9.0, 11.0] ```` @@ -80,8 +81,8 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([4.0, 5.0, 6.0, 7.0, 8.0]); - final vector2 = MLVector.from([2.0, 3.0, 2.0, 3.0, 2.0]); + final vector1 = Vector.from([4.0, 5.0, 6.0, 7.0, 8.0]); + final vector2 = Vector.from([2.0, 3.0, 2.0, 3.0, 2.0]); final result = vector1 - vector2; print(result.toList()); // [2.0, 2.0, 4.0, 4.0, 6.0] ```` @@ -90,8 +91,8 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); - final vector2 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1 * vector2; print(result.toList()); // [2.0, 6.0, 12.0, 20.0, 30.0] ```` @@ -100,8 +101,8 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([6.0, 12.0, 24.0, 48.0, 96.0]); - final vector2 = MLVector.from([3.0, 4.0, 6.0, 8.0, 12.0]); + final vector1 = Vector.from([6.0, 12.0, 24.0, 48.0, 96.0]); + final vector2 = Vector.from([3.0, 4.0, 6.0, 8.0, 12.0]); final result = vector1 / vector2; print(result.toList()); // [2.0, 3.0, 4.0, 6.0, 8.0] ```` @@ -110,7 +111,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1.norm(); print(result); // sqrt(2^2 + 3^2 + 4^2 + 5^2 + 6^2) = sqrt(90) ~~ 9.48 ```` @@ -119,7 +120,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1.norm(Norm.manhattan); print(result); // 2 + 3 + 4 + 5 + 6 = 20.0 ```` @@ -128,7 +129,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1.mean(); print(result); // (2 + 3 + 4 + 5 + 6) / 5 = 4.0 ```` @@ -137,7 +138,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1.sum(); print(result); // 2 + 3 + 4 + 5 + 6 = 20.0 (equivalent to Manhattan norm) ```` @@ -146,8 +147,8 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); - final vector2 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1.dot(vector2); print(result); // 1.0 * 2.0 + 2.0 * 3.0 + 3.0 * 4.0 + 4.0 * 5.0 + 5.0 * 6.0 = 70.0 ```` @@ -156,7 +157,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); final scalar = 5.0; final result = vector1 + scalar; print(result.toList()); // [6.0, 7.0, 8.0, 9.0, 10.0] @@ -166,7 +167,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); final scalar = 5.0; final result = vector1 - scalar; print(result.toList()); // [-4.0, -3.0, -2.0, -1.0, 0.0] @@ -176,7 +177,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); final scalar = 5.0; final result = vector1 * scalar; print(result.toList()); // [5.0, 10.0, 15.0, 20.0, 25.0] @@ -186,7 +187,7 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([25.0, 50.0, 75.0, 100.0, 125.0]); + final vector1 = Vector.from([25.0, 50.0, 75.0, 100.0, 125.0]); final scalar = 5.0; final result = vector1.scalarDiv(scalar); print(result.toList()); // [5.0, 10.0, 15.0, 20.0, 25.0] @@ -196,8 +197,8 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); - final vector2 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1.distanceTo(vector2); print(result); // ~~2.23 ```` @@ -206,8 +207,8 @@ At the present moment most common vector operations are implemented: ````Dart import 'package:ml_linalg/linalg.dart'; - final vector1 = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); - final vector2 = MLVector.from([2.0, 3.0, 4.0, 5.0, 6.0]); + final vector1 = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Vector.from([2.0, 3.0, 4.0, 5.0, 6.0]); final result = vector1.distanceTo(vector2, Norm.manhattan); print(result); // 5.0 ```` @@ -219,7 +220,7 @@ Performs mapping from one vector to another in efficient way (using simd computa ````Dart import 'package:ml_linalg/linalg.dart'; - final vector = MLVector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector = Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); final result = vector.fastMap((Float32x4 element, int offsetStart, int offsetEnd) { // offsetStart - start index for the current vectorized element, e.g. if `element` is second in the inner collection, // the offsetStart will be 4 (because Float32x4 contains 4 elements) @@ -240,12 +241,12 @@ Also, a class for matrix is available. It is based on Float32x4 and Float32x4Vec ````Dart import 'package:ml_linalg/linalg.dart'; -final matrix1 = MLMatrix.from([ +final matrix1 = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, .0, -2.0, -3.0], ]); -final matrix2 = MLMatrix.from([ +final matrix2 = Matrix.from([ [10.0, 20.0, 30.0, 40.0], [-5.0, 16.0, 2.0, 18.0], [2.0, -1.0, -2.0, -7.0], @@ -262,7 +263,7 @@ print(matrix1 + matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; -final matrix = MLMatrix.from([ +final matrix = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, .0, -2.0, -3.0], @@ -279,12 +280,12 @@ print(matrix + 7); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, .0, -2.0, -3.0], ]); - final vector = MLVector.from([2.0, 3.0, 4.0, 5.0]); + final vector = Vector.from([2.0, 3.0, 4.0, 5.0]); final result = matrix * vector; print(result); // a vector-column [ @@ -298,12 +299,12 @@ print(matrix + 7); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix1 = MLMatrix.from([ + final matrix1 = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, .0, -2.0, -3.0], ]); - final matrix2 = MLMatrix.from([ + final matrix2 = Matrix.from([ [1.0, 2.0], [5.0, 6.0], [9.0, .0], @@ -322,7 +323,7 @@ print(matrix + 7); ````Dart import 'package:ml_linalg/linalg.dart'; -final matrix = MLMatrix.from([ +final matrix = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, .0, -2.0, -3.0], @@ -339,12 +340,12 @@ print(matrix * 3); ````Dart import 'package:ml_linalg/linalg.dart'; -final matrix1 = MLMatrix.from([ +final matrix1 = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, .0, -2.0, -3.0], ]); -final matrix2 = MLMatrix.from([ +final matrix2 = Matrix.from([ [10.0, 20.0, 30.0, 40.0], [-5.0, 16.0, 2.0, 18.0], [2.0, -1.0, -2.0, -7.0], @@ -361,7 +362,7 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, .0, -2.0, -3.0], @@ -380,7 +381,7 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], ]); @@ -392,7 +393,7 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [11.0, 12.0, 13.0, 14.0], [15.0, 16.0, 17.0, 18.0], [21.0, 22.0, 23.0, 24.0], @@ -405,11 +406,11 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], ]); - final modifier = MLVector.filled(4, 2.0); + final modifier = Vector.filled(4, 2.0); final newMatrix = matrix.rowsMap((row) => row + modifier); print(newMatrix); // [ @@ -422,11 +423,11 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], ]); - final modifier = MLVector.filled(2, 2.0); + final modifier = Vector.filled(2, 2.0); final newMatrix = matrix.columnsMap((column) => column + modifier); print(newMatrix); // [ @@ -439,7 +440,7 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [11.0, 12.0, 13.0, 14.0], [15.0, 16.0, 17.0, 18.0], [21.0, 22.0, 23.0, 24.0], @@ -457,7 +458,7 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [11.0, 12.0, 13.0, 14.0], [15.0, 16.0, 17.0, 18.0], [21.0, 22.0, 23.0, 24.0], @@ -472,7 +473,7 @@ print(matrix1 - matrix2); ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [11.0, 12.0, 13.0, 14.0], [15.0, 16.0, 0.0, 18.0], [21.0, 22.0, -23.0, 24.0], @@ -490,7 +491,7 @@ Performs mapping from one matrix to another in efficient way (using simd computa ````Dart import 'package:ml_linalg/linalg.dart'; - final matrix = MLMatrix.from([ + final matrix = Matrix.from([ [11.0, 12.0, 13.0, 14.0], [15.0, 16.0, 0.0, 18.0], [21.0, 22.0, -23.0, 24.0], @@ -536,7 +537,7 @@ print(result); ````dart import 'package:ml_linalg/linalg.dart'; -final matrix = MLMatrix.from([ +final matrix = Matrix.from([ [11.0, 12.0, 13.0, 14.0], [15.0, 16.0, 0.0, 18.0], [21.0, 22.0, -23.0, 24.0], diff --git a/lib/matrix.dart b/lib/matrix.dart index fdbb650d..f3bdb779 100644 --- a/lib/matrix.dart +++ b/lib/matrix.dart @@ -6,9 +6,9 @@ import 'package:ml_linalg/src/matrix/float32x4/float32x4_matrix.dart'; import 'package:ml_linalg/vector.dart'; /// An algebraic matrix -abstract class MLMatrix { +abstract class Matrix { /// Creates a matrix from a two dimensional list - factory MLMatrix.from(List> source, {Type dtype = Float32x4}) { + factory Matrix.from(List> source, {Type dtype = Float32x4}) { switch (dtype) { case Float32x4: return Float32x4Matrix.from(source); @@ -18,7 +18,7 @@ abstract class MLMatrix { } /// Creates a matrix with predefined row vectors - factory MLMatrix.rows(List source, {Type dtype = Float32x4}) { + factory Matrix.rows(List source, {Type dtype = Float32x4}) { switch (dtype) { case Float32x4: return Float32x4Matrix.rows(source); @@ -28,7 +28,7 @@ abstract class MLMatrix { } /// Creates a matrix with predefined column vectors - factory MLMatrix.columns(List source, {Type dtype = Float32x4}) { + factory Matrix.columns(List source, {Type dtype = Float32x4}) { switch (dtype) { case Float32x4: return Float32x4Matrix.columns(source); @@ -37,6 +37,8 @@ abstract class MLMatrix { } } + Type get dtype; + /// Returns a number of matrix row int get rowsNum; @@ -47,61 +49,61 @@ abstract class MLMatrix { Iterable operator [](int index); /// Performs sum of the matrix and a matrix/ a vector/ a scalar/ whatever - MLMatrix operator +(Object value); + Matrix operator +(Object value); /// Performs subtraction of the matrix and a matrix/ a vector/ a scalar/ /// whatever - MLMatrix operator -(Object value); + Matrix operator -(Object value); /// Performs multiplication of the matrix and a matrix/ a vector/ a scalar/ /// whatever - MLMatrix operator *(Object value); + Matrix operator *(Object value); /// Performs division of the matrix by a matrix/ a vector/ a scalar/ /// whatever - MLMatrix operator /(Object value); + Matrix operator /(Object value); /// Performs transposition of the matrix - MLMatrix transpose(); + Matrix transpose(); /// Cuts out a part of the matrix bounded by [rows] and [columns] range - MLMatrix submatrix({Range rows, Range columns}); + Matrix submatrix({Range rows, Range columns}); /// Creates a new matrix, consisted of different segments of the matrix - MLMatrix pick({Iterable rowRanges, Iterable columnRanges}); + Matrix pick({Iterable rowRanges, Iterable columnRanges}); /// Returns a column of the matrix, resided on [index] - MLVector getColumn(int index, {bool tryCache = true, bool mutable = false}); + Vector getColumn(int index, {bool tryCache = true, bool mutable = false}); /// Returns a row of the matrix, resided on [index] - MLVector getRow(int index, {bool tryCache = true, bool mutable = false}); + Vector getRow(int index, {bool tryCache = true, bool mutable = false}); /// Reduces all the matrix columns to only column, using [combiner] function - MLVector reduceColumns(MLVector combiner(MLVector combine, MLVector vector), - {MLVector initValue}); + Vector reduceColumns(Vector combiner(Vector combine, Vector vector), + {Vector initValue}); /// Reduces all the matrix rows to only row, using [combiner] function - MLVector reduceRows(MLVector combiner(MLVector combine, MLVector vector), - {MLVector initValue}); + Vector reduceRows(Vector combiner(Vector combine, Vector vector), + {Vector initValue}); /// Performs column-wise mapping of this matrix to a new one via passed /// [mapper] function - MLMatrix mapColumns(MLVector mapper(MLVector column)); + Matrix mapColumns(Vector mapper(Vector column)); /// Performs row-wise mapping of this matrix to a new one via passed /// [mapper] function - MLMatrix mapRows(MLVector mapper(MLVector row)); + Matrix mapRows(Vector mapper(Vector row)); /// Creates a new matrix, efficiently iterating through all the matrix /// elements (several floating point elements in a time) and applying the /// [mapper] function - MLMatrix fastMap(E mapper(E columnElement)); + Matrix fastMap(E mapper(E columnElement)); /// Tries to convert the matrix to a vector. /// /// It fails, if the matrix's both numbers of columns and rows are greater /// than `1` - MLVector toVector({bool mutable = false}); + Vector toVector({bool mutable = false}); /// Returns max value of the matrix double max(); @@ -118,4 +120,7 @@ abstract class MLMatrix { /// [columnValues] - values, that are going to be placed one by one in the /// target column void setColumn(int columnNum, Iterable columnValues); + + /// Extracts non-repeated matrix rows and pack them into matrix + Matrix uniqueRows(); } diff --git a/lib/src/matrix/float32x4/float32_data_helper_mixin.dart b/lib/src/matrix/float32x4/float32_data_helper_mixin.dart index 65f75a32..613ccdd6 100644 --- a/lib/src/matrix/float32x4/float32_data_helper_mixin.dart +++ b/lib/src/matrix/float32x4/float32_data_helper_mixin.dart @@ -1,8 +1,8 @@ import 'dart:typed_data'; -import 'package:ml_linalg/src/matrix/ml_matrix_data_store.dart'; +import 'package:ml_linalg/src/matrix/matrix_data_store.dart'; -abstract class Float32DataHelperMixin implements MLMatrixDataStore { +abstract class Float32DataHelperMixin implements MatrixDataStore { @override void updateByteData(int elementNum, double value) { diff --git a/lib/src/matrix/float32x4/float32x4_matrix.dart b/lib/src/matrix/float32x4/float32x4_matrix.dart index c7c1764d..065325f9 100644 --- a/lib/src/matrix/float32x4/float32x4_matrix.dart +++ b/lib/src/matrix/float32x4/float32x4_matrix.dart @@ -6,46 +6,31 @@ import 'package:ml_linalg/matrix.dart'; import 'package:ml_linalg/src/matrix/float32x4/float32_data_helper_mixin.dart'; import 'package:ml_linalg/src/matrix/float32x4/float32_matrix_iterator.dart'; import 'package:ml_linalg/src/matrix/float32x4/float32x4_matrix_factory_mixin.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_data_store.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_fast_iterable_mixin.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_mixin.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_validator_mixin.dart'; +import 'package:ml_linalg/src/matrix/matrix_data_store.dart'; +import 'package:ml_linalg/src/matrix/matrix_fast_iterable_mixin.dart'; +import 'package:ml_linalg/src/matrix/matrix_mixin.dart'; +import 'package:ml_linalg/src/matrix/matrix_validator_mixin.dart'; import 'package:ml_linalg/src/vector/float32x4/float32x4_vector_factory_mixin.dart'; import 'package:ml_linalg/vector.dart'; class Float32x4Matrix extends Object with IterableMixin>, - MLMatrixValidatorMixin, + MatrixValidatorMixin, Float32x4MatrixFactoryMixin, Float32x4VectorFactoryMixin, Float32DataHelperMixin, - MLMatrixFastIterableMixin, - MLMatrixMixin - implements MLMatrixDataStore, MLMatrix { - - @override - final int rowsNum; - - @override - final int columnsNum; - - @override - final ByteData data; - - @override - final List columnsCache; - - @override - final List rowsCache; + MatrixFastIterableMixin, + MatrixMixin + implements MatrixDataStore, Matrix { Float32x4Matrix.from(Iterable> source) : rowsNum = source.length, columnsNum = source.first.length, data = ByteData( source.length * source.first.length * Float32List.bytesPerElement), - rowsCache = List(source.length), - columnsCache = List(source.first.length) { + rowsCache = List(source.length), + columnsCache = List(source.first.length) { final flattened = flatten2dimList(source, (i, j) => i * columnsNum + j); data.buffer.asFloat32List().setAll(0, flattened); } @@ -65,12 +50,12 @@ class Float32x4Matrix extends Object /// {a3} {b3} {c3} /// {a4} {b4} {c4} /// ``` - Float32x4Matrix.columns(Iterable source) + Float32x4Matrix.columns(Iterable source) : rowsNum = source.first.length, columnsNum = source.length, data = ByteData( source.length * source.first.length * Float32List.bytesPerElement), - rowsCache = List(source.first.length), + rowsCache = List(source.first.length), columnsCache = source.toList(growable: false) { // TODO: try to set the source values right in the byte data buffer // inside `flatten2dimList` method @@ -79,13 +64,13 @@ class Float32x4Matrix extends Object } /// vectors from [source] will serve as rows of the matrix - Float32x4Matrix.rows(Iterable source) + Float32x4Matrix.rows(Iterable source) : rowsNum = source.length, columnsNum = source.first.length, data = ByteData( source.length * source.first.length * Float32List.bytesPerElement), rowsCache = source.toList(growable: false), - columnsCache = List(source.first.length) { + columnsCache = List(source.first.length) { // TODO: try to set the source values right in the byte data buffer // inside `flatten2dimList` method final flattened = flatten2dimList(source, (i, j) => i * columnsNum + j); @@ -95,14 +80,32 @@ class Float32x4Matrix extends Object Float32x4Matrix.flattened( Iterable source, this.rowsNum, this.columnsNum) : data = ByteData(rowsNum * columnsNum * Float32List.bytesPerElement), - rowsCache = List(rowsNum), - columnsCache = List(columnsNum) { + rowsCache = List(rowsNum), + columnsCache = List(columnsNum) { if (source.length != rowsNum * columnsNum) { throw Exception('Invalid matrix dimension is provided'); } data.buffer.asFloat32List().setAll(0, source); } + @override + final Type dtype = Float32x4; + + @override + final int rowsNum; + + @override + final int columnsNum; + + @override + final ByteData data; + + @override + final List columnsCache; + + @override + final List rowsCache; + @override Iterator> get iterator => Float32MatrixIterator(data, columnsNum); diff --git a/lib/src/matrix/float32x4/float32x4_matrix_factory_mixin.dart b/lib/src/matrix/float32x4/float32x4_matrix_factory_mixin.dart index c407fc91..6b917b32 100644 --- a/lib/src/matrix/float32x4/float32x4_matrix_factory_mixin.dart +++ b/lib/src/matrix/float32x4/float32x4_matrix_factory_mixin.dart @@ -1,23 +1,23 @@ import 'package:ml_linalg/matrix.dart'; import 'package:ml_linalg/src/matrix/float32x4/float32x4_matrix.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_factory.dart'; +import 'package:ml_linalg/src/matrix/matrix_factory.dart'; import 'package:ml_linalg/vector.dart'; -abstract class Float32x4MatrixFactoryMixin implements MLMatrixFactory { +abstract class Float32x4MatrixFactoryMixin implements MatrixFactory { @override - MLMatrix createMatrixFrom(Iterable> source) => + Matrix createMatrixFrom(Iterable> source) => Float32x4Matrix.from(source); @override - MLMatrix createMatrixFromFlattened( + Matrix createMatrixFromFlattened( Iterable source, int rowsNum, int columnsNum) => Float32x4Matrix.flattened(source, rowsNum, columnsNum); @override - MLMatrix createMatrixFromRows(Iterable source) => + Matrix createMatrixFromRows(Iterable source) => Float32x4Matrix.rows(source); @override - MLMatrix createMatrixFromColumns(Iterable source) => + Matrix createMatrixFromColumns(Iterable source) => Float32x4Matrix.columns(source); } diff --git a/lib/src/matrix/ml_matrix_data_store.dart b/lib/src/matrix/matrix_data_store.dart similarity index 58% rename from lib/src/matrix/ml_matrix_data_store.dart rename to lib/src/matrix/matrix_data_store.dart index a1c1e787..412b14a5 100644 --- a/lib/src/matrix/ml_matrix_data_store.dart +++ b/lib/src/matrix/matrix_data_store.dart @@ -2,9 +2,9 @@ import 'dart:typed_data'; import 'package:ml_linalg/vector.dart'; -abstract class MLMatrixDataStore { - List get columnsCache; - List get rowsCache; +abstract class MatrixDataStore { + List get columnsCache; + List get rowsCache; ByteData get data; void updateByteData(int elementNum, double value); } diff --git a/lib/src/matrix/matrix_factory.dart b/lib/src/matrix/matrix_factory.dart new file mode 100644 index 00000000..ca261ec3 --- /dev/null +++ b/lib/src/matrix/matrix_factory.dart @@ -0,0 +1,10 @@ +import 'package:ml_linalg/matrix.dart'; +import 'package:ml_linalg/vector.dart'; + +abstract class MatrixFactory { + Matrix createMatrixFrom(Iterable> source); + Matrix createMatrixFromFlattened( + Iterable source, int rowsNum, int columnsNum); + Matrix createMatrixFromRows(Iterable source); + Matrix createMatrixFromColumns(Iterable source); +} diff --git a/lib/src/matrix/ml_matrix_fast_iterable_mixin.dart b/lib/src/matrix/matrix_fast_iterable_mixin.dart similarity index 62% rename from lib/src/matrix/ml_matrix_fast_iterable_mixin.dart rename to lib/src/matrix/matrix_fast_iterable_mixin.dart index bc25c929..617d4f7b 100644 --- a/lib/src/matrix/ml_matrix_fast_iterable_mixin.dart +++ b/lib/src/matrix/matrix_fast_iterable_mixin.dart @@ -1,11 +1,11 @@ import 'package:ml_linalg/matrix.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_factory.dart'; +import 'package:ml_linalg/src/matrix/matrix_factory.dart'; import 'package:ml_linalg/vector.dart'; -abstract class MLMatrixFastIterableMixin implements MLMatrixFactory, MLMatrix { +mixin MatrixFastIterableMixin implements MatrixFactory, Matrix { @override - MLMatrix fastMap(T mapper(T element)) { - final source = List.generate( + Matrix fastMap(T mapper(T element)) { + final source = List.generate( rowsNum, (int i) => (getRow(i)).fastMap( (T element, int startOffset, int endOffset) => mapper(element))); diff --git a/lib/src/matrix/ml_matrix_mixin.dart b/lib/src/matrix/matrix_mixin.dart similarity index 68% rename from lib/src/matrix/ml_matrix_mixin.dart rename to lib/src/matrix/matrix_mixin.dart index 9cdaee6e..d2711502 100644 --- a/lib/src/matrix/ml_matrix_mixin.dart +++ b/lib/src/matrix/matrix_mixin.dart @@ -4,23 +4,23 @@ import 'dart:typed_data'; import 'package:ml_linalg/matrix.dart'; import 'package:ml_linalg/matrix_norm.dart'; import 'package:ml_linalg/range.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_data_store.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_factory.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_validatior.dart'; -import 'package:ml_linalg/src/vector/ml_vector_factory.dart'; +import 'package:ml_linalg/src/matrix/matrix_data_store.dart'; +import 'package:ml_linalg/src/matrix/matrix_factory.dart'; +import 'package:ml_linalg/src/matrix/matrix_validatior.dart'; +import 'package:ml_linalg/src/vector/vector_factory.dart'; import 'package:ml_linalg/vector.dart'; -abstract class MLMatrixMixin> +mixin MatrixMixin> implements Iterable>, - MLMatrixDataStore, - MLMatrixFactory, - MLVectorFactory, - MLMatrixValidator, - MLMatrix { + MatrixDataStore, + MatrixFactory, + VectorFactory, + MatrixValidator, + Matrix { @override - MLMatrix operator +(Object value) { - if (value is MLMatrix) { + Matrix operator +(Object value) { + if (value is Matrix) { return _matrixAdd(value); } else if (value is num) { return _matrixScalarAdd(value.toDouble()); @@ -31,8 +31,8 @@ abstract class MLMatrixMixin> } @override - MLMatrix operator -(Object value) { - if (value is MLMatrix) { + Matrix operator -(Object value) { + if (value is Matrix) { return _matrixSub(value); } else if (value is num) { return _matrixScalarSub(value.toDouble()); @@ -49,10 +49,10 @@ abstract class MLMatrixMixin> /// let `N` be a number of columns, so the multiplication is /// available only for X by N * N by Y matrices, that causes X by Y matrix @override - MLMatrix operator *(Object value) { - if (value is MLVector) { + Matrix operator *(Object value) { + if (value is Vector) { return _matrixVectorMul(value); - } else if (value is MLMatrix) { + } else if (value is Matrix) { return _matrixMul(value); } else if (value is num) { return _matrixScalarMul(value.toDouble()); @@ -64,10 +64,10 @@ abstract class MLMatrixMixin> /// Performs division of the matrix by vector, matrix or scalar @override - MLMatrix operator /(Object value) { - if (value is MLVector) { + Matrix operator /(Object value) { + if (value is Vector) { return _matrixByVectorDiv(value); - } else if (value is MLMatrix) { + } else if (value is Matrix) { return _matrixByMatrixDiv(value); } else if (value is num) { return _matrixByScalarDiv(value.toDouble()); @@ -81,13 +81,13 @@ abstract class MLMatrixMixin> List operator [](int index) => _query(index * columnsNum, columnsNum); @override - MLMatrix transpose() { - final source = List.generate(rowsNum, getRow); + Matrix transpose() { + final source = List.generate(rowsNum, getRow); return createMatrixFromColumns(source); } @override - MLVector getRow(int index, {bool tryCache = true, bool mutable = false}) { + Vector getRow(int index, {bool tryCache = true, bool mutable = false}) { if (tryCache) { rowsCache[index] ??= createVectorFrom(this[index], mutable); return rowsCache[index]; @@ -97,7 +97,7 @@ abstract class MLMatrixMixin> } @override - MLVector getColumn(int index, {bool tryCache = true, bool mutable = false}) { + Vector getColumn(int index, {bool tryCache = true, bool mutable = false}) { if (columnsCache[index] == null || !tryCache) { final result = List(rowsNum); for (int i = 0; i < rowsNum; i++) { @@ -114,7 +114,7 @@ abstract class MLMatrixMixin> } @override - MLMatrix submatrix({Range rows, Range columns}) { + Matrix submatrix({Range rows, Range columns}) { rows ??= Range(0, rowsNum); columns ??= Range(0, columnsNum); @@ -131,7 +131,7 @@ abstract class MLMatrixMixin> } @override - MLMatrix pick({Iterable rowRanges, Iterable columnRanges}) { + Matrix pick({Iterable rowRanges, Iterable columnRanges}) { rowRanges ??= [Range(0, rowsNum)]; columnRanges ??= [Range(0, columnsNum)]; final rows = _collectVectors(rowRanges, getRow, rowsNum); @@ -142,26 +142,38 @@ abstract class MLMatrixMixin> } @override - MLVector reduceColumns( - MLVector Function(MLVector combine, MLVector vector) combiner, - {MLVector initValue}) => + Vector reduceColumns( + Vector Function(Vector combine, Vector vector) combiner, + {Vector initValue}) => _reduce(combiner, columnsNum, getColumn, initValue: initValue); @override - MLVector reduceRows( - MLVector Function(MLVector combine, MLVector vector) combiner, - {MLVector initValue}) => + Vector reduceRows( + Vector Function(Vector combine, Vector vector) combiner, + {Vector initValue}) => _reduce(combiner, rowsNum, getRow, initValue: initValue); @override - MLMatrix mapColumns(MLVector mapper(MLVector columns)) => - MLMatrix.columns(List.generate(columnsNum, - (int i) => mapper(getColumn(i)))); + Matrix mapColumns(Vector mapper(Vector columns)) => + Matrix.columns(List.generate(columnsNum, + (int i) => mapper(getColumn(i))), dtype: dtype); @override - MLMatrix mapRows(MLVector mapper(MLVector row)) => - MLMatrix.rows(List.generate(rowsNum, - (int i) => mapper(getRow(i)))); + Matrix mapRows(Vector mapper(Vector row)) => + Matrix.rows(List.generate(rowsNum, + (int i) => mapper(getRow(i))), dtype: dtype); + + @override + Matrix uniqueRows() { + final checked = []; + for (int i = 0; i < rowsNum; i++) { + final row = getRow(i); + if (!checked.contains(row)) { + checked.add(row); + } + } + return Matrix.rows(checked, dtype: dtype); + } List flatten2dimList( Iterable> rows, int Function(int i, int j) accessor) { @@ -180,7 +192,7 @@ abstract class MLMatrixMixin> } @override - MLVector toVector({bool mutable = false}) { + Vector toVector({bool mutable = false}) { if (columnsNum == 1) { return getColumn(0, tryCache: !mutable, mutable: mutable); } else if (rowsNum == 1) { @@ -211,10 +223,10 @@ abstract class MLMatrixMixin> } @override - double max() => _findExtrema((MLVector row) => row.max()); + double max() => _findExtrema((Vector row) => row.max()); @override - double min() => _findExtrema((MLVector row) => row.min()); + double min() => _findExtrema((Vector row) => row.min()); @override double norm([MatrixNorm norm = MatrixNorm.frobenius]) { @@ -239,8 +251,8 @@ abstract class MLMatrixMixin> } // clear rows cache rowsCache.fillRange(0, rowsNum, null); - columnsCache[columnNum] = columnValues is MLVector - ? columnValues : MLVector.from(columnValues); + columnsCache[columnNum] = columnValues is Vector + ? columnValues : Vector.from(columnValues); final values = columnValues.toList(growable: false); for (int i = 0, j = 0; i < rowsNum * columnsNum; i++) { if (i == 0 && columnNum != 0) { @@ -252,19 +264,19 @@ abstract class MLMatrixMixin> } } - double _findExtrema(double callback(MLVector vector)) { + double _findExtrema(double callback(Vector vector)) { int i = 0; - return callback(reduceRows((MLVector result, MLVector row) { + return callback(reduceRows((Vector result, Vector row) { result[i++] = callback(row); return result; - }, initValue: MLVector.zero(rowsNum, isMutable: true))); + }, initValue: Vector.zero(rowsNum, isMutable: true))); } - MLVector _reduce( - MLVector Function(MLVector combine, MLVector vector) combiner, + Vector _reduce( + Vector Function(Vector combine, Vector vector) combiner, int length, - MLVector Function(int index) getVector, - {MLVector initValue}) { + Vector Function(int index) getVector, + {Vector initValue}) { var reduced = initValue ?? getVector(0); final startIndex = initValue != null ? 0 : 1; for (int i = startIndex; i < length; i++) { @@ -273,7 +285,7 @@ abstract class MLMatrixMixin> return reduced; } - MLMatrix _matrixVectorMul(MLVector vector) { + Matrix _matrixVectorMul(Vector vector) { if (vector.length != columnsNum) { throw Exception( 'The dimension of the vector ${vector} and the columns number of ' @@ -285,7 +297,7 @@ abstract class MLMatrixMixin> return createMatrixFromColumns([vectorColumn]); } - MLMatrix _matrixMul(MLMatrix matrix) { + Matrix _matrixMul(Matrix matrix) { checkColumnsAndRowsNumber(this, matrix); final source = List(rowsNum * matrix.columnsNum); for (int i = 0; i < rowsNum; i++) { @@ -297,7 +309,7 @@ abstract class MLMatrixMixin> return createMatrixFromFlattened(source, rowsNum, matrix.columnsNum); } - MLMatrix _matrixByVectorDiv(MLVector vector) { + Matrix _matrixByVectorDiv(Vector vector) { if (vector.length == rowsNum) { return mapColumns((column) => column / vector); } @@ -308,60 +320,60 @@ abstract class MLMatrixMixin> 'vector of length equals ${vector.length}'); } - MLMatrix _matrixByMatrixDiv(MLMatrix matrix) { + Matrix _matrixByMatrixDiv(Matrix matrix) { checkDimensions(this, matrix, errorTitle: 'Cannot perform matrix by matrix ' 'division'); return _matrix2matrixOperation( - matrix, (MLVector first, MLVector second) => first / second); + matrix, (Vector first, Vector second) => first / second); } - MLMatrix _matrixAdd(MLMatrix matrix) { + Matrix _matrixAdd(Matrix matrix) { checkDimensions(this, matrix, errorTitle: 'Cannot perform matrix addition'); return _matrix2matrixOperation( - matrix, (MLVector first, MLVector second) => first + second); + matrix, (Vector first, Vector second) => first + second); } - MLMatrix _matrixSub(MLMatrix matrix) { + Matrix _matrixSub(Matrix matrix) { checkDimensions(this, matrix, errorTitle: 'Cannot perform matrix subtraction'); return _matrix2matrixOperation( - matrix, (MLVector first, MLVector second) => first - second); + matrix, (Vector first, Vector second) => first - second); } - MLMatrix _matrixScalarAdd(double scalar) => _matrix2scalarOperation( - scalar, (double val, MLVector vector) => vector + val); + Matrix _matrixScalarAdd(double scalar) => _matrix2scalarOperation( + scalar, (double val, Vector vector) => vector + val); - MLMatrix _matrixScalarSub(double scalar) => _matrix2scalarOperation( - scalar, (double val, MLVector vector) => vector - val); + Matrix _matrixScalarSub(double scalar) => _matrix2scalarOperation( + scalar, (double val, Vector vector) => vector - val); - MLMatrix _matrixScalarMul(double scalar) => _matrix2scalarOperation( - scalar, (double val, MLVector vector) => vector * val); + Matrix _matrixScalarMul(double scalar) => _matrix2scalarOperation( + scalar, (double val, Vector vector) => vector * val); - MLMatrix _matrixByScalarDiv(double scalar) => _matrix2scalarOperation( - scalar, (double val, MLVector vector) => vector / val); + Matrix _matrixByScalarDiv(double scalar) => _matrix2scalarOperation( + scalar, (double val, Vector vector) => vector / val); - MLMatrix _matrix2matrixOperation( - MLMatrix matrix, MLVector operation(MLVector first, MLVector second)) { + Matrix _matrix2matrixOperation( + Matrix matrix, Vector operation(Vector first, Vector second)) { final elementGenFn = (int i) => operation(getRow(i), matrix.getRow(i)); - final source = List.generate(rowsNum, elementGenFn); + final source = List.generate(rowsNum, elementGenFn); return createMatrixFromRows(source); } - MLMatrix _matrix2scalarOperation( - double scalar, MLVector operation(double scalar, MLVector vector)) { + Matrix _matrix2scalarOperation( + double scalar, Vector operation(double scalar, Vector vector)) { // TODO: use vectorized type (e.g. Float32x4) instead of `double` // TODO: use then `fastMap` to accelerate computations final elementGenFn = (int i) => operation(scalar, getRow(i)); - final source = List.generate(rowsNum, elementGenFn); + final source = List.generate(rowsNum, elementGenFn); return createMatrixFromRows(source); } Float32List _query(int index, int length) => data.buffer.asFloat32List(index * Float32List.bytesPerElement, length); - List _collectVectors( - Iterable ranges, MLVector getVector(int i), int maxValue) { - final vectors = []; + List _collectVectors( + Iterable ranges, Vector getVector(int i), int maxValue) { + final vectors = []; for (final range in ranges) { if (range.end > maxValue) { throw RangeError.range(range.end, 0, maxValue); diff --git a/lib/src/matrix/ml_matrix_validatior.dart b/lib/src/matrix/matrix_validatior.dart similarity index 51% rename from lib/src/matrix/ml_matrix_validatior.dart rename to lib/src/matrix/matrix_validatior.dart index 539c9389..6dd12249 100644 --- a/lib/src/matrix/ml_matrix_validatior.dart +++ b/lib/src/matrix/matrix_validatior.dart @@ -1,8 +1,8 @@ import 'package:ml_linalg/matrix.dart'; -abstract class MLMatrixValidator { - void checkDimensions(MLMatrix first, MLMatrix second, +abstract class MatrixValidator { + void checkDimensions(Matrix first, Matrix second, {String errorTitle = 'Cannot perform the operation'}); - void checkColumnsAndRowsNumber(MLMatrix first, MLMatrix second, + void checkColumnsAndRowsNumber(Matrix first, Matrix second, {String errorTitle = 'Cannot perform the operation'}); } diff --git a/lib/src/matrix/ml_matrix_validator_mixin.dart b/lib/src/matrix/matrix_validator_mixin.dart similarity index 73% rename from lib/src/matrix/ml_matrix_validator_mixin.dart rename to lib/src/matrix/matrix_validator_mixin.dart index 4fb3dd95..e0f3e347 100644 --- a/lib/src/matrix/ml_matrix_validator_mixin.dart +++ b/lib/src/matrix/matrix_validator_mixin.dart @@ -1,9 +1,9 @@ import 'package:ml_linalg/matrix.dart'; -import 'package:ml_linalg/src/matrix/ml_matrix_validatior.dart'; +import 'package:ml_linalg/src/matrix/matrix_validatior.dart'; -abstract class MLMatrixValidatorMixin implements MLMatrixValidator { +mixin MatrixValidatorMixin implements MatrixValidator { @override - void checkDimensions(MLMatrix first, MLMatrix second, + void checkDimensions(Matrix first, Matrix second, {String errorTitle = 'Cannot perform the operation'}) { if (first.rowsNum != second.rowsNum || first.columnsNum != second.columnsNum) { @@ -13,7 +13,7 @@ abstract class MLMatrixValidatorMixin implements MLMatrixValidator { } @override - void checkColumnsAndRowsNumber(MLMatrix first, MLMatrix second, + void checkColumnsAndRowsNumber(Matrix first, Matrix second, {String errorTitle = 'Cannot perform the operation'}) { if (first.columnsNum != second.rowsNum) { throw Exception( diff --git a/lib/src/matrix/ml_matrix_factory.dart b/lib/src/matrix/ml_matrix_factory.dart deleted file mode 100644 index 0b4856be..00000000 --- a/lib/src/matrix/ml_matrix_factory.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:ml_linalg/matrix.dart'; -import 'package:ml_linalg/vector.dart'; - -abstract class MLMatrixFactory { - MLMatrix createMatrixFrom(Iterable> source); - MLMatrix createMatrixFromFlattened( - Iterable source, int rowsNum, int columnsNum); - MLMatrix createMatrixFromRows(Iterable source); - MLMatrix createMatrixFromColumns(Iterable source); -} diff --git a/lib/src/vector/common/float32_list_factory_mixin.dart b/lib/src/vector/common/float32_list_factory_mixin.dart index 68292436..6da7337f 100644 --- a/lib/src/vector/common/float32_list_factory_mixin.dart +++ b/lib/src/vector/common/float32_list_factory_mixin.dart @@ -1,8 +1,8 @@ import 'dart:typed_data'; -import 'package:ml_linalg/src/vector/ml_typed_list_factory.dart'; +import 'package:ml_linalg/src/vector/typed_list_factory.dart'; -class Float32ListFactoryMixin implements MLTypedListFactory { +mixin Float32ListFactoryMixin implements TypedListFactory { @override Float32List createTypedList(int length) => Float32List(length); diff --git a/lib/src/vector/float32x4/float32x4_data_store_mixin.dart b/lib/src/vector/float32x4/float32x4_data_store_mixin.dart index 1e653324..0670c43b 100644 --- a/lib/src/vector/float32x4/float32x4_data_store_mixin.dart +++ b/lib/src/vector/float32x4/float32x4_data_store_mixin.dart @@ -1,9 +1,9 @@ import 'dart:typed_data'; -import 'package:ml_linalg/src/vector/ml_vector_data_store.dart'; +import 'package:ml_linalg/src/vector/vector_data_store.dart'; -class Float32x4DataStoreMixin - implements MLVectorDataStore { +mixin Float32x4DataStoreMixin + implements VectorDataStore { @override Float32x4List data; diff --git a/lib/src/vector/float32x4/float32x4_operations_mixin.dart b/lib/src/vector/float32x4/float32x4_operations_mixin.dart index f9acc59d..b91c5659 100644 --- a/lib/src/vector/float32x4/float32x4_operations_mixin.dart +++ b/lib/src/vector/float32x4/float32x4_operations_mixin.dart @@ -1,10 +1,10 @@ import 'dart:math' as math; import 'dart:typed_data'; -import 'package:ml_linalg/src/vector/ml_simd_operations_helper.dart'; +import 'package:ml_linalg/src/vector/simd_operations_helper.dart'; -class Float32x4OperationsMixin - implements MLSimdOperationsHelper { +mixin Float32x4OperationsMixin + implements SimdOperationsHelper { @override final bucketSize = 4; @@ -38,6 +38,10 @@ class Float32x4OperationsMixin @override Float32x4 simdAbs(Float32x4 a) => a.abs(); + @override + bool areValuesEqual(Float32x4 a, Float32x4 b) => + a.equal(b).signMask == 15; + @override double singleSIMDSum(Float32x4 a) => (a.x.isNaN ? 0.0 : a.x) + diff --git a/lib/src/vector/float32x4/float32x4_vector.dart b/lib/src/vector/float32x4/float32x4_vector.dart index 5558726c..ee3ef24b 100644 --- a/lib/src/vector/float32x4/float32x4_vector.dart +++ b/lib/src/vector/float32x4/float32x4_vector.dart @@ -7,8 +7,8 @@ import 'package:ml_linalg/src/vector/common/float32_list_factory_mixin.dart'; import 'package:ml_linalg/src/vector/float32x4/float32x4_data_store_mixin.dart'; import 'package:ml_linalg/src/vector/float32x4/float32x4_operations_mixin.dart'; import 'package:ml_linalg/src/vector/float32x4/float32x4_vector_factory_mixin.dart'; -import 'package:ml_linalg/src/vector/ml_simd_vector_fast_iterable_mixin.dart'; -import 'package:ml_linalg/src/vector/ml_simd_vector_operations_mixin.dart'; +import 'package:ml_linalg/src/vector/simd_vector_fast_iterable_mixin.dart'; +import 'package:ml_linalg/src/vector/simd_vector_mixin.dart'; import 'package:ml_linalg/vector.dart'; /// Vector with SIMD (single instruction, multiple data) architecture support @@ -22,24 +22,19 @@ import 'package:ml_linalg/vector.dart'; /// - Each SIMD-typed value is a "cell", that contains several floating point values (2 or 4). /// - Sequence of SIMD-values forms a "computation lane", where computations are performed with each floating point element /// simultaneously (in parallel) -class Float32x4Vector extends Object - with +class Float32x4Vector with IterableMixin, Float32ListFactoryMixin, Float32x4OperationsMixin, Float32x4VectorFactoryMixin, Float32x4DataStoreMixin, - MLSimdVectorFastIterableMixin, - MLSimdVectorOperationsMixin - implements MLVector { - @override - final bool isMutable; - + SimdVectorFastIterableMixin, + SimdVectorMixin + implements Vector { /// Creates a vector from collection Float32x4Vector.from(Iterable source, {this.isMutable = false}) { length = source.length; - final List _source = - source is List ? source : source.toList(growable: false); + final _source = source.toList(growable: false); data = convertCollectionToSIMDList(_source); } @@ -71,4 +66,10 @@ class Float32x4Vector extends Object final source = List.generate(length, (_) => random.nextDouble()); data = convertCollectionToSIMDList(source); } + + @override + final Type dtype = Float32x4; + + @override + final bool isMutable; } diff --git a/lib/src/vector/float32x4/float32x4_vector_factory_mixin.dart b/lib/src/vector/float32x4/float32x4_vector_factory_mixin.dart index d3e7e155..90469e44 100644 --- a/lib/src/vector/float32x4/float32x4_vector_factory_mixin.dart +++ b/lib/src/vector/float32x4/float32x4_vector_factory_mixin.dart @@ -1,17 +1,17 @@ import 'dart:typed_data'; import 'package:ml_linalg/src/vector/float32x4/float32x4_vector.dart'; -import 'package:ml_linalg/src/vector/ml_vector_factory.dart'; +import 'package:ml_linalg/src/vector/vector_factory.dart'; import 'package:ml_linalg/vector.dart'; -abstract class Float32x4VectorFactoryMixin - implements MLVectorFactory { +mixin Float32x4VectorFactoryMixin + implements VectorFactory { @override - MLVector createVectorFrom(Iterable source, [bool mutable = false]) => + Vector createVectorFrom(Iterable source, [bool mutable = false]) => Float32x4Vector.from(source, isMutable: mutable); @override - MLVector createVectorFromSIMDList(Float32x4List source, + Vector createVectorFromSIMDList(Float32x4List source, [int length, bool mutable = false]) => Float32x4Vector.fromSIMDList(source, origLength: length, isMutable: mutable); diff --git a/lib/src/vector/ml_vector_factory.dart b/lib/src/vector/ml_vector_factory.dart deleted file mode 100644 index ec503293..00000000 --- a/lib/src/vector/ml_vector_factory.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:ml_linalg/vector.dart'; - -abstract class MLVectorFactory> { - MLVector createVectorFrom(Iterable source, [bool mutable = false]); - MLVector createVectorFromSIMDList(S source, - [int length, bool mutable = false]); -} diff --git a/lib/src/vector/ml_simd_operations_helper.dart b/lib/src/vector/simd_operations_helper.dart similarity index 94% rename from lib/src/vector/ml_simd_operations_helper.dart rename to lib/src/vector/simd_operations_helper.dart index fc4b731f..9f586e80 100644 --- a/lib/src/vector/ml_simd_operations_helper.dart +++ b/lib/src/vector/simd_operations_helper.dart @@ -1,4 +1,4 @@ -abstract class MLSimdOperationsHelper> { +abstract class SimdOperationsHelper> { /// number of lanes (it is 2 or 4 elements currently supported to be processed simultaneously, this characteristic /// restricted by computing platform architecture) int get bucketSize; @@ -39,6 +39,8 @@ abstract class MLSimdOperationsHelper> { /// prepares a simd value comprised of maximum values of both [a] and [b] E selectMax(E a, E b); + bool areValuesEqual(E a, E b); + /// returns a maximal element (lane) of [a] double getMaxLane(E a); diff --git a/lib/src/vector/ml_simd_vector_fast_iterable_mixin.dart b/lib/src/vector/simd_vector_fast_iterable_mixin.dart similarity index 56% rename from lib/src/vector/ml_simd_vector_fast_iterable_mixin.dart rename to lib/src/vector/simd_vector_fast_iterable_mixin.dart index c8f04709..615c5eb7 100644 --- a/lib/src/vector/ml_simd_vector_fast_iterable_mixin.dart +++ b/lib/src/vector/simd_vector_fast_iterable_mixin.dart @@ -1,18 +1,18 @@ import 'dart:math' as math; -import 'package:ml_linalg/src/vector/ml_simd_operations_helper.dart'; -import 'package:ml_linalg/src/vector/ml_vector_data_store.dart'; -import 'package:ml_linalg/src/vector/ml_vector_factory.dart'; +import 'package:ml_linalg/src/vector/simd_operations_helper.dart'; +import 'package:ml_linalg/src/vector/vector_data_store.dart'; +import 'package:ml_linalg/src/vector/vector_factory.dart'; import 'package:ml_linalg/vector.dart'; -abstract class MLSimdVectorFastIterableMixin> +mixin SimdVectorFastIterableMixin> implements - MLVectorFactory, - MLVectorDataStore, - MLSimdOperationsHelper, - MLVector { + VectorFactory, + VectorDataStore, + SimdOperationsHelper, + Vector { @override - MLVector fastMap( + Vector fastMap( T mapper(T element, int offsetStartIdx, int offsetEndIdx)) { final list = createSIMDList(data.length) as List; for (int i = 0; i < data.length; i++) { diff --git a/lib/src/vector/ml_simd_vector_operations_mixin.dart b/lib/src/vector/simd_vector_mixin.dart similarity index 79% rename from lib/src/vector/ml_simd_vector_operations_mixin.dart rename to lib/src/vector/simd_vector_mixin.dart index bb9691b1..50c678fc 100644 --- a/lib/src/vector/ml_simd_vector_operations_mixin.dart +++ b/lib/src/vector/simd_vector_mixin.dart @@ -4,20 +4,21 @@ import 'dart:typed_data'; import 'package:ml_linalg/matrix.dart'; import 'package:ml_linalg/norm.dart'; -import 'package:ml_linalg/src/vector/ml_simd_operations_helper.dart'; -import 'package:ml_linalg/src/vector/ml_vector_data_store.dart'; -import 'package:ml_linalg/src/vector/ml_vector_factory.dart'; -import 'package:ml_linalg/src/vector/ml_typed_list_factory.dart'; +import 'package:ml_linalg/src/vector/simd_operations_helper.dart'; +import 'package:ml_linalg/src/vector/vector_data_store.dart'; +import 'package:ml_linalg/src/vector/vector_factory.dart'; +import 'package:ml_linalg/src/vector/typed_list_factory.dart'; import 'package:ml_linalg/vector.dart'; +import 'package:quiver/core.dart'; -abstract class MLSimdVectorOperationsMixin> +mixin SimdVectorMixin> implements IterableMixin, - MLSimdOperationsHelper, - MLTypedListFactory, - MLVectorDataStore, - MLVectorFactory, - MLVector { + SimdOperationsHelper, + TypedListFactory, + VectorDataStore, + VectorFactory, + Vector { S get dataWithoutLastBucket => sublist(data, 0, data.length - 1); @override @@ -27,10 +28,35 @@ abstract class MLSimdVectorOperationsMixin> bool get _isLastBucketNotFull => length % bucketSize > 0; @override - MLVector operator +(Object value) { - if (value is MLVector) { + bool operator ==(Object obj) { + if (obj is Vector) { + // TODO: consider checking hashcode here to compare two vectors + if (length != obj.length) { + return false; + } + for (int i = 0; i < data.length; i++) { + if (!areValuesEqual(data[i], (obj as VectorDataStore).data[i])) { + return false; + } + } + return true; + } + return false; + } + + @override + int get hashCode { + _hash ??= hashObjects(data); + return _hash; + } + + int _hash; + + @override + Vector operator +(Object value) { + if (value is Vector) { return _elementWiseVectorOperation(value, simdSum); - } else if (value is MLMatrix) { + } else if (value is Matrix) { final other = value.toVector(); return _elementWiseVectorOperation(other, simdSum); } else if (value is num) { @@ -41,10 +67,10 @@ abstract class MLSimdVectorOperationsMixin> } @override - MLVector operator -(Object value) { - if (value is MLVector) { + Vector operator -(Object value) { + if (value is Vector) { return _elementWiseVectorOperation(value, simdSub); - } else if (value is MLMatrix) { + } else if (value is Matrix) { final other = value.toVector(); return _elementWiseVectorOperation(other, simdSub); } else if (value is num) { @@ -55,10 +81,10 @@ abstract class MLSimdVectorOperationsMixin> } @override - MLVector operator *(Object value) { - if (value is MLVector) { + Vector operator *(Object value) { + if (value is Vector) { return _elementWiseVectorOperation(value, simdMul); - } else if (value is MLMatrix) { + } else if (value is Matrix) { return _matrixMul(value); } else if (value is num) { return _elementWiseFloatScalarOperation(value.toDouble(), simdScale); @@ -67,8 +93,8 @@ abstract class MLSimdVectorOperationsMixin> } @override - MLVector operator /(Object value) { - if (value is MLVector) { + Vector operator /(Object value) { + if (value is Vector) { return _elementWiseVectorOperation(value, simdDiv); } else if (value is num) { return _elementWiseFloatScalarOperation(1 / value, simdScale); @@ -77,22 +103,22 @@ abstract class MLSimdVectorOperationsMixin> } @override - MLVector toIntegerPower(int power) => _elementWisePow(power); + Vector toIntegerPower(int power) => _elementWisePow(power); /// Returns a vector filled with absolute values of an each component of [this] vector @override - MLVector abs() => + Vector abs() => _elementWiseSelfOperation((E element, [int i]) => simdAbs(element)); @override - double dot(MLVector vector) => (this * vector).sum(); + double dot(Vector vector) => (this * vector).sum(); /// Returns sum of all vector components @override double sum() => singleSIMDSum(data.reduce(simdSum)); @override - double distanceTo(MLVector vector, [Norm norm = Norm.euclidean]) => + double distanceTo(Vector vector, [Norm norm = Norm.euclidean]) => (this - vector).norm(norm); @override @@ -140,7 +166,7 @@ abstract class MLSimdVectorOperationsMixin> } @override - MLVector query(Iterable indexes) { + Vector query(Iterable indexes) { final list = createTypedList(indexes.length); int i = 0; for (final idx in indexes) { @@ -150,7 +176,7 @@ abstract class MLSimdVectorOperationsMixin> } @override - MLVector unique() { + Vector unique() { final unique = []; for (int i = 0; i < length; i++) { final el = this[i]; @@ -179,7 +205,7 @@ abstract class MLSimdVectorOperationsMixin> } @override - MLVector subvector(int start, [int end]) { + Vector subvector(int start, [int end]) { final collection = bufferAsTypedList((data as TypedData).buffer, start, (end > length ? length : end) - start); return createVectorFrom(collection); @@ -234,7 +260,7 @@ abstract class MLSimdVectorOperationsMixin> } /// Returns a vector as a result of applying to [this] any element-wise operation with a simd value - MLVector _elementWiseFloatScalarOperation( + Vector _elementWiseFloatScalarOperation( double scalar, E operation(E a, double b)) { final list = createSIMDList(data.length); for (int i = 0; i < data.length; i++) { @@ -244,7 +270,7 @@ abstract class MLSimdVectorOperationsMixin> } /// Returns a vector as a result of applying to [this] any element-wise operation with a simd value - MLVector _elementWiseSimdScalarOperation(E simdVal, E operation(E a, E b)) { + Vector _elementWiseSimdScalarOperation(E simdVal, E operation(E a, E b)) { final list = createSIMDList(data.length); for (int i = 0; i < data.length; i++) { list[i] = operation(data[i], simdVal); @@ -253,16 +279,16 @@ abstract class MLSimdVectorOperationsMixin> } /// Returns a vector as a result of applying to [this] any element-wise operation with a vector (e.g. vector addition) - MLVector _elementWiseVectorOperation(MLVector vector, E operation(E a, E b)) { + Vector _elementWiseVectorOperation(Vector vector, E operation(E a, E b)) { if (vector.length != length) throw _mismatchLengthError(); final list = createSIMDList(data.length); for (int i = 0; i < data.length; i++) { - list[i] = operation(data[i], (vector as MLVectorDataStore).data[i]); + list[i] = operation(data[i], (vector as VectorDataStore).data[i]); } return createVectorFromSIMDList(list, length); } - MLVector _elementWiseSelfOperation(E operation(E element, [int index])) { + Vector _elementWiseSelfOperation(E operation(E element, [int index])) { final list = createSIMDList(data.length); for (int i = 0; i < data.length; i++) { list[i] = operation(data[i], i); @@ -271,7 +297,7 @@ abstract class MLSimdVectorOperationsMixin> } /// Returns a vector as a result of applying to [this] element-wise raising to the integer power - MLVector _elementWisePow(int exp) { + Vector _elementWisePow(int exp) { final list = createSIMDList(data.length); for (int i = 0; i < data.length; i++) { list[i] = _simdToIntPow(data[i], exp); @@ -279,7 +305,7 @@ abstract class MLSimdVectorOperationsMixin> return createVectorFromSIMDList(list, length); } - MLVector _matrixMul(MLMatrix matrix) { + Vector _matrixMul(Matrix matrix) { if (length != matrix.rowsNum) { throw Exception( 'Multiplication by a matrix with diffrent number of rows than the vector length is not allowed:' diff --git a/lib/src/vector/ml_typed_list_factory.dart b/lib/src/vector/typed_list_factory.dart similarity index 94% rename from lib/src/vector/ml_typed_list_factory.dart rename to lib/src/vector/typed_list_factory.dart index e23ea6f3..5f2a5575 100644 --- a/lib/src/vector/ml_typed_list_factory.dart +++ b/lib/src/vector/typed_list_factory.dart @@ -1,6 +1,6 @@ import 'dart:typed_data' show ByteBuffer; -abstract class MLTypedListFactory { +abstract class TypedListFactory { /// returns a typed list with List createTypedListFromByteBuffer(ByteBuffer data); diff --git a/lib/src/vector/ml_vector_data_store.dart b/lib/src/vector/vector_data_store.dart similarity index 56% rename from lib/src/vector/ml_vector_data_store.dart rename to lib/src/vector/vector_data_store.dart index 80ca9e89..dd3c41ad 100644 --- a/lib/src/vector/ml_vector_data_store.dart +++ b/lib/src/vector/vector_data_store.dart @@ -1,4 +1,4 @@ -abstract class MLVectorDataStore> { +abstract class VectorDataStore> { S data; int length; List toList({bool growable = false}); diff --git a/lib/src/vector/vector_factory.dart b/lib/src/vector/vector_factory.dart new file mode 100644 index 00000000..485bb934 --- /dev/null +++ b/lib/src/vector/vector_factory.dart @@ -0,0 +1,7 @@ +import 'package:ml_linalg/vector.dart'; + +abstract class VectorFactory> { + Vector createVectorFrom(Iterable source, [bool mutable = false]); + Vector createVectorFromSIMDList(S source, + [int length, bool mutable = false]); +} diff --git a/lib/vector.dart b/lib/vector.dart index b3cc5005..2b489bfe 100644 --- a/lib/vector.dart +++ b/lib/vector.dart @@ -5,13 +5,13 @@ import 'package:ml_linalg/src/vector/float32x4/float32x4_vector.dart'; import 'norm.dart'; /// An algebraic vector (ordered set of elements). -abstract class MLVector implements Iterable { +abstract class Vector implements Iterable { /// Creates a vector from a collection [source]. /// /// It converts the collection of [double]-type elements into a collection of /// [Float32x4] elements. If [isMutable] is true, one can alter the vector, /// for example, via `[]=` operator - factory MLVector.from(Iterable source, + factory Vector.from(Iterable source, {bool isMutable, Type dtype = Float32x4}) { switch (dtype) { case Float32x4: @@ -25,7 +25,7 @@ abstract class MLVector implements Iterable { /// /// If [isMutable] is true, one can alter the vector, for example, via `[]=` /// operator - factory MLVector.filled(int length, double value, + factory Vector.filled(int length, double value, {bool isMutable, Type dtype = Float32x4}) { switch (dtype) { case Float32x4: @@ -39,7 +39,7 @@ abstract class MLVector implements Iterable { /// /// If [isMutable] is true, one can alter the vector, for example, via `[]=` /// operator - factory MLVector.zero(int length, {bool isMutable, Type dtype = Float32x4}) { + factory Vector.zero(int length, {bool isMutable, Type dtype = Float32x4}) { switch (dtype) { case Float32x4: return Float32x4Vector.zero(length, isMutable: isMutable); @@ -53,7 +53,7 @@ abstract class MLVector implements Iterable { /// /// If [isMutable] is true, one can alter the vector, for example, via `[]=` /// operator - factory MLVector.randomFilled(int length, + factory Vector.randomFilled(int length, {int seed, bool isMutable, Type dtype = Float32x4}) { switch (dtype) { case Float32x4: @@ -64,6 +64,8 @@ abstract class MLVector implements Iterable { } } + Type get dtype; + /// Can someone mutate the vector, e.g. via []= operator, or not bool get isMutable; @@ -74,30 +76,30 @@ abstract class MLVector implements Iterable { void operator []=(int index, double value); /// Vector addition (element-wise operation) - MLVector operator +(Object value); + Vector operator +(Object value); /// Vector subtraction (element-wise operation) - MLVector operator -(Object value); + Vector operator -(Object value); /// Vector multiplication (element-wise operation) - MLVector operator *(Object value); + Vector operator *(Object value); /// Element-wise division - MLVector operator /(Object value); + Vector operator /(Object value); - /// Creates a new [MLVector] containing elements of this [MLVector] raised to + /// Creates a new [Vector] containing elements of this [Vector] raised to /// the integer [power] - MLVector toIntegerPower(int power); + Vector toIntegerPower(int power); /// Returns a vector with absolute value of each vector element - MLVector abs(); + Vector abs(); /// Returns a dot (inner) product of [this] and [vector] - double dot(MLVector vector); + double dot(Vector vector); /// Returns a distance between [this] and [vector] with vector norm type /// considering - double distanceTo(MLVector vector, [Norm norm = Norm.euclidean]); + double distanceTo(Vector vector, [Norm norm = Norm.euclidean]); /// Returns a mean value of [this] vector double mean(); @@ -116,14 +118,14 @@ abstract class MLVector implements Iterable { /// Returns a vector composed of elements which are located on the passed /// indexes - MLVector query(Iterable indexes); + Vector query(Iterable indexes); /// Returns a vector composed of unique vector's elements - MLVector unique(); + Vector unique(); - MLVector fastMap( + Vector fastMap( E mapper(E element, int offsetStartIdx, int offsetEndIdx)); /// Cuts out a part of the vector - MLVector subvector(int start, [int end]); + Vector subvector(int start, [int end]); } diff --git a/pubspec.lock b/pubspec.lock index 04a75a5b..71f269d5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -56,7 +56,7 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "0.4.0" + version: "0.4.1" build_resolvers: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.2.7" + version: "1.2.8" build_runner_core: dependency: transitive description: @@ -98,7 +98,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "6.3.0" + version: "6.3.1" charcode: dependency: transitive description: @@ -336,7 +336,7 @@ packages: name: package_resolver url: "https://pub.dartlang.org" source: hosted - version: "1.0.7" + version: "1.0.10" path: dependency: transitive description: @@ -350,7 +350,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.5.0" platform: dependency: transitive description: @@ -394,7 +394,7 @@ packages: source: hosted version: "0.1.4" quiver: - dependency: transitive + dependency: "direct main" description: name: quiver url: "https://pub.dartlang.org" @@ -562,4 +562,4 @@ packages: source: hosted version: "2.1.15" sdks: - dart: ">=2.1.0 <3.0.0" + dart: ">=2.2.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index f4a1f75a..16ed6225 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,10 @@ author: Ilia Gyrdymov homepage: https://github.com/gyrdym/ml_linalg environment: - sdk: '>=2.1.0 <3.0.0' + sdk: '>=2.2.0 <3.0.0' + +dependencies: + quiver: '>=2.0.0 <3.0.0' dev_dependencies: benchmark_harness: ">=1.0.0 <2.0.0" diff --git a/test/float32x4_matrix_test.dart b/test/float32x4_matrix_test.dart index 52bbcc2e..bf3760fe 100644 --- a/test/float32x4_matrix_test.dart +++ b/test/float32x4_matrix_test.dart @@ -95,10 +95,10 @@ void main() { final row1 = matrix.getRow(0); final row2 = matrix.getRow(1); - expect(row1 is MLVector, isTrue); + expect(row1 is Vector, isTrue); expect(row1, [11.0, 12.0, 13.0, 14.0]); - expect(row2 is MLVector, isTrue); + expect(row2 is Vector, isTrue); expect(row2, [15.0, 16.0, 17.0, 18.0]); }); @@ -144,16 +144,16 @@ void main() { final column3 = matrix.getColumn(2); final column4 = matrix.getColumn(3); - expect(column1 is MLVector, isTrue); + expect(column1 is Vector, isTrue); expect(column1, [11.0, 15.0, 21.0]); - expect(column2 is MLVector, isTrue); + expect(column2 is Vector, isTrue); expect(column2, [12.0, 16.0, 22.0]); - expect(column3 is MLVector, isTrue); + expect(column3 is Vector, isTrue); expect(column3, [13.0, 17.0, 23.0]); - expect(column4 is MLVector, isTrue); + expect(column4 is Vector, isTrue); expect(column4, [14.0, 18.0, 24.0]); }); @@ -370,7 +370,7 @@ void main() { [15.0, 16.0, 17.0, 18.0], [21.0, 22.0, 23.0, 24.0], ]); - final modifier = MLVector.filled(3, 2.0); + final modifier = Vector.filled(3, 2.0); final actual = matrix.mapColumns((column) => column + modifier); final expected = [ [13.0, 14.0, 15.0, 16.0], @@ -386,7 +386,7 @@ void main() { [15.0, 16.0, 17.0, 18.0], [21.0, 22.0, 23.0, 24.0], ]); - final modifier = MLVector.filled(4, 1.0); + final modifier = Vector.filled(4, 1.0); final actual = matrix.mapRows((row) => row - modifier); final expected = [ [10.0, 11.0, 12.0, 13.0], @@ -749,7 +749,7 @@ void main() { ]); final column1 = matrix.toVector(); final column2 = matrix.toVector(); - expect(column1 is MLVector, isTrue); + expect(column1 is Vector, isTrue); expect(column1, equals([1.0, 5.0, 9.0])); expect(identical(column1, column2), isTrue); }); @@ -763,7 +763,7 @@ void main() { final column1 = matrix.toVector(mutable: true); final column2 = matrix.toVector(mutable: true); - expect(column1 is MLVector, isTrue); + expect(column1 is Vector, isTrue); expect(column1.isMutable, isTrue); expect(column1, equals([1.0, 5.0, 9.0])); expect(identical(column1, column2), isFalse); @@ -776,7 +776,7 @@ void main() { ]); final row1 = matrix.toVector(); final row2 = matrix.toVector(); - expect(row1 is MLVector, isTrue); + expect(row1 is Vector, isTrue); expect(row1, equals([4.0, 8.0, 12.0, 16.0])); expect(identical(row1, row2), isTrue); }); @@ -788,7 +788,7 @@ void main() { final row1 = matrix.toVector(mutable: true); final row2 = matrix.toVector(mutable: true); - expect(row1 is MLVector, isTrue); + expect(row1 is Vector, isTrue); expect(row1.isMutable, isTrue); expect(row1, equals([4.0, 8.0, 12.0, 16.0])); expect(identical(row1, row2), isFalse); @@ -806,6 +806,46 @@ void main() { }); }); + group('Float32x4Matrix.uniqueRows', () { + test('should return the same row vectors as the matrix rows if all the ' + 'rows are unique', () { + final matrix = Float32x4Matrix.from([ + [4.0, 8.0, 12.0, 16.0, 34.0], + [20.0, 24.0, 28.0, 32.0, 23.0], + [36.0, .0, -8.0, -12.0, 12.0], + [16.0, 1.0, -18.0, 3.0, 11.0], + [112.0, 10.0, 34.0, 2.0, 10.0], + ]); + final actual = matrix.uniqueRows(); + final expected = [ + [4.0, 8.0, 12.0, 16.0, 34.0], + [20.0, 24.0, 28.0, 32.0, 23.0], + [36.0, .0, -8.0, -12.0, 12.0], + [16.0, 1.0, -18.0, 3.0, 11.0], + [112.0, 10.0, 34.0, 2.0, 10.0], + ]; + expect(actual, equals(expected)); + }); + + test('should return just unique rows', () { + final matrix = Float32x4Matrix.from([ + [4.0, 8.0, 12.0, 16.0, 34.0], + [20.0, 24.0, 28.0, 32.0, 23.0], + [36.0, .0, -8.0, -12.0, 12.0], + [20.0, 24.0, 28.0, 32.0, 23.0], + [36.0, .0, -8.0, -12.0, 12.0], + [36.0, .0, -8.0, -12.0, 12.0], + ]); + final actual = matrix.uniqueRows(); + final expected = [ + [4.0, 8.0, 12.0, 16.0, 34.0], + [20.0, 24.0, 28.0, 32.0, 23.0], + [36.0, .0, -8.0, -12.0, 12.0], + ]; + expect(actual, equals(expected)); + }); + }); + group('Float32x4Matrix.setColumn', () { test('should set a new column by column index', () { final matrix = Float32x4Matrix.from([ diff --git a/test/float32x4_vector_test.dart b/test/float32x4_vector_test.dart index 8317e023..e168b1cd 100644 --- a/test/float32x4_vector_test.dart +++ b/test/float32x4_vector_test.dart @@ -123,9 +123,57 @@ void main() { expect(actual.length, equals(5)); }); - test( - 'should throw an exception if one tries to sum vectors of different lengths', - () { + test('should compare with another vector and return `true` if vectors are' + 'equal', () { + final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + expect(vector1 == vector2, isTrue); + }); + + test('should compare with another vector and return `true` if vectors are' + 'have all zero values', () { + final vector1 = Float32x4Vector.from([0.0, 0.0, 0.0, 0.0, 0.0]); + final vector2 = Float32x4Vector.from([0.0, 0.0, 0.0, 0.0, 0.0]); + expect(vector1 == vector2, isTrue); + }); + + test('should compare with another vector and return `false` if vectors are' + 'different', () { + final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Float32x4Vector.from([1.0, 2.0, 30.0, 4.0, 5.0]); + expect(vector1 == vector2, isFalse); + }); + + test('should compare with another vector and return `false` if vectors are' + 'have opposite values', () { + final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Float32x4Vector.from([-1.0, -2.0, -3.0, -4.0, -5.0]); + expect(vector1 == vector2, isFalse); + }); + + test('should compare with another vector and return `false` if one vector' + 'have all zero values', () { + final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + final vector2 = Float32x4Vector.from([0.0, 0.0, 0.0, 0.0, 0.0]); + expect(vector1 == vector2, isFalse); + }); + + test('should compare with another vector and return `false` if vectors ' + 'have different lengths', () { + final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); + final vector2 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); + expect(vector1 == vector2, isFalse); + }); + + test('should compare with another object and return `false` if another ' + 'object is not a vector', () { + final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); + final vector2 = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; + expect(vector1 == vector2, isFalse); + }); + + test('should throw an exception if one tries to sum vectors of different ' + 'lengths', () { final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); final vector2 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); expect(() => vector1 + vector2, throwsRangeError); @@ -165,9 +213,8 @@ void main() { expect(result.length, equals(5)); }); - test( - 'should throw an exception if one tries to subtract a vector of different length', - () { + test('should throw an exception if one tries to subtract a vector of ' + 'different length', () { final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); final vector2 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); expect(() => vector1 - vector2, throwsRangeError); @@ -216,9 +263,8 @@ void main() { expect(actual.length, equals(5)); }); - test( - 'should throw an error if one tries to multiple by a vector of different length', - () { + test('should throw an error if one tries to multiple by a vector of ' + 'different length', () { final vector1 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0]); final vector2 = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); expect(() => vector1 * vector2, throwsRangeError); @@ -471,16 +517,14 @@ void main() { expect(() => vector[100], throwsRangeError); }); - test( - 'should not allow to assign a value via indexed access if it is immutable ([]= operator)', - () { + test('should not allow to assign a value via indexed access if it is ' + 'immutable ([]= operator)', () { final vector = Float32x4Vector.from([1.0, 2.0]); // immutable by default expect(() => vector[0] = 3.0, throwsUnsupportedError); }); - test( - 'should perform value assignment via indexed access if it is mutable ([]= operator)', - () { + test('should perform value assignment via indexed access if it is mutable ' + '([]= operator)', () { final vector = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0], isMutable: true); vector[0] = 6.0; @@ -491,9 +535,8 @@ void main() { expect(vector, equals([6.0, 7.0, 8.0, 9.0, 10.0])); }); - test( - 'should throw range error if one tries to set a value on non-existing index', - () { + test('should throw range error if one tries to set a value on non-existing ' + 'index', () { final vector = Float32x4Vector.from([1.0, 2.0, 3.0, 4.0, 5.0], isMutable: true); expect(() => vector[20] = 2.0, throwsRangeError);