diff --git a/src/Numerics/LinearAlgebra/Double/DenseVector.cs b/src/Numerics/LinearAlgebra/Double/DenseVector.cs index e846f644..ee6891c7 100644 --- a/src/Numerics/LinearAlgebra/Double/DenseVector.cs +++ b/src/Numerics/LinearAlgebra/Double/DenseVector.cs @@ -512,11 +512,25 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// /// The negated vector. /// Added as an alternative to the unary negation operator. - public virtual Vector Negate() + public override Vector Negate() { var result = new DenseVector(Count); Parallel.For(0, Count, i => result[i] = -Data[i]); return result; } + + /// + /// Multiplies a scalar to each element of the vector. + /// + /// The scalar to multiply. + public override void Multiply(double scalar) + { + if (scalar.AlmostEqual(1.0)) + { + return; + } + + _linearAlgebra.ScaleArray(scalar, Data); + } } } \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Double/Vector.cs b/src/Numerics/LinearAlgebra/Double/Vector.cs index fcb2625c..e8c97ae0 100644 --- a/src/Numerics/LinearAlgebra/Double/Vector.cs +++ b/src/Numerics/LinearAlgebra/Double/Vector.cs @@ -324,7 +324,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); } - CopyTo(result); + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + result.Add(scalar); } @@ -473,7 +477,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); } - CopyTo(result); + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + result.Subtract(scalar); } @@ -590,7 +598,145 @@ namespace MathNet.Numerics.LinearAlgebra.Double return ret; } + /// + /// Multiplies a scalar to each element of the vector. + /// + /// The scalar to multiply. + public virtual void Multiply(double scalar) + { + if (scalar.AlmostEqual(1.0)) + { + return; + } + + Parallel.For(0, Count, i => this[i] *= scalar); + } + + /// + /// Multiplies a scalar to each element of the vector and stores the result in the result vector. + /// + /// The scalar to multiply. + /// The vector to store the result of the multiplication. + /// If the result vector is . + /// If this vector and are not the same size. + public virtual void Multiply(double scalar, Vector result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (Count != result.Count) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); + } + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + result.Multiply(scalar); + } + + /// + /// Multiplies a vector with a scalar. + /// + /// The vector to scale. + /// The scalar value. + /// The result of the multiplication. + /// If is . + public static Vector operator *(Vector leftSide, double rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + var ret = leftSide.Clone(); + ret.Multiply(rightSide); + return ret; + } + + /// + /// Multiplies a vector with a scalar. + /// + /// The scalar value. + /// The vector to scale. + /// The result of the multiplication. + /// If is . + public static Vector operator *(double leftSide, Vector rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + var ret = rightSide.Clone(); + ret.Multiply(leftSide); + return ret; + } + + /// + /// Divides each element of the vector by a scalar. + /// + /// The scalar to divide with. + public virtual void Divide(double scalar) + { + if (scalar.AlmostEqual(1.0)) + { + return; + } + + Multiply(1.0 / scalar); + } + + /// + /// Divides each element of the vector by a scalar and stores the result in the result vector. + /// + /// The scalar to divide with. + /// The vector to store the result of the division. + /// If the result vector is . + /// If this vector and are not the same size. + public virtual void Divide(double scalar, Vector result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (Count != result.Count) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); + } + + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + result.Multiply(1.0 / scalar); + } + + /// + /// Divides a vector with a scalar. + /// + /// The vector to divide. + /// The scalar value. + /// The result of the division. + /// If is . + public static Vector operator /(Vector leftSide, double rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + var ret = leftSide.Clone(); + ret.Multiply(1.0 / rightSide); + return ret; + } + #region Implemented Interfaces #region ICloneable diff --git a/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs b/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs index 71dc7b02..fe719268 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs @@ -571,7 +571,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } - [Test] [MultipleAsserts] public void CanSubtractVectorFromItselfUsingResultVector() @@ -602,6 +601,185 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } + [Test] + [MultipleAsserts] + public void CanDivideVectorByScalar() + { + var vector = CreateVector(_data); + vector.Divide(2.0); + + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] / 2.0, vector[i]); + } + + vector.Divide(1.0); + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] / 2.0, vector[i]); + } + } + + [Test] + [MultipleAsserts] + public void CanDivideVectorByScalarUsingResultVector() + { + var vector = CreateVector(_data); + var result = CreateVector(_data.Length); + vector.Divide(2.0, result); + + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i], vector[i], "Making sure the original vector wasn't modified."); + Assert.AreEqual(_data[i] / 2.0, result[i]); + } + + vector.Divide(1.0, result); + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i], result[i]); + } + } + + [Test] + [MultipleAsserts] + public void CanMultiplyVectorByScalar() + { + var vector = CreateVector(_data); + vector.Multiply(2.0); + + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] * 2.0, vector[i]); + } + + vector.Multiply(1.0); + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] * 2.0, vector[i]); + } + } + + [Test] + [MultipleAsserts] + public void CanMultiplyVectorByScalarUsingResultVector() + { + var vector = CreateVector(_data); + var result = CreateVector(_data.Length); + vector.Multiply(2.0, result); + + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i], vector[i], "Making sure the original vector wasn't modified."); + Assert.AreEqual(_data[i] * 2.0, result[i]); + } + + vector.Multiply(1.0, result); + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i], result[i]); + } + } + + [Test] + public void ThrowsArgumentNullExceptionWhenMultiplyingScalarWithNullResultVector() + { + var vector = CreateVector(_data.Length); + Assert.Throws(() => vector.Multiply(1.0, null)); + } + + [Test] + public void ThrowsArgumentNullExceptionWhenDividingScalarWithNullResultVector() + { + var vector = CreateVector(_data.Length); + Assert.Throws(() => vector.Divide(1.0, null)); + } + + [Test] + public void ThrowsArgumentExceptionWhenMultiplyingScalarWithWrongSizeResultVector() + { + var vector = CreateVector(_data.Length); + var result = CreateVector(_data.Length + 1); + Assert.Throws(() => vector.Multiply(0.0, result)); + } + + [Test] + public void ThrowsArgumentExceptionWhenDividingScalarWithWrongSizeResultVector() + { + var vector = CreateVector(_data.Length); + var result = CreateVector(_data.Length + 1); + Assert.Throws(() => vector.Divide(0.0, result)); + } + + [Test] + [MultipleAsserts] + public void CanMultiplyVectorByScalarUsingOperators() + { + var vector = CreateVector(_data); + vector = vector * 2.0; + + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] * 2.0, vector[i]); + } + + vector = vector * 1.0; + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] * 2.0, vector[i]); + } + + vector = CreateVector(_data); + vector = 2.0 * vector; + + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] * 2.0, vector[i]); + } + + vector = 1.0 * vector; + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] * 2.0, vector[i]); + } + } + + [Test] + [MultipleAsserts] + public void CanDivideVectorByScalarUsingOperators() + { + var vector = CreateVector(_data); + vector = vector / 2.0; + + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] / 2.0, vector[i]); + } + + vector = vector / 1.0; + for (var i = 0; i < _data.Length; i++) + { + Assert.AreEqual(_data[i] / 2.0, vector[i]); + } + } + + [Test] + [MultipleAsserts] + public void OperatorMultiplyThrowsArgumentNullExceptionWhenVectorIsNull() + { + Vector vector = null; + Vector result = null; + Assert.Throws(() => result = vector * 2.0); + Assert.Throws(() => result = 2.0 * vector); + } + + [Test] + public void OperatorDivideThrowsArgumentNullExceptionWhenVectorIsNull() + { + Vector vector = null; + Assert.Throws(() => vector = vector / 2.0); + } + protected abstract Vector CreateVector(int size); protected abstract Vector CreateVector(IList data);