From 91e2673ba6d4344492ca815eb0061ae6322eff80 Mon Sep 17 00:00:00 2001 From: Amit Agarwal Date: Thu, 3 Mar 2016 13:15:17 -0800 Subject: [PATCH] Removed copy constructor and assignment operator from top-level Matrix type to prevent unwanted silent deep copies of Matrix objects which can be very expensive. This revealed several instances of unwanted copying of entire matrices that have also been fixed as part of this change --- Source/Common/Include/Sequences.h | 49 +++++++++++++++--- .../ComputationNetwork.cpp | 13 +++-- .../ComputationNetworkLib/ComputationNode.h | 4 +- .../ConvolutionalNodes.h | 2 +- .../ComputationNetworkLib/EvaluationNodes.h | 6 +-- .../LinearAlgebraNodes.h | 26 +++++----- .../ComputationNetworkLib/NonlinearityNodes.h | 6 +-- .../ComputationNetworkLib/PreComputeNodes.h | 6 +-- Source/ComputationNetworkLib/RecurrentNodes.h | 4 +- Source/ComputationNetworkLib/ReshapingNodes.h | 2 +- .../SpecialPurposeNodes.h | 6 +-- Source/ComputationNetworkLib/TrainingNodes.h | 22 ++++---- Source/Math/Matrix.cpp | 50 +++++++------------ Source/Math/Matrix.h | 12 +++-- Source/SGDLib/DataReaderHelpers.h | 2 +- .../parallelforwardbackward.cpp | 4 +- .../MathTests/ConvolutionEngineTests.cpp | 22 ++++---- Tests/UnitTests/MathTests/MatrixBlasTests.cpp | 12 ++--- .../MathTests/MatrixFileWriteReadTests.cpp | 4 +- .../MatrixSparseDenseInteractionsTests.cpp | 32 ++++++------ Tests/UnitTests/MathTests/MatrixTests.cpp | 14 +++--- 21 files changed, 163 insertions(+), 135 deletions(-) diff --git a/Source/Common/Include/Sequences.h b/Source/Common/Include/Sequences.h index 18c1b3fe04ac..d5e333f40069 100644 --- a/Source/Common/Include/Sequences.h +++ b/Source/Common/Include/Sequences.h @@ -109,17 +109,54 @@ struct MBLayout // copy the content of another MBLayoutPtr over // Use this instead of actual assignment to make it super-obvious that this is not copying the pointer but actual content. The pointer is kept fixed. - void CopyFrom(const MBLayoutPtr &other) + void CopyFrom(const MBLayoutPtr& other) { - *this = *other; + m_numTimeSteps = other->m_numTimeSteps; + m_numParallelSequences = other->m_numParallelSequences; + m_sequences = other->m_sequences; + m_numFramesDeclared = other->m_numFramesDeclared; + m_numGapFrames = other->m_numFramesDeclared; + + m_distanceToStart.SetValue(other->m_distanceToStart); + m_distanceToEnd.SetValue(other->m_distanceToEnd); + + m_distanceToNearestStart = other->m_distanceToNearestStart; + m_distanceToNearestEnd = other->m_distanceToNearestEnd; + + m_timeStepHasGap = other->m_timeStepHasGap; + + m_columnsValidityMask.SetValue(other->m_columnsValidityMask); + m_writable = other->m_writable; } + + // Destructive copy that steals ownership if the content, like std::move() + // Note: For some reason the VC++ compiler does not generate the + // move assignment and we have to do this ourselves void MoveFrom(MBLayoutPtr other) { - *this = move(*other); + m_numTimeSteps = other->m_numTimeSteps; + m_numParallelSequences = other->m_numParallelSequences; + m_sequences = std::move(other->m_sequences); + m_numFramesDeclared = other->m_numFramesDeclared; + m_numGapFrames = other->m_numFramesDeclared; + + m_distanceToStart = std::move(other->m_distanceToStart); + m_distanceToEnd = std::move(other->m_distanceToEnd); + + m_distanceToNearestStart = std::move(other->m_distanceToNearestStart); + m_distanceToNearestEnd = std::move(other->m_distanceToNearestEnd); + + m_timeStepHasGap = std::move(other->m_timeStepHasGap); + + m_columnsValidityMask = std::move(other->m_columnsValidityMask); + m_writable = other->m_writable; + other->Init(0, 0); - } // destructive copy that steals ownership if the content, like std::move() -private: - MBLayout &operator=(const MBLayout &) = default; // make this private --use CopyFrom() instead, which makes it very clear that it's copying content, not copying the reference + } + + MBLayout(const MBLayout&) = delete; + MBLayout& operator=(const MBLayout&) = delete; + public: // resize and reset all frames to None (note: this is an invalid state and must be fixed by caller afterwards) void Init(size_t numParallelSequences, size_t numTimeSteps) diff --git a/Source/ComputationNetworkLib/ComputationNetwork.cpp b/Source/ComputationNetworkLib/ComputationNetwork.cpp index 8f6312703c98..6a79f88ea035 100644 --- a/Source/ComputationNetworkLib/ComputationNetwork.cpp +++ b/Source/ComputationNetworkLib/ComputationNetwork.cpp @@ -913,7 +913,7 @@ void ComputationNetwork::PerformSVDecomposition(const map& SVDCo shared_ptr> pNode = dynamic_pointer_cast>(m_nameToNodeMap[name]); // Step 1. do SVD decomposition - Matrix A = pNode->ValueAsMatrix(); + Matrix A = pNode->ValueAsMatrix().DeepClone(); // it is a vector, no need to do it if (A.GetNumCols() == 1 || A.GetNumRows() == 1) @@ -991,8 +991,8 @@ void ComputationNetwork::PerformSVDecomposition(const map& SVDCo shared_ptr> pLeft = AddNodeToNetWithElemType(New>(m_deviceId, leftChildName, m, r)); shared_ptr> pRight = AddNodeToNetWithElemType(New>(m_deviceId, rightChildName, r, n)); - pLeft->ValueAsMatrix() = redU; - pRight->ValueAsMatrix() = redVT; + pLeft->ValueAsMatrix() = std::move(redU); + pRight->ValueAsMatrix() = std::move(redVT); shared_ptr> pTimes = AddNodeToNetAndAttachInputs(New>(m_deviceId, name + L"-SVD"), pLeft, pRight); @@ -1212,9 +1212,8 @@ void ComputationNetwork::SaveToDbnFile(ComputationNetworkPtr net, const std::wst ComputationNodeBasePtr meanNode = normalizationNodes.front()->GetInputs()[1]; ComputationNodeBasePtr stdNode = normalizationNodes.front()->GetInputs()[2]; - Matrix meanNodeMatrix = meanNode->As>()->Value(); - Matrix stdNodeMatrix = stdNode->As>()->Value(); - Matrix invStdNodeMatrix(stdNodeMatrix.ElementInverse()); + Matrix meanNodeMatrix = meanNode->As>()->Value().DeepClone(); + Matrix invStdNodeMatrix(std::move(stdNode->As>()->Value().DeepClone().ElementInverse())); std::vector priorNodes = WhereNode(net->GetAllNodes(), GetAllPriorNodes); if (priorNodes.size() != 1) @@ -1297,7 +1296,7 @@ void ComputationNetwork::SaveToDbnFile(ComputationNetworkPtr net, const std::wst } // Write out the main weight matrix - auto weight = (layer->Node->As>()->Value()); + auto weight = (layer->Node->As>()->Value().DeepClone()); auto transpose = weight.Transpose(); PutMatrix(&transpose, "W"); diff --git a/Source/ComputationNetworkLib/ComputationNode.h b/Source/ComputationNetworkLib/ComputationNode.h index e92e5e73c793..30dca5b48d57 100644 --- a/Source/ComputationNetworkLib/ComputationNode.h +++ b/Source/ComputationNetworkLib/ComputationNode.h @@ -907,9 +907,9 @@ class ComputationNode : public ComputationNodeBase // abstract class that cannot if (flags & CopyNodeFlags::copyNodeValue) { auto node = DownCast(nodeP); - *node->m_value = *m_value; + node->m_value->SetValue(*m_value); if (m_gradient) - *node->m_gradient = *m_gradient; + node->m_gradient->SetValue(*m_gradient); else node->m_gradient = nullptr; } diff --git a/Source/ComputationNetworkLib/ConvolutionalNodes.h b/Source/ComputationNetworkLib/ConvolutionalNodes.h index 5fabbcf0d712..f7df90ef1766 100644 --- a/Source/ComputationNetworkLib/ConvolutionalNodes.h +++ b/Source/ComputationNetworkLib/ConvolutionalNodes.h @@ -144,7 +144,7 @@ class ConvolutionNode : public ComputationNode, public NumInputs<2> node->m_imageLayoutKind = m_imageLayoutKind; - *node->m_tempMatrix = *m_tempMatrix; + node->m_tempMatrix->SetValue(*m_tempMatrix); } } diff --git a/Source/ComputationNetworkLib/EvaluationNodes.h b/Source/ComputationNetworkLib/EvaluationNodes.h index 5f77f7242fb7..03eb755a82a9 100644 --- a/Source/ComputationNetworkLib/EvaluationNodes.h +++ b/Source/ComputationNetworkLib/EvaluationNodes.h @@ -101,9 +101,9 @@ class ErrorPredictionNode : public ComputationNodeNonLooping /*ComputationNode*/ if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_maxIndexes0 = *m_maxIndexes0; - *node->m_maxIndexes1 = *m_maxIndexes1; - *node->m_maxValues = *m_maxValues; + node->m_maxIndexes0->SetValue(*m_maxIndexes0); + node->m_maxIndexes1->SetValue(*m_maxIndexes1); + node->m_maxValues->SetValue(*m_maxValues); } } // request matrices needed to do node function value evaluation diff --git a/Source/ComputationNetworkLib/LinearAlgebraNodes.h b/Source/ComputationNetworkLib/LinearAlgebraNodes.h index 9e52fb4a15e4..6b65a65598ec 100644 --- a/Source/ComputationNetworkLib/LinearAlgebraNodes.h +++ b/Source/ComputationNetworkLib/LinearAlgebraNodes.h @@ -556,8 +556,8 @@ class DiagTimesNode : public ComputationNode, public NumInputs<2> if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_innerproduct = *m_innerproduct; - *node->m_rightGradient = *m_rightGradient; + node->m_innerproduct->SetValue(*m_innerproduct); + node->m_rightGradient->SetValue(*m_rightGradient); } } // request matrices that are needed for gradient computation @@ -895,11 +895,11 @@ class CosDistanceNode : public ComputationNode, public NumInputs<2> if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_invNorm0 = *m_invNorm0; - *node->m_invNorm1 = *m_invNorm1; - *node->m_leftTerm = *m_leftTerm; - *node->m_rightTerm = *m_rightTerm; - *node->m_temp = *m_temp; + node->m_invNorm0->SetValue(*m_invNorm0); + node->m_invNorm1->SetValue(*m_invNorm1); + node->m_leftTerm->SetValue(*m_leftTerm); + node->m_rightTerm->SetValue(*m_rightTerm); + node->m_temp->SetValue(*m_temp); } } // request matrices needed to do node function value evaluation @@ -1212,12 +1212,12 @@ class CosDistanceWithNegativeSamplesNode : public ComputationNode, pub if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_invNorm0 = *m_invNorm0; - *node->m_invNorm1 = *m_invNorm1; - *node->m_invNormSquare = *m_invNormSquare; - *node->m_leftTerm = *m_leftTerm; - *node->m_rightTerm = *m_rightTerm; - *node->m_temp = *m_temp; + node->m_invNorm0->SetValue(*m_invNorm0); + node->m_invNorm1->SetValue(*m_invNorm1); + node->m_invNormSquare->SetValue(*m_invNormSquare); + node->m_leftTerm->SetValue(*m_leftTerm); + node->m_rightTerm->SetValue(*m_rightTerm); + node->m_temp->SetValue(*m_temp); } } // request matrices needed to do node function value evaluation diff --git a/Source/ComputationNetworkLib/NonlinearityNodes.h b/Source/ComputationNetworkLib/NonlinearityNodes.h index ba63f05d7134..9aa5beeea5a3 100644 --- a/Source/ComputationNetworkLib/NonlinearityNodes.h +++ b/Source/ComputationNetworkLib/NonlinearityNodes.h @@ -180,7 +180,7 @@ class SoftmaxNodeBase : public ComputationNode, public NumInputs<1> if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_gradientTemp = *m_gradientTemp; + node->m_gradientTemp->SetValue(*m_gradientTemp); } } @@ -258,7 +258,7 @@ class SoftmaxNode : public SoftmaxNodeBase if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_diff = *m_diff; + node->m_diff->SetValue(*m_diff); } } // request matrices that are needed for gradient computation @@ -331,7 +331,7 @@ class LogSoftmaxNode : public SoftmaxNodeBase if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_softmax = *m_softmax; + node->m_softmax->SetValue(*m_softmax); } } // request matrices that are needed for gradient computation diff --git a/Source/ComputationNetworkLib/PreComputeNodes.h b/Source/ComputationNetworkLib/PreComputeNodes.h index 09f8c39358e6..612ba3f20c37 100644 --- a/Source/ComputationNetworkLib/PreComputeNodes.h +++ b/Source/ComputationNetworkLib/PreComputeNodes.h @@ -398,9 +398,9 @@ class InvStdDevNode : public MeanInvStdDevNodeBase if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - node->m_mean = m_mean; - node->m_var = m_var; - node->m_temp = m_temp; + node->m_mean.SetValue(m_mean); + node->m_var.SetValue(m_var); + node->m_temp.SetValue(m_temp); } } diff --git a/Source/ComputationNetworkLib/RecurrentNodes.h b/Source/ComputationNetworkLib/RecurrentNodes.h index eae0cb99acb8..816fb34fc294 100644 --- a/Source/ComputationNetworkLib/RecurrentNodes.h +++ b/Source/ComputationNetworkLib/RecurrentNodes.h @@ -254,7 +254,7 @@ class DelayedValueNodeBase : public ComputationNode, public IRecurrent // - we don't need to keep anything if all sequences are closed (sentence end) // This condition includes full-sequence mode. // TODO: Can we optimize this and only copy if there is a sequence spanning across the end of the MB? And add a check to BeginForwardProp() to make sure we got one if there is a boundary at the start? - m_delayedValue = Input(0)->Value(); + m_delayedValue.SetValue(Input(0)->Value()); if (!m_delayedActivationMBLayout) m_delayedActivationMBLayout = make_shared(); m_delayedActivationMBLayout->CopyFrom(m_pMBLayout); @@ -379,7 +379,7 @@ class DelayedValueNodeBase : public ComputationNode, public IRecurrent auto node = dynamic_pointer_cast>(nodeP); node->m_timeStep = m_timeStep; node->m_initialActivationValue = m_initialActivationValue; - node->m_delayedValue = m_delayedValue; + node->m_delayedValue.SetValue(m_delayedValue); if (m_delayedActivationMBLayout) (node->m_delayedActivationMBLayout = make_shared())->CopyFrom(m_delayedActivationMBLayout); else diff --git a/Source/ComputationNetworkLib/ReshapingNodes.h b/Source/ComputationNetworkLib/ReshapingNodes.h index c83f0e070506..13f4db87216d 100644 --- a/Source/ComputationNetworkLib/ReshapingNodes.h +++ b/Source/ComputationNetworkLib/ReshapingNodes.h @@ -621,7 +621,7 @@ class DiagonalNode : public ComputationNodeNonLooping, public NumInput // BUGBUG: This should use the memshare mechanism. // TODO: use tensor lib, then this will be easy, no memsharing needed Matrix diag(gradientValues.GetNumRows(), gradientValues.GetNumCols(), gradientValues.GetDeviceId()); - diag = gradientValues; + diag.SetValue(gradientValues); diag.Resize(gradientValues.GetNumCols(), 1); inputGradientValues.SetValue(0); diff --git a/Source/ComputationNetworkLib/SpecialPurposeNodes.h b/Source/ComputationNetworkLib/SpecialPurposeNodes.h index 0f9b4d2161c3..438cb48fe790 100644 --- a/Source/ComputationNetworkLib/SpecialPurposeNodes.h +++ b/Source/ComputationNetworkLib/SpecialPurposeNodes.h @@ -564,9 +564,9 @@ class SequenceWithSoftmaxNode : public ComputationNodeNonLooping, publ { auto node = dynamic_pointer_cast>(nodeP); - *node->m_logSoftmaxOfRight = *m_logSoftmaxOfRight; - *node->m_softmaxOfRight = *m_softmaxOfRight; - *node->m_gammaFromLattice = *m_gammaFromLattice; + node->m_logSoftmaxOfRight->SetValue(*m_logSoftmaxOfRight); + node->m_softmaxOfRight->SetValue(*m_softmaxOfRight); + node->m_gammaFromLattice->SetValue(*m_gammaFromLattice); node->m_fsSmoothingWeight = m_fsSmoothingWeight; node->m_frameDropThreshold = m_frameDropThreshold; node->m_doReferenceAlignment = m_doReferenceAlignment; diff --git a/Source/ComputationNetworkLib/TrainingNodes.h b/Source/ComputationNetworkLib/TrainingNodes.h index b91dd0c3de89..d867a64124d8 100644 --- a/Source/ComputationNetworkLib/TrainingNodes.h +++ b/Source/ComputationNetworkLib/TrainingNodes.h @@ -85,7 +85,7 @@ class SquareErrorNode : public ComputationNodeNonLooping /*ComputationNode*/>(nodeP); - *node->m_leftMinusRight = *m_leftMinusRight; + node->m_leftMinusRight->SetValue(*m_leftMinusRight); } } @@ -214,8 +214,8 @@ class CrossEntropyWithSoftmaxNode : public ComputationNodeNonLooping /*Computati if (flags & CopyNodeFlags::copyNodeValue) { auto node = dynamic_pointer_cast>(nodeP); - *node->m_logSoftmaxOfRight = *m_logSoftmaxOfRight; - *node->m_softmaxOfRight = *m_softmaxOfRight; + node->m_logSoftmaxOfRight->SetValue(*m_logSoftmaxOfRight); + node->m_softmaxOfRight->SetValue(*m_softmaxOfRight); } } @@ -325,8 +325,8 @@ class CrossEntropyNode : public ComputationNodeNonLooping /*ComputationNode*/>(nodeP); - *node->m_logOfRight = *m_logOfRight; - *node->m_leftDivRight = *m_leftDivRight; + node->m_logOfRight->SetValue(*m_logOfRight); + node->m_leftDivRight->SetValue(*m_leftDivRight); } } @@ -430,7 +430,7 @@ class MatrixL1RegNode : public ComputationNodeNonLooping /*ComputationNode*/>(nodeP); - *node->m_gradientOfL1Norm = *m_gradientOfL1Norm; + node->m_gradientOfL1Norm->SetValue(*m_gradientOfL1Norm); } } @@ -860,7 +860,7 @@ class ClassBasedCrossEntropyWithSoftmaxNode : public ComputationNodeNonLooping / assert(m_nbrCls == Input(CLASSPROBINDATA)->GetSampleMatrixNumRows()); // compute the class posteriors - m_clsLogSoftmax = Input(CLASSPROBINDATA)->Value(); + m_clsLogSoftmax.SetValue(Input(CLASSPROBINDATA)->Value()); m_clsLogSoftmax.InplaceLogSoftmax(true); // log m_clsSoftmax.AssignExpOf(m_clsLogSoftmax); // non-log @@ -1330,7 +1330,7 @@ class LogisticNode : public ComputationNodeNonLooping /*ComputationNode*/& classOneProbabilities = Input(1)->ValueFor(fr); Matrix& classZeroLabels = *m_classZeroLabels; - Matrix ones = ConstOnes(classOneLabels.GetNumRows(), classOneLabels.GetNumCols(), classOneLabels.GetDeviceId()); + Matrix ones = ConstOnes(classOneLabels.GetNumRows(), classOneLabels.GetNumCols(), classOneLabels.GetDeviceId()).DeepClone(); // compute the indices for the class 0 indices classZeroLabels.AssignDifferenceOf(ones, classOneLabels); @@ -1409,9 +1409,9 @@ class LogisticNode : public ComputationNodeNonLooping /*ComputationNode*/>(nodeP); - *node->m_classZeroLabels = *m_classZeroLabels; - *node->m_result = *m_result; - *node->m_temp = *m_temp; + node->m_classZeroLabels->SetValue(*m_classZeroLabels); + node->m_result->SetValue(*m_result); + node->m_temp->SetValue(*m_temp); } } diff --git a/Source/Math/Matrix.cpp b/Source/Math/Matrix.cpp index 4eb1dd74761c..a73fa4166712 100644 --- a/Source/Math/Matrix.cpp +++ b/Source/Math/Matrix.cpp @@ -406,9 +406,9 @@ Matrix::Matrix(const size_t numRows, const size_t numCols, ElemType* p //copy constructor, deep copy template -Matrix::Matrix(const Matrix& deepCopyFrom) - : Matrix(deepCopyFrom, deepCopyFrom.GetDeviceId()) +Matrix Matrix::DeepClone() const { + return Matrix(*this, this->GetDeviceId()); } template @@ -433,17 +433,6 @@ Matrix::Matrix(const Matrix& deepCopyFrom, DEVICEID_TYPE dev m_preferredDeviceId = deepCopyFrom.m_preferredDeviceId; } -//assignment operator, deep copy -template -Matrix& Matrix::operator=(const Matrix& deepCopyFrom) -{ - if (this != &deepCopyFrom) - { - SetValue(deepCopyFrom); - } - return *this; -} - //move constructor, shallow copy template Matrix::Matrix(Matrix&& moveFrom) @@ -633,7 +622,7 @@ void Matrix::ShiftBy(int numShift) { Matrix inp = ColumnSlice(i + numShift, 1); Matrix out = ColumnSlice(i, 1); - out = inp; + out.SetValue(inp); } for (size_t i = 0; i < min(GetNumCols(), -numShift); i++) ColumnSlice(i, 1).SetValue(0); @@ -837,7 +826,7 @@ Matrix Matrix::Diagonal() const } template -Matrix Matrix::AssignDiagonalValuesTo(Matrix& diag) const +void Matrix::AssignDiagonalValuesTo(Matrix& diag) const { int devId = GetDeviceId(); DecideAndMoveToRightDevice(*this, diag); @@ -885,8 +874,6 @@ Matrix Matrix::AssignDiagonalValuesTo(Matrix& diag { RuntimeError("Unknown matrix type"); } - - return diag; } //this function will change the matrix type between DENSE and SPARSE. @@ -1518,7 +1505,7 @@ Matrix Matrix::RepMat(const Matrix& frmMat, const Matrix c(nRows, newCols, frmMat.GetDeviceId()); for (size_t i = 0; i < colRatio; i++) { - c.ColumnSlice(i * nCols, nCols) = frmMat; + c.ColumnSlice(i * nCols, nCols).SetValue(frmMat); } return c; @@ -1633,7 +1620,7 @@ Matrix Matrix::operator+(const Matrix& a) const { if (GetNumElements() == 1) { - Matrix c(a); + Matrix c(a.DeepClone()); DISPATCH_MATRIX_ON_FLAG(this, &c, @@ -1645,7 +1632,7 @@ Matrix Matrix::operator+(const Matrix& a) const } else if (a.GetNumElements() == 1) { - Matrix c(*this); + Matrix c(this->DeepClone()); DISPATCH_MATRIX_ON_FLAG(&a, &c, @@ -1657,7 +1644,7 @@ Matrix Matrix::operator+(const Matrix& a) const } else { - Matrix c(*this); // this implementation will introduce a copy overhead. but make resue of the code + Matrix c(this->DeepClone()); // this implementation will introduce a copy overhead. but make resue of the code c += a; return c; } @@ -1913,7 +1900,7 @@ Matrix& Matrix::operator-=(const Matrix& a) template Matrix Matrix::operator-(const Matrix& a) const { - Matrix c(*this); // this implementation will introduce a copy overhead. but make resue of the code + Matrix c(this->DeepClone()); // this implementation will introduce a copy overhead. but make resue of the code ScaleAndAdd(-1, a, c); return c; } @@ -1967,9 +1954,9 @@ Matrix& Matrix::AssignProductOf(const Matrix& a, c if (a.GetNumElements() == 1) { if (transposeB) - (*this) = AssignTransposeOf(b); + AssignTransposeOf(b); else - (*this) = b; + this->SetValue(b); DISPATCH_MATRIX_ON_FLAG(this, nullptr, @@ -1981,9 +1968,9 @@ Matrix& Matrix::AssignProductOf(const Matrix& a, c else if (b.GetNumElements() == 1) { if (transposeA) - (*this) = AssignTransposeOf(a); + AssignTransposeOf(a); else - (*this) = a; + this->SetValue(a); DISPATCH_MATRIX_ON_FLAG(this, nullptr, @@ -2844,7 +2831,7 @@ Matrix& Matrix::AssignTruncateBottomOf(const MatrixSetValue(a); return *this; } } @@ -2852,7 +2839,7 @@ Matrix& Matrix::AssignTruncateBottomOf(const MatrixSetValue(a); return *this; } } @@ -2908,7 +2895,7 @@ Matrix& Matrix::AssignTruncateTopOf(const Matrix& { if (!isfinite((float) threshold)) { - (*this) = a; + this->SetValue(a); return *this; } } @@ -2916,7 +2903,7 @@ Matrix& Matrix::AssignTruncateTopOf(const Matrix& { if (!isfinite(threshold)) { - (*this) = a; + this->SetValue(a); return *this; } } @@ -4012,7 +3999,7 @@ void Matrix::SVD(const Matrix& A, Matrix& SIGMA, M DISPATCH_MATRIX_ON_FLAG(&A, nullptr, - Matrix tA = A; + Matrix tA = A.DeepClone(); CPUMatrix::SVD(*tA.m_CPUMatrix, *SIGMA.m_CPUMatrix, *U.m_CPUMatrix, *VT.m_CPUMatrix, *W.m_CPUMatrix); SIGMA.SetDataLocation(CPU); U.SetDataLocation(CPU); @@ -5100,6 +5087,7 @@ template size_t Matrix::GetNumRows() const; template size_t Matrix::GetNumCols() const; template void Matrix::SetValue(const char); template void Matrix::SetValue(size_t numRows, const size_t numCols, int deviceId, char* pArray, size_t matrixFlags); +template void Matrix::SetValue(const Matrix&, MatrixFormat); template bool Matrix::IsEmpty() const; template void Matrix::Resize(const size_t numRows, const size_t numCols, const size_t numNZElemToReserve, bool growOnly); diff --git a/Source/Math/Matrix.h b/Source/Math/Matrix.h index 68de0c538cc5..a159dd13a824 100644 --- a/Source/Math/Matrix.h +++ b/Source/Math/Matrix.h @@ -90,11 +90,15 @@ class MATH_API Matrix : public MatrixBase Matrix(FILE* f, const char* matrixName, DEVICEID_TYPE deviceId, const MatrixType matrixType = DENSE); // matrixName is used to verify that correct matrix is read. Matrix(const size_t numRows, const size_t numCols, DEVICEID_TYPE deviceId, const MatrixType matrixType = DENSE, const MatrixFormat matrixFormat = matrixFormatDense); Matrix(const size_t numRows, const size_t numCols, ElemType* pArray, DEVICEID_TYPE deviceId, const size_t matrixFlags = matrixFlagNormal, const size_t nnz = 0); - Matrix(const Matrix& deepCopyFrom); // copy constructor, deep copy Matrix(const Matrix& deepCopyFrom, DEVICEID_TYPE deviceId); - Matrix& operator=(const Matrix& deepCopyFrom); // assignment operator, deep copy Matrix(Matrix&& moveFrom); // move constructor, shallow copy - Matrix& operator=(Matrix&& moveFrom); // move coment operator, shallow copy + Matrix& operator=(Matrix&& moveFrom); // move assignment operator, shallow copy + + Matrix DeepClone() const; + + // Disallow deep copy construction and assignment + Matrix(const Matrix& deepCopyFrom) = delete; + Matrix& operator=(const Matrix& deepCopyFrom) = delete; static Matrix Ones(const size_t rows, const size_t cols, DEVICEID_TYPE deviceId); static Matrix Zeros(const size_t rows, const size_t cols, DEVICEID_TYPE deviceId); @@ -183,7 +187,7 @@ class MATH_API Matrix : public MatrixBase void CopyColumnsStrided(const Matrix& fromMatrix, size_t numCols, size_t srcNumColsStride, size_t destNumColsStride); Matrix Diagonal() const; - Matrix AssignDiagonalValuesTo(Matrix& diag) const; + void AssignDiagonalValuesTo(Matrix& diag) const; void ShiftBy(int numShift); // TODO: all these scalars should be passed as doubles and cast down inside diff --git a/Source/SGDLib/DataReaderHelpers.h b/Source/SGDLib/DataReaderHelpers.h index 58326cadf0c6..73d6d6cec09d 100644 --- a/Source/SGDLib/DataReaderHelpers.h +++ b/Source/SGDLib/DataReaderHelpers.h @@ -396,7 +396,7 @@ namespace Microsoft { namespace MSR { namespace CNTK { { wstring nodeName = node->GetName(); shared_ptr> pLearnableNode = node; - auto funvalue = pLearnableNode->Value(); // gradient may not be allocated when this function is first called + auto& funvalue = pLearnableNode->Value(); // gradient may not be allocated when this function is first called size_t nrow = funvalue.GetNumRows(); size_t ncol = funvalue.GetNumCols(); if (m_cachedGradient.find(nodeName) == m_cachedGradient.end()) diff --git a/Source/SequenceTrainingLib/parallelforwardbackward.cpp b/Source/SequenceTrainingLib/parallelforwardbackward.cpp index 9b5fc26f943e..3d5781c3f5e0 100644 --- a/Source/SequenceTrainingLib/parallelforwardbackward.cpp +++ b/Source/SequenceTrainingLib/parallelforwardbackward.cpp @@ -574,11 +574,11 @@ struct parallelstateimpl // template void setloglls(const Microsoft::MSR::CNTK::Matrix& loglls) { - *cudalogLLs = loglls; + cudalogLLs->SetValue(loglls); } void getgamma(Microsoft::MSR::CNTK::Matrix& loglls) { - loglls = *errorsignalgpu; + loglls.SetValue(*errorsignalgpu); } template void copyalignments(edgealignments& edgeAlignments) diff --git a/Tests/UnitTests/MathTests/ConvolutionEngineTests.cpp b/Tests/UnitTests/MathTests/ConvolutionEngineTests.cpp index 7ca177cd9bd8..478d2c3acc9b 100644 --- a/Tests/UnitTests/MathTests/ConvolutionEngineTests.cpp +++ b/Tests/UnitTests/MathTests/ConvolutionEngineTests.cpp @@ -425,7 +425,7 @@ BOOST_AUTO_TEST_CASE(MaxPoolBackward) eng->Forward(*inT, in, *poolT, *outT, out); // For gradients, use the same values as outputs. - SingleMatrix srcGrad(out); + SingleMatrix srcGrad(out.DeepClone()); SingleMatrix grad(inW * inH * cmap, n, deviceId); grad.SetValue(1); @@ -541,7 +541,7 @@ BOOST_AUTO_TEST_CASE(AvgPoolBackward) eng->Forward(*inT, in, *poolT, *outT, out); // For gradients, use the same values as outputs. - SingleMatrix srcGrad(out); + SingleMatrix srcGrad(out.DeepClone()); SingleMatrix grad(inW * inH * cmap, n, deviceId); grad.SetValue(1); @@ -671,21 +671,21 @@ BOOST_AUTO_TEST_CASE(BatchNormalizationForwardTrain) SingleMatrix runMeanBuf(deviceId); SingleMatrix runMean = initMat(runMeanBuf, crowScaleBias, 1, buf); - SingleMatrix runMeanExp(runMean); + SingleMatrix runMeanExp(runMean.DeepClone()); SingleMatrix runInvStdDevBuf(deviceId); SingleMatrix runInvStdDev = initMat(runInvStdDevBuf, crowScaleBias, 1, buf); - SingleMatrix runInvStdDevExp(runInvStdDev); + SingleMatrix runInvStdDevExp(runInvStdDev.DeepClone()); SingleMatrix saveMeanBuf(deviceId); SingleMatrix saveMean = initMat(saveMeanBuf, crowScaleBias, 1, buf); - SingleMatrix saveMeanExp(saveMean); + SingleMatrix saveMeanExp(saveMean.DeepClone()); SingleMatrix saveInvStdDevBuf(deviceId); SingleMatrix saveInvStdDev = initMat(saveInvStdDevBuf, crowScaleBias, 1, buf); - SingleMatrix saveInvStdDevExp(saveInvStdDev); + SingleMatrix saveInvStdDevExp(saveInvStdDev.DeepClone()); SingleMatrix outBuf(deviceId); SingleMatrix out = initMat(outBuf, crow, ccol, buf); - SingleMatrix outExp(out); + SingleMatrix outExp(out.DeepClone()); CudaTimer time1; time1.Start(); @@ -800,7 +800,7 @@ BOOST_AUTO_TEST_CASE(BatchNormalizationForwardInference) SingleMatrix outBuf(deviceId); SingleMatrix out = initMat(outBuf, crow, ccol, buf); - SingleMatrix outExp(out); + SingleMatrix outExp(out.DeepClone()); CudaTimer time1; time1.Start(); @@ -982,14 +982,14 @@ BOOST_AUTO_TEST_CASE(BatchNormalizationBackward) SingleMatrix dScaleBuf(deviceId); SingleMatrix dScale = initMat(dScaleBuf, crowScaleBias, 1, buf); - SingleMatrix dScaleExp(dScale); + SingleMatrix dScaleExp(dScale.DeepClone()); SingleMatrix dBiasBuf(deviceId); SingleMatrix dBias = initMat(dBiasBuf, crowScaleBias, 1, buf); - SingleMatrix dBiasExp(dBias); + SingleMatrix dBiasExp(dBias.DeepClone()); SingleMatrix dxBuf(deviceId); SingleMatrix dx = initMat(dxBuf, crow, ccol, buf); - SingleMatrix dxExp(dx); + SingleMatrix dxExp(dx.DeepClone()); CudaTimer time1; time1.Start(); diff --git a/Tests/UnitTests/MathTests/MatrixBlasTests.cpp b/Tests/UnitTests/MathTests/MatrixBlasTests.cpp index 24bc3349a8fc..e3791f93ca37 100644 --- a/Tests/UnitTests/MathTests/MatrixBlasTests.cpp +++ b/Tests/UnitTests/MathTests/MatrixBlasTests.cpp @@ -122,7 +122,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixScaleAndAdd, RandomSeedFixture) const int seed = rand(); const SingleMatrix singleMatrixA = SingleMatrix::RandomUniform(1024, 512, c_deviceIdZero , - 12.34f, 55.2312f, seed + 0); const SingleMatrix singleMatrixB = SingleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34f, 55.2312f, seed + 1); - SingleMatrix singleMatrixC(singleMatrixB); + SingleMatrix singleMatrixC(singleMatrixB.DeepClone()); const float alpha = 0.34213f; SingleMatrix::ScaleAndAdd(alpha, singleMatrixA, singleMatrixC); foreach_coord (i, j, singleMatrixC) @@ -134,7 +134,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixScaleAndAdd, RandomSeedFixture) // TODO: Split into separate test case WI# 82 const SingleMatrix singleMatrixA1 = SingleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34f, 55.2312f, seed + 2); const SingleMatrix singleMatrixB1 = SingleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34f, 55.2312f, seed + 3); - SingleMatrix singleMatrixC1(singleMatrixB1); // C1==B1 + SingleMatrix singleMatrixC1(singleMatrixB1.DeepClone()); // C1==B1 const float beta = -1.4654f; SingleMatrix::ScaleAndAdd(alpha, singleMatrixA1, beta, singleMatrixC1); // C1=alpha*A1+beta*C1 foreach_coord (i, j, singleMatrixC1) @@ -146,7 +146,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixScaleAndAdd, RandomSeedFixture) // TODO: Split into separate test case WI# 82 const SingleMatrix singleMatrixA2 = SingleMatrix::RandomUniform(1024, 1, c_deviceIdZero, -12.34f, 55.2312f, seed + 4); const SingleMatrix singleMatrixB2 = SingleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34f, 55.2312f, seed + 5); // Column - SingleMatrix singleMatrixC2(singleMatrixB2); // C2==B2 + SingleMatrix singleMatrixC2(singleMatrixB2.DeepClone()); // C2==B2 const float betaOne = 1; SingleMatrix::ScaleAndAdd(alpha, singleMatrixA2, betaOne, singleMatrixC2); // C2=alpha*A1+beta*C1 foreach_coord (i, j, singleMatrixC2) @@ -162,7 +162,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixScaleAndAdd_double, RandomSeedFixture) const int seed = rand(); DoubleMatrix matrixA = DoubleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34, 55.2312, seed + 0); DoubleMatrix matrixB = DoubleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34, 55.2312, seed + 1); - DoubleMatrix matrixC(matrixB); + DoubleMatrix matrixC(matrixB.DeepClone()); const float alpha = 0.34213f; DoubleMatrix::ScaleAndAdd(alpha, matrixA, matrixC); foreach_coord (i, j, matrixC) @@ -174,7 +174,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixScaleAndAdd_double, RandomSeedFixture) // TODO: Split into separate test case WI# 82 DoubleMatrix matrixA1 = DoubleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34f, 55.2312f, seed + 2); DoubleMatrix matrixB1 = DoubleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34f, 55.2312f, seed + 3); - DoubleMatrix matrixC1(matrixB1); // C1==B1 + DoubleMatrix matrixC1(matrixB1.DeepClone()); // C1==B1 const float beta = -1.4654f; DoubleMatrix::ScaleAndAdd(alpha, matrixA1, beta, matrixC1); // C1=alpha*A1+beta*C1 foreach_coord (i, j, matrixC1) @@ -186,7 +186,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixScaleAndAdd_double, RandomSeedFixture) // TODO: Split into separate test case WI# 82 DoubleMatrix matrixA2 = DoubleMatrix::RandomUniform(1024, 1, c_deviceIdZero, -12.34, 55.2312, seed + 4); DoubleMatrix matrixB2 = DoubleMatrix::RandomUniform(1024, 512, c_deviceIdZero, -12.34, 55.2312, seed + 5); // Column - DoubleMatrix matrixC2(matrixB2); // C2==B2 + DoubleMatrix matrixC2(matrixB2.DeepClone()); // C2==B2 const float betaOne = 1; DoubleMatrix::ScaleAndAdd(alpha, matrixA2, betaOne, matrixC2); // C2=alpha*A1+beta*C1 foreach_coord (i, j, matrixC2) diff --git a/Tests/UnitTests/MathTests/MatrixFileWriteReadTests.cpp b/Tests/UnitTests/MathTests/MatrixFileWriteReadTests.cpp index 9a90472d9109..7905131c18f6 100644 --- a/Tests/UnitTests/MathTests/MatrixFileWriteReadTests.cpp +++ b/Tests/UnitTests/MathTests/MatrixFileWriteReadTests.cpp @@ -41,7 +41,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixFileWriteRead, RandomSeedFixture) { // Test Matrix in Dense mode Matrix matrix = Matrix::RandomUniform(43, 10, c_deviceIdZero, - 26.3f, 30.2f, IncrementCounter()); - Matrix matrixCopy = matrix; + Matrix matrixCopy = matrix.DeepClone(); std::wstring fileName(L"M.txt"); File file(fileName, fileOptionsText | fileOptionsReadWrite); @@ -56,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixFileWriteRead, RandomSeedFixture) // Test Matrix in Sparse mode Matrix matrixSparse = Matrix::RandomUniform(43, 10, c_deviceIdZero, - 26.3f, 30.2f, IncrementCounter()); - Matrix matrixSparseCopy = matrixSparse; + Matrix matrixSparseCopy = matrixSparse.DeepClone(); matrixSparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSR, true); diff --git a/Tests/UnitTests/MathTests/MatrixSparseDenseInteractionsTests.cpp b/Tests/UnitTests/MathTests/MatrixSparseDenseInteractionsTests.cpp index 37750dc1b7f4..e0a0bc142928 100644 --- a/Tests/UnitTests/MathTests/MatrixSparseDenseInteractionsTests.cpp +++ b/Tests/UnitTests/MathTests/MatrixSparseDenseInteractionsTests.cpp @@ -46,13 +46,13 @@ BOOST_FIXTURE_TEST_CASE(MatrixSparseTimesDense, RandomSeedFixture) mAdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -3.0f, 0.1f, IncrementCounter()), 0); // MATRIX mAsparse becomes sparse - Matrix mAsparse(mAdense); + Matrix mAsparse(mAdense.DeepClone()); mAsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSR, true); // DENSE Matrix mB = Matrix::RandomGaussian(dim2, dim3, c_deviceIdZero, 1.0f, 4.0f, IncrementCounter()); Matrix mC = Matrix::RandomGaussian(dim1, dim3, c_deviceIdZero, 1.0f, 2.0f, IncrementCounter()); - Matrix mD(mC); + Matrix mD(mC.DeepClone()); float alpha = 0.3f; float beta = 2.0f; @@ -72,12 +72,12 @@ BOOST_FIXTURE_TEST_CASE(MatrixDenseTimesSparse, RandomSeedFixture) Matrix mAdense(c_deviceIdZero); mAdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -3.0f, 0.1f, IncrementCounter()), 0); - Matrix mAsparse(mAdense); + Matrix mAsparse(mAdense.DeepClone()); mAsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSC, true); Matrix mB = Matrix::RandomGaussian(dim2, dim1, c_deviceIdZero, 1.0f, 4.0f, IncrementCounter()); Matrix mC = Matrix::RandomGaussian(dim2, dim2, c_deviceIdZero, 1.0f, 2.0f, IncrementCounter()); - Matrix mD(mC); + Matrix mD(mC.DeepClone()); bool transposeA = false, transposeB = false; float alpha = 0.3f; @@ -102,12 +102,12 @@ BOOST_FIXTURE_TEST_CASE(CPUMatrixDenseTimesSparse, RandomSeedFixture) Matrix mAdense(CPUDEVICE); mAdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -3.0f, 0.1f, IncrementCounter()), 0); - Matrix mAsparse(mAdense); + Matrix mAsparse(mAdense.DeepClone()); mAsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSC, true); Matrix mB = Matrix::RandomGaussian(dim2, dim1, CPUDEVICE, 1, 4, IncrementCounter()); Matrix mC = Matrix::RandomGaussian(dim2, dim2, CPUDEVICE, 1, 2, IncrementCounter()); - Matrix mD(mC); + Matrix mD(mC.DeepClone()); bool transposeA = false, transposeB = false; float alpha = 0.3f; @@ -157,17 +157,17 @@ BOOST_FIXTURE_TEST_CASE(MatrixSparseTimesSparse, RandomSeedFixture) { Matrix mAdense(c_deviceIdZero); mAdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -3.0f, 0.1f, IncrementCounter()), 0); - Matrix mAsparse(mAdense); + Matrix mAsparse(mAdense.DeepClone()); mAsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSR, true); Matrix mBdense(c_deviceIdZero); mBdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim2, dim1, c_deviceIdZero, -5.0f, 0.4f, IncrementCounter()), 0); - Matrix mBsparse(mBdense); + Matrix mBsparse(mBdense.DeepClone()); mBsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSR, true); Matrix mCdense(c_deviceIdZero); mCdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim1, c_deviceIdZero, -4.0f, 0.2f, IncrementCounter()), 0); - Matrix mCsparse(mCdense); + Matrix mCsparse(mCdense.DeepClone()); mCsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSR, true); bool transposeA = false, transposeB = false; @@ -193,11 +193,11 @@ BOOST_FIXTURE_TEST_CASE(MatrixSparsePlusSparse, RandomSeedFixture) { Matrix mAdense(c_deviceIdZero); mAdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -3.0f, 0.1f, IncrementCounter()), 0); - Matrix mAsparse(mAdense); + Matrix mAsparse(mAdense.DeepClone()); Matrix mBdense(c_deviceIdZero); mBdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -5.0f, 0.4f, IncrementCounter()), 0); - Matrix mBsparse(mBdense); + Matrix mBsparse(mBdense.DeepClone()); float alpha = 1.0f * rand() / RAND_MAX; Matrix::ScaleAndAdd(alpha, mAdense, mBdense); @@ -217,7 +217,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixDensePlusSparse, RandomSeedFixture) Matrix mBdense(c_deviceIdZero); mBdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -5.0f, 0.4f, IncrementCounter()), 0); - Matrix mBsparse(mBdense); + Matrix mBsparse(mBdense.DeepClone()); float alpha = 1.0f * rand() / RAND_MAX; Matrix::ScaleAndAdd(alpha, mAdense, mBdense); @@ -233,11 +233,11 @@ BOOST_FIXTURE_TEST_CASE(MatrixSparsePlusDense, RandomSeedFixture) { Matrix mAdense(c_deviceIdZero); mAdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -3.0f, 0.1f, IncrementCounter()), 0); - Matrix mAsparse(mAdense); + Matrix mAsparse(mAdense.DeepClone()); Matrix mBdense(c_deviceIdZero); mBdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -5.0f, 0.4f, IncrementCounter()), 0); - Matrix Bd1(mBdense); + Matrix Bd1(mBdense.DeepClone()); float alpha = 1.0f * rand() / RAND_MAX; Matrix::ScaleAndAdd(alpha, mAdense, mBdense); @@ -252,12 +252,12 @@ BOOST_FIXTURE_TEST_CASE(MatrixSparseElementWisePower, RandomSeedFixture) { Matrix mAdense(c_deviceIdZero); mAdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -3.0f, 0.1f, IncrementCounter()), 0); - Matrix mAsparse(mAdense); + Matrix mAsparse(mAdense.DeepClone()); mAsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSR, true); Matrix mBdense(c_deviceIdZero); mBdense.AssignTruncateBottomOf(Matrix::RandomUniform(dim1, dim2, c_deviceIdZero, -5.0f, 0.4f, IncrementCounter()), 0); - Matrix mBsparse(mBdense); + Matrix mBsparse(mBdense.DeepClone()); mBsparse.SwitchToMatrixType(MatrixType::SPARSE, matrixFormatSparseCSR, true); mAdense ^= 2.3f; diff --git a/Tests/UnitTests/MathTests/MatrixTests.cpp b/Tests/UnitTests/MathTests/MatrixTests.cpp index f9062bdb9d5c..c297e66c3f8d 100644 --- a/Tests/UnitTests/MathTests/MatrixTests.cpp +++ b/Tests/UnitTests/MathTests/MatrixTests.cpp @@ -92,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixDeepCopy, RandomSeedFixture) BOOST_CHECK_EQUAL(b.GetNumRows(), 50); BOOST_CHECK_EQUAL(b.GetNumCols(), 100); - b = a; + b.SetValue(a); BOOST_CHECK_EQUAL(a.GetNumRows(), 0); BOOST_CHECK_EQUAL(a.GetNumCols(), 0); BOOST_CHECK_EQUAL(b.GetNumRows(), 0); @@ -107,7 +107,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixDeepCopy, RandomSeedFixture) b(2, 3) = 9; BOOST_CHECK_EQUAL(b(2, 3), 9); - b = a; + b.SetValue(a); BOOST_CHECK_EQUAL(a.GetNumRows(), 0); BOOST_CHECK_EQUAL(a.GetNumCols(), 0); BOOST_CHECK_EQUAL(b.GetNumRows(), 0); @@ -500,7 +500,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixAddAndSub, RandomSeedFixture) m3 = m1 - 10; BOOST_CHECK(m3.IsEqualTo(m0)); - SingleMatrix m33(m3); + SingleMatrix m33(m3.DeepClone()); m3 += 10; BOOST_CHECK(m3.IsEqualTo(m1)); @@ -545,7 +545,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixElementOps, RandomSeedFixture) BOOST_CHECK(m3.IsEqualTo(m1, c_epsilonFloatE4)); SingleMatrix m4 = SingleMatrix::Zeros(2, 3, c_deviceIdZero); - m4 = m4.AddElementProductOf(m0, m00); + m4.SetValue(m4.AddElementProductOf(m0, m00)); BOOST_CHECK(m4.IsEqualTo(m1, c_epsilonFloatE4)); m3 = m0 ^ 4; @@ -697,7 +697,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixColumnElementMultiply, RandomSeedFixture) Matrix m = Matrix::RandomUniform(429, 1024, c_deviceIdZero, -3.4f, 1, IncrementCounter()); Matrix a = Matrix::Ones(429, 1, c_deviceIdZero); - Matrix mCopy(m); + Matrix mCopy(m.DeepClone()); m.ColumnElementMultiplyWith(a); BOOST_CHECK(mCopy.IsEqualTo(m, c_epsilonFloatE4)); @@ -757,7 +757,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixAssignXOf, RandomSeedFixture) } // AddElementProductOf - Matrix c_copy(c); + Matrix c_copy(c.DeepClone()); c.AddElementProductOf(a, b); foreach_coord (i, j, c) { @@ -789,7 +789,7 @@ BOOST_FIXTURE_TEST_CASE(MatrixAssignXOf, RandomSeedFixture) } Matrix m3 = Matrix::RandomUniform(42, 12, c_deviceIdZero, -5, 2, IncrementCounter()); - Matrix m4(m3); + Matrix m4(m3.DeepClone()); m3.AddSignOf(m1); foreach_coord (i, j, m3) {