From 6335412a133afaeac2b10de4976d3e943865969d Mon Sep 17 00:00:00 2001 From: Wolfgang Manousek Date: Wed, 18 Nov 2015 09:49:55 +0100 Subject: [PATCH 1/2] Add Math/CNTKMathTest/MatrixUnitTests to Tests/UnitTests/MathTests/MathTests cleanup files in Math/CNTKMathTest/CNTKMathTest and Tests/UnitTests/MathTests/MathTests --- Math/CNTKMathTest/CNTKMathTest.vcxproj | 1 - Math/CNTKMathTest/MatrixUnitTests.cpp | 886 ------------------ Tests/UnitTests/MathTests/MathTests.vcxproj | 1 + Tests/UnitTests/MathTests/MatrixTests.cpp | 953 ++++++++++++++++++++ Tests/UnitTests/MathTests/constant.cpp | 11 - Tests/UnitTests/MathTests/constant.h | 9 - Tests/UnitTests/MathTests/constants.cpp | 1 + Tests/UnitTests/MathTests/constants.h | 3 +- 8 files changed, 957 insertions(+), 908 deletions(-) delete mode 100644 Math/CNTKMathTest/MatrixUnitTests.cpp create mode 100644 Tests/UnitTests/MathTests/MatrixTests.cpp delete mode 100644 Tests/UnitTests/MathTests/constant.cpp delete mode 100644 Tests/UnitTests/MathTests/constant.h diff --git a/Math/CNTKMathTest/CNTKMathTest.vcxproj b/Math/CNTKMathTest/CNTKMathTest.vcxproj index 7dbe33f79b3b..88d23cf84b8a 100644 --- a/Math/CNTKMathTest/CNTKMathTest.vcxproj +++ b/Math/CNTKMathTest/CNTKMathTest.vcxproj @@ -114,7 +114,6 @@ - Create Create diff --git a/Math/CNTKMathTest/MatrixUnitTests.cpp b/Math/CNTKMathTest/MatrixUnitTests.cpp deleted file mode 100644 index aa9cec15cc43..000000000000 --- a/Math/CNTKMathTest/MatrixUnitTests.cpp +++ /dev/null @@ -1,886 +0,0 @@ -// -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// -#include "stdafx.h" -#include "CppUnitTest.h" -#include "..\Math\Matrix.h" -#include "..\Math\CPUMatrix.h" -#include "..\Math\GPUMatrix.h" -#include "..\Math\CPUSparseMatrix.h" -#include "..\Math\GPUSparseMatrix.h" -#include "..\Math\Helpers.h" - -#pragma warning (disable: 4244 4245 4305) // conversions and truncations; we don't care in this test project - -#define epsilon 0.000001 -#define IDX2C(i,j,ld) (((j)*(ld))+(i)) // 0 based indexing - -using namespace Microsoft::MSR::CNTK; -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - - -namespace CNTKMathTest -{ - TEST_CLASS(MatrixUnitTest) - { - - public: - - //This test should fail if you don't have CUDA GPU (or working under remote desktop) - TEST_METHOD(MatrixConsturctors) - { - SingleMatrix A0; - SingleMatrix A1(AUTOPLACEMATRIX); - SingleMatrix A2(-1); - SingleMatrix A3((size_t)13,(size_t)12,(DEVICEID_TYPE)0); - - Assert::AreEqual(0,A0.GetNumRows()); - Assert::AreEqual(0,A0.GetNumCols()); - Assert::AreEqual(0,A1.GetNumRows()); - Assert::AreEqual(0,A2.GetNumCols()); - Assert::AreEqual(13,A3.GetNumRows()); - Assert::AreEqual(12,A3.GetNumCols()); - } - - TEST_METHOD(MatrixMoveTest) - { - //no moves required - SingleMatrix a; - SingleMatrix b; - b.Resize(100,100); - std::swap(a,b); - - //potentially a move is required - SingleMatrix A; - SingleMatrix B; - B.Resize(100,100); - B(12,13)=14; //this will move whole matrix B from GPU to CPU - std::swap(A,B); // this will not only swap A and B but will put them to their preferred device (GPU if present) - - //This is deep copy, not move - SingleMatrix a1; - SingleMatrix b1; - b1.Resize(12,34); - b1=a1; - - SingleMatrix a2; - SingleMatrix b2; - b2.Resize(12,34); - b2(2,3)=9; - b2=a2; - } - - - TEST_METHOD(MatrixAssignmentOperatorsAndInitializers) - { - //Zeros - SingleMatrix A0 = SingleMatrix::Zeros(12,32); - Assert::AreEqual(12,A0.GetNumRows()); - Assert::AreEqual(32,A0.GetNumCols()); - foreach_coord(i,j,A0) - { - Assert::AreEqual(0,A0(i,j)); - } - - //Eye - SingleMatrix A1 = SingleMatrix::Eye(56); - Assert::AreEqual(56,A1.GetNumRows()); - Assert::AreEqual(56,A1.GetNumCols()); - foreach_coord(i,j,A1) - { - if (i!=j) - { - float x = A1(i,j); - Assert::AreEqual(0,x); - } - else - { - float x = A1(i,j); - Assert::AreEqual(1,x); - } - } - - //Ones - SingleMatrix A2 = SingleMatrix::Ones(12,56); - Assert::AreEqual(12,A2.GetNumRows()); - Assert::AreEqual(56,A2.GetNumCols()); - foreach_coord(i,j,A2) - { - Assert::AreEqual(1,A2(i,j)); - } - - //SetGaussianRandomValue - SingleMatrix A3= SingleMatrix::RandomGaussian(640,230,0,2,-1); - float avg = 0; - foreach_coord(i,j,A3) - { - avg+=A3(i,j); - } - avg/=(640*230); - float std=0; - foreach_coord(i,j,A3) - { - std+=((A3(i,j)-avg)*(A3(i,j)-avg)/(640*230)); - } - std=sqrt(std); - //Assert::IsTrue(fabs(avg-0)<0.01); - //WARNING: The deviance seems to be off for both CPU and GPU implementations - //Assert::IsTrue(fabs(std-2)<0.01); - - //RandomUniform - SingleMatrix A4 = SingleMatrix::RandomUniform(435, 100, -26.3, 30.2); - bool has_small=false; - bool has_big=false; - foreach_coord(i,j,A4) - { - Assert::IsTrue((A4(i,j)>=-26.3)&&(A4(i,j)<30.2)); - if (A4(i,j)<-3) - has_small=true; - if (A4(i,j)>3) - has_big=true; - } - Assert::IsTrue(has_small); - Assert::IsTrue(has_big); - - //RandomUniform - SingleMatrix A5((size_t)429,(size_t)1024); - A5.SetUniformRandomValue(-0.01,0.01); - foreach_coord(i,j,A5) - { - Assert::IsTrue(A5(i,j)<=0.01&&A5(i,j)>=-0.01); - } - - //Check that seed allows results reproduce - //!!!WE NOW INITIALIZE SEED PER PROCESS!!! - /* - SingleMatrix A6 = SingleMatrix::RandomUniform(5,6,-1,3,1234); - SingleMatrix A7 = SingleMatrix::RandomUniform(5,6,-1,3,1234); - SingleMatrix A8 = SingleMatrix::RandomUniform(5,6,-1,3,12346); - SingleMatrix A9 = SingleMatrix::RandomUniform(5,6,-1,3); - - Assert::IsTrue(A6.IsEqualTo(A7)); - //Assert::IsTrue(!A8.IsEqualTo(A7)); */ - - } - - TEST_METHOD(MatrixSetValueMethods) - { - //void SetValue(const ElemType v); - SingleMatrix A((size_t)32,(size_t)12); - Assert::AreEqual(32,A.GetNumRows()); - Assert::AreEqual(12,A.GetNumCols()); - Assert::AreEqual(12*32,A.GetNumElements()); - float v= -32.3451; - A.SetValue(v); - foreach_coord(i,j,A) - { - Assert::AreEqual(v,A(i,j)); - } - - //void SetValue(const Matrix& deepCopyFrom); - SingleMatrix B; - B.SetValue(A); - foreach_coord(i,j,B) - { - Assert::AreEqual(v,B(i,j)); - } - - //void SetValue(const size_t numRows, const size_t numCols, ElemType *pArray, const bool srcIsColMajor); - float *arr = new float[6]; - arr[0]=123;arr[1]=0.23;arr[2]=-22;arr[3]=63;arr[4]=43.42; - arr[5]=324.3;arr[6]=99912; - B.SetValue(2,3,B.GetDeviceId(),arr,matrixFlagNormal); - - SingleMatrix B1; - B1.SetValue(2, 3, B.GetDeviceId(), arr); - foreach_coord(i,j,B) - { - Assert::AreEqual(arr[IDX2C(i,j,2)],B(i,j)); - Assert::AreEqual(arr[IDX2C(i,j,2)],B1(i,j)); - } - - SingleMatrix BBBB = SingleMatrix::Zeros(6,8); - BBBB.SetColumn(arr,3); - for (int i=0;i<6;++i) - { - Assert::AreEqual(arr[i],BBBB(i,3)); - } - - - //void SetDiagonalValue(const ElemType v); - SingleMatrix C(4,4,AUTOPLACEMATRIX); - float val = -0.00332; - C.SetDiagonalValue(val); - foreach_coord(i,j,C) - { - if (i==j) - Assert::AreEqual(val,C(i,j)); - else - Assert::AreEqual(0,C(i,j)); - } - - //void SetDiagonalValue(const Matrix& vector); - SingleMatrix D(4,1,AUTOPLACEMATRIX); - float val1=43.324; - D.SetValue(val1); - C.SetDiagonalValue(D); - foreach_coord(i,j,C) - { - if (i==j) - Assert::AreEqual(val1,C(i,j)); - else - Assert::AreEqual(0,C(i,j)); - } - - SingleMatrix C1(5,5,AUTOPLACEMATRIX); - SingleMatrix D1(1,5,AUTOPLACEMATRIX); - float val2=0.53; - D1=D1.Transpose(); - D1.SetValue(val2); - C1.SetDiagonalValue(D1); - foreach_coord(i,j,C1) - { - if (i==j) - Assert::AreEqual(val2,C1(i,j)); - else - Assert::AreEqual(0,C1(i,j)); - } - } - - TEST_METHOD(MatrixTransposeTest) - { - SingleMatrix A= SingleMatrix::RandomGaussian(64,23,0,2); - Assert::AreEqual(64,A.GetNumRows()); - Assert::AreEqual(23,A.GetNumCols()); - - SingleMatrix B=A.Transpose(); - - Assert::AreEqual(23,B.GetNumRows()); - Assert::AreEqual(64,B.GetNumCols()); - - foreach_coord(i,j,A) - { - Assert::AreEqual(A(i,j),B(j,i)); - } - } - - TEST_METHOD(MatrixMultiAndDiv) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M00((size_t)2, (size_t)3); - M00(0,0) = 10; M00(0,1) = 20; M00(0,2) = 30; - M00(1,0) = 40; M00(1,1) = 50; M00(1,2) = 60; - - SingleMatrix M1((size_t)2,(size_t)3); - M1.Reshape(3,2); - M1(0,0) = 11; M1(0,1) = 15; - M1(1,0) = 14; M1(1,1) = 13; - M1(2,0) = 12; M1(2,1) = 16; - - SingleMatrix M2((size_t)2,(size_t)2); - M2(0,0) = 75; M2(0,1) = 89; - M2(1,0) = 186; M2(1,1) = 221; - - SingleMatrix M3 = M0 * M1; - Assert::IsTrue(M3.IsEqualTo(M2)); - - M3 = M0 * 10; - Assert::IsTrue(M3.IsEqualTo(M00)); - - M3 = M3 / 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - M3 *= 10; - Assert::IsTrue(M3.IsEqualTo(M00)); - - M3 /= 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - SingleMatrix::MultiplyAndWeightedAdd(1, M0, false, M1, false, 0, M3); - Assert::IsTrue(M3.IsEqualTo(M2)); - - M1.Reshape(2,3); - SingleMatrix::MultiplyAndWeightedAdd(1, M0, false, M1, true, 0, M3); - M2(0,0) = 74; M2(0,1) = 92; - M2(1,0) = 182; M2(1,1) = 227; - Assert::IsTrue(M3.IsEqualTo(M2)); - - SingleMatrix::MultiplyAndWeightedAdd(10, M0, false, M1, true, 2, M3); - M2(0,0) = 888; M2(0,1) = 1104; - M2(1,0) = 2184; M2(1,1) = 2724; - Assert::IsTrue(M3.IsEqualTo(M2)); - - SingleMatrix::MultiplyAndWeightedAdd(1, M0, true, M1, false, 0, M3); - M2.Resize(3,3); - M2(0,0) = 67; M2(0,1) = 72; M2(0,2) = 77; - M2(1,0) = 92; M2(1,1) = 99; M2(1,2) = 106; - M2(2,0) = 117; M2(2,1) = 126; M2(2,2) = 135; - Assert::IsTrue(M3.IsEqualTo(M2)); - - //Multiplications of arbitrary matrix with 1x1 matrix - - SingleMatrix A((size_t)2,(size_t)3); - A(0,0) = 1; A(0,1) = 2; A(0,2) = 3; - A(1,0) = 4; A(1,1) = 5; A(1,2) = 6; - - SingleMatrix B = SingleMatrix::Eye(1); - - SingleMatrix C=A*B; - Assert::IsTrue(C.IsEqualTo(A)); - C=B*A; - Assert::IsTrue(C.IsEqualTo(A)); - B(0,0)=0.5; - B.InplaceAbs(); - C=A*B; - - SingleMatrix D((size_t)2,(size_t)3); - D(0,0) = 0.5; D(0,1) = 1; D(0,2) = 1.5; - D(1,0) = 2; D(1,1) = 2.5; D(1,2) = 3; - Assert::IsTrue(C.IsEqualTo(D)); - } - - TEST_METHOD(MatrixTranspose) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M1((size_t)3,(size_t)2); - M1(0,0) = 1; M1(0,1) = 4; - M1(1,0) = 2; M1(1,1) = 5; - M1(2,0) = 3; M1(2,1) = 6; - - SingleMatrix M2 = M0.Transpose(); - Assert::IsTrue(M2.IsEqualTo(M1, 0.0001)); - - M2.AssignTransposeOf(M1); - Assert::IsTrue(M2.IsEqualTo(M0, 0.0001)); - } - - TEST_METHOD(MatrixAddAndSub) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M1((size_t)2,(size_t)3); - M1(0,0) = 11; M1(0,1) = 12; M1(0,2) = 13; - M1(1,0) = 14; M1(1,1) = 15; M1(1,2) = 16; - - SingleMatrix M2((size_t)2,(size_t)3); - M2(0,0) = 12; M2(0,1) = 14; M2(0,2) = 16; - M2(1,0) = 18; M2(1,1) = 20; M2(1,2) = 22; - - SingleMatrix M3 = M2 - M0; - Assert::IsTrue(M3.IsEqualTo(M1)); - - M3 += M0; - Assert::IsTrue(M3.IsEqualTo(M2)); - - M3 = M0 + 10; - Assert::IsTrue(M3.IsEqualTo(M1)); - - M3 -= 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - M3 = M1 + M0; - Assert::IsTrue(M3.IsEqualTo(M2)); - SingleMatrix M4=SingleMatrix::Eye(3); - SingleMatrix M5 = M0*M4 + M1; - - M3 -= M0; - Assert::IsTrue(M3.IsEqualTo(M1)); - - M3 = M1 - 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - SingleMatrix M33(M3); //M4==M3 - M3 += 10; - Assert::IsTrue(M3.IsEqualTo(M1)); - - SingleMatrix M55=SingleMatrix::Eye(1); - M55(0,0)=10; - M55.InplaceAbs(); - M33 += M55;//M5 is 1x1 matrix - Assert::IsTrue(M33.IsEqualTo(M1)); - M33 -= 10; - M33 = M33 + 10; - Assert::IsTrue(M33.IsEqualTo(M1)); - } - - TEST_METHOD(MatrixElementOps) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M00((size_t)2,(size_t)3); - M00(0,0) = 1.0; M00(0,1) = 1/2.0; M00(0,2) = 1/3.0; - M00(1,0) = 1/4.0; M00(1,1) = 1/5.0; M00(1,2) = 1/6.0; - - SingleMatrix M1((size_t)2, (size_t)3); - M1(0,0) = 1; M1(0,1) = 1; M1(0,2) = 1; - M1(1,0) = 1; M1(1,1) = 1; M1(1,2) = 1; - - SingleMatrix M3; - M3.AssignElementProductOf(M0, M00); - Assert::IsTrue(M3.IsEqualTo(M1, 0.0001)); - - SingleMatrix M4=SingleMatrix::Zeros(2,3); - M4 = M4.AddElementProductOf(M0,M00); - Assert::IsTrue(M4.IsEqualTo(M1,0.0001)); - - M3 = M0 ^ 4; - SingleMatrix M2((size_t)2,(size_t)3); - M2(0,0) = 1; M2(0,1) = 16; M2(0,2) = 81; - M2(1,0) = 256; M2(1,1) = 625; M2(1,2) = 1296; - Assert::IsTrue(M3.IsEqualTo(M2,0.001)); - - M3.SetValue(M0); - M3 ^= 4; - Assert::IsTrue(M3.IsEqualTo(M2, 0.001)); - - M3.SetValue(M0); - M3.ElementMultiplyWith(M00); - Assert::IsTrue(M3.IsEqualTo(M1, 0.001)); - - M3.SetValue(M0); - M3.ElementInverse(); - Assert::IsTrue(M3.IsEqualTo(M00, 0.001)); - - M2(0,0) = 0.7311; M2(0,1) = 0.8808; M2(0,2) = 0.9526; - M2(1,0) = 0.9820; M2(1,1) = 0.9933; M2(1,2) = 0.9975; - M3.AssignElementDivisionOf(M2, M0); - M2.ElementMultiplyWith(M00); - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceSigmoid(); - M2(0,0) = 0.7311; M2(0,1) = 0.8808; M2(0,2) = 0.9526; - M2(1,0) = 0.9820; M2(1,1) = 0.9933; M2(1,2) = 0.9975; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceTanh(); - M2(0,0) = 0.7616; M2(0,1) = 0.9640; M2(0,2) = 0.9951; - M2(1,0) = 0.9993; M2(1,1) = 0.9999; M2(1,2) = 1.0000; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceLogSoftmax(true); - M3.InplaceExp(); - M2(0,0) = 0.0474; M2(0,1) = 0.0474; M2(0,2) = 0.0474; - M2(1,0) = 0.9526; M2(1,1) = 0.9526; M2(1,2) = 0.9526; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceLogSoftmax(false); - M3.InplaceExp(); - M2(0,0) = 0.0900; M2(0,1) = 0.2447; M2(0,2) = 0.6652; - M2(1,0) = 0.0900; M2(1,1) = 0.2447; M2(1,2) = 0.6652; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceHardmax(true); - M2(0, 0) = 0.0; M2(0, 1) = 0.0; M2(0, 2) = 0.0; - M2(1, 0) = 1.0; M2(1, 1) = 1.0; M2(1, 2) = 1.0; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceSqrt(); - M2(0,0) = 1; M2(0,1) = 1.4142; M2(0,2) = 1.7321; - M2(1,0) = 2; M2(1,1) = 2.2361; M2(1,2) = 2.4495; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceExp(); - M2(0,0) = 2.7183; M2(0,1) = 7.3891; M2(0,2) = 20.0855; - M2(1,0) = 54.5982; M2(1,1) = 148.4132; M2(1,2) = 403.4288; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceExp(); - M2(0,0) = 2.7183; M2(0,1) = 7.3891; M2(0,2) = 20.0855; - M2(1,0) = 54.5982; M2(1,1) = 148.4132; M2(1,2) = 403.4288; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.InplaceLog(); - Assert::IsTrue(M3.IsEqualTo(M0, 0.0001)); - - M3.SetValue(M0); - M3.InplaceTruncateBottom(2); - M2(0,0) = 2; M2(0,1) = 2; M2(0,2) = 3; - M2(1,0) = 4; M2(1,1) = 5; M2(1,2) = 6; - Assert::IsTrue(M3.IsEqualTo(M2, 0.001)); - - M3.SetValue(M0); - M3.InplaceTruncateTop(4); - M2(0,0) = 1; M2(0,1) = 2; M2(0,2) = 3; - M2(1,0) = 4; M2(1,1) = 4; M2(1,2) = 4; - Assert::IsTrue(M3.IsEqualTo(M2, 0.001)); - } - - TEST_METHOD(MatrixColumnElementMultiplyWithVsCPUMatrix) - { - CPUMatrix MCPU = CPUMatrix::RandomUniform(429,1024,-3.4,1); - CPUMatrix ACPU = CPUMatrix::Ones(429,1); - CPUMatrix MCPU_copy(MCPU); - MCPU.ColumnElementMultiplyWith(ACPU); - Assert::IsTrue(MCPU_copy.IsEqualTo(MCPU,0.0001)); - - // - Matrix M = Matrix::RandomUniform(429,1024,-3.4,1); - Matrix A = Matrix::Ones(429,1); - Matrix M_copy(M); - M.ColumnElementMultiplyWith(A); - Assert::IsTrue(M_copy.IsEqualTo(M,0.0001)); - - CPUMatrix MC1 = CPUMatrix::RandomUniform(429,1024,-3.4,1); - CPUMatrix MC2 = CPUMatrix::RandomUniform(429,1,0,3); - MC1.ColumnElementMultiplyWith(MC2); - - Matrix M1(MC1.GetNumRows(),MC1.GetNumCols(),MC1.GetArray(),matrixFlagNormal); - Matrix M2(MC2.GetNumRows(),MC2.GetNumCols(),MC2.GetArray(),matrixFlagNormal); - M1.ColumnElementMultiplyWith(M2); - - foreach_coord(i,j,M2) - { - Assert::IsTrue(fabs(M2(i,j)-MC2(i,j))<0.00001); - } - } - - TEST_METHOD(MatrixAssignXOf) - { - //AssignDifferenceOf - Matrix A = Matrix::RandomUniform(429,1024,5,32); - Matrix B = Matrix::RandomUniform(429,1024,5,32); - Matrix C; - C.AssignDifferenceOf(A,B); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==A(i,j)-B(i,j)); - } - float x=234.2; - C.AssignDifferenceOf(A,x); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==A(i,j)-x); - } - - C.AssignDifferenceOf(x,A); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==x-A(i,j)); - } - - C.AssignDifferenceOf(1,A); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==1-A(i,j)); - } - // - - //AssignElementProductOf - C.AssignElementProductOf(A,B); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==A(i,j)*B(i,j)); - } - - //AddElementProductOf - Matrix C_copy(C); - C.AddElementProductOf(A,B); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==C_copy(i,j)+A(i,j)*B(i,j)); - } - - //AssignSigmoidOf - CPUMatrix AC = CPUMatrix::RandomUniform(429,1024,5,32); - CPUMatrix BC = CPUMatrix::RandomUniform(429,1024,-5,12); - Matrix D(AC.GetNumRows(),AC.GetNumCols(),AC.GetArray(),matrixFlagNormal); - Matrix E(BC.GetNumRows(),BC.GetNumCols(),BC.GetArray(),matrixFlagNormal); - AC.AssignSigmoidOf(BC); - D.AssignSigmoidOf(E); - foreach_coord(i,j,AC) - { - Assert::IsTrue(fabs(AC(i,j)-D(i,j))<0.00001); - } - - //AssignSignOf - Matrix M1 = Matrix::RandomUniform(42,12,-5,12); - Matrix M2((size_t)4, (size_t)5); - M2.AssignSignOf(M1); - foreach_coord(i,j,M1) - { - float v = M1(i,j); - float expected = (v == (float)0? (float)0 : (v > 0? (float)1 : (float)(-1))); - float actual = M2(i,j); - Assert::AreEqual(expected, actual); - } - - Matrix M3 = Matrix::RandomUniform(42,12,-5,2);; - Matrix M4(M3); - M3.AddSignOf(M1); - foreach_coord(i,j,M3) - { - float v = M1(i,j); - Assert::AreEqual(M4(i,j)+(v == (float)0? (float)0 : (v > 0? (float)1 : (float)(-1))),M3(i,j)); - } - - - //AssignTruncateBottom and Top - Matrix M5((size_t)2, (size_t)2); - M5(0,0)=1; M5(0,1)=2; - M5(1,0)=3; M5(1,1)=4; - - Matrix M6; - M6.AssignTruncateBottomOf(M5,3); - Assert::AreEqual(3,M6(0,0)); - Assert::AreEqual(3,M6(0,1)); - Assert::AreEqual(3,M6(1,0)); - Assert::AreEqual(4,M6(1,1)); - - - Matrix M7; - M7.AssignTruncateTopOf(M5,3); - Assert::AreEqual(1,M7(0,0)); - Assert::AreEqual(2,M7(0,1)); - Assert::AreEqual(3,M7(1,0)); - Assert::AreEqual(3,M7(1,1)); - } - - TEST_METHOD(MatrixSum) - { - Matrix M=Matrix::Ones(429,1024,0); - float sum = M.SumOfElements(); - Assert::AreEqual(429*1024,sum); - - CPUMatrix MCPU=CPUMatrix::Ones(429,1024); - float sumCPU = MCPU.SumOfElements(); - Assert::AreEqual(429*1024,sumCPU); - - Matrix M1=Matrix::Ones(42,332); - M1*=-1; - float sum1 = M1.SumOfElements(); - Assert::AreEqual(-1*42*332,sum1); - - Matrix M2=Matrix::Ones(3,2); - M2*=-1; - float sum2 = M2.SumOfElements(); - Assert::AreEqual(-1*3*2,sum2); - } - - TEST_METHOD(MatrixColumnSlice) - { - float *fArray = new float[6]; - fArray[0] = 1; fArray[1] = 4; fArray[2] = 2; - fArray[3] = 5; fArray[4] = 3; fArray[5] = 6; - Matrix M0(2, 3, fArray, matrixFlagNormal); - - Matrix M1(2, 2, fArray, matrixFlagNormal); - - Matrix M2 = M0.ColumnSlice(0,2); - Assert::IsTrue(M2.IsEqualTo(M1, 0.0001)); - - Matrix M3(2, 2, fArray+2, matrixFlagNormal); - - M2 = M0.ColumnSlice(1,2); - Assert::IsTrue(M2.IsEqualTo(M3, 0.0001)); - - - size_t k=100, n=20, m=50; - - Matrix AG((size_t)k,(size_t)n); - AG.SetUniformRandomValue(-1,1); - - Matrix BG((size_t)n,(size_t)m); - BG.SetUniformRandomValue(-1,1); - - Matrix CG((size_t)k,(size_t)m); - CG.SetUniformRandomValue(-1,1); - Matrix DG((size_t)k,(size_t)m); - DG.SetValue(CG); - - Matrix::MultiplyAndAdd(AG, false, BG, false, DG); - - for (int i=0; i col_BG = BG.ColumnSlice(i,1); - Matrix col_CG = CG.ColumnSlice(i,1); - Matrix::MultiplyAndAdd(AG, false, col_BG, false, col_CG); - } - Assert::IsTrue(CG.IsEqualTo(DG, 0.0001)); - } - - TEST_METHOD(MatrixKhatriRaoProduct) - { - float *fArray = new float[24]; - fArray[0] = 0.8147f; fArray[3] = 0.9134f; fArray[6] = 0.2785f; fArray[9] = 0.9649f; - fArray[1] = 0.9058f; fArray[4] = 0.6324f; fArray[7] = 0.5469f; fArray[10] = 0.1576f; - fArray[2] = 0.1270f; fArray[5] = 0.0975f; fArray[8] = 0.9575f; fArray[11] = 0.9706f; - Matrix A(3,4,fArray); - - fArray[0] = 0.9572f; fArray[2] = 0.8003f; fArray[4] = 0.4218f; fArray[6] = 0.7922f; - fArray[1] = 0.4854f; fArray[3] = 0.1419f; fArray[5] = 0.9157f; fArray[7] = 0.9595f; - Matrix B(2,4,fArray); - - fArray[0] = 0.7798f; fArray[6] = 0.7310f; fArray[12] = 0.1175f; fArray[18] = 0.7644f; - fArray[1] = 0.8670f; fArray[7] = 0.5061f; fArray[13] = 0.2307f; fArray[19] = 0.1249f; - fArray[2] = 0.1215f; fArray[8] = 0.0781f; fArray[14] = 0.4038f; fArray[20] = 0.7689f; - fArray[3] = 0.3954f; fArray[9] = 0.1296f; fArray[15] = 0.2550f; fArray[21] = 0.9258f; - fArray[4] = 0.4396f; fArray[10] = 0.0897f; fArray[16] = 0.5008f; fArray[22] = 0.1512f; - fArray[5] = 0.0616f; fArray[11] = 0.0138f; fArray[17] = 0.8768f; fArray[23] = 0.9313f; - Matrix D(6,4, fArray); - - Matrix C; - C.AssignKhatriRaoProductOf(A, B); - Assert::IsTrue(C.IsEqualTo(D, 0.0001f)); - } - TEST_METHOD(MatrixAddColumnReshapeProductOf) - { - float *fArray = new float[12]; - fArray[0] = 0.6557f; fArray[6] = 0.7431f; - fArray[1] = 0.0357f; fArray[7] = 0.3922f; - fArray[2] = 0.8491f; fArray[8] = 0.6555f; - fArray[3] = 0.9340f; fArray[9] = 0.1712f; - fArray[4] = 0.6787f; fArray[10] = 0.7060f; - fArray[5] = 0.7577f; fArray[11] = 0.0318f; - Matrix A(6,2,fArray); - - fArray[0] = 0.2769f; fArray[3] = 0.8235f; - fArray[1] = 0.0462f; fArray[4] = 0.6948f; - fArray[2] = 0.0971f; fArray[5] = 0.3171f; - Matrix B(3,2,fArray); - - fArray[0] = 0.2867f; fArray[2] = 1.2913f; - fArray[1] = 0.1266f; fArray[3] = 0.4520f; - Matrix D0(2,2,fArray); - - fArray[0] = 0.2657f; fArray[2] = 1.0923f; - fArray[1] = 0.3636f; fArray[3] = 0.6416f; - Matrix D1(2,2,fArray); - - Matrix C((size_t)2, (size_t)2); - C.SetValue(0.0f); - C.AddColumnReshapeProductOf(A, B, false); - Assert::IsTrue(C.IsEqualTo(D0, 0.0001f)); - - C.SetValue(0.0f); - C.AddColumnReshapeProductOf(A, B, true); - Assert::IsTrue(C.IsEqualTo(D1, 0.0001f)); - } - - TEST_METHOD(MatrixCopy) - { - const size_t crow = 3; - const size_t ccol = 2; - // Matrices are stored as column-major so below is 3x2 matrix. - float src[] = { - 1.0f, 3.0f, 4.0f, - 6.0f, 2.0f, 5.0f }; - // REVIEW alexeyk: for now only GPU implementation is available. - int deviceId = 0; - Matrix srcM(crow, ccol, src, matrixFlagNormal, deviceId); - // Test full copy. - CPUMatrix actualM(crow, ccol); - srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); - - std::vector expected = { - 1.0f, 3.0f, 4.0f, - 6.0f, 2.0f, 5.0f }; - Assert::IsTrue(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); - - // Test tile copy. - actualM.Resize(crow - 1, ccol - 1); - actualM.SetValue(std::numeric_limits::quiet_NaN()); - srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); - - expected = { 1.0f, 3.0f }; - Assert::IsTrue(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); - } - - TEST_METHOD(MatrixHasElement) - { - for (int deviceId : { -1, 0 }) - { - const size_t size = 3; - float src[size] = { 0.0f, 1.0f, 2.0f }; - SingleMatrix m1(1, size, src, matrixFlagNormal, deviceId); - Assert::IsTrue(SingleMatrix::HasElement(m1, 1.0f)); - Assert::IsFalse(SingleMatrix::HasElement(m1, -1.0f)); - - float qnan = std::numeric_limits::quiet_NaN(); - Assert::IsFalse(SingleMatrix::HasElement(m1, qnan)); - float posInf = std::numeric_limits::infinity(); - Assert::IsFalse(SingleMatrix::HasElement(m1, posInf)); - - m1(0, 1) = qnan; - Assert::IsTrue(SingleMatrix::HasElement(m1, qnan)); - - m1(0, 1) = posInf; - Assert::IsTrue(SingleMatrix::HasElement(m1, posInf)); - } - } - - TEST_METHOD(MatrixVectorMax) - { - // Matrices are stored as column-major so below is 3x2 matrix. - float src[] = { - 1.0f, 3.0f, 4.0f, - 6.0f, 2.0f, 5.0f }; - - float expectedIdx[] = { - 2.0f, 1.0f, - 0.0f, 2.0f }; - - float expectedVal[] = { - 4.0f, 3.0f, - 6.0f, 5.0f }; - - for (int deviceId : { -1, AUTOPLACEMATRIX }) - { - Matrix expIdx(2, 2, expectedIdx, matrixFlagNormal, deviceId); - Matrix expVal(2, 2, expectedVal, matrixFlagNormal, deviceId); - - Matrix actual(3, 2, src, matrixFlagNormal, deviceId); - Matrix actualIdx(deviceId); - Matrix actualVal(deviceId); - - int topK = 2; - actual.VectorMax(actualIdx, actualVal, true, topK); - Assert::IsTrue(actualIdx.IsEqualTo(expIdx)); - Assert::IsTrue(actualVal.IsEqualTo(expVal)); - } - } - - TEST_METHOD(MatrixAssignNumOfDiff) - { - float labels[] = { 1.0f, 2.0f, 3.0f }; - - // Matrices are stored as column-major so below is 2x3 matrix. - float topKResults[] = { - 1.0f, 3.0f, - 4.0f, 6.0f, - 2.0f, 3.0f }; - - for (int deviceId : { -1, AUTOPLACEMATRIX }) - { - Matrix lbl(1, 3, labels, matrixFlagNormal, deviceId); - Matrix topKRes(2, 3, topKResults, matrixFlagNormal, deviceId); - - Matrix actual(deviceId); - actual.AssignNumOfDiff(lbl, topKRes, true); - - float expectedDiff = 1.0; - Assert::AreEqual(expectedDiff, actual.Get00Element()); - } - } - - }; -} \ No newline at end of file diff --git a/Tests/UnitTests/MathTests/MathTests.vcxproj b/Tests/UnitTests/MathTests/MathTests.vcxproj index 43e332257e01..1ad2242b445f 100644 --- a/Tests/UnitTests/MathTests/MathTests.vcxproj +++ b/Tests/UnitTests/MathTests/MathTests.vcxproj @@ -124,6 +124,7 @@ + Create Create diff --git a/Tests/UnitTests/MathTests/MatrixTests.cpp b/Tests/UnitTests/MathTests/MatrixTests.cpp new file mode 100644 index 000000000000..caffda35355e --- /dev/null +++ b/Tests/UnitTests/MathTests/MatrixTests.cpp @@ -0,0 +1,953 @@ +// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// +#include "stdafx.h" +#include "../../../Math/Math/Matrix.h" +#include "../../../Math/Math/CPUMatrix.h" +#include "../../../Math/Math/Helpers.h" + +#define IDX2C(i,j,ld) (((j)*(ld))+(i)) // 0 based indexing + +#define SIGNUM(v) ((v) > 0.0f ? 1.0f : -1.0f) +#define SIGNUMZ(v) ((v) == 0.0f ? 0.0f : (SIGNUM(v))) + +using namespace Microsoft::MSR::CNTK; + +namespace Microsoft +{ + namespace MSR + { + namespace CNTK + { + namespace Test + { + BOOST_AUTO_TEST_SUITE(MatrixUnitTests) + + BOOST_AUTO_TEST_CASE(MatrixConstructors) + { + SingleMatrix a0; + SingleMatrix a1(AUTOPLACEMATRIX); + SingleMatrix a2(-1); + SingleMatrix a3(13, 12, AUTOPLACEMATRIX); + + BOOST_CHECK_EQUAL(0, a0.GetNumRows()); + BOOST_CHECK_EQUAL(0, a0.GetNumCols()); + BOOST_CHECK_EQUAL(0, a1.GetNumRows()); + BOOST_CHECK_EQUAL(0, a1.GetNumCols()); + BOOST_CHECK_EQUAL(13, a3.GetNumRows()); + BOOST_CHECK_EQUAL(12, a3.GetNumCols()); + + BOOST_CHECK_EQUAL(a0.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(a1.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(a2.GetDeviceId(), CPUDEVICE); + BOOST_CHECK_EQUAL(a3.GetDeviceId(), c_deviceIdZero); + } + + BOOST_AUTO_TEST_CASE(MatrixMoveTest1) + { + //no moves required + SingleMatrix a; + SingleMatrix b; + b.Resize(50, 100); + + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + BOOST_CHECK_EQUAL(a.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(b.GetDeviceId(), c_deviceIdZero); + + std::swap(a, b); + BOOST_CHECK_EQUAL(a.GetNumRows(), 50); + BOOST_CHECK_EQUAL(a.GetNumCols(), 100); + BOOST_CHECK_EQUAL(a.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(b.GetDeviceId(), c_deviceIdZero); + } + + BOOST_AUTO_TEST_CASE(MatrixMoveTest2) + { + //potentially a move is required + SingleMatrix a; + SingleMatrix b; + b.Resize(50, 100); + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + BOOST_CHECK_EQUAL(a.GetDeviceId(), 0); + BOOST_CHECK_EQUAL(b.GetDeviceId(), 0); + + b(12, 13) = 14; //this will move whole matrix B from GPU to CPU + BOOST_CHECK_EQUAL(b.GetDeviceId(), -1); + + std::swap(a, b); // this will not only swap A and B but will put them to their preferred device (GPU if present) + BOOST_CHECK_EQUAL(a.GetNumRows(), 50); + BOOST_CHECK_EQUAL(a.GetNumCols(), 100); + BOOST_CHECK_EQUAL(b.GetNumRows(), 0); + BOOST_CHECK_EQUAL(b.GetNumCols(), 0); + BOOST_CHECK_EQUAL(a.GetDeviceId(), -1); + BOOST_CHECK_EQUAL(b.GetDeviceId(), 0); + } + + BOOST_AUTO_TEST_CASE(MatrixDeepCopy) + { + //This is deep copy, not move + SingleMatrix a; + SingleMatrix b; + + b.Resize(50, 100); + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + + b = a; + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 0); + BOOST_CHECK_EQUAL(b.GetNumCols(), 0); + + b.Resize(50, 100); + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + + b(2, 3) = 9; + BOOST_CHECK_EQUAL(b(2, 3), 9); + + b = a; + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 0); + BOOST_CHECK_EQUAL(b.GetNumCols(), 0); + } + + BOOST_AUTO_TEST_CASE(MatrixInitZero) + { + SingleMatrix a = SingleMatrix::Zeros(12, 32); + BOOST_CHECK_EQUAL(a.GetNumRows(), 12); + BOOST_CHECK_EQUAL(a.GetNumCols(), 32); + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(a(i, j), 0.0); + } + } + + BOOST_AUTO_TEST_CASE(MatrixInitEye) + { + SingleMatrix a = SingleMatrix::Eye(56); + BOOST_CHECK_EQUAL(a.GetNumRows(), 56); + BOOST_CHECK_EQUAL(a.GetNumCols(), 56); + + foreach_coord(i, j, a) + { + if (i != j) + { + BOOST_CHECK_EQUAL(a(i, j), 0.0); + } + else + { + BOOST_CHECK_EQUAL(a(i, j), 1.0); + } + } + } + + BOOST_AUTO_TEST_CASE(MatrixInitOnes) + { + SingleMatrix a = SingleMatrix::Ones(12, 56); + BOOST_CHECK_EQUAL(a.GetNumRows(), 12); + BOOST_CHECK_EQUAL(a.GetNumCols(), 56); + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(a(i, j), 1.0); + } + } + + BOOST_AUTO_TEST_CASE(MatrixInitGaussianRand) + { + SingleMatrix a = SingleMatrix::RandomGaussian(640, 230, 0.0f, 2.0f, (unsigned long)-1); + BOOST_CHECK_EQUAL(a.GetNumRows(), 640); + BOOST_CHECK_EQUAL(a.GetNumCols(), 230); + + float avg = 0; + foreach_coord(i, j, a) + { + avg += a(i, j); + } + avg /= (640 * 230); + + float std = 0; + foreach_coord(i, j, a) + { + std += ((a(i, j) - avg) * (a(i, j) - avg)); + } + std = sqrt (std / (640 * 230)); + + BOOST_CHECK_LE(fabs(avg), c_epsilonFloatE2); + BOOST_CHECK_LE(fabs(std - 2), c_epsilonFloatE2); + } + + BOOST_AUTO_TEST_CASE(MatrixInitRandomUniform) + { + SingleMatrix a = SingleMatrix::RandomUniform(435, 100, -26.3f, 30.2f); + bool has_small = false; + bool has_big = false; + foreach_coord(i, j, a) + { + BOOST_CHECK(a(i, j) >= -26.3); + BOOST_CHECK(a(i, j) <= 30.2); + if (a(i, j) < -3) + { + has_small = true; + } + if (a(i, j) > 3) + { + has_big = true; + } + } + BOOST_CHECK(has_small); + BOOST_CHECK(has_big); + } + + BOOST_AUTO_TEST_CASE(MatrixInitRandomUniformSeed) + { + SingleMatrix a = SingleMatrix::RandomUniform(429, 1024, -0.01f, 0.01f, 4711uL); + foreach_coord(i, j, a) + { + BOOST_CHECK(a(i, j) >= -0.01 && a(i, j) <= 0.01); + } + + // SingleMatrix b = SingleMatrix::RandomUniform(429, 1024, (float)-0.01, (float) 0.01, (unsigned long)4711); + // BOOST_CHECK(a.IsEqualTo(b)); + } + + BOOST_AUTO_TEST_CASE(MatrixSetValueMethods) + { + //void SetValue(const ElemType v); + SingleMatrix a(32, 12, AUTOPLACEMATRIX); + BOOST_CHECK_EQUAL(32, a.GetNumRows()); + BOOST_CHECK_EQUAL(12, a.GetNumCols()); + BOOST_CHECK_EQUAL(12 * 32, a.GetNumElements()); + float v = -32.3451f; + a.SetValue(v); + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(v, a(i, j)); + } + + //void SetValue(const Matrix& deepCopyFrom); + SingleMatrix b; + b.SetValue(a); + foreach_coord(i, j, b) + { + BOOST_CHECK_EQUAL(v, b(i, j)); + } + + //void SetValue(const size_t numRows, const size_t numCols, ElemType *pArray, const bool srcIsColMajor); + std::array arrVector = { 123.0f, 0.23f, -22.0f, 63.0f, 43.42f, 324.3f, 99912.0f }; + + float *arr = arrVector.data(); + b.SetValue(2, 3, b.GetDeviceId(), arr, matrixFlagNormal); + + SingleMatrix b1; + b1.SetValue(2, 3, b.GetDeviceId(), arr); + foreach_coord(i, j, b1) + { + BOOST_CHECK_EQUAL(arr[IDX2C(i, j, 2)], b(i, j)); + BOOST_CHECK_EQUAL(arr[IDX2C(i, j, 2)], b1(i, j)); + } + + SingleMatrix bbbb = SingleMatrix::Zeros(6, 8); + bbbb.SetColumn(arr, 3); + for (int i = 0; i<6; ++i) + { + BOOST_CHECK_EQUAL(arr[i], bbbb(i, 3)); + } + + //void SetDiagonalValue(const ElemType v); + SingleMatrix c(4, 4, AUTOPLACEMATRIX); + float val = -0.00332f; + c.SetDiagonalValue(val); + foreach_coord(i, j, c) + { + if (i == j) + BOOST_CHECK_EQUAL(val, c(i, j)); + else + BOOST_CHECK_EQUAL(0, c(i, j)); + } + + //void SetDiagonalValue(const Matrix& vector); + SingleMatrix d(4, 1, AUTOPLACEMATRIX); + float val1 = 43.324f; + d.SetValue(val1); + c.SetDiagonalValue(d); + foreach_coord(i, j, c) + { + if (i == j) + BOOST_CHECK_EQUAL(val1, c(i, j)); + else + BOOST_CHECK_EQUAL(0, c(i, j)); + } + + SingleMatrix c1(5, 5, AUTOPLACEMATRIX); + SingleMatrix d1(1, 5, AUTOPLACEMATRIX); + float val2 = 0.53f; + d1 = d1.Transpose(); + d1.SetValue(val2); + c1.SetDiagonalValue(d1); + foreach_coord(i, j, c1) + { + if (i == j) + BOOST_CHECK_EQUAL(val2, c1(i, j)); + else + BOOST_CHECK_EQUAL(0, c1(i, j)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixTransposeTest) + { + SingleMatrix a = SingleMatrix::RandomGaussian(64, 23, 0, 2); + BOOST_CHECK_EQUAL(64, a.GetNumRows()); + BOOST_CHECK_EQUAL(23, a.GetNumCols()); + + SingleMatrix b = a.Transpose(); + + BOOST_CHECK_EQUAL(23, b.GetNumRows()); + BOOST_CHECK_EQUAL(64, b.GetNumCols()); + + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(a(i, j), b(j, i)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixMultiAndDiv) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m00(2, 3, AUTOPLACEMATRIX); + m00(0, 0) = 10; m00(0, 1) = 20; m00(0, 2) = 30; + m00(1, 0) = 40; m00(1, 1) = 50; m00(1, 2) = 60; + + SingleMatrix m1(2, 3, AUTOPLACEMATRIX); + m1.Reshape(3, 2); + m1(0, 0) = 11; m1(0, 1) = 15; + m1(1, 0) = 14; m1(1, 1) = 13; + m1(2, 0) = 12; m1(2, 1) = 16; + + SingleMatrix m2(2, 2, AUTOPLACEMATRIX); + m2(0, 0) = 75; m2(0, 1) = 89; + m2(1, 0) = 186; m2(1, 1) = 221; + + SingleMatrix m3 = m0 * m1; + BOOST_CHECK(m3.IsEqualTo(m2)); + + m3 = m0 * 10; + BOOST_CHECK(m3.IsEqualTo(m00)); + + m3 = m3 / 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + m3 *= 10; + BOOST_CHECK(m3.IsEqualTo(m00)); + + m3 /= 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + SingleMatrix::MultiplyAndWeightedAdd(1, m0, false, m1, false, 0, m3); + BOOST_CHECK(m3.IsEqualTo(m2)); + + m1.Reshape(2, 3); + SingleMatrix::MultiplyAndWeightedAdd(1, m0, false, m1, true, 0, m3); + m2(0, 0) = 74; m2(0, 1) = 92; + m2(1, 0) = 182; m2(1, 1) = 227; + BOOST_CHECK(m3.IsEqualTo(m2)); + + SingleMatrix::MultiplyAndWeightedAdd(10, m0, false, m1, true, 2, m3); + m2(0, 0) = 888; m2(0, 1) = 1104; + m2(1, 0) = 2184; m2(1, 1) = 2724; + BOOST_CHECK(m3.IsEqualTo(m2)); + + SingleMatrix::MultiplyAndWeightedAdd(1, m0, true, m1, false, 0, m3); + m2.Resize(3, 3); + m2(0, 0) = 67; m2(0, 1) = 72; m2(0, 2) = 77; + m2(1, 0) = 92; m2(1, 1) = 99; m2(1, 2) = 106; + m2(2, 0) = 117; m2(2, 1) = 126; m2(2, 2) = 135; + BOOST_CHECK(m3.IsEqualTo(m2)); + + //Multiplications of arbitrary matrix with 1x1 matrix + + SingleMatrix a(2, 3, AUTOPLACEMATRIX); + a(0, 0) = 1; a(0, 1) = 2; a(0, 2) = 3; + a(1, 0) = 4; a(1, 1) = 5; a(1, 2) = 6; + + SingleMatrix b = SingleMatrix::Eye(1); + + SingleMatrix c = a * b; + BOOST_CHECK(c.IsEqualTo(a)); + c = b * a; + BOOST_CHECK(c.IsEqualTo(a)); + b(0, 0) = 0.5; + b.InplaceAbs(); + c = a * b; + + SingleMatrix d(2, 3, AUTOPLACEMATRIX); + d(0, 0) = 0.5; d(0, 1) = 1; d(0, 2) = 1.5; + d(1, 0) = 2; d(1, 1) = 2.5; d(1, 2) = 3; + BOOST_CHECK(c.IsEqualTo(d)); + } + + BOOST_AUTO_TEST_CASE(MatrixTranspose) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m1(3, 2, AUTOPLACEMATRIX); + m1(0, 0) = 1; m1(0, 1) = 4; + m1(1, 0) = 2; m1(1, 1) = 5; + m1(2, 0) = 3; m1(2, 1) = 6; + + SingleMatrix m2 = m0.Transpose(); + BOOST_CHECK(m2.IsEqualTo(m1, c_epsilonFloatE4)); + + m2.AssignTransposeOf(m1); + BOOST_CHECK(m2.IsEqualTo(m0, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixAddAndSub) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m1(2, 3, AUTOPLACEMATRIX); + m1(0, 0) = 11; m1(0, 1) = 12; m1(0, 2) = 13; + m1(1, 0) = 14; m1(1, 1) = 15; m1(1, 2) = 16; + + SingleMatrix m2(2, 3, AUTOPLACEMATRIX); + m2(0, 0) = 12; m2(0, 1) = 14; m2(0, 2) = 16; + m2(1, 0) = 18; m2(1, 1) = 20; m2(1, 2) = 22; + + SingleMatrix m3 = m2 - m0; + BOOST_CHECK(m3.IsEqualTo(m1)); + + m3 += m0; + BOOST_CHECK(m3.IsEqualTo(m2)); + + m3 = m0 + 10; + BOOST_CHECK(m3.IsEqualTo(m1)); + + m3 -= 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + m3 = m1 + m0; + BOOST_CHECK(m3.IsEqualTo(m2)); + SingleMatrix m4 = SingleMatrix::Eye(3); + + m3 -= m0; + BOOST_CHECK(m3.IsEqualTo(m1)); + + m3 = m1 - 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + SingleMatrix m33(m3); + m3 += 10; + BOOST_CHECK(m3.IsEqualTo(m1)); + + SingleMatrix m55 = SingleMatrix::Eye(1); + m55(0, 0) = 10; + m55.InplaceAbs(); + m33 += m55; + BOOST_CHECK(m33.IsEqualTo(m1)); + m33 -= 10; + m33 = m33 + 10; + BOOST_CHECK(m33.IsEqualTo(m1)); + } + + BOOST_AUTO_TEST_CASE(MatrixElementOps) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m00(2, 3, AUTOPLACEMATRIX); + m00(0, 0) = 1.0f; m00(0, 1) = static_cast (1 / 2.0); m00(0, 2) = static_cast (1 / 3.0); + m00(1, 0) = static_cast (1 / 4.0); m00(1, 1) = static_cast(1 / 5.0); m00(1, 2) = static_cast(1 / 6.0); + + SingleMatrix m1(2, 3, AUTOPLACEMATRIX); + m1(0, 0) = 1; m1(0, 1) = 1; m1(0, 2) = 1; + m1(1, 0) = 1; m1(1, 1) = 1; m1(1, 2) = 1; + + SingleMatrix m3; + m3.AssignElementProductOf(m0, m00); + BOOST_CHECK(m3.IsEqualTo(m1, c_epsilonFloatE4)); + + SingleMatrix m4 = SingleMatrix::Zeros(2, 3); + m4 = m4.AddElementProductOf(m0, m00); + BOOST_CHECK(m4.IsEqualTo(m1, c_epsilonFloatE4)); + + m3 = m0 ^ 4; + SingleMatrix m2(2, 3, AUTOPLACEMATRIX); + m2(0, 0) = 1; m2(0, 1) = 16; m2(0, 2) = 81; + m2(1, 0) = 256; m2(1, 1) = 625; m2(1, 2) = 1296; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3 ^= 4; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3.ElementMultiplyWith(m00); + BOOST_CHECK(m3.IsEqualTo(m1, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3.ElementInverse(); + BOOST_CHECK(m3.IsEqualTo(m00, c_epsilonFloatE3)); + + m2(0, 0) = 0.7311f; m2(0, 1) = 0.8808f; m2(0, 2) = 0.9526f; + m2(1, 0) = 0.9820f; m2(1, 1) = 0.9933f; m2(1, 2) = 0.9975f; + m3.AssignElementDivisionOf(m2, m0); + m2.ElementMultiplyWith(m00); + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceSigmoid(); + m2(0, 0) = 0.7311f; m2(0, 1) = 0.8808f; m2(0, 2) = 0.9526f; + m2(1, 0) = 0.9820f; m2(1, 1) = 0.9933f; m2(1, 2) = 0.9975f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceTanh(); + m2(0, 0) = 0.7616f; m2(0, 1) = 0.9640f; m2(0, 2) = 0.9951f; + m2(1, 0) = 0.9993f; m2(1, 1) = 0.9999f; m2(1, 2) = 1.0000f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceLogSoftmax(true); + m3.InplaceExp(); + m2(0, 0) = 0.0474f; m2(0, 1) = 0.0474f; m2(0, 2) = 0.0474f; + m2(1, 0) = 0.9526f; m2(1, 1) = 0.9526f; m2(1, 2) = 0.9526f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceLogSoftmax(false); + m3.InplaceExp(); + m2(0, 0) = 0.0900f; m2(0, 1) = 0.2447f; m2(0, 2) = 0.6652f; + m2(1, 0) = 0.0900f; m2(1, 1) = 0.2447f; m2(1, 2) = 0.6652f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceHardmax(true); + m2(0, 0) = 0.0f; m2(0, 1) = 0.0f; m2(0, 2) = 0.0f; + m2(1, 0) = 1.0f; m2(1, 1) = 1.0f; m2(1, 2) = 1.0f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceSqrt(); + m2(0, 0) = 1.0f; m2(0, 1) = 1.4142f; m2(0, 2) = 1.7321f; + m2(1, 0) = 2.0f; m2(1, 1) = 2.2361f; m2(1, 2) = 2.4495f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceExp(); + m2(0, 0) = 2.7183f; m2(0, 1) = 7.3891f; m2(0, 2) = 20.0855f; + m2(1, 0) = 54.5982f; m2(1, 1) = 148.4132f; m2(1, 2) = 403.4288f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceExp(); + m2(0, 0) = 2.7183f; m2(0, 1) = 7.3891f; m2(0, 2) = 20.0855f; + m2(1, 0) = 54.5982f; m2(1, 1) = 148.4132f; m2(1, 2) = 403.4288f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.InplaceLog(); + BOOST_CHECK(m3.IsEqualTo(m0, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceTruncateBottom(2); + m2(0, 0) = 2; m2(0, 1) = 2; m2(0, 2) = 3; + m2(1, 0) = 4; m2(1, 1) = 5; m2(1, 2) = 6; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3.InplaceTruncateTop(4); + m2(0, 0) = 1; m2(0, 1) = 2; m2(0, 2) = 3; + m2(1, 0) = 4; m2(1, 1) = 4; m2(1, 2) = 4; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + } + + BOOST_AUTO_TEST_CASE(MatrixColumnElementMultiply) + { + CPUMatrix mcpu = CPUMatrix::RandomUniform(429, 1024, -3.4f, 1); + CPUMatrix acpu = CPUMatrix::Ones(429, 1); + CPUMatrix mcpuCopy(mcpu); + + mcpu.ColumnElementMultiplyWith(acpu); + BOOST_CHECK(mcpuCopy.IsEqualTo(mcpu, c_epsilonFloatE4)); + + Matrix m = Matrix::RandomUniform(429, 1024, -3.4f, 1); + Matrix a = Matrix::Ones(429, 1); + Matrix mCopy(m); + + m.ColumnElementMultiplyWith(a); + BOOST_CHECK(mCopy.IsEqualTo(m, c_epsilonFloatE4)); + + CPUMatrix mc1 = CPUMatrix::RandomUniform(429, 1024, -3.4f, 1); + CPUMatrix mc2 = CPUMatrix::RandomUniform(429, 1, 0, 3); + mc1.ColumnElementMultiplyWith(mc2); + + Matrix m1(mc1.GetNumRows(), mc1.GetNumCols(), mc1.GetArray(), matrixFlagNormal); + Matrix m2(mc2.GetNumRows(), mc2.GetNumCols(), mc2.GetArray(), matrixFlagNormal); + m1.ColumnElementMultiplyWith(m2); + + foreach_coord(i, j, m2) + { + BOOST_CHECK_LT(fabs(m2(i, j) - mc2(i, j)), c_epsilonFloatE5); + } + } + + BOOST_AUTO_TEST_CASE(MatrixAssignXOf) + { + //AssignDifferenceOf + Matrix a = Matrix::RandomUniform(429, 1024, 5, 32); + Matrix b = Matrix::RandomUniform(429, 1024, 5, 32); + Matrix c; + + c.AssignDifferenceOf(a, b); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), a(i, j) - b(i, j)); + } + + float x = 234.2f; + c.AssignDifferenceOf(a, x); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), a(i, j) - x); + } + + c.AssignDifferenceOf(x, a); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), x - a(i, j)); + } + + c.AssignDifferenceOf(1, a); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), 1 - a(i, j)); + } + // + + //AssignElementProductOf + c.AssignElementProductOf(a, b); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), a(i, j) * b(i, j)); + } + + //AddElementProductOf + Matrix c_copy(c); + c.AddElementProductOf(a, b); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), c_copy(i, j) + a(i, j) * b(i, j)); + } + + //AssignSigmoidOf + CPUMatrix ac = CPUMatrix::RandomUniform(429, 1024, 5, 32); + CPUMatrix bc = CPUMatrix::RandomUniform(429, 1024, -5, 12); + Matrix d(ac.GetNumRows(), ac.GetNumCols(), ac.GetArray(), matrixFlagNormal); + Matrix e(bc.GetNumRows(), bc.GetNumCols(), bc.GetArray(), matrixFlagNormal); + ac.AssignSigmoidOf(bc); + d.AssignSigmoidOf(e); + foreach_coord(i, j, ac) + { + BOOST_CHECK_LT(fabs(ac(i, j) - d(i, j)), c_epsilonFloatE5); + } + + //AssignSignOf + Matrix m1 = Matrix::RandomUniform(42, 12, -5, 12); + Matrix m2(4, 5, AUTOPLACEMATRIX); + m2.AssignSignOf(m1); + foreach_coord(i, j, m1) + { + float v = m1(i, j); + float expected = SIGNUMZ(v); + float actual = m2(i, j); + BOOST_CHECK_EQUAL(expected, actual); + } + + Matrix m3 = Matrix::RandomUniform(42, 12, -5, 2); + Matrix m4(m3); + m3.AddSignOf(m1); + foreach_coord(i, j, m3) + { + float v = m1(i, j); + BOOST_CHECK_EQUAL(m4(i, j) + SIGNUMZ(v), m3(i, j)); + } + + //AssignTruncateBottom and Top + Matrix m5(2, 2, AUTOPLACEMATRIX); + m5(0, 0) = 1; m5(0, 1) = 2; + m5(1, 0) = 3; m5(1, 1) = 4; + + Matrix m6; + m6.AssignTruncateBottomOf(m5, 3); + BOOST_CHECK_EQUAL(3, m6(0, 0)); + BOOST_CHECK_EQUAL(3, m6(0, 1)); + BOOST_CHECK_EQUAL(3, m6(1, 0)); + BOOST_CHECK_EQUAL(4, m6(1, 1)); + + + Matrix m7; + m7.AssignTruncateTopOf(m5, 3); + BOOST_CHECK_EQUAL(1, m7(0, 0)); + BOOST_CHECK_EQUAL(2, m7(0, 1)); + BOOST_CHECK_EQUAL(3, m7(1, 0)); + BOOST_CHECK_EQUAL(3, m7(1, 1)); + } + + BOOST_AUTO_TEST_CASE(MatrixSumOfElements) + { + Matrix m = Matrix::Ones(429, 1024, 0); + float sum = m.SumOfElements(); + BOOST_CHECK_EQUAL(429 * 1024, sum); + + CPUMatrix mcpu = CPUMatrix::Ones(429, 1024); + float sumCPU = mcpu.SumOfElements(); + BOOST_CHECK_EQUAL(429 * 1024, sumCPU); + + Matrix m1 = Matrix::Ones(42, 332); + m1 *= -1; + float sum1 = m1.SumOfElements(); + BOOST_CHECK_EQUAL(-1 * 42 * 332, sum1); + + Matrix m2 = Matrix::Ones(3, 2); + m2 *= -1; + float sum2 = m2.SumOfElements(); + BOOST_CHECK_EQUAL(-1 * 3 * 2, sum2); + } + + BOOST_AUTO_TEST_CASE(MatrixColumnSlice) + { + std::array arr = { 1, 2, 3, 4, 5, 6 }; + auto * fArray = arr.data(); + + Matrix m0(2, 3, fArray, matrixFlagNormal); + + Matrix m1(2, 2, fArray, matrixFlagNormal); + + Matrix m2 = m0.ColumnSlice(0, 2); + BOOST_CHECK(m2.IsEqualTo(m1, c_epsilonFloatE4)); + + Matrix m3(2, 2, fArray + 2, matrixFlagNormal); + + m2 = m0.ColumnSlice(1, 2); + BOOST_CHECK(m2.IsEqualTo(m3, c_epsilonFloatE4)); + + size_t k = 100, n = 20, m = 50; + + Matrix ag(k, n, AUTOPLACEMATRIX); + ag.SetUniformRandomValue(-1, 1); + + Matrix bg(n, m, AUTOPLACEMATRIX); + bg.SetUniformRandomValue(-1, 1); + + Matrix cg(k, m, AUTOPLACEMATRIX); + cg.SetUniformRandomValue(-1, 1); + + Matrix dg(k, m, AUTOPLACEMATRIX); + dg.SetValue(cg); + + Matrix::MultiplyAndAdd(ag, false, bg, false, dg); + + for (int i = 0; i colBg = bg.ColumnSlice(i, 1); + Matrix colCg = cg.ColumnSlice(i, 1); + Matrix::MultiplyAndAdd(ag, false, colBg, false, colCg); + } + BOOST_CHECK(cg.IsEqualTo(dg, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixKhatriRaoProduct) + { + std::array arr = + { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 }; + + auto *fArray = arr.data(); + fArray[0] = 0.8147f; fArray[3] = 0.9134f; fArray[6] = 0.2785f; fArray[9] = 0.9649f; + fArray[1] = 0.9058f; fArray[4] = 0.6324f; fArray[7] = 0.5469f; fArray[10] = 0.1576f; + fArray[2] = 0.1270f; fArray[5] = 0.0975f; fArray[8] = 0.9575f; fArray[11] = 0.9706f; + Matrix a(3, 4, fArray); + + fArray[0] = 0.9572f; fArray[2] = 0.8003f; fArray[4] = 0.4218f; fArray[6] = 0.7922f; + fArray[1] = 0.4854f; fArray[3] = 0.1419f; fArray[5] = 0.9157f; fArray[7] = 0.9595f; + Matrix b(2, 4, fArray); + + fArray[0] = 0.7798f; fArray[6] = 0.7310f; fArray[12] = 0.1175f; fArray[18] = 0.7644f; + fArray[1] = 0.8670f; fArray[7] = 0.5061f; fArray[13] = 0.2307f; fArray[19] = 0.1249f; + fArray[2] = 0.1215f; fArray[8] = 0.0781f; fArray[14] = 0.4038f; fArray[20] = 0.7689f; + fArray[3] = 0.3954f; fArray[9] = 0.1296f; fArray[15] = 0.2550f; fArray[21] = 0.9258f; + fArray[4] = 0.4396f; fArray[10] = 0.0897f; fArray[16] = 0.5008f; fArray[22] = 0.1512f; + fArray[5] = 0.0616f; fArray[11] = 0.0138f; fArray[17] = 0.8768f; fArray[23] = 0.9313f; + Matrix d(6, 4, fArray); + + Matrix c; + c.AssignKhatriRaoProductOf(a, b); + BOOST_CHECK(c.IsEqualTo(d, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixAddColumnReshapeProductOf) + { + std::array arr = + { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 }; + + auto *fArray = arr.data(); + fArray[0] = 0.6557f; fArray[6] = 0.7431f; + fArray[1] = 0.0357f; fArray[7] = 0.3922f; + fArray[2] = 0.8491f; fArray[8] = 0.6555f; + fArray[3] = 0.9340f; fArray[9] = 0.1712f; + fArray[4] = 0.6787f; fArray[10] = 0.7060f; + fArray[5] = 0.7577f; fArray[11] = 0.0318f; + Matrix a(6, 2, fArray); + + fArray[0] = 0.2769f; fArray[3] = 0.8235f; + fArray[1] = 0.0462f; fArray[4] = 0.6948f; + fArray[2] = 0.0971f; fArray[5] = 0.3171f; + Matrix b(3, 2, fArray); + + fArray[0] = 0.2867f; fArray[2] = 1.2913f; + fArray[1] = 0.1266f; fArray[3] = 0.4520f; + Matrix d0(2, 2, fArray); + + fArray[0] = 0.2657f; fArray[2] = 1.0923f; + fArray[1] = 0.3636f; fArray[3] = 0.6416f; + Matrix d1(2, 2, fArray); + + Matrix c(2, 2, AUTOPLACEMATRIX); + c.SetValue(0.0f); + c.AddColumnReshapeProductOf(a, b, false); + BOOST_CHECK(c.IsEqualTo(d0, c_epsilonFloatE4)); + + c.SetValue(0.0f); + c.AddColumnReshapeProductOf(a, b, true); + BOOST_CHECK(c.IsEqualTo(d1, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixCopy) + { + const size_t crow = 3; + const size_t ccol = 2; + // Matrices are stored as column-major so below is 3x2 matrix. + float src[] = { + 1.0f, 3.0f, 4.0f, + 6.0f, 2.0f, 5.0f }; + + Matrix srcM(crow, ccol, src, matrixFlagNormal, c_deviceIdZero); + // Test full copy. + CPUMatrix actualM(crow, ccol); + srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); + + std::vector expected = { + 1.0f, 3.0f, 4.0f, + 6.0f, 2.0f, 5.0f }; + BOOST_CHECK(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); + + // Test tile copy. + actualM.Resize(crow - 1, ccol - 1); + actualM.SetValue(std::numeric_limits::quiet_NaN()); + srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); + + expected = { 1.0f, 3.0f }; + BOOST_CHECK(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); + } + + BOOST_AUTO_TEST_CASE(MatrixHasElement) + { + for (auto deviceId : { CPUDEVICE, c_deviceIdZero }) + { + const size_t size = 3; + float src[size] = { 0.0f, 1.0f, 2.0f }; + SingleMatrix m1(1, size, src, matrixFlagNormal, deviceId); + BOOST_CHECK(SingleMatrix::HasElement(m1, 1.0f)); + BOOST_CHECK(!SingleMatrix::HasElement(m1, -1.0f)); + + auto qnan = std::numeric_limits::quiet_NaN(); + BOOST_CHECK(!SingleMatrix::HasElement(m1, qnan)); + auto posInf = std::numeric_limits::infinity(); + BOOST_CHECK(!SingleMatrix::HasElement(m1, posInf)); + + m1(0, 1) = qnan; + BOOST_CHECK(SingleMatrix::HasElement(m1, qnan)); + + m1(0, 1) = posInf; + BOOST_CHECK(SingleMatrix::HasElement(m1, posInf)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixVectorMax) + { + // Matrices are stored as column-major so below is 3x2 matrix. + float src[] = { + 1.0f, 3.0f, 4.0f, + 6.0f, 2.0f, 5.0f }; + + float expectedIdx[] = { + 2.0f, 1.0f, + 0.0f, 2.0f }; + + float expectedVal[] = { + 4.0f, 3.0f, + 6.0f, 5.0f }; + + for (auto deviceId : { CPUDEVICE, AUTOPLACEMATRIX }) + { + Matrix expIdx(2, 2, expectedIdx, matrixFlagNormal, deviceId); + Matrix expVal(2, 2, expectedVal, matrixFlagNormal, deviceId); + + Matrix actual(3, 2, src, matrixFlagNormal, deviceId); + Matrix actualIdx(deviceId); + Matrix actualVal(deviceId); + + auto topK = 2; + actual.VectorMax(actualIdx, actualVal, true, topK); + BOOST_CHECK(actualIdx.IsEqualTo(expIdx)); + BOOST_CHECK(actualVal.IsEqualTo(expVal)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixAssignNumOfDiff) + { + float labels[] = { 1.0f, 2.0f, 3.0f }; + + // Matrices are stored as column-major so below is 2x3 matrix. + float topKResults[] = { + 1.0f, 3.0f, + 4.0f, 6.0f, + 2.0f, 3.0f }; + + for (auto deviceId : { CPUDEVICE, AUTOPLACEMATRIX }) + { + Matrix lbl(1, 3, labels, matrixFlagNormal, deviceId); + Matrix topKRes(2, 3, topKResults, matrixFlagNormal, deviceId); + + Matrix actual(deviceId); + actual.AssignNumOfDiff(lbl, topKRes, true); + + float expectedDiff = 1.0; + BOOST_CHECK_EQUAL(expectedDiff, actual.Get00Element()); + } + } + BOOST_AUTO_TEST_SUITE_END() + } + } + } +} \ No newline at end of file diff --git a/Tests/UnitTests/MathTests/constant.cpp b/Tests/UnitTests/MathTests/constant.cpp deleted file mode 100644 index 7925d1afe0ca..000000000000 --- a/Tests/UnitTests/MathTests/constant.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// -#include "stdafx.h" - -const int c_deviceIdZero = 0; - -const float c_epsilonFloatE5 = 0.00001f; - diff --git a/Tests/UnitTests/MathTests/constant.h b/Tests/UnitTests/MathTests/constant.h deleted file mode 100644 index 9d408957df60..000000000000 --- a/Tests/UnitTests/MathTests/constant.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#pragma once - -extern const int c_deviceIdZero; - -extern const float c_epsilonFloatE5; \ No newline at end of file diff --git a/Tests/UnitTests/MathTests/constants.cpp b/Tests/UnitTests/MathTests/constants.cpp index dd17710455f4..272810daf7c8 100644 --- a/Tests/UnitTests/MathTests/constants.cpp +++ b/Tests/UnitTests/MathTests/constants.cpp @@ -10,3 +10,4 @@ const int c_deviceIdZero = 0; const float c_epsilonFloatE5 = 0.00001f; const float c_epsilonFloatE4 = 0.0001f; const float c_epsilonFloatE3 = 0.001f; +const float c_epsilonFloatE2 = 0.01f; \ No newline at end of file diff --git a/Tests/UnitTests/MathTests/constants.h b/Tests/UnitTests/MathTests/constants.h index f32510701560..cdcc5e250dfd 100644 --- a/Tests/UnitTests/MathTests/constants.h +++ b/Tests/UnitTests/MathTests/constants.h @@ -9,4 +9,5 @@ extern const int c_deviceIdZero; extern const float c_epsilonFloatE5; extern const float c_epsilonFloatE4; -extern const float c_epsilonFloatE3; \ No newline at end of file +extern const float c_epsilonFloatE3; +extern const float c_epsilonFloatE2; \ No newline at end of file From 35739887da0b3d9786196c57b787681015c55529 Mon Sep 17 00:00:00 2001 From: Wolfgang Manousek Date: Wed, 18 Nov 2015 09:49:55 +0100 Subject: [PATCH 2/2] Add Math/CNTKMathTest/MatrixUnitTests to Tests/UnitTests/MathTests/MathTests cleanup files in Math/CNTKMathTest/CNTKMathTest and Tests/UnitTests/MathTests/MathTests minor change in Scripts/run_boost_unit_tests to log only error --- Math/CNTKMathTest/CNTKMathTest.vcxproj | 1 - Math/CNTKMathTest/MatrixUnitTests.cpp | 886 ------------------ Scripts/run_boost_unit_tests.py | 2 +- Tests/UnitTests/MathTests/MathTests.vcxproj | 1 + Tests/UnitTests/MathTests/MatrixTests.cpp | 953 ++++++++++++++++++++ Tests/UnitTests/MathTests/constant.cpp | 11 - Tests/UnitTests/MathTests/constant.h | 9 - Tests/UnitTests/MathTests/constants.cpp | 1 + Tests/UnitTests/MathTests/constants.h | 3 +- 9 files changed, 958 insertions(+), 909 deletions(-) delete mode 100644 Math/CNTKMathTest/MatrixUnitTests.cpp create mode 100644 Tests/UnitTests/MathTests/MatrixTests.cpp delete mode 100644 Tests/UnitTests/MathTests/constant.cpp delete mode 100644 Tests/UnitTests/MathTests/constant.h diff --git a/Math/CNTKMathTest/CNTKMathTest.vcxproj b/Math/CNTKMathTest/CNTKMathTest.vcxproj index 7dbe33f79b3b..88d23cf84b8a 100644 --- a/Math/CNTKMathTest/CNTKMathTest.vcxproj +++ b/Math/CNTKMathTest/CNTKMathTest.vcxproj @@ -114,7 +114,6 @@ - Create Create diff --git a/Math/CNTKMathTest/MatrixUnitTests.cpp b/Math/CNTKMathTest/MatrixUnitTests.cpp deleted file mode 100644 index aa9cec15cc43..000000000000 --- a/Math/CNTKMathTest/MatrixUnitTests.cpp +++ /dev/null @@ -1,886 +0,0 @@ -// -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// -#include "stdafx.h" -#include "CppUnitTest.h" -#include "..\Math\Matrix.h" -#include "..\Math\CPUMatrix.h" -#include "..\Math\GPUMatrix.h" -#include "..\Math\CPUSparseMatrix.h" -#include "..\Math\GPUSparseMatrix.h" -#include "..\Math\Helpers.h" - -#pragma warning (disable: 4244 4245 4305) // conversions and truncations; we don't care in this test project - -#define epsilon 0.000001 -#define IDX2C(i,j,ld) (((j)*(ld))+(i)) // 0 based indexing - -using namespace Microsoft::MSR::CNTK; -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - - -namespace CNTKMathTest -{ - TEST_CLASS(MatrixUnitTest) - { - - public: - - //This test should fail if you don't have CUDA GPU (or working under remote desktop) - TEST_METHOD(MatrixConsturctors) - { - SingleMatrix A0; - SingleMatrix A1(AUTOPLACEMATRIX); - SingleMatrix A2(-1); - SingleMatrix A3((size_t)13,(size_t)12,(DEVICEID_TYPE)0); - - Assert::AreEqual(0,A0.GetNumRows()); - Assert::AreEqual(0,A0.GetNumCols()); - Assert::AreEqual(0,A1.GetNumRows()); - Assert::AreEqual(0,A2.GetNumCols()); - Assert::AreEqual(13,A3.GetNumRows()); - Assert::AreEqual(12,A3.GetNumCols()); - } - - TEST_METHOD(MatrixMoveTest) - { - //no moves required - SingleMatrix a; - SingleMatrix b; - b.Resize(100,100); - std::swap(a,b); - - //potentially a move is required - SingleMatrix A; - SingleMatrix B; - B.Resize(100,100); - B(12,13)=14; //this will move whole matrix B from GPU to CPU - std::swap(A,B); // this will not only swap A and B but will put them to their preferred device (GPU if present) - - //This is deep copy, not move - SingleMatrix a1; - SingleMatrix b1; - b1.Resize(12,34); - b1=a1; - - SingleMatrix a2; - SingleMatrix b2; - b2.Resize(12,34); - b2(2,3)=9; - b2=a2; - } - - - TEST_METHOD(MatrixAssignmentOperatorsAndInitializers) - { - //Zeros - SingleMatrix A0 = SingleMatrix::Zeros(12,32); - Assert::AreEqual(12,A0.GetNumRows()); - Assert::AreEqual(32,A0.GetNumCols()); - foreach_coord(i,j,A0) - { - Assert::AreEqual(0,A0(i,j)); - } - - //Eye - SingleMatrix A1 = SingleMatrix::Eye(56); - Assert::AreEqual(56,A1.GetNumRows()); - Assert::AreEqual(56,A1.GetNumCols()); - foreach_coord(i,j,A1) - { - if (i!=j) - { - float x = A1(i,j); - Assert::AreEqual(0,x); - } - else - { - float x = A1(i,j); - Assert::AreEqual(1,x); - } - } - - //Ones - SingleMatrix A2 = SingleMatrix::Ones(12,56); - Assert::AreEqual(12,A2.GetNumRows()); - Assert::AreEqual(56,A2.GetNumCols()); - foreach_coord(i,j,A2) - { - Assert::AreEqual(1,A2(i,j)); - } - - //SetGaussianRandomValue - SingleMatrix A3= SingleMatrix::RandomGaussian(640,230,0,2,-1); - float avg = 0; - foreach_coord(i,j,A3) - { - avg+=A3(i,j); - } - avg/=(640*230); - float std=0; - foreach_coord(i,j,A3) - { - std+=((A3(i,j)-avg)*(A3(i,j)-avg)/(640*230)); - } - std=sqrt(std); - //Assert::IsTrue(fabs(avg-0)<0.01); - //WARNING: The deviance seems to be off for both CPU and GPU implementations - //Assert::IsTrue(fabs(std-2)<0.01); - - //RandomUniform - SingleMatrix A4 = SingleMatrix::RandomUniform(435, 100, -26.3, 30.2); - bool has_small=false; - bool has_big=false; - foreach_coord(i,j,A4) - { - Assert::IsTrue((A4(i,j)>=-26.3)&&(A4(i,j)<30.2)); - if (A4(i,j)<-3) - has_small=true; - if (A4(i,j)>3) - has_big=true; - } - Assert::IsTrue(has_small); - Assert::IsTrue(has_big); - - //RandomUniform - SingleMatrix A5((size_t)429,(size_t)1024); - A5.SetUniformRandomValue(-0.01,0.01); - foreach_coord(i,j,A5) - { - Assert::IsTrue(A5(i,j)<=0.01&&A5(i,j)>=-0.01); - } - - //Check that seed allows results reproduce - //!!!WE NOW INITIALIZE SEED PER PROCESS!!! - /* - SingleMatrix A6 = SingleMatrix::RandomUniform(5,6,-1,3,1234); - SingleMatrix A7 = SingleMatrix::RandomUniform(5,6,-1,3,1234); - SingleMatrix A8 = SingleMatrix::RandomUniform(5,6,-1,3,12346); - SingleMatrix A9 = SingleMatrix::RandomUniform(5,6,-1,3); - - Assert::IsTrue(A6.IsEqualTo(A7)); - //Assert::IsTrue(!A8.IsEqualTo(A7)); */ - - } - - TEST_METHOD(MatrixSetValueMethods) - { - //void SetValue(const ElemType v); - SingleMatrix A((size_t)32,(size_t)12); - Assert::AreEqual(32,A.GetNumRows()); - Assert::AreEqual(12,A.GetNumCols()); - Assert::AreEqual(12*32,A.GetNumElements()); - float v= -32.3451; - A.SetValue(v); - foreach_coord(i,j,A) - { - Assert::AreEqual(v,A(i,j)); - } - - //void SetValue(const Matrix& deepCopyFrom); - SingleMatrix B; - B.SetValue(A); - foreach_coord(i,j,B) - { - Assert::AreEqual(v,B(i,j)); - } - - //void SetValue(const size_t numRows, const size_t numCols, ElemType *pArray, const bool srcIsColMajor); - float *arr = new float[6]; - arr[0]=123;arr[1]=0.23;arr[2]=-22;arr[3]=63;arr[4]=43.42; - arr[5]=324.3;arr[6]=99912; - B.SetValue(2,3,B.GetDeviceId(),arr,matrixFlagNormal); - - SingleMatrix B1; - B1.SetValue(2, 3, B.GetDeviceId(), arr); - foreach_coord(i,j,B) - { - Assert::AreEqual(arr[IDX2C(i,j,2)],B(i,j)); - Assert::AreEqual(arr[IDX2C(i,j,2)],B1(i,j)); - } - - SingleMatrix BBBB = SingleMatrix::Zeros(6,8); - BBBB.SetColumn(arr,3); - for (int i=0;i<6;++i) - { - Assert::AreEqual(arr[i],BBBB(i,3)); - } - - - //void SetDiagonalValue(const ElemType v); - SingleMatrix C(4,4,AUTOPLACEMATRIX); - float val = -0.00332; - C.SetDiagonalValue(val); - foreach_coord(i,j,C) - { - if (i==j) - Assert::AreEqual(val,C(i,j)); - else - Assert::AreEqual(0,C(i,j)); - } - - //void SetDiagonalValue(const Matrix& vector); - SingleMatrix D(4,1,AUTOPLACEMATRIX); - float val1=43.324; - D.SetValue(val1); - C.SetDiagonalValue(D); - foreach_coord(i,j,C) - { - if (i==j) - Assert::AreEqual(val1,C(i,j)); - else - Assert::AreEqual(0,C(i,j)); - } - - SingleMatrix C1(5,5,AUTOPLACEMATRIX); - SingleMatrix D1(1,5,AUTOPLACEMATRIX); - float val2=0.53; - D1=D1.Transpose(); - D1.SetValue(val2); - C1.SetDiagonalValue(D1); - foreach_coord(i,j,C1) - { - if (i==j) - Assert::AreEqual(val2,C1(i,j)); - else - Assert::AreEqual(0,C1(i,j)); - } - } - - TEST_METHOD(MatrixTransposeTest) - { - SingleMatrix A= SingleMatrix::RandomGaussian(64,23,0,2); - Assert::AreEqual(64,A.GetNumRows()); - Assert::AreEqual(23,A.GetNumCols()); - - SingleMatrix B=A.Transpose(); - - Assert::AreEqual(23,B.GetNumRows()); - Assert::AreEqual(64,B.GetNumCols()); - - foreach_coord(i,j,A) - { - Assert::AreEqual(A(i,j),B(j,i)); - } - } - - TEST_METHOD(MatrixMultiAndDiv) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M00((size_t)2, (size_t)3); - M00(0,0) = 10; M00(0,1) = 20; M00(0,2) = 30; - M00(1,0) = 40; M00(1,1) = 50; M00(1,2) = 60; - - SingleMatrix M1((size_t)2,(size_t)3); - M1.Reshape(3,2); - M1(0,0) = 11; M1(0,1) = 15; - M1(1,0) = 14; M1(1,1) = 13; - M1(2,0) = 12; M1(2,1) = 16; - - SingleMatrix M2((size_t)2,(size_t)2); - M2(0,0) = 75; M2(0,1) = 89; - M2(1,0) = 186; M2(1,1) = 221; - - SingleMatrix M3 = M0 * M1; - Assert::IsTrue(M3.IsEqualTo(M2)); - - M3 = M0 * 10; - Assert::IsTrue(M3.IsEqualTo(M00)); - - M3 = M3 / 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - M3 *= 10; - Assert::IsTrue(M3.IsEqualTo(M00)); - - M3 /= 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - SingleMatrix::MultiplyAndWeightedAdd(1, M0, false, M1, false, 0, M3); - Assert::IsTrue(M3.IsEqualTo(M2)); - - M1.Reshape(2,3); - SingleMatrix::MultiplyAndWeightedAdd(1, M0, false, M1, true, 0, M3); - M2(0,0) = 74; M2(0,1) = 92; - M2(1,0) = 182; M2(1,1) = 227; - Assert::IsTrue(M3.IsEqualTo(M2)); - - SingleMatrix::MultiplyAndWeightedAdd(10, M0, false, M1, true, 2, M3); - M2(0,0) = 888; M2(0,1) = 1104; - M2(1,0) = 2184; M2(1,1) = 2724; - Assert::IsTrue(M3.IsEqualTo(M2)); - - SingleMatrix::MultiplyAndWeightedAdd(1, M0, true, M1, false, 0, M3); - M2.Resize(3,3); - M2(0,0) = 67; M2(0,1) = 72; M2(0,2) = 77; - M2(1,0) = 92; M2(1,1) = 99; M2(1,2) = 106; - M2(2,0) = 117; M2(2,1) = 126; M2(2,2) = 135; - Assert::IsTrue(M3.IsEqualTo(M2)); - - //Multiplications of arbitrary matrix with 1x1 matrix - - SingleMatrix A((size_t)2,(size_t)3); - A(0,0) = 1; A(0,1) = 2; A(0,2) = 3; - A(1,0) = 4; A(1,1) = 5; A(1,2) = 6; - - SingleMatrix B = SingleMatrix::Eye(1); - - SingleMatrix C=A*B; - Assert::IsTrue(C.IsEqualTo(A)); - C=B*A; - Assert::IsTrue(C.IsEqualTo(A)); - B(0,0)=0.5; - B.InplaceAbs(); - C=A*B; - - SingleMatrix D((size_t)2,(size_t)3); - D(0,0) = 0.5; D(0,1) = 1; D(0,2) = 1.5; - D(1,0) = 2; D(1,1) = 2.5; D(1,2) = 3; - Assert::IsTrue(C.IsEqualTo(D)); - } - - TEST_METHOD(MatrixTranspose) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M1((size_t)3,(size_t)2); - M1(0,0) = 1; M1(0,1) = 4; - M1(1,0) = 2; M1(1,1) = 5; - M1(2,0) = 3; M1(2,1) = 6; - - SingleMatrix M2 = M0.Transpose(); - Assert::IsTrue(M2.IsEqualTo(M1, 0.0001)); - - M2.AssignTransposeOf(M1); - Assert::IsTrue(M2.IsEqualTo(M0, 0.0001)); - } - - TEST_METHOD(MatrixAddAndSub) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M1((size_t)2,(size_t)3); - M1(0,0) = 11; M1(0,1) = 12; M1(0,2) = 13; - M1(1,0) = 14; M1(1,1) = 15; M1(1,2) = 16; - - SingleMatrix M2((size_t)2,(size_t)3); - M2(0,0) = 12; M2(0,1) = 14; M2(0,2) = 16; - M2(1,0) = 18; M2(1,1) = 20; M2(1,2) = 22; - - SingleMatrix M3 = M2 - M0; - Assert::IsTrue(M3.IsEqualTo(M1)); - - M3 += M0; - Assert::IsTrue(M3.IsEqualTo(M2)); - - M3 = M0 + 10; - Assert::IsTrue(M3.IsEqualTo(M1)); - - M3 -= 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - M3 = M1 + M0; - Assert::IsTrue(M3.IsEqualTo(M2)); - SingleMatrix M4=SingleMatrix::Eye(3); - SingleMatrix M5 = M0*M4 + M1; - - M3 -= M0; - Assert::IsTrue(M3.IsEqualTo(M1)); - - M3 = M1 - 10; - Assert::IsTrue(M3.IsEqualTo(M0)); - - SingleMatrix M33(M3); //M4==M3 - M3 += 10; - Assert::IsTrue(M3.IsEqualTo(M1)); - - SingleMatrix M55=SingleMatrix::Eye(1); - M55(0,0)=10; - M55.InplaceAbs(); - M33 += M55;//M5 is 1x1 matrix - Assert::IsTrue(M33.IsEqualTo(M1)); - M33 -= 10; - M33 = M33 + 10; - Assert::IsTrue(M33.IsEqualTo(M1)); - } - - TEST_METHOD(MatrixElementOps) - { - SingleMatrix M0((size_t)2,(size_t)3); - M0(0,0) = 1; M0(0,1) = 2; M0(0,2) = 3; - M0(1,0) = 4; M0(1,1) = 5; M0(1,2) = 6; - - SingleMatrix M00((size_t)2,(size_t)3); - M00(0,0) = 1.0; M00(0,1) = 1/2.0; M00(0,2) = 1/3.0; - M00(1,0) = 1/4.0; M00(1,1) = 1/5.0; M00(1,2) = 1/6.0; - - SingleMatrix M1((size_t)2, (size_t)3); - M1(0,0) = 1; M1(0,1) = 1; M1(0,2) = 1; - M1(1,0) = 1; M1(1,1) = 1; M1(1,2) = 1; - - SingleMatrix M3; - M3.AssignElementProductOf(M0, M00); - Assert::IsTrue(M3.IsEqualTo(M1, 0.0001)); - - SingleMatrix M4=SingleMatrix::Zeros(2,3); - M4 = M4.AddElementProductOf(M0,M00); - Assert::IsTrue(M4.IsEqualTo(M1,0.0001)); - - M3 = M0 ^ 4; - SingleMatrix M2((size_t)2,(size_t)3); - M2(0,0) = 1; M2(0,1) = 16; M2(0,2) = 81; - M2(1,0) = 256; M2(1,1) = 625; M2(1,2) = 1296; - Assert::IsTrue(M3.IsEqualTo(M2,0.001)); - - M3.SetValue(M0); - M3 ^= 4; - Assert::IsTrue(M3.IsEqualTo(M2, 0.001)); - - M3.SetValue(M0); - M3.ElementMultiplyWith(M00); - Assert::IsTrue(M3.IsEqualTo(M1, 0.001)); - - M3.SetValue(M0); - M3.ElementInverse(); - Assert::IsTrue(M3.IsEqualTo(M00, 0.001)); - - M2(0,0) = 0.7311; M2(0,1) = 0.8808; M2(0,2) = 0.9526; - M2(1,0) = 0.9820; M2(1,1) = 0.9933; M2(1,2) = 0.9975; - M3.AssignElementDivisionOf(M2, M0); - M2.ElementMultiplyWith(M00); - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceSigmoid(); - M2(0,0) = 0.7311; M2(0,1) = 0.8808; M2(0,2) = 0.9526; - M2(1,0) = 0.9820; M2(1,1) = 0.9933; M2(1,2) = 0.9975; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceTanh(); - M2(0,0) = 0.7616; M2(0,1) = 0.9640; M2(0,2) = 0.9951; - M2(1,0) = 0.9993; M2(1,1) = 0.9999; M2(1,2) = 1.0000; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceLogSoftmax(true); - M3.InplaceExp(); - M2(0,0) = 0.0474; M2(0,1) = 0.0474; M2(0,2) = 0.0474; - M2(1,0) = 0.9526; M2(1,1) = 0.9526; M2(1,2) = 0.9526; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceLogSoftmax(false); - M3.InplaceExp(); - M2(0,0) = 0.0900; M2(0,1) = 0.2447; M2(0,2) = 0.6652; - M2(1,0) = 0.0900; M2(1,1) = 0.2447; M2(1,2) = 0.6652; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceHardmax(true); - M2(0, 0) = 0.0; M2(0, 1) = 0.0; M2(0, 2) = 0.0; - M2(1, 0) = 1.0; M2(1, 1) = 1.0; M2(1, 2) = 1.0; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceSqrt(); - M2(0,0) = 1; M2(0,1) = 1.4142; M2(0,2) = 1.7321; - M2(1,0) = 2; M2(1,1) = 2.2361; M2(1,2) = 2.4495; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceExp(); - M2(0,0) = 2.7183; M2(0,1) = 7.3891; M2(0,2) = 20.0855; - M2(1,0) = 54.5982; M2(1,1) = 148.4132; M2(1,2) = 403.4288; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.SetValue(M0); - M3.InplaceExp(); - M2(0,0) = 2.7183; M2(0,1) = 7.3891; M2(0,2) = 20.0855; - M2(1,0) = 54.5982; M2(1,1) = 148.4132; M2(1,2) = 403.4288; - Assert::IsTrue(M3.IsEqualTo(M2, 0.0001)); - - M3.InplaceLog(); - Assert::IsTrue(M3.IsEqualTo(M0, 0.0001)); - - M3.SetValue(M0); - M3.InplaceTruncateBottom(2); - M2(0,0) = 2; M2(0,1) = 2; M2(0,2) = 3; - M2(1,0) = 4; M2(1,1) = 5; M2(1,2) = 6; - Assert::IsTrue(M3.IsEqualTo(M2, 0.001)); - - M3.SetValue(M0); - M3.InplaceTruncateTop(4); - M2(0,0) = 1; M2(0,1) = 2; M2(0,2) = 3; - M2(1,0) = 4; M2(1,1) = 4; M2(1,2) = 4; - Assert::IsTrue(M3.IsEqualTo(M2, 0.001)); - } - - TEST_METHOD(MatrixColumnElementMultiplyWithVsCPUMatrix) - { - CPUMatrix MCPU = CPUMatrix::RandomUniform(429,1024,-3.4,1); - CPUMatrix ACPU = CPUMatrix::Ones(429,1); - CPUMatrix MCPU_copy(MCPU); - MCPU.ColumnElementMultiplyWith(ACPU); - Assert::IsTrue(MCPU_copy.IsEqualTo(MCPU,0.0001)); - - // - Matrix M = Matrix::RandomUniform(429,1024,-3.4,1); - Matrix A = Matrix::Ones(429,1); - Matrix M_copy(M); - M.ColumnElementMultiplyWith(A); - Assert::IsTrue(M_copy.IsEqualTo(M,0.0001)); - - CPUMatrix MC1 = CPUMatrix::RandomUniform(429,1024,-3.4,1); - CPUMatrix MC2 = CPUMatrix::RandomUniform(429,1,0,3); - MC1.ColumnElementMultiplyWith(MC2); - - Matrix M1(MC1.GetNumRows(),MC1.GetNumCols(),MC1.GetArray(),matrixFlagNormal); - Matrix M2(MC2.GetNumRows(),MC2.GetNumCols(),MC2.GetArray(),matrixFlagNormal); - M1.ColumnElementMultiplyWith(M2); - - foreach_coord(i,j,M2) - { - Assert::IsTrue(fabs(M2(i,j)-MC2(i,j))<0.00001); - } - } - - TEST_METHOD(MatrixAssignXOf) - { - //AssignDifferenceOf - Matrix A = Matrix::RandomUniform(429,1024,5,32); - Matrix B = Matrix::RandomUniform(429,1024,5,32); - Matrix C; - C.AssignDifferenceOf(A,B); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==A(i,j)-B(i,j)); - } - float x=234.2; - C.AssignDifferenceOf(A,x); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==A(i,j)-x); - } - - C.AssignDifferenceOf(x,A); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==x-A(i,j)); - } - - C.AssignDifferenceOf(1,A); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==1-A(i,j)); - } - // - - //AssignElementProductOf - C.AssignElementProductOf(A,B); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==A(i,j)*B(i,j)); - } - - //AddElementProductOf - Matrix C_copy(C); - C.AddElementProductOf(A,B); - foreach_coord(i,j,C) - { - Assert::IsTrue(C(i,j)==C_copy(i,j)+A(i,j)*B(i,j)); - } - - //AssignSigmoidOf - CPUMatrix AC = CPUMatrix::RandomUniform(429,1024,5,32); - CPUMatrix BC = CPUMatrix::RandomUniform(429,1024,-5,12); - Matrix D(AC.GetNumRows(),AC.GetNumCols(),AC.GetArray(),matrixFlagNormal); - Matrix E(BC.GetNumRows(),BC.GetNumCols(),BC.GetArray(),matrixFlagNormal); - AC.AssignSigmoidOf(BC); - D.AssignSigmoidOf(E); - foreach_coord(i,j,AC) - { - Assert::IsTrue(fabs(AC(i,j)-D(i,j))<0.00001); - } - - //AssignSignOf - Matrix M1 = Matrix::RandomUniform(42,12,-5,12); - Matrix M2((size_t)4, (size_t)5); - M2.AssignSignOf(M1); - foreach_coord(i,j,M1) - { - float v = M1(i,j); - float expected = (v == (float)0? (float)0 : (v > 0? (float)1 : (float)(-1))); - float actual = M2(i,j); - Assert::AreEqual(expected, actual); - } - - Matrix M3 = Matrix::RandomUniform(42,12,-5,2);; - Matrix M4(M3); - M3.AddSignOf(M1); - foreach_coord(i,j,M3) - { - float v = M1(i,j); - Assert::AreEqual(M4(i,j)+(v == (float)0? (float)0 : (v > 0? (float)1 : (float)(-1))),M3(i,j)); - } - - - //AssignTruncateBottom and Top - Matrix M5((size_t)2, (size_t)2); - M5(0,0)=1; M5(0,1)=2; - M5(1,0)=3; M5(1,1)=4; - - Matrix M6; - M6.AssignTruncateBottomOf(M5,3); - Assert::AreEqual(3,M6(0,0)); - Assert::AreEqual(3,M6(0,1)); - Assert::AreEqual(3,M6(1,0)); - Assert::AreEqual(4,M6(1,1)); - - - Matrix M7; - M7.AssignTruncateTopOf(M5,3); - Assert::AreEqual(1,M7(0,0)); - Assert::AreEqual(2,M7(0,1)); - Assert::AreEqual(3,M7(1,0)); - Assert::AreEqual(3,M7(1,1)); - } - - TEST_METHOD(MatrixSum) - { - Matrix M=Matrix::Ones(429,1024,0); - float sum = M.SumOfElements(); - Assert::AreEqual(429*1024,sum); - - CPUMatrix MCPU=CPUMatrix::Ones(429,1024); - float sumCPU = MCPU.SumOfElements(); - Assert::AreEqual(429*1024,sumCPU); - - Matrix M1=Matrix::Ones(42,332); - M1*=-1; - float sum1 = M1.SumOfElements(); - Assert::AreEqual(-1*42*332,sum1); - - Matrix M2=Matrix::Ones(3,2); - M2*=-1; - float sum2 = M2.SumOfElements(); - Assert::AreEqual(-1*3*2,sum2); - } - - TEST_METHOD(MatrixColumnSlice) - { - float *fArray = new float[6]; - fArray[0] = 1; fArray[1] = 4; fArray[2] = 2; - fArray[3] = 5; fArray[4] = 3; fArray[5] = 6; - Matrix M0(2, 3, fArray, matrixFlagNormal); - - Matrix M1(2, 2, fArray, matrixFlagNormal); - - Matrix M2 = M0.ColumnSlice(0,2); - Assert::IsTrue(M2.IsEqualTo(M1, 0.0001)); - - Matrix M3(2, 2, fArray+2, matrixFlagNormal); - - M2 = M0.ColumnSlice(1,2); - Assert::IsTrue(M2.IsEqualTo(M3, 0.0001)); - - - size_t k=100, n=20, m=50; - - Matrix AG((size_t)k,(size_t)n); - AG.SetUniformRandomValue(-1,1); - - Matrix BG((size_t)n,(size_t)m); - BG.SetUniformRandomValue(-1,1); - - Matrix CG((size_t)k,(size_t)m); - CG.SetUniformRandomValue(-1,1); - Matrix DG((size_t)k,(size_t)m); - DG.SetValue(CG); - - Matrix::MultiplyAndAdd(AG, false, BG, false, DG); - - for (int i=0; i col_BG = BG.ColumnSlice(i,1); - Matrix col_CG = CG.ColumnSlice(i,1); - Matrix::MultiplyAndAdd(AG, false, col_BG, false, col_CG); - } - Assert::IsTrue(CG.IsEqualTo(DG, 0.0001)); - } - - TEST_METHOD(MatrixKhatriRaoProduct) - { - float *fArray = new float[24]; - fArray[0] = 0.8147f; fArray[3] = 0.9134f; fArray[6] = 0.2785f; fArray[9] = 0.9649f; - fArray[1] = 0.9058f; fArray[4] = 0.6324f; fArray[7] = 0.5469f; fArray[10] = 0.1576f; - fArray[2] = 0.1270f; fArray[5] = 0.0975f; fArray[8] = 0.9575f; fArray[11] = 0.9706f; - Matrix A(3,4,fArray); - - fArray[0] = 0.9572f; fArray[2] = 0.8003f; fArray[4] = 0.4218f; fArray[6] = 0.7922f; - fArray[1] = 0.4854f; fArray[3] = 0.1419f; fArray[5] = 0.9157f; fArray[7] = 0.9595f; - Matrix B(2,4,fArray); - - fArray[0] = 0.7798f; fArray[6] = 0.7310f; fArray[12] = 0.1175f; fArray[18] = 0.7644f; - fArray[1] = 0.8670f; fArray[7] = 0.5061f; fArray[13] = 0.2307f; fArray[19] = 0.1249f; - fArray[2] = 0.1215f; fArray[8] = 0.0781f; fArray[14] = 0.4038f; fArray[20] = 0.7689f; - fArray[3] = 0.3954f; fArray[9] = 0.1296f; fArray[15] = 0.2550f; fArray[21] = 0.9258f; - fArray[4] = 0.4396f; fArray[10] = 0.0897f; fArray[16] = 0.5008f; fArray[22] = 0.1512f; - fArray[5] = 0.0616f; fArray[11] = 0.0138f; fArray[17] = 0.8768f; fArray[23] = 0.9313f; - Matrix D(6,4, fArray); - - Matrix C; - C.AssignKhatriRaoProductOf(A, B); - Assert::IsTrue(C.IsEqualTo(D, 0.0001f)); - } - TEST_METHOD(MatrixAddColumnReshapeProductOf) - { - float *fArray = new float[12]; - fArray[0] = 0.6557f; fArray[6] = 0.7431f; - fArray[1] = 0.0357f; fArray[7] = 0.3922f; - fArray[2] = 0.8491f; fArray[8] = 0.6555f; - fArray[3] = 0.9340f; fArray[9] = 0.1712f; - fArray[4] = 0.6787f; fArray[10] = 0.7060f; - fArray[5] = 0.7577f; fArray[11] = 0.0318f; - Matrix A(6,2,fArray); - - fArray[0] = 0.2769f; fArray[3] = 0.8235f; - fArray[1] = 0.0462f; fArray[4] = 0.6948f; - fArray[2] = 0.0971f; fArray[5] = 0.3171f; - Matrix B(3,2,fArray); - - fArray[0] = 0.2867f; fArray[2] = 1.2913f; - fArray[1] = 0.1266f; fArray[3] = 0.4520f; - Matrix D0(2,2,fArray); - - fArray[0] = 0.2657f; fArray[2] = 1.0923f; - fArray[1] = 0.3636f; fArray[3] = 0.6416f; - Matrix D1(2,2,fArray); - - Matrix C((size_t)2, (size_t)2); - C.SetValue(0.0f); - C.AddColumnReshapeProductOf(A, B, false); - Assert::IsTrue(C.IsEqualTo(D0, 0.0001f)); - - C.SetValue(0.0f); - C.AddColumnReshapeProductOf(A, B, true); - Assert::IsTrue(C.IsEqualTo(D1, 0.0001f)); - } - - TEST_METHOD(MatrixCopy) - { - const size_t crow = 3; - const size_t ccol = 2; - // Matrices are stored as column-major so below is 3x2 matrix. - float src[] = { - 1.0f, 3.0f, 4.0f, - 6.0f, 2.0f, 5.0f }; - // REVIEW alexeyk: for now only GPU implementation is available. - int deviceId = 0; - Matrix srcM(crow, ccol, src, matrixFlagNormal, deviceId); - // Test full copy. - CPUMatrix actualM(crow, ccol); - srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); - - std::vector expected = { - 1.0f, 3.0f, 4.0f, - 6.0f, 2.0f, 5.0f }; - Assert::IsTrue(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); - - // Test tile copy. - actualM.Resize(crow - 1, ccol - 1); - actualM.SetValue(std::numeric_limits::quiet_NaN()); - srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); - - expected = { 1.0f, 3.0f }; - Assert::IsTrue(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); - } - - TEST_METHOD(MatrixHasElement) - { - for (int deviceId : { -1, 0 }) - { - const size_t size = 3; - float src[size] = { 0.0f, 1.0f, 2.0f }; - SingleMatrix m1(1, size, src, matrixFlagNormal, deviceId); - Assert::IsTrue(SingleMatrix::HasElement(m1, 1.0f)); - Assert::IsFalse(SingleMatrix::HasElement(m1, -1.0f)); - - float qnan = std::numeric_limits::quiet_NaN(); - Assert::IsFalse(SingleMatrix::HasElement(m1, qnan)); - float posInf = std::numeric_limits::infinity(); - Assert::IsFalse(SingleMatrix::HasElement(m1, posInf)); - - m1(0, 1) = qnan; - Assert::IsTrue(SingleMatrix::HasElement(m1, qnan)); - - m1(0, 1) = posInf; - Assert::IsTrue(SingleMatrix::HasElement(m1, posInf)); - } - } - - TEST_METHOD(MatrixVectorMax) - { - // Matrices are stored as column-major so below is 3x2 matrix. - float src[] = { - 1.0f, 3.0f, 4.0f, - 6.0f, 2.0f, 5.0f }; - - float expectedIdx[] = { - 2.0f, 1.0f, - 0.0f, 2.0f }; - - float expectedVal[] = { - 4.0f, 3.0f, - 6.0f, 5.0f }; - - for (int deviceId : { -1, AUTOPLACEMATRIX }) - { - Matrix expIdx(2, 2, expectedIdx, matrixFlagNormal, deviceId); - Matrix expVal(2, 2, expectedVal, matrixFlagNormal, deviceId); - - Matrix actual(3, 2, src, matrixFlagNormal, deviceId); - Matrix actualIdx(deviceId); - Matrix actualVal(deviceId); - - int topK = 2; - actual.VectorMax(actualIdx, actualVal, true, topK); - Assert::IsTrue(actualIdx.IsEqualTo(expIdx)); - Assert::IsTrue(actualVal.IsEqualTo(expVal)); - } - } - - TEST_METHOD(MatrixAssignNumOfDiff) - { - float labels[] = { 1.0f, 2.0f, 3.0f }; - - // Matrices are stored as column-major so below is 2x3 matrix. - float topKResults[] = { - 1.0f, 3.0f, - 4.0f, 6.0f, - 2.0f, 3.0f }; - - for (int deviceId : { -1, AUTOPLACEMATRIX }) - { - Matrix lbl(1, 3, labels, matrixFlagNormal, deviceId); - Matrix topKRes(2, 3, topKResults, matrixFlagNormal, deviceId); - - Matrix actual(deviceId); - actual.AssignNumOfDiff(lbl, topKRes, true); - - float expectedDiff = 1.0; - Assert::AreEqual(expectedDiff, actual.Get00Element()); - } - } - - }; -} \ No newline at end of file diff --git a/Scripts/run_boost_unit_tests.py b/Scripts/run_boost_unit_tests.py index b57247727ac8..7f45bbdfb7b6 100644 --- a/Scripts/run_boost_unit_tests.py +++ b/Scripts/run_boost_unit_tests.py @@ -18,7 +18,7 @@ def runBoostUnitTests(testDir, outputDir): if test.lower().endswith(".exe"): outputFile = os.path.join(outputDir, test + ".xml") print "Running test executable %s with result in %s" % (test, outputFile) - subprocess.check_call([os.path.join(testDir, test), "--log_format=XML", "--log_sink=%s" % outputFile, "--log_level=all", "--report_level=no"]) + subprocess.check_call([os.path.join(testDir, test), "--log_format=XML", "--log_sink=%s" % outputFile, "--log_level=error", "--report_level=no"]) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Runs all boost unit tests in the directory") diff --git a/Tests/UnitTests/MathTests/MathTests.vcxproj b/Tests/UnitTests/MathTests/MathTests.vcxproj index 43e332257e01..1ad2242b445f 100644 --- a/Tests/UnitTests/MathTests/MathTests.vcxproj +++ b/Tests/UnitTests/MathTests/MathTests.vcxproj @@ -124,6 +124,7 @@ + Create Create diff --git a/Tests/UnitTests/MathTests/MatrixTests.cpp b/Tests/UnitTests/MathTests/MatrixTests.cpp new file mode 100644 index 000000000000..caffda35355e --- /dev/null +++ b/Tests/UnitTests/MathTests/MatrixTests.cpp @@ -0,0 +1,953 @@ +// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// +#include "stdafx.h" +#include "../../../Math/Math/Matrix.h" +#include "../../../Math/Math/CPUMatrix.h" +#include "../../../Math/Math/Helpers.h" + +#define IDX2C(i,j,ld) (((j)*(ld))+(i)) // 0 based indexing + +#define SIGNUM(v) ((v) > 0.0f ? 1.0f : -1.0f) +#define SIGNUMZ(v) ((v) == 0.0f ? 0.0f : (SIGNUM(v))) + +using namespace Microsoft::MSR::CNTK; + +namespace Microsoft +{ + namespace MSR + { + namespace CNTK + { + namespace Test + { + BOOST_AUTO_TEST_SUITE(MatrixUnitTests) + + BOOST_AUTO_TEST_CASE(MatrixConstructors) + { + SingleMatrix a0; + SingleMatrix a1(AUTOPLACEMATRIX); + SingleMatrix a2(-1); + SingleMatrix a3(13, 12, AUTOPLACEMATRIX); + + BOOST_CHECK_EQUAL(0, a0.GetNumRows()); + BOOST_CHECK_EQUAL(0, a0.GetNumCols()); + BOOST_CHECK_EQUAL(0, a1.GetNumRows()); + BOOST_CHECK_EQUAL(0, a1.GetNumCols()); + BOOST_CHECK_EQUAL(13, a3.GetNumRows()); + BOOST_CHECK_EQUAL(12, a3.GetNumCols()); + + BOOST_CHECK_EQUAL(a0.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(a1.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(a2.GetDeviceId(), CPUDEVICE); + BOOST_CHECK_EQUAL(a3.GetDeviceId(), c_deviceIdZero); + } + + BOOST_AUTO_TEST_CASE(MatrixMoveTest1) + { + //no moves required + SingleMatrix a; + SingleMatrix b; + b.Resize(50, 100); + + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + BOOST_CHECK_EQUAL(a.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(b.GetDeviceId(), c_deviceIdZero); + + std::swap(a, b); + BOOST_CHECK_EQUAL(a.GetNumRows(), 50); + BOOST_CHECK_EQUAL(a.GetNumCols(), 100); + BOOST_CHECK_EQUAL(a.GetDeviceId(), c_deviceIdZero); + BOOST_CHECK_EQUAL(b.GetDeviceId(), c_deviceIdZero); + } + + BOOST_AUTO_TEST_CASE(MatrixMoveTest2) + { + //potentially a move is required + SingleMatrix a; + SingleMatrix b; + b.Resize(50, 100); + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + BOOST_CHECK_EQUAL(a.GetDeviceId(), 0); + BOOST_CHECK_EQUAL(b.GetDeviceId(), 0); + + b(12, 13) = 14; //this will move whole matrix B from GPU to CPU + BOOST_CHECK_EQUAL(b.GetDeviceId(), -1); + + std::swap(a, b); // this will not only swap A and B but will put them to their preferred device (GPU if present) + BOOST_CHECK_EQUAL(a.GetNumRows(), 50); + BOOST_CHECK_EQUAL(a.GetNumCols(), 100); + BOOST_CHECK_EQUAL(b.GetNumRows(), 0); + BOOST_CHECK_EQUAL(b.GetNumCols(), 0); + BOOST_CHECK_EQUAL(a.GetDeviceId(), -1); + BOOST_CHECK_EQUAL(b.GetDeviceId(), 0); + } + + BOOST_AUTO_TEST_CASE(MatrixDeepCopy) + { + //This is deep copy, not move + SingleMatrix a; + SingleMatrix b; + + b.Resize(50, 100); + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + + b = a; + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 0); + BOOST_CHECK_EQUAL(b.GetNumCols(), 0); + + b.Resize(50, 100); + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 50); + BOOST_CHECK_EQUAL(b.GetNumCols(), 100); + + b(2, 3) = 9; + BOOST_CHECK_EQUAL(b(2, 3), 9); + + b = a; + BOOST_CHECK_EQUAL(a.GetNumRows(), 0); + BOOST_CHECK_EQUAL(a.GetNumCols(), 0); + BOOST_CHECK_EQUAL(b.GetNumRows(), 0); + BOOST_CHECK_EQUAL(b.GetNumCols(), 0); + } + + BOOST_AUTO_TEST_CASE(MatrixInitZero) + { + SingleMatrix a = SingleMatrix::Zeros(12, 32); + BOOST_CHECK_EQUAL(a.GetNumRows(), 12); + BOOST_CHECK_EQUAL(a.GetNumCols(), 32); + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(a(i, j), 0.0); + } + } + + BOOST_AUTO_TEST_CASE(MatrixInitEye) + { + SingleMatrix a = SingleMatrix::Eye(56); + BOOST_CHECK_EQUAL(a.GetNumRows(), 56); + BOOST_CHECK_EQUAL(a.GetNumCols(), 56); + + foreach_coord(i, j, a) + { + if (i != j) + { + BOOST_CHECK_EQUAL(a(i, j), 0.0); + } + else + { + BOOST_CHECK_EQUAL(a(i, j), 1.0); + } + } + } + + BOOST_AUTO_TEST_CASE(MatrixInitOnes) + { + SingleMatrix a = SingleMatrix::Ones(12, 56); + BOOST_CHECK_EQUAL(a.GetNumRows(), 12); + BOOST_CHECK_EQUAL(a.GetNumCols(), 56); + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(a(i, j), 1.0); + } + } + + BOOST_AUTO_TEST_CASE(MatrixInitGaussianRand) + { + SingleMatrix a = SingleMatrix::RandomGaussian(640, 230, 0.0f, 2.0f, (unsigned long)-1); + BOOST_CHECK_EQUAL(a.GetNumRows(), 640); + BOOST_CHECK_EQUAL(a.GetNumCols(), 230); + + float avg = 0; + foreach_coord(i, j, a) + { + avg += a(i, j); + } + avg /= (640 * 230); + + float std = 0; + foreach_coord(i, j, a) + { + std += ((a(i, j) - avg) * (a(i, j) - avg)); + } + std = sqrt (std / (640 * 230)); + + BOOST_CHECK_LE(fabs(avg), c_epsilonFloatE2); + BOOST_CHECK_LE(fabs(std - 2), c_epsilonFloatE2); + } + + BOOST_AUTO_TEST_CASE(MatrixInitRandomUniform) + { + SingleMatrix a = SingleMatrix::RandomUniform(435, 100, -26.3f, 30.2f); + bool has_small = false; + bool has_big = false; + foreach_coord(i, j, a) + { + BOOST_CHECK(a(i, j) >= -26.3); + BOOST_CHECK(a(i, j) <= 30.2); + if (a(i, j) < -3) + { + has_small = true; + } + if (a(i, j) > 3) + { + has_big = true; + } + } + BOOST_CHECK(has_small); + BOOST_CHECK(has_big); + } + + BOOST_AUTO_TEST_CASE(MatrixInitRandomUniformSeed) + { + SingleMatrix a = SingleMatrix::RandomUniform(429, 1024, -0.01f, 0.01f, 4711uL); + foreach_coord(i, j, a) + { + BOOST_CHECK(a(i, j) >= -0.01 && a(i, j) <= 0.01); + } + + // SingleMatrix b = SingleMatrix::RandomUniform(429, 1024, (float)-0.01, (float) 0.01, (unsigned long)4711); + // BOOST_CHECK(a.IsEqualTo(b)); + } + + BOOST_AUTO_TEST_CASE(MatrixSetValueMethods) + { + //void SetValue(const ElemType v); + SingleMatrix a(32, 12, AUTOPLACEMATRIX); + BOOST_CHECK_EQUAL(32, a.GetNumRows()); + BOOST_CHECK_EQUAL(12, a.GetNumCols()); + BOOST_CHECK_EQUAL(12 * 32, a.GetNumElements()); + float v = -32.3451f; + a.SetValue(v); + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(v, a(i, j)); + } + + //void SetValue(const Matrix& deepCopyFrom); + SingleMatrix b; + b.SetValue(a); + foreach_coord(i, j, b) + { + BOOST_CHECK_EQUAL(v, b(i, j)); + } + + //void SetValue(const size_t numRows, const size_t numCols, ElemType *pArray, const bool srcIsColMajor); + std::array arrVector = { 123.0f, 0.23f, -22.0f, 63.0f, 43.42f, 324.3f, 99912.0f }; + + float *arr = arrVector.data(); + b.SetValue(2, 3, b.GetDeviceId(), arr, matrixFlagNormal); + + SingleMatrix b1; + b1.SetValue(2, 3, b.GetDeviceId(), arr); + foreach_coord(i, j, b1) + { + BOOST_CHECK_EQUAL(arr[IDX2C(i, j, 2)], b(i, j)); + BOOST_CHECK_EQUAL(arr[IDX2C(i, j, 2)], b1(i, j)); + } + + SingleMatrix bbbb = SingleMatrix::Zeros(6, 8); + bbbb.SetColumn(arr, 3); + for (int i = 0; i<6; ++i) + { + BOOST_CHECK_EQUAL(arr[i], bbbb(i, 3)); + } + + //void SetDiagonalValue(const ElemType v); + SingleMatrix c(4, 4, AUTOPLACEMATRIX); + float val = -0.00332f; + c.SetDiagonalValue(val); + foreach_coord(i, j, c) + { + if (i == j) + BOOST_CHECK_EQUAL(val, c(i, j)); + else + BOOST_CHECK_EQUAL(0, c(i, j)); + } + + //void SetDiagonalValue(const Matrix& vector); + SingleMatrix d(4, 1, AUTOPLACEMATRIX); + float val1 = 43.324f; + d.SetValue(val1); + c.SetDiagonalValue(d); + foreach_coord(i, j, c) + { + if (i == j) + BOOST_CHECK_EQUAL(val1, c(i, j)); + else + BOOST_CHECK_EQUAL(0, c(i, j)); + } + + SingleMatrix c1(5, 5, AUTOPLACEMATRIX); + SingleMatrix d1(1, 5, AUTOPLACEMATRIX); + float val2 = 0.53f; + d1 = d1.Transpose(); + d1.SetValue(val2); + c1.SetDiagonalValue(d1); + foreach_coord(i, j, c1) + { + if (i == j) + BOOST_CHECK_EQUAL(val2, c1(i, j)); + else + BOOST_CHECK_EQUAL(0, c1(i, j)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixTransposeTest) + { + SingleMatrix a = SingleMatrix::RandomGaussian(64, 23, 0, 2); + BOOST_CHECK_EQUAL(64, a.GetNumRows()); + BOOST_CHECK_EQUAL(23, a.GetNumCols()); + + SingleMatrix b = a.Transpose(); + + BOOST_CHECK_EQUAL(23, b.GetNumRows()); + BOOST_CHECK_EQUAL(64, b.GetNumCols()); + + foreach_coord(i, j, a) + { + BOOST_CHECK_EQUAL(a(i, j), b(j, i)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixMultiAndDiv) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m00(2, 3, AUTOPLACEMATRIX); + m00(0, 0) = 10; m00(0, 1) = 20; m00(0, 2) = 30; + m00(1, 0) = 40; m00(1, 1) = 50; m00(1, 2) = 60; + + SingleMatrix m1(2, 3, AUTOPLACEMATRIX); + m1.Reshape(3, 2); + m1(0, 0) = 11; m1(0, 1) = 15; + m1(1, 0) = 14; m1(1, 1) = 13; + m1(2, 0) = 12; m1(2, 1) = 16; + + SingleMatrix m2(2, 2, AUTOPLACEMATRIX); + m2(0, 0) = 75; m2(0, 1) = 89; + m2(1, 0) = 186; m2(1, 1) = 221; + + SingleMatrix m3 = m0 * m1; + BOOST_CHECK(m3.IsEqualTo(m2)); + + m3 = m0 * 10; + BOOST_CHECK(m3.IsEqualTo(m00)); + + m3 = m3 / 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + m3 *= 10; + BOOST_CHECK(m3.IsEqualTo(m00)); + + m3 /= 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + SingleMatrix::MultiplyAndWeightedAdd(1, m0, false, m1, false, 0, m3); + BOOST_CHECK(m3.IsEqualTo(m2)); + + m1.Reshape(2, 3); + SingleMatrix::MultiplyAndWeightedAdd(1, m0, false, m1, true, 0, m3); + m2(0, 0) = 74; m2(0, 1) = 92; + m2(1, 0) = 182; m2(1, 1) = 227; + BOOST_CHECK(m3.IsEqualTo(m2)); + + SingleMatrix::MultiplyAndWeightedAdd(10, m0, false, m1, true, 2, m3); + m2(0, 0) = 888; m2(0, 1) = 1104; + m2(1, 0) = 2184; m2(1, 1) = 2724; + BOOST_CHECK(m3.IsEqualTo(m2)); + + SingleMatrix::MultiplyAndWeightedAdd(1, m0, true, m1, false, 0, m3); + m2.Resize(3, 3); + m2(0, 0) = 67; m2(0, 1) = 72; m2(0, 2) = 77; + m2(1, 0) = 92; m2(1, 1) = 99; m2(1, 2) = 106; + m2(2, 0) = 117; m2(2, 1) = 126; m2(2, 2) = 135; + BOOST_CHECK(m3.IsEqualTo(m2)); + + //Multiplications of arbitrary matrix with 1x1 matrix + + SingleMatrix a(2, 3, AUTOPLACEMATRIX); + a(0, 0) = 1; a(0, 1) = 2; a(0, 2) = 3; + a(1, 0) = 4; a(1, 1) = 5; a(1, 2) = 6; + + SingleMatrix b = SingleMatrix::Eye(1); + + SingleMatrix c = a * b; + BOOST_CHECK(c.IsEqualTo(a)); + c = b * a; + BOOST_CHECK(c.IsEqualTo(a)); + b(0, 0) = 0.5; + b.InplaceAbs(); + c = a * b; + + SingleMatrix d(2, 3, AUTOPLACEMATRIX); + d(0, 0) = 0.5; d(0, 1) = 1; d(0, 2) = 1.5; + d(1, 0) = 2; d(1, 1) = 2.5; d(1, 2) = 3; + BOOST_CHECK(c.IsEqualTo(d)); + } + + BOOST_AUTO_TEST_CASE(MatrixTranspose) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m1(3, 2, AUTOPLACEMATRIX); + m1(0, 0) = 1; m1(0, 1) = 4; + m1(1, 0) = 2; m1(1, 1) = 5; + m1(2, 0) = 3; m1(2, 1) = 6; + + SingleMatrix m2 = m0.Transpose(); + BOOST_CHECK(m2.IsEqualTo(m1, c_epsilonFloatE4)); + + m2.AssignTransposeOf(m1); + BOOST_CHECK(m2.IsEqualTo(m0, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixAddAndSub) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m1(2, 3, AUTOPLACEMATRIX); + m1(0, 0) = 11; m1(0, 1) = 12; m1(0, 2) = 13; + m1(1, 0) = 14; m1(1, 1) = 15; m1(1, 2) = 16; + + SingleMatrix m2(2, 3, AUTOPLACEMATRIX); + m2(0, 0) = 12; m2(0, 1) = 14; m2(0, 2) = 16; + m2(1, 0) = 18; m2(1, 1) = 20; m2(1, 2) = 22; + + SingleMatrix m3 = m2 - m0; + BOOST_CHECK(m3.IsEqualTo(m1)); + + m3 += m0; + BOOST_CHECK(m3.IsEqualTo(m2)); + + m3 = m0 + 10; + BOOST_CHECK(m3.IsEqualTo(m1)); + + m3 -= 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + m3 = m1 + m0; + BOOST_CHECK(m3.IsEqualTo(m2)); + SingleMatrix m4 = SingleMatrix::Eye(3); + + m3 -= m0; + BOOST_CHECK(m3.IsEqualTo(m1)); + + m3 = m1 - 10; + BOOST_CHECK(m3.IsEqualTo(m0)); + + SingleMatrix m33(m3); + m3 += 10; + BOOST_CHECK(m3.IsEqualTo(m1)); + + SingleMatrix m55 = SingleMatrix::Eye(1); + m55(0, 0) = 10; + m55.InplaceAbs(); + m33 += m55; + BOOST_CHECK(m33.IsEqualTo(m1)); + m33 -= 10; + m33 = m33 + 10; + BOOST_CHECK(m33.IsEqualTo(m1)); + } + + BOOST_AUTO_TEST_CASE(MatrixElementOps) + { + SingleMatrix m0(2, 3, AUTOPLACEMATRIX); + m0(0, 0) = 1; m0(0, 1) = 2; m0(0, 2) = 3; + m0(1, 0) = 4; m0(1, 1) = 5; m0(1, 2) = 6; + + SingleMatrix m00(2, 3, AUTOPLACEMATRIX); + m00(0, 0) = 1.0f; m00(0, 1) = static_cast (1 / 2.0); m00(0, 2) = static_cast (1 / 3.0); + m00(1, 0) = static_cast (1 / 4.0); m00(1, 1) = static_cast(1 / 5.0); m00(1, 2) = static_cast(1 / 6.0); + + SingleMatrix m1(2, 3, AUTOPLACEMATRIX); + m1(0, 0) = 1; m1(0, 1) = 1; m1(0, 2) = 1; + m1(1, 0) = 1; m1(1, 1) = 1; m1(1, 2) = 1; + + SingleMatrix m3; + m3.AssignElementProductOf(m0, m00); + BOOST_CHECK(m3.IsEqualTo(m1, c_epsilonFloatE4)); + + SingleMatrix m4 = SingleMatrix::Zeros(2, 3); + m4 = m4.AddElementProductOf(m0, m00); + BOOST_CHECK(m4.IsEqualTo(m1, c_epsilonFloatE4)); + + m3 = m0 ^ 4; + SingleMatrix m2(2, 3, AUTOPLACEMATRIX); + m2(0, 0) = 1; m2(0, 1) = 16; m2(0, 2) = 81; + m2(1, 0) = 256; m2(1, 1) = 625; m2(1, 2) = 1296; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3 ^= 4; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3.ElementMultiplyWith(m00); + BOOST_CHECK(m3.IsEqualTo(m1, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3.ElementInverse(); + BOOST_CHECK(m3.IsEqualTo(m00, c_epsilonFloatE3)); + + m2(0, 0) = 0.7311f; m2(0, 1) = 0.8808f; m2(0, 2) = 0.9526f; + m2(1, 0) = 0.9820f; m2(1, 1) = 0.9933f; m2(1, 2) = 0.9975f; + m3.AssignElementDivisionOf(m2, m0); + m2.ElementMultiplyWith(m00); + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceSigmoid(); + m2(0, 0) = 0.7311f; m2(0, 1) = 0.8808f; m2(0, 2) = 0.9526f; + m2(1, 0) = 0.9820f; m2(1, 1) = 0.9933f; m2(1, 2) = 0.9975f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceTanh(); + m2(0, 0) = 0.7616f; m2(0, 1) = 0.9640f; m2(0, 2) = 0.9951f; + m2(1, 0) = 0.9993f; m2(1, 1) = 0.9999f; m2(1, 2) = 1.0000f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceLogSoftmax(true); + m3.InplaceExp(); + m2(0, 0) = 0.0474f; m2(0, 1) = 0.0474f; m2(0, 2) = 0.0474f; + m2(1, 0) = 0.9526f; m2(1, 1) = 0.9526f; m2(1, 2) = 0.9526f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceLogSoftmax(false); + m3.InplaceExp(); + m2(0, 0) = 0.0900f; m2(0, 1) = 0.2447f; m2(0, 2) = 0.6652f; + m2(1, 0) = 0.0900f; m2(1, 1) = 0.2447f; m2(1, 2) = 0.6652f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceHardmax(true); + m2(0, 0) = 0.0f; m2(0, 1) = 0.0f; m2(0, 2) = 0.0f; + m2(1, 0) = 1.0f; m2(1, 1) = 1.0f; m2(1, 2) = 1.0f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceSqrt(); + m2(0, 0) = 1.0f; m2(0, 1) = 1.4142f; m2(0, 2) = 1.7321f; + m2(1, 0) = 2.0f; m2(1, 1) = 2.2361f; m2(1, 2) = 2.4495f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceExp(); + m2(0, 0) = 2.7183f; m2(0, 1) = 7.3891f; m2(0, 2) = 20.0855f; + m2(1, 0) = 54.5982f; m2(1, 1) = 148.4132f; m2(1, 2) = 403.4288f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceExp(); + m2(0, 0) = 2.7183f; m2(0, 1) = 7.3891f; m2(0, 2) = 20.0855f; + m2(1, 0) = 54.5982f; m2(1, 1) = 148.4132f; m2(1, 2) = 403.4288f; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE4)); + + m3.InplaceLog(); + BOOST_CHECK(m3.IsEqualTo(m0, c_epsilonFloatE4)); + + m3.SetValue(m0); + m3.InplaceTruncateBottom(2); + m2(0, 0) = 2; m2(0, 1) = 2; m2(0, 2) = 3; + m2(1, 0) = 4; m2(1, 1) = 5; m2(1, 2) = 6; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + + m3.SetValue(m0); + m3.InplaceTruncateTop(4); + m2(0, 0) = 1; m2(0, 1) = 2; m2(0, 2) = 3; + m2(1, 0) = 4; m2(1, 1) = 4; m2(1, 2) = 4; + BOOST_CHECK(m3.IsEqualTo(m2, c_epsilonFloatE3)); + } + + BOOST_AUTO_TEST_CASE(MatrixColumnElementMultiply) + { + CPUMatrix mcpu = CPUMatrix::RandomUniform(429, 1024, -3.4f, 1); + CPUMatrix acpu = CPUMatrix::Ones(429, 1); + CPUMatrix mcpuCopy(mcpu); + + mcpu.ColumnElementMultiplyWith(acpu); + BOOST_CHECK(mcpuCopy.IsEqualTo(mcpu, c_epsilonFloatE4)); + + Matrix m = Matrix::RandomUniform(429, 1024, -3.4f, 1); + Matrix a = Matrix::Ones(429, 1); + Matrix mCopy(m); + + m.ColumnElementMultiplyWith(a); + BOOST_CHECK(mCopy.IsEqualTo(m, c_epsilonFloatE4)); + + CPUMatrix mc1 = CPUMatrix::RandomUniform(429, 1024, -3.4f, 1); + CPUMatrix mc2 = CPUMatrix::RandomUniform(429, 1, 0, 3); + mc1.ColumnElementMultiplyWith(mc2); + + Matrix m1(mc1.GetNumRows(), mc1.GetNumCols(), mc1.GetArray(), matrixFlagNormal); + Matrix m2(mc2.GetNumRows(), mc2.GetNumCols(), mc2.GetArray(), matrixFlagNormal); + m1.ColumnElementMultiplyWith(m2); + + foreach_coord(i, j, m2) + { + BOOST_CHECK_LT(fabs(m2(i, j) - mc2(i, j)), c_epsilonFloatE5); + } + } + + BOOST_AUTO_TEST_CASE(MatrixAssignXOf) + { + //AssignDifferenceOf + Matrix a = Matrix::RandomUniform(429, 1024, 5, 32); + Matrix b = Matrix::RandomUniform(429, 1024, 5, 32); + Matrix c; + + c.AssignDifferenceOf(a, b); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), a(i, j) - b(i, j)); + } + + float x = 234.2f; + c.AssignDifferenceOf(a, x); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), a(i, j) - x); + } + + c.AssignDifferenceOf(x, a); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), x - a(i, j)); + } + + c.AssignDifferenceOf(1, a); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), 1 - a(i, j)); + } + // + + //AssignElementProductOf + c.AssignElementProductOf(a, b); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), a(i, j) * b(i, j)); + } + + //AddElementProductOf + Matrix c_copy(c); + c.AddElementProductOf(a, b); + foreach_coord(i, j, c) + { + BOOST_CHECK_EQUAL(c(i, j), c_copy(i, j) + a(i, j) * b(i, j)); + } + + //AssignSigmoidOf + CPUMatrix ac = CPUMatrix::RandomUniform(429, 1024, 5, 32); + CPUMatrix bc = CPUMatrix::RandomUniform(429, 1024, -5, 12); + Matrix d(ac.GetNumRows(), ac.GetNumCols(), ac.GetArray(), matrixFlagNormal); + Matrix e(bc.GetNumRows(), bc.GetNumCols(), bc.GetArray(), matrixFlagNormal); + ac.AssignSigmoidOf(bc); + d.AssignSigmoidOf(e); + foreach_coord(i, j, ac) + { + BOOST_CHECK_LT(fabs(ac(i, j) - d(i, j)), c_epsilonFloatE5); + } + + //AssignSignOf + Matrix m1 = Matrix::RandomUniform(42, 12, -5, 12); + Matrix m2(4, 5, AUTOPLACEMATRIX); + m2.AssignSignOf(m1); + foreach_coord(i, j, m1) + { + float v = m1(i, j); + float expected = SIGNUMZ(v); + float actual = m2(i, j); + BOOST_CHECK_EQUAL(expected, actual); + } + + Matrix m3 = Matrix::RandomUniform(42, 12, -5, 2); + Matrix m4(m3); + m3.AddSignOf(m1); + foreach_coord(i, j, m3) + { + float v = m1(i, j); + BOOST_CHECK_EQUAL(m4(i, j) + SIGNUMZ(v), m3(i, j)); + } + + //AssignTruncateBottom and Top + Matrix m5(2, 2, AUTOPLACEMATRIX); + m5(0, 0) = 1; m5(0, 1) = 2; + m5(1, 0) = 3; m5(1, 1) = 4; + + Matrix m6; + m6.AssignTruncateBottomOf(m5, 3); + BOOST_CHECK_EQUAL(3, m6(0, 0)); + BOOST_CHECK_EQUAL(3, m6(0, 1)); + BOOST_CHECK_EQUAL(3, m6(1, 0)); + BOOST_CHECK_EQUAL(4, m6(1, 1)); + + + Matrix m7; + m7.AssignTruncateTopOf(m5, 3); + BOOST_CHECK_EQUAL(1, m7(0, 0)); + BOOST_CHECK_EQUAL(2, m7(0, 1)); + BOOST_CHECK_EQUAL(3, m7(1, 0)); + BOOST_CHECK_EQUAL(3, m7(1, 1)); + } + + BOOST_AUTO_TEST_CASE(MatrixSumOfElements) + { + Matrix m = Matrix::Ones(429, 1024, 0); + float sum = m.SumOfElements(); + BOOST_CHECK_EQUAL(429 * 1024, sum); + + CPUMatrix mcpu = CPUMatrix::Ones(429, 1024); + float sumCPU = mcpu.SumOfElements(); + BOOST_CHECK_EQUAL(429 * 1024, sumCPU); + + Matrix m1 = Matrix::Ones(42, 332); + m1 *= -1; + float sum1 = m1.SumOfElements(); + BOOST_CHECK_EQUAL(-1 * 42 * 332, sum1); + + Matrix m2 = Matrix::Ones(3, 2); + m2 *= -1; + float sum2 = m2.SumOfElements(); + BOOST_CHECK_EQUAL(-1 * 3 * 2, sum2); + } + + BOOST_AUTO_TEST_CASE(MatrixColumnSlice) + { + std::array arr = { 1, 2, 3, 4, 5, 6 }; + auto * fArray = arr.data(); + + Matrix m0(2, 3, fArray, matrixFlagNormal); + + Matrix m1(2, 2, fArray, matrixFlagNormal); + + Matrix m2 = m0.ColumnSlice(0, 2); + BOOST_CHECK(m2.IsEqualTo(m1, c_epsilonFloatE4)); + + Matrix m3(2, 2, fArray + 2, matrixFlagNormal); + + m2 = m0.ColumnSlice(1, 2); + BOOST_CHECK(m2.IsEqualTo(m3, c_epsilonFloatE4)); + + size_t k = 100, n = 20, m = 50; + + Matrix ag(k, n, AUTOPLACEMATRIX); + ag.SetUniformRandomValue(-1, 1); + + Matrix bg(n, m, AUTOPLACEMATRIX); + bg.SetUniformRandomValue(-1, 1); + + Matrix cg(k, m, AUTOPLACEMATRIX); + cg.SetUniformRandomValue(-1, 1); + + Matrix dg(k, m, AUTOPLACEMATRIX); + dg.SetValue(cg); + + Matrix::MultiplyAndAdd(ag, false, bg, false, dg); + + for (int i = 0; i colBg = bg.ColumnSlice(i, 1); + Matrix colCg = cg.ColumnSlice(i, 1); + Matrix::MultiplyAndAdd(ag, false, colBg, false, colCg); + } + BOOST_CHECK(cg.IsEqualTo(dg, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixKhatriRaoProduct) + { + std::array arr = + { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 }; + + auto *fArray = arr.data(); + fArray[0] = 0.8147f; fArray[3] = 0.9134f; fArray[6] = 0.2785f; fArray[9] = 0.9649f; + fArray[1] = 0.9058f; fArray[4] = 0.6324f; fArray[7] = 0.5469f; fArray[10] = 0.1576f; + fArray[2] = 0.1270f; fArray[5] = 0.0975f; fArray[8] = 0.9575f; fArray[11] = 0.9706f; + Matrix a(3, 4, fArray); + + fArray[0] = 0.9572f; fArray[2] = 0.8003f; fArray[4] = 0.4218f; fArray[6] = 0.7922f; + fArray[1] = 0.4854f; fArray[3] = 0.1419f; fArray[5] = 0.9157f; fArray[7] = 0.9595f; + Matrix b(2, 4, fArray); + + fArray[0] = 0.7798f; fArray[6] = 0.7310f; fArray[12] = 0.1175f; fArray[18] = 0.7644f; + fArray[1] = 0.8670f; fArray[7] = 0.5061f; fArray[13] = 0.2307f; fArray[19] = 0.1249f; + fArray[2] = 0.1215f; fArray[8] = 0.0781f; fArray[14] = 0.4038f; fArray[20] = 0.7689f; + fArray[3] = 0.3954f; fArray[9] = 0.1296f; fArray[15] = 0.2550f; fArray[21] = 0.9258f; + fArray[4] = 0.4396f; fArray[10] = 0.0897f; fArray[16] = 0.5008f; fArray[22] = 0.1512f; + fArray[5] = 0.0616f; fArray[11] = 0.0138f; fArray[17] = 0.8768f; fArray[23] = 0.9313f; + Matrix d(6, 4, fArray); + + Matrix c; + c.AssignKhatriRaoProductOf(a, b); + BOOST_CHECK(c.IsEqualTo(d, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixAddColumnReshapeProductOf) + { + std::array arr = + { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 }; + + auto *fArray = arr.data(); + fArray[0] = 0.6557f; fArray[6] = 0.7431f; + fArray[1] = 0.0357f; fArray[7] = 0.3922f; + fArray[2] = 0.8491f; fArray[8] = 0.6555f; + fArray[3] = 0.9340f; fArray[9] = 0.1712f; + fArray[4] = 0.6787f; fArray[10] = 0.7060f; + fArray[5] = 0.7577f; fArray[11] = 0.0318f; + Matrix a(6, 2, fArray); + + fArray[0] = 0.2769f; fArray[3] = 0.8235f; + fArray[1] = 0.0462f; fArray[4] = 0.6948f; + fArray[2] = 0.0971f; fArray[5] = 0.3171f; + Matrix b(3, 2, fArray); + + fArray[0] = 0.2867f; fArray[2] = 1.2913f; + fArray[1] = 0.1266f; fArray[3] = 0.4520f; + Matrix d0(2, 2, fArray); + + fArray[0] = 0.2657f; fArray[2] = 1.0923f; + fArray[1] = 0.3636f; fArray[3] = 0.6416f; + Matrix d1(2, 2, fArray); + + Matrix c(2, 2, AUTOPLACEMATRIX); + c.SetValue(0.0f); + c.AddColumnReshapeProductOf(a, b, false); + BOOST_CHECK(c.IsEqualTo(d0, c_epsilonFloatE4)); + + c.SetValue(0.0f); + c.AddColumnReshapeProductOf(a, b, true); + BOOST_CHECK(c.IsEqualTo(d1, c_epsilonFloatE4)); + } + + BOOST_AUTO_TEST_CASE(MatrixCopy) + { + const size_t crow = 3; + const size_t ccol = 2; + // Matrices are stored as column-major so below is 3x2 matrix. + float src[] = { + 1.0f, 3.0f, 4.0f, + 6.0f, 2.0f, 5.0f }; + + Matrix srcM(crow, ccol, src, matrixFlagNormal, c_deviceIdZero); + // Test full copy. + CPUMatrix actualM(crow, ccol); + srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); + + std::vector expected = { + 1.0f, 3.0f, 4.0f, + 6.0f, 2.0f, 5.0f }; + BOOST_CHECK(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); + + // Test tile copy. + actualM.Resize(crow - 1, ccol - 1); + actualM.SetValue(std::numeric_limits::quiet_NaN()); + srcM.CopySection(actualM.GetNumRows(), actualM.GetNumCols(), actualM.BufferPointer(), actualM.GetNumRows()); + + expected = { 1.0f, 3.0f }; + BOOST_CHECK(actualM.IsEqualTo(CPUMatrix(actualM.GetNumRows(), actualM.GetNumCols(), expected.data(), matrixFlagNormal))); + } + + BOOST_AUTO_TEST_CASE(MatrixHasElement) + { + for (auto deviceId : { CPUDEVICE, c_deviceIdZero }) + { + const size_t size = 3; + float src[size] = { 0.0f, 1.0f, 2.0f }; + SingleMatrix m1(1, size, src, matrixFlagNormal, deviceId); + BOOST_CHECK(SingleMatrix::HasElement(m1, 1.0f)); + BOOST_CHECK(!SingleMatrix::HasElement(m1, -1.0f)); + + auto qnan = std::numeric_limits::quiet_NaN(); + BOOST_CHECK(!SingleMatrix::HasElement(m1, qnan)); + auto posInf = std::numeric_limits::infinity(); + BOOST_CHECK(!SingleMatrix::HasElement(m1, posInf)); + + m1(0, 1) = qnan; + BOOST_CHECK(SingleMatrix::HasElement(m1, qnan)); + + m1(0, 1) = posInf; + BOOST_CHECK(SingleMatrix::HasElement(m1, posInf)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixVectorMax) + { + // Matrices are stored as column-major so below is 3x2 matrix. + float src[] = { + 1.0f, 3.0f, 4.0f, + 6.0f, 2.0f, 5.0f }; + + float expectedIdx[] = { + 2.0f, 1.0f, + 0.0f, 2.0f }; + + float expectedVal[] = { + 4.0f, 3.0f, + 6.0f, 5.0f }; + + for (auto deviceId : { CPUDEVICE, AUTOPLACEMATRIX }) + { + Matrix expIdx(2, 2, expectedIdx, matrixFlagNormal, deviceId); + Matrix expVal(2, 2, expectedVal, matrixFlagNormal, deviceId); + + Matrix actual(3, 2, src, matrixFlagNormal, deviceId); + Matrix actualIdx(deviceId); + Matrix actualVal(deviceId); + + auto topK = 2; + actual.VectorMax(actualIdx, actualVal, true, topK); + BOOST_CHECK(actualIdx.IsEqualTo(expIdx)); + BOOST_CHECK(actualVal.IsEqualTo(expVal)); + } + } + + BOOST_AUTO_TEST_CASE(MatrixAssignNumOfDiff) + { + float labels[] = { 1.0f, 2.0f, 3.0f }; + + // Matrices are stored as column-major so below is 2x3 matrix. + float topKResults[] = { + 1.0f, 3.0f, + 4.0f, 6.0f, + 2.0f, 3.0f }; + + for (auto deviceId : { CPUDEVICE, AUTOPLACEMATRIX }) + { + Matrix lbl(1, 3, labels, matrixFlagNormal, deviceId); + Matrix topKRes(2, 3, topKResults, matrixFlagNormal, deviceId); + + Matrix actual(deviceId); + actual.AssignNumOfDiff(lbl, topKRes, true); + + float expectedDiff = 1.0; + BOOST_CHECK_EQUAL(expectedDiff, actual.Get00Element()); + } + } + BOOST_AUTO_TEST_SUITE_END() + } + } + } +} \ No newline at end of file diff --git a/Tests/UnitTests/MathTests/constant.cpp b/Tests/UnitTests/MathTests/constant.cpp deleted file mode 100644 index 7925d1afe0ca..000000000000 --- a/Tests/UnitTests/MathTests/constant.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// -#include "stdafx.h" - -const int c_deviceIdZero = 0; - -const float c_epsilonFloatE5 = 0.00001f; - diff --git a/Tests/UnitTests/MathTests/constant.h b/Tests/UnitTests/MathTests/constant.h deleted file mode 100644 index 9d408957df60..000000000000 --- a/Tests/UnitTests/MathTests/constant.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#pragma once - -extern const int c_deviceIdZero; - -extern const float c_epsilonFloatE5; \ No newline at end of file diff --git a/Tests/UnitTests/MathTests/constants.cpp b/Tests/UnitTests/MathTests/constants.cpp index dd17710455f4..272810daf7c8 100644 --- a/Tests/UnitTests/MathTests/constants.cpp +++ b/Tests/UnitTests/MathTests/constants.cpp @@ -10,3 +10,4 @@ const int c_deviceIdZero = 0; const float c_epsilonFloatE5 = 0.00001f; const float c_epsilonFloatE4 = 0.0001f; const float c_epsilonFloatE3 = 0.001f; +const float c_epsilonFloatE2 = 0.01f; \ No newline at end of file diff --git a/Tests/UnitTests/MathTests/constants.h b/Tests/UnitTests/MathTests/constants.h index f32510701560..cdcc5e250dfd 100644 --- a/Tests/UnitTests/MathTests/constants.h +++ b/Tests/UnitTests/MathTests/constants.h @@ -9,4 +9,5 @@ extern const int c_deviceIdZero; extern const float c_epsilonFloatE5; extern const float c_epsilonFloatE4; -extern const float c_epsilonFloatE3; \ No newline at end of file +extern const float c_epsilonFloatE3; +extern const float c_epsilonFloatE2; \ No newline at end of file