From 9b72b71ebf81956c9241426ec45e2e15399b8737 Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Thu, 6 Jan 2011 23:02:00 +0800 Subject: [PATCH] sparse vector optimizations --- src/MathNet.Numerics.5.1.ReSharper | 13 +- .../LinearAlgebra/Complex/DenseVector.cs | 16 + .../LinearAlgebra/Complex/SparseMatrix.cs | 2 +- .../LinearAlgebra/Complex/SparseVector.cs | 576 ++++++------------ src/Numerics/LinearAlgebra/Complex/Vector.cs | 101 ++- .../LinearAlgebra/Complex32/DenseVector.cs | 16 + .../LinearAlgebra/Complex32/SparseMatrix.cs | 2 +- .../LinearAlgebra/Complex32/SparseVector.cs | 548 ++++++----------- .../LinearAlgebra/Complex32/Vector.cs | 99 ++- .../LinearAlgebra/Double/DenseVector.cs | 16 + .../LinearAlgebra/Double/SparseMatrix.cs | 24 +- .../LinearAlgebra/Double/SparseVector.cs | 566 ++++++----------- src/Numerics/LinearAlgebra/Double/Vector.cs | 96 ++- src/Numerics/LinearAlgebra/Generic/Vector.cs | 36 +- .../LinearAlgebra/Single/DenseVector.cs | 16 + .../LinearAlgebra/Single/SparseMatrix.cs | 2 +- .../LinearAlgebra/Single/SparseVector.cs | 539 ++++++---------- src/Numerics/LinearAlgebra/Single/Vector.cs | 98 ++- .../Complex/UserDefinedVectorTests.cs | 22 +- .../Complex32/UserDefinedVectorTests.cs | 23 +- .../Double/UserDefinedVectorTests.cs | 23 +- .../Single/UserDefinedVectorTests.cs | 23 +- 22 files changed, 1125 insertions(+), 1732 deletions(-) diff --git a/src/MathNet.Numerics.5.1.ReSharper b/src/MathNet.Numerics.5.1.ReSharper index 46415860..af81e577 100644 --- a/src/MathNet.Numerics.5.1.ReSharper +++ b/src/MathNet.Numerics.5.1.ReSharper @@ -15,7 +15,10 @@ cancelled pre preconditioner Preconditioners -indetermined +indetermined +indices +Pointwise +Frobenius @@ -561,7 +564,7 @@ indetermined - false + true Any @@ -593,7 +596,7 @@ indetermined - false + true Any @@ -657,7 +660,7 @@ indetermined - false + true Any @@ -686,7 +689,7 @@ indetermined - false + true Any diff --git a/src/Numerics/LinearAlgebra/Complex/DenseVector.cs b/src/Numerics/LinearAlgebra/Complex/DenseVector.cs index b743b1a4..630c778c 100644 --- a/src/Numerics/LinearAlgebra/Complex/DenseVector.cs +++ b/src/Numerics/LinearAlgebra/Complex/DenseVector.cs @@ -1334,5 +1334,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex index => otherVector.Data[index] = Data[index].Conjugate()); } } + + /// Gets the value at the given . + /// The index of the value to get or set. + /// The value of the vector at the given . + internal protected override Complex At(int index) + { + return Data[index]; + } + + /// Sets the at the given . + /// The index of the value to get or set. + /// The value to set. + internal protected override void At(int index, Complex value) + { + Data[index] = value; + } } } diff --git a/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs index ddcd222e..88b945d2 100644 --- a/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs @@ -194,7 +194,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// /// The matrix to copy. public SparseMatrix(Matrix matrix) - : base(matrix.RowCount, matrix.ColumnCount) + : this(matrix.RowCount, matrix.ColumnCount) { var sparseMatrix = matrix as SparseMatrix; diff --git a/src/Numerics/LinearAlgebra/Complex/SparseVector.cs b/src/Numerics/LinearAlgebra/Complex/SparseVector.cs index 551ca0b4..64146344 100644 --- a/src/Numerics/LinearAlgebra/Complex/SparseVector.cs +++ b/src/Numerics/LinearAlgebra/Complex/SparseVector.cs @@ -38,13 +38,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// /// A vector with sparse storage. /// + /// The sparse vector is not thread safe. public class SparseVector : Vector { - /// - /// Lock object for the indexer. - /// - private readonly object _lockObject = new object(); - /// /// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored. /// @@ -130,7 +126,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex { for (var i = 0; i < other.Count; i++) { - this[i] = other[i]; + this[i] = other.At(i); } } else @@ -174,9 +170,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// /// The array to create this vector from. /// The vector copy the array. Any changes to the vector will NOT change the array. - public SparseVector(Complex[] array) : this(array.Length) + public SparseVector(IList array) : this(array.Count) { - for (var i = 0; i < array.Length; i++) + for (var i = 0; i < array.Count; i++) { this[i] = array[i]; } @@ -193,7 +189,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex var matrix = new SparseMatrix(Count, 1); for (var i = 0; i < NonZerosCount; i++) { - matrix[_nonZeroIndices[i], 0] = _nonZeroValues[i]; + matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); } return matrix; @@ -208,55 +204,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex var matrix = new SparseMatrix(1, Count); for (var i = 0; i < NonZerosCount; i++) { - matrix[0, _nonZeroIndices[i]] = _nonZeroValues[i]; + matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); } return matrix; } - /// Gets or sets the value at the given . - /// The index of the value to get or set. - /// The value of the vector at the given . - /// If is negative or - /// greater than the size of the vector. - public override Complex this[int index] - { - get - { - // If index is out of bounds - if ((index < 0) || (index >= Count)) - { - throw new IndexOutOfRangeException(); - } - - lock (_lockObject) - { - // Search if item idex exists in NonZeroIndices array in range "0 - complex nonzero values count" - var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); - if (itemIndex >= 0) - { - return _nonZeroValues[itemIndex]; - } - } - - return Complex.Zero; - } - - set - { - // If index is out of bounds - if ((index < 0) || (index >= Count)) - { - throw new IndexOutOfRangeException(); - } - - lock (_lockObject) - { - SetValue(index, value); - } - } - } - /// /// Creates a matrix with the given dimensions using the same storage type /// as this vector. @@ -330,10 +283,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex var otherVector = target as SparseVector; if (otherVector == null) { - CommonParallel.For( - 0, - Count, - index => target[index] = this[index]); + target.Clear(); + + for (var index = 0; index < NonZerosCount; index++) + { + target.At(_nonZeroIndices[index], _nonZeroValues[index]); + } } else { @@ -392,147 +347,42 @@ namespace MathNet.Numerics.LinearAlgebra.Complex } } } + #region Operators and supplementary functions /// - /// Adds a complex to each element of the vector. - /// - /// The complex to add. - /// A copy of the vector with the complex added. - public override Vector Add(Complex complex) - { - if (complex == Complex.Zero) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] += complex; - } - - return copy; - } - - /// - /// Adds a complex to each element of the vector and stores the result in the result vector. - /// - /// The complex to add. - /// The vector to store the result of the addition. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Add(Complex complex, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Add(complex, result); - } - - /// - /// Adds another vector to this vector. + /// Adds a scalar to each element of the vector and stores the result in the result vector. /// - /// The vector to add to this one. - /// A new vector containing the sum of both vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Add(Vector other) - { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Add(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(Complex.One, sparseVector); - return copy; - } - - /// - /// Adds the scaled sparse vector. - /// - /// The alpha. - /// The other. - private void AddScaledSparseVector(Complex alpha, SparseVector other) + /// + /// The scalar to add. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(Complex scalar, Vector result) { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) + if (scalar == Complex.Zero) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } - if (alpha == Complex.Zero) - { return; } - // I don't use ILinearAlgebraProvider because we will get no benefit due to "lock" in this[index] - // Possible fucniton in ILinearAlgebraProvider may be AddSparseVectorToScaledSparseVector(T[] y, int[] yIndices, T alpha, T[] x, int[] xIndices); - // But it require to develop value setting algorithm and due to "lock" it will be even more greedy then implemented below - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, result)) { - // Adding the same instance of sparse vector. That means if we modify "this" then "other" will be modified too. - // To avoid such problem lets change values in internal storage of "this" - if (alpha == Complex.One) - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += _nonZeroValues[i]; - } - } - else if (alpha == -Complex.One) - { - Clear(); // Vector is subtracted from itself - return; - } - else - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += alpha * _nonZeroValues[i]; - } - } + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += scalar); } else { - // "this" and "other" are different objects, so by modifying "this" the "other" object will not be changed - if (alpha == Complex.One) + for (var index = 0; index < Count; index++) { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += other._nonZeroValues[i]; - } - } - else - { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += alpha * other._nonZeroValues[i]; - } + result.At(index, At(index) + scalar); } } } @@ -540,53 +390,26 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// /// Adds another vector to this vector and stores the result into the result vector. /// - /// The vector to add to this one. - /// The vector to store the result of the addition. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Add(Vector other, Vector result) + /// + /// The vector to add to this one. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) + if (ReferenceEquals(this, result)) { - var tmp = Add(other); - tmp.CopyTo(result); + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += _nonZeroValues[index]); } else { - var sparse = result as SparseVector; - if (sparse == null) + for (var index = 0; index < Count; index++) { - base.Add(other, result); - } - else - { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Add(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(Complex.One, sparseother); - } + result.At(index, At(index) + other.At(index)); } } } @@ -637,130 +460,39 @@ namespace MathNet.Numerics.LinearAlgebra.Complex } /// - /// Subtracts a complex from each element of the vector. - /// - /// The complex to subtract. - /// A new vector containing the subtraction of this vector and the complex. - public override Vector Subtract(Complex complex) - { - if (complex == Complex.Zero) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] -= complex; - } - - return copy; - } - - /// - /// Subtracts a complex from each element of the vector and stores the result in the result vector. - /// - /// The complex to subtract. - /// The vector to store the result of the subtraction. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Subtract(Complex complex, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Subtract(complex, result); - } - - /// - /// Subtracts another vector from this vector. + /// Subtracts a scalar from each element of the vector and stores the result in the result vector. /// - /// The vector to subtract from this one. - /// A new vector containing the subtraction of the the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Subtract(Vector other) + /// + /// The scalar to subtract. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(Complex scalar, Vector result) { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Subtract(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(-Complex.One, sparseVector); - return copy; + DoAdd(-scalar, result); } /// /// Subtracts another vector to this vector and stores the result into the result vector. /// - /// The vector to subtract from this one. - /// The vector to store the result of the subtraction. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Subtract(Vector other, Vector result) + /// + /// The vector to subtract from this one. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) + if (ReferenceEquals(this, other)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); + result.Clear(); + return; } - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) - { - var tmp = Subtract(other); - tmp.CopyTo(result); - } - else + for (var index = 0; index < Count; index++) { - var sparse = result as SparseVector; - if (sparse == null) - { - base.Subtract(other, result); - } - else - { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Subtract(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(-Complex.One, sparseother); - } - } + result.At(index, At(index) - other.At(index)); } } @@ -835,52 +567,81 @@ namespace MathNet.Numerics.LinearAlgebra.Complex } /// - /// Multiplies a complex to each element of the vector. + /// Multiplies a scalar to each element of the vector and stores the result in the result vector. /// - /// The complex to multiply. - /// A new vector that is the multiplication of the vector and the complex. - public override Vector Multiply(Complex complex) + /// + /// The scalar to multiply. + /// + /// + /// The vector to store the result of the multiplication. + /// + protected override void DoMultiply(Complex scalar, Vector result) { - if (complex == Complex.One) + if (scalar == Complex.One) { - return Clone(); + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + return; } - if (complex == Complex.Zero) + if (scalar == Complex.Zero) { - return new SparseVector(Count); + result.Clear(); + return; } - var copy = new SparseVector(this); - Control.LinearAlgebraProvider.ScaleArray(complex, copy._nonZeroValues, copy._nonZeroValues); - return copy; + var sparseResult = result as SparseVector; + if (sparseResult == null) + { + result.Clear(); + for (var index = 0; index < NonZerosCount; index++) + { + result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); + } + } + else + { + if (!ReferenceEquals(this, result)) + { + sparseResult.NonZerosCount = NonZerosCount; + sparseResult._nonZeroIndices = new int[NonZerosCount]; + Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, _nonZeroIndices.Length * Constants.SizeOfInt); + sparseResult._nonZeroValues = new Complex[_nonZeroValues.Length]; + } + + Control.LinearAlgebraProvider.ScaleArray(scalar, _nonZeroValues, sparseResult._nonZeroValues); + } } /// /// Computes the dot product between this vector and another vector. /// - /// The other vector to add. - /// The result of the addition. - /// If is not of the same size. - /// If is . - public override Complex DotProduct(Vector other) + /// + /// The other vector to add. + /// + /// s + /// The result of the addition. + /// + protected override Complex DoDotProduct(Vector other) { - if (other == null) - { - throw new ArgumentNullException("other"); - } + var result = Complex.Zero; - if (Count != other.Count) + if (ReferenceEquals(this, other)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * _nonZeroValues[i]; + } } - - var result = Complex.Zero; - - // base implementation iterates though all elements, but we need only take non-zeros - for (var i = 0; i < NonZerosCount; i++) + else { - result += _nonZeroValues[i] * other[_nonZeroIndices[i]]; + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); + } } return result; @@ -1023,7 +784,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex var result = new SparseVector(length); for (var i = index; i < index + length; i++) { - result[i - index] = this[i]; + result.At(i - index, At(i)); } return result; @@ -1049,7 +810,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex for (var i = 0; i < values.Length; i++) { - this[i] = values[i]; + At(i, values[i]); } } @@ -1084,35 +845,51 @@ namespace MathNet.Numerics.LinearAlgebra.Complex } /// - /// Pointwise multiplies this vector with another vector. + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. /// /// The vector to pointwise multiply with this one. - /// A new vector which is the pointwise multiplication of the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector PointwiseMultiply(Vector other) + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Vector other, Vector result) { - if (other == null) + if (ReferenceEquals(this, other)) { - throw new ArgumentNullException("other"); + for (var i = 0; i < NonZerosCount; i++) + { + _nonZeroValues[i] *= _nonZeroValues[i]; + } } - - if (Count != other.Count) + else { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, other.At(index) * _nonZeroValues[i]); + } } + } - var copy = new SparseVector(Count); - for (var i = 0; i < _nonZeroIndices.Length; i++) + /// + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. + /// + /// The vector to pointwise multiply with this one. + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseDivide(Vector other, Vector result) + { + if (ReferenceEquals(this, other)) { - var d = _nonZeroValues[i] * other[_nonZeroIndices[i]]; - if (d != Complex.Zero) + for (var i = 0; i < NonZerosCount; i++) { - copy[_nonZeroIndices[i]] = d; + _nonZeroValues[i] /= _nonZeroValues[i]; + } + } + else + { + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, _nonZeroValues[i] / other.At(index)); } } - - return copy; } /// @@ -1123,7 +900,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// Matrix M[i,j] = u[i]*v[j] /// If the u vector is . /// If the v vector is . - public static Matrix /*SparseMatrix*/ OuterProduct(SparseVector u, SparseVector v) + public static Matrix OuterProduct(SparseVector u, SparseVector v) { if (u == null) { @@ -1361,13 +1138,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex } #endregion + /// + /// Gets the value at the given index. + /// + /// Value real index in array + /// The value at the given index. + internal protected override Complex At(int index) + { + // Search if item idex exists in NonZeroIndices array in range "0 - real nonzero values count" + var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); + return itemIndex >= 0 ? _nonZeroValues[itemIndex] : Complex.Zero; + } + /// /// Delete, Add or Update the value in NonZeroValues and NonZeroIndices /// /// Value real index in array /// The value to set. /// This method assume that index is between 0 and Array Size - private void SetValue(int index, Complex value) + internal protected override void At(int index, Complex value) { // Search if "index" already exists in range "0 - complex nonzero values count" var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); @@ -1549,5 +1338,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex yield return new KeyValuePair(_nonZeroIndices[i], _nonZeroValues[i]); } } + + /// + /// Returns the data contained in the vector as an array. + /// + /// + /// The vector's data as an array. + /// + public override Complex[] ToArray() + { + var ret = new Complex[Count]; + for (var i = 0; i < NonZerosCount; i++) + { + ret[_nonZeroIndices[i]] = _nonZeroValues[i]; + } + + return ret; + } } } diff --git a/src/Numerics/LinearAlgebra/Complex/Vector.cs b/src/Numerics/LinearAlgebra/Complex/Vector.cs index e0440e25..39c3ca9f 100644 --- a/src/Numerics/LinearAlgebra/Complex/Vector.cs +++ b/src/Numerics/LinearAlgebra/Complex/Vector.cs @@ -63,10 +63,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// protected override void DoAdd(Complex scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + scalar); + } } /// @@ -80,10 +80,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// protected override void DoAdd(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + other.At(index)); + } } /// @@ -111,10 +111,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// protected override void DoSubtract(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] - other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) - other.At(index)); + } } /// @@ -128,10 +128,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// protected override void DoMultiply(Complex scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * scalar); + } } /// @@ -145,10 +145,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// protected override void DoDivide(Complex scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / scalar); + DoMultiply(1 / scalar, result); } /// @@ -158,10 +155,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// The vector to store the result of the pointwise multiplication. protected override void DoPointwiseMultiply(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * other.At(index)); + } } /// @@ -171,10 +168,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// The vector to store the result of the pointwise division. protected override void DoPointwiseDivide(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) / other.At(index)); + } } /// @@ -183,7 +180,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// /// The other vector to add. /// - /// s + /// /// The result of the addition. /// protected override Complex DoDotProduct(Vector other) @@ -191,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex return CommonParallel.Aggregate( 0, Count, - i => this[i] * other[i]); + i => At(i) * other.At(i)); } /// @@ -200,7 +197,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// The value of the absolute minimum element. public override Complex AbsoluteMinimum() { - return this[AbsoluteMinimumIndex()].Magnitude; + return At(AbsoluteMinimumIndex()).Magnitude; } /// @@ -210,10 +207,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex public override int AbsoluteMinimumIndex() { var index = 0; - var min = this[index].Magnitude; + var min = At(index).Magnitude; for (var i = 1; i < Count; i++) { - var test = this[i].Magnitude; + var test = At(i).Magnitude; if (test < min) { index = i; @@ -230,7 +227,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// The value of the absolute maximum element. public override Complex AbsoluteMaximum() { - return this[AbsoluteMaximumIndex()].Magnitude; + return At(AbsoluteMaximumIndex()).Magnitude; } /// @@ -240,10 +237,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex public override int AbsoluteMaximumIndex() { var index = 0; - var max = this[index].Magnitude; + var max = At(index).Magnitude; for (var i = 1; i < Count; i++) { - var test = this[i].Magnitude; + var test = At(i).Magnitude; if (test > max) { index = i; @@ -263,7 +260,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex return CommonParallel.Aggregate( 0, Count, - i => this[i]); + i => At(i)); } /// @@ -275,7 +272,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex return CommonParallel.Aggregate( 0, Count, - i => this[i].Magnitude); + i => At(i).Magnitude); } /// @@ -285,7 +282,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// The p value. /// /// - /// Scalar ret = (sum(abs(this[i])^p))^(1/p) + /// Scalar ret = (sum(abs(At(i))^p))^(1/p) /// public override Complex Norm(double p) { @@ -299,14 +296,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex return CommonParallel.Select( 0, Count, - (index, localData) => Math.Max(localData, this[index].Magnitude), + (index, localData) => Math.Max(localData, At(index).Magnitude), Math.Max); } var sum = CommonParallel.Aggregate( 0, Count, - index => Math.Pow(this[index].Magnitude, p)); + index => Math.Pow(At(index).Magnitude, p)); return Math.Pow(sum, 1.0 / p); } @@ -317,11 +314,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// Target vector protected override void DoConjugate(Vector target) { - CopyTo(target); - CommonParallel.For( - 0, - Count, - index => target[index] = this[index].Conjugate()); + for (var index = 0; index < Count; index++) + { + target.At(index, At(index).Conjugate()); + } } /// @@ -336,10 +332,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex public override Vector Negate() { var result = CreateVector(Count); - CommonParallel.For( - 0, - Count, - index => result[index] = -this[index]); + + for (var index = 0; index < Count; index++) + { + result.At(index, -At(index)); + } return result; } @@ -364,7 +361,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex var vector = CreateVector(length); for (var index = 0; index < length; index++) { - vector[index] = new Complex(randomDistribution.Sample(), randomDistribution.Sample()); + vector.At(index, new Complex(randomDistribution.Sample(), randomDistribution.Sample())); } return vector; @@ -390,7 +387,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex var vector = CreateVector(length); for (var index = 0; index < length; index++) { - vector[index] = new Complex(randomDistribution.Sample(), randomDistribution.Sample()); + vector.At(index, new Complex(randomDistribution.Sample(), randomDistribution.Sample())); } return vector; diff --git a/src/Numerics/LinearAlgebra/Complex32/DenseVector.cs b/src/Numerics/LinearAlgebra/Complex32/DenseVector.cs index 2214e708..158f6888 100644 --- a/src/Numerics/LinearAlgebra/Complex32/DenseVector.cs +++ b/src/Numerics/LinearAlgebra/Complex32/DenseVector.cs @@ -1387,5 +1387,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 index => otherVector.Data[index] = Data[index].Conjugate()); } } + + /// Gets the value at the given . + /// The index of the value to get or set. + /// The value of the vector at the given . + internal protected override Complex32 At(int index) + { + return Data[index]; + } + + /// Sets the at the given . + /// The index of the value to get or set. + /// The value to set. + internal protected override void At(int index, Complex32 value) + { + Data[index] = value; + } } } diff --git a/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs index 584a13e4..ee35a380 100644 --- a/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs @@ -189,7 +189,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// /// The matrix to copy. public SparseMatrix(Matrix matrix) - : base(matrix.RowCount, matrix.ColumnCount) + : this(matrix.RowCount, matrix.ColumnCount) { var sparseMatrix = matrix as SparseMatrix; diff --git a/src/Numerics/LinearAlgebra/Complex32/SparseVector.cs b/src/Numerics/LinearAlgebra/Complex32/SparseVector.cs index 3ceedb9f..991f32c8 100644 --- a/src/Numerics/LinearAlgebra/Complex32/SparseVector.cs +++ b/src/Numerics/LinearAlgebra/Complex32/SparseVector.cs @@ -38,13 +38,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// /// A vector with sparse storage. /// + /// The sparse vector is not thread safe. public class SparseVector : Vector { - /// - /// Lock object for the indexer. - /// - private readonly object _lockObject = new object(); - /// /// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored. /// @@ -130,7 +126,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 { for (var i = 0; i < other.Count; i++) { - this[i] = other[i]; + this[i] = other.At(i); } } else @@ -174,9 +170,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// /// The array to create this vector from. /// The vector copy the array. Any changes to the vector will NOT change the array. - public SparseVector(Complex32[] array) : this(array.Length) + public SparseVector(IList array) : this(array.Count) { - for (var i = 0; i < array.Length; i++) + for (var i = 0; i < array.Count; i++) { this[i] = array[i]; } @@ -193,7 +189,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 var matrix = new SparseMatrix(Count, 1); for (var i = 0; i < NonZerosCount; i++) { - matrix[_nonZeroIndices[i], 0] = _nonZeroValues[i]; + matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); } return matrix; @@ -208,7 +204,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 var matrix = new SparseMatrix(1, Count); for (var i = 0; i < NonZerosCount; i++) { - matrix[0, _nonZeroIndices[i]] = _nonZeroValues[i]; + matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); } return matrix; @@ -229,17 +225,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 throw new IndexOutOfRangeException(); } - lock (_lockObject) - { - // Search if item idex exists in NonZeroIndices array in range "0 - complex nonzero values count" - var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); - if (itemIndex >= 0) - { - return _nonZeroValues[itemIndex]; - } - } - - return Complex32.Zero; + return At(index); } set @@ -250,10 +236,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 throw new IndexOutOfRangeException(); } - lock (_lockObject) - { - SetValue(index, value); - } + At(index, value); } } @@ -330,10 +313,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 var otherVector = target as SparseVector; if (otherVector == null) { - CommonParallel.For( - 0, - Count, - index => target[index] = this[index]); + target.Clear(); + + for (var index = 0; index < NonZerosCount; index++) + { + target.At(_nonZeroIndices[index], _nonZeroValues[index]); + } } else { @@ -392,147 +377,42 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 } } } + #region Operators and supplementary functions /// - /// Adds a complex to each element of the vector. + /// Adds a scalar to each element of the vector and stores the result in the result vector. /// - /// The complex to add. - /// A copy of the vector with the complex added. - public override Vector Add(Complex32 complex) - { - if (complex == Complex32.Zero) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] += complex; - } - - return copy; - } - - /// - /// Adds a complex to each element of the vector and stores the result in the result vector. - /// - /// The complex to add. - /// The vector to store the result of the addition. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Add(Complex32 complex, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Add(complex, result); - } - - /// - /// Adds another vector to this vector. - /// - /// The vector to add to this one. - /// A new vector containing the sum of both vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Add(Vector other) - { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Add(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(Complex32.One, sparseVector); - return copy; - } - - /// - /// Adds the scaled sparse vector. - /// - /// The alpha. - /// The other. - private void AddScaledSparseVector(Complex32 alpha, SparseVector other) + /// + /// The scalar to add. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(Complex32 scalar, Vector result) { - if (other == null) + if (scalar == Complex32.Zero) { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } - if (alpha == Complex32.Zero) - { return; } - // I don't use ILinearAlgebraProvider because we will get no benefit due to "lock" in this[index] - // Possible fucniton in ILinearAlgebraProvider may be AddSparseVectorToScaledSparseVector(T[] y, int[] yIndices, T alpha, T[] x, int[] xIndices); - // But it require to develop value setting algorithm and due to "lock" it will be even more greedy then implemented below - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, result)) { - // Adding the same instance of sparse vector. That means if we modify "this" then "other" will be modified too. - // To avoid such problem lets change values in internal storage of "this" - if (alpha == Complex32.One) - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += _nonZeroValues[i]; - } - } - else if (alpha == -Complex32.One) - { - Clear(); // Vector is subtracted from itself - return; - } - else - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += alpha * _nonZeroValues[i]; - } - } + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += scalar); } else { - // "this" and "other" are different objects, so by modifying "this" the "other" object will not be changed - if (alpha == Complex32.One) + for (var index = 0; index < Count; index++) { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += other._nonZeroValues[i]; - } - } - else - { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += alpha * other._nonZeroValues[i]; - } + result.At(index, At(index) + scalar); } } } @@ -540,53 +420,26 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// /// Adds another vector to this vector and stores the result into the result vector. /// - /// The vector to add to this one. - /// The vector to store the result of the addition. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Add(Vector other, Vector result) + /// + /// The vector to add to this one. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) + if (ReferenceEquals(this, result)) { - var tmp = Add(other); - tmp.CopyTo(result); + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += _nonZeroValues[index]); } else { - var sparse = result as SparseVector; - if (sparse == null) + for (var index = 0; index < Count; index++) { - base.Add(other, result); - } - else - { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Add(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(Complex32.One, sparseother); - } + result.At(index, At(index) + other.At(index)); } } } @@ -637,130 +490,39 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 } /// - /// Subtracts a complex from each element of the vector. - /// - /// The complex to subtract. - /// A new vector containing the subtraction of this vector and the complex. - public override Vector Subtract(Complex32 complex) - { - if (complex == Complex32.Zero) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] -= complex; - } - - return copy; - } - - /// - /// Subtracts a complex from each element of the vector and stores the result in the result vector. - /// - /// The complex to subtract. - /// The vector to store the result of the subtraction. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Subtract(Complex32 complex, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Subtract(complex, result); - } - - /// - /// Subtracts another vector from this vector. + /// Subtracts a scalar from each element of the vector and stores the result in the result vector. /// - /// The vector to subtract from this one. - /// A new vector containing the subtraction of the the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Subtract(Vector other) + /// + /// The scalar to subtract. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(Complex32 scalar, Vector result) { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Subtract(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(-Complex32.One, sparseVector); - return copy; + DoAdd(-scalar, result); } /// /// Subtracts another vector to this vector and stores the result into the result vector. /// - /// The vector to subtract from this one. - /// The vector to store the result of the subtraction. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Subtract(Vector other, Vector result) + /// + /// The vector to subtract from this one. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) + if (ReferenceEquals(this, other)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); + result.Clear(); + return; } - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) - { - var tmp = Subtract(other); - tmp.CopyTo(result); - } - else + for (var index = 0; index < Count; index++) { - var sparse = result as SparseVector; - if (sparse == null) - { - base.Subtract(other, result); - } - else - { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Subtract(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(-Complex32.One, sparseother); - } - } + result.At(index, At(index) - other.At(index)); } } @@ -835,52 +597,81 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 } /// - /// Multiplies a complex to each element of the vector. + /// Multiplies a scalar to each element of the vector and stores the result in the result vector. /// - /// The complex to multiply. - /// A new vector that is the multiplication of the vector and the complex. - public override Vector Multiply(Complex32 complex) + /// + /// The scalar to multiply. + /// + /// + /// The vector to store the result of the multiplication. + /// + protected override void DoMultiply(Complex32 scalar, Vector result) { - if (complex == Complex32.One) + if (scalar == Complex32.One) { - return Clone(); + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + return; } - if (complex == Complex32.Zero) + if (scalar == Complex32.Zero) { - return new SparseVector(Count); + result.Clear(); + return; } - var copy = new SparseVector(this); - Control.LinearAlgebraProvider.ScaleArray(complex, copy._nonZeroValues, copy._nonZeroValues); - return copy; + var sparseResult = result as SparseVector; + if (sparseResult == null) + { + result.Clear(); + for (var index = 0; index < NonZerosCount; index++) + { + result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); + } + } + else + { + if (!ReferenceEquals(this, result)) + { + sparseResult.NonZerosCount = NonZerosCount; + sparseResult._nonZeroIndices = new int[NonZerosCount]; + Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, _nonZeroIndices.Length * Constants.SizeOfInt); + sparseResult._nonZeroValues = new Complex32[_nonZeroValues.Length]; + } + + Control.LinearAlgebraProvider.ScaleArray(scalar, _nonZeroValues, sparseResult._nonZeroValues); + } } /// /// Computes the dot product between this vector and another vector. /// - /// The other vector to add. - /// The result of the addition. - /// If is not of the same size. - /// If is . - public override Complex32 DotProduct(Vector other) + /// + /// The other vector to add. + /// + /// s + /// The result of the addition. + /// + protected override Complex32 DoDotProduct(Vector other) { - if (other == null) - { - throw new ArgumentNullException("other"); - } + var result = Complex32.Zero; - if (Count != other.Count) + if (ReferenceEquals(this, other)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * _nonZeroValues[i]; + } } - - var result = Complex32.Zero; - - // base implementation iterates though all elements, but we need only take non-zeros - for (var i = 0; i < NonZerosCount; i++) + else { - result += _nonZeroValues[i] * other[_nonZeroIndices[i]]; + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); + } } return result; @@ -1023,7 +814,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 var result = new SparseVector(length); for (var i = index; i < index + length; i++) { - result[i - index] = this[i]; + result.At(i - index, At(i)); } return result; @@ -1049,7 +840,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 for (var i = 0; i < values.Length; i++) { - this[i] = values[i]; + At(i, values[i]); } } @@ -1084,35 +875,51 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 } /// - /// Pointwise multiplies this vector with another vector. + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. /// /// The vector to pointwise multiply with this one. - /// A new vector which is the pointwise multiplication of the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector PointwiseMultiply(Vector other) + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Vector other, Vector result) { - if (other == null) + if (ReferenceEquals(this, other)) { - throw new ArgumentNullException("other"); + for (var i = 0; i < NonZerosCount; i++) + { + _nonZeroValues[i] *= _nonZeroValues[i]; + } } - - if (Count != other.Count) + else { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, other.At(index) * _nonZeroValues[i]); + } } + } - var copy = new SparseVector(Count); - for (var i = 0; i < _nonZeroIndices.Length; i++) + /// + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. + /// + /// The vector to pointwise multiply with this one. + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseDivide(Vector other, Vector result) + { + if (ReferenceEquals(this, other)) { - var d = _nonZeroValues[i] * other[_nonZeroIndices[i]]; - if (d != Complex32.Zero) + for (var i = 0; i < NonZerosCount; i++) { - copy[_nonZeroIndices[i]] = d; + _nonZeroValues[i] /= _nonZeroValues[i]; + } + } + else + { + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, _nonZeroValues[i] / other.At(index)); } } - - return copy; } /// @@ -1361,13 +1168,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 } #endregion + /// + /// Gets the value at the given index. + /// + /// Value real index in array + /// The value at the given index. + internal protected override Complex32 At(int index) + { + // Search if item idex exists in NonZeroIndices array in range "0 - real nonzero values count" + var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); + return itemIndex >= 0 ? _nonZeroValues[itemIndex] : Complex32.Zero; + } + /// /// Delete, Add or Update the value in NonZeroValues and NonZeroIndices /// /// Value real index in array /// The value to set. /// This method assume that index is between 0 and Array Size - private void SetValue(int index, Complex32 value) + internal protected override void At(int index, Complex32 value) { // Search if "index" already exists in range "0 - complex nonzero values count" var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); @@ -1549,5 +1368,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 yield return new KeyValuePair(_nonZeroIndices[i], _nonZeroValues[i]); } } + + /// + /// Returns the data contained in the vector as an array. + /// + /// + /// The vector's data as an array. + /// + public override Complex32[] ToArray() + { + var ret = new Complex32[Count]; + for (var i = 0; i < NonZerosCount; i++) + { + ret[_nonZeroIndices[i]] = _nonZeroValues[i]; + } + + return ret; + } } } diff --git a/src/Numerics/LinearAlgebra/Complex32/Vector.cs b/src/Numerics/LinearAlgebra/Complex32/Vector.cs index ea0f3dc7..9db2acf2 100644 --- a/src/Numerics/LinearAlgebra/Complex32/Vector.cs +++ b/src/Numerics/LinearAlgebra/Complex32/Vector.cs @@ -63,10 +63,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// protected override void DoAdd(Complex32 scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + scalar); + } } /// @@ -80,10 +80,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// protected override void DoAdd(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + other.At(index)); + } } /// @@ -111,10 +111,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// protected override void DoSubtract(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] - other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) - other.At(index)); + } } /// @@ -128,10 +128,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// protected override void DoMultiply(Complex32 scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * scalar); + } } /// @@ -145,10 +145,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// protected override void DoDivide(Complex32 scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / scalar); + DoMultiply(1 / scalar, result); } /// @@ -158,10 +155,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// The vector to store the result of the pointwise multiplication. protected override void DoPointwiseMultiply(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * other.At(index)); + } } /// @@ -171,10 +168,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// The vector to store the result of the pointwise division. protected override void DoPointwiseDivide(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) / other.At(index)); + } } /// @@ -191,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 return CommonParallel.Aggregate( 0, Count, - i => this[i] * other[i]); + i => At(i) * other.At(i)); } /// @@ -200,7 +197,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// The value of the absolute minimum element. public override Complex32 AbsoluteMinimum() { - return this[AbsoluteMinimumIndex()].Magnitude; + return At(AbsoluteMinimumIndex()).Magnitude; } /// @@ -210,10 +207,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 public override int AbsoluteMinimumIndex() { var index = 0; - var min = this[index].Magnitude; + var min = At(index).Magnitude; for (var i = 1; i < Count; i++) { - var test = this[i].Magnitude; + var test = At(i).Magnitude; if (test < min) { index = i; @@ -230,7 +227,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// The value of the absolute maximum element. public override Complex32 AbsoluteMaximum() { - return this[AbsoluteMaximumIndex()].Magnitude; + return At(AbsoluteMaximumIndex()).Magnitude; } /// @@ -240,10 +237,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 public override int AbsoluteMaximumIndex() { var index = 0; - var max = this[index].Magnitude; + var max = At(index).Magnitude; for (var i = 1; i < Count; i++) { - var test = this[i].Magnitude; + var test = At(i).Magnitude; if (test > max) { index = i; @@ -263,7 +260,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 return CommonParallel.Aggregate( 0, Count, - i => this[i]); + i => At(i)); } /// @@ -275,7 +272,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 return CommonParallel.Aggregate( 0, Count, - i => this[i].Magnitude); + i => At(i).Magnitude); } /// @@ -285,7 +282,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// The p value. /// /// - /// Scalar ret = (sum(abs(this[i])^p))^(1/p) + /// Scalar ret = (sum(abs(At(i))^p))^(1/p) /// public override Complex32 Norm(double p) { @@ -299,14 +296,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 return CommonParallel.Select( 0, Count, - (index, localData) => Math.Max(localData, this[index].Magnitude), + (index, localData) => Math.Max(localData, At(index).Magnitude), Common.Max); } var sum = CommonParallel.Aggregate( 0, Count, - index => Math.Pow(this[index].Magnitude, p)); + index => Math.Pow(At(index).Magnitude, p)); return (float)Math.Pow(sum, 1.0 / p); } @@ -317,11 +314,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// Target vector protected override void DoConjugate(Vector target) { - CopyTo(target); - CommonParallel.For( - 0, - Count, - index => target[index] = this[index].Conjugate()); + for (var index = 0; index < Count; index++) + { + target.At(index, At(index).Conjugate()); + } } /// @@ -336,10 +332,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 public override Vector Negate() { var result = CreateVector(Count); - CommonParallel.For( - 0, - Count, - index => result[index] = -this[index]); + + for (var index = 0; index < Count; index++) + { + result.At(index, -At(index)); + } return result; } @@ -410,7 +407,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 var vector = CreateVector(length); for (var index = 0; index < length; index++) { - vector[index] = new Complex32(Convert.ToSingle(randomDistribution.Sample()), Convert.ToSingle(randomDistribution.Sample())); + vector.At(index, new Complex32(Convert.ToSingle(randomDistribution.Sample()), Convert.ToSingle(randomDistribution.Sample()))); } return vector; @@ -436,7 +433,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 var vector = CreateVector(length); for (var index = 0; index < length; index++) { - vector[index] = new Complex32(Convert.ToSingle(randomDistribution.Sample()), Convert.ToSingle(randomDistribution.Sample())); + vector.At(index, new Complex32(Convert.ToSingle(randomDistribution.Sample()), Convert.ToSingle(randomDistribution.Sample()))); } return vector; diff --git a/src/Numerics/LinearAlgebra/Double/DenseVector.cs b/src/Numerics/LinearAlgebra/Double/DenseVector.cs index 1a39a081..d3003ff0 100644 --- a/src/Numerics/LinearAlgebra/Double/DenseVector.cs +++ b/src/Numerics/LinearAlgebra/Double/DenseVector.cs @@ -1393,5 +1393,21 @@ namespace MathNet.Numerics.LinearAlgebra.Double { Array.Clear(Data, 0, Data.Length); } + + /// Gets the value at the given . + /// The index of the value to get or set. + /// The value of the vector at the given . + internal protected override double At(int index) + { + return Data[index]; + } + + /// Sets the at the given . + /// The index of the value to get or set. + /// The value to set. + internal protected override void At(int index, double value) + { + Data[index] = value; + } } } diff --git a/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs index 0aa76e6d..52e15e65 100644 --- a/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs @@ -187,7 +187,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// the values from the given matrix. /// /// The matrix to copy. - public SparseMatrix(Matrix matrix) : base(matrix.RowCount, matrix.ColumnCount) + public SparseMatrix(Matrix matrix) : this(matrix.RowCount, matrix.ColumnCount) { var sparseMatrix = matrix as SparseMatrix; @@ -608,8 +608,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double { lock (_lockObject) { - var index = FindItem(row, column); - return index >= 0 ? _nonZeroValues[index] : 0.0; + return GetValueAt(row, column); } } @@ -634,6 +633,25 @@ namespace MathNet.Numerics.LinearAlgebra.Double } #region Internal methods - CRS storage implementation + + /// + /// Retrieves the requested element without range checking. + /// + /// + /// The row of the element. + /// + /// + /// The column of the element. + /// + /// + /// The requested element. + /// + private double GetValueAt(int row, int column) + { + var index = FindItem(row, column); + return index >= 0 ? _nonZeroValues[index] : 0.0; + } + /// /// Created this method because we cannot call "virtual At" in constructor of the class, but we need to do it /// diff --git a/src/Numerics/LinearAlgebra/Double/SparseVector.cs b/src/Numerics/LinearAlgebra/Double/SparseVector.cs index f80d0277..b8be1d2a 100644 --- a/src/Numerics/LinearAlgebra/Double/SparseVector.cs +++ b/src/Numerics/LinearAlgebra/Double/SparseVector.cs @@ -38,13 +38,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// /// A vector with sparse storage. /// + /// The sparse vector is not thread safe. public class SparseVector : Vector { - /// - /// Lock object for the indexer. - /// - private readonly object _lockObject = new object(); - /// /// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored. /// @@ -130,7 +126,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double { for (var i = 0; i < other.Count; i++) { - this[i] = other[i]; + this[i] = other.At(i); } } else @@ -168,9 +164,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// /// The array to create this vector from. /// The vector copy the array. Any changes to the vector will NOT change the array. - public SparseVector(double[] array) : this(array.Length) + public SparseVector(IList array) : this(array.Count) { - for (var i = 0; i < array.Length; i++) + for (var i = 0; i < array.Count; i++) { this[i] = array[i]; } @@ -187,7 +183,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double var matrix = new SparseMatrix(Count, 1); for (var i = 0; i < NonZerosCount; i++) { - matrix[_nonZeroIndices[i], 0] = _nonZeroValues[i]; + matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); } return matrix; @@ -202,55 +198,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double var matrix = new SparseMatrix(1, Count); for (var i = 0; i < NonZerosCount; i++) { - matrix[0, _nonZeroIndices[i]] = _nonZeroValues[i]; + matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); } return matrix; } - /// Gets or sets the value at the given . - /// The index of the value to get or set. - /// The value of the vector at the given . - /// If is negative or - /// greater than the size of the vector. - public override double this[int index] - { - get - { - // If index is out of bounds - if ((index < 0) || (index >= Count)) - { - throw new IndexOutOfRangeException(); - } - - lock (_lockObject) - { - // Search if item idex exists in NonZeroIndices array in range "0 - real nonzero values count" - var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); - if (itemIndex >= 0) - { - return _nonZeroValues[itemIndex]; - } - } - - return 0.0; - } - - set - { - // If index is out of bounds - if ((index < 0) || (index >= Count)) - { - throw new IndexOutOfRangeException(); - } - - lock (_lockObject) - { - SetValue(index, value); - } - } - } - /// /// Creates a matrix with the given dimensions using the same storage type /// as this vector. @@ -324,10 +277,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double var otherVector = target as SparseVector; if (otherVector == null) { - CommonParallel.For( - 0, - Count, - index => target[index] = this[index]); + target.Clear(); + + for (var index = 0; index < NonZerosCount; index++) + { + target.At(_nonZeroIndices[index], _nonZeroValues[index]); + } } else { @@ -343,145 +298,39 @@ namespace MathNet.Numerics.LinearAlgebra.Double #region Operators and supplementary functions - /// - /// Adds a scalar to each element of the vector. - /// - /// The scalar to add. - /// A copy of the vector with the scalar added. - public override Vector Add(double scalar) - { - if (scalar == 0.0) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] += scalar; - } - - return copy; - } - /// /// Adds a scalar to each element of the vector and stores the result in the result vector. /// - /// The scalar to add. - /// The vector to store the result of the addition. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Add(double scalar, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Add(scalar, result); - } - - /// - /// Adds another vector to this vector. - /// - /// The vector to add to this one. - /// A new vector containing the sum of both vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Add(Vector other) - { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Add(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(1.0, sparseVector); - return copy; - } - - /// - /// Adds the scaled sparse vector. - /// - /// The alpha. - /// The other. - private void AddScaledSparseVector(double alpha, SparseVector other) + /// + /// The scalar to add. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(double scalar, Vector result) { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) + if (scalar == 0.0) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } - if (alpha == 0.0) - { return; } - // I don't use ILinearAlgebraProvider because we will get no benefit due to "lock" in this[index] - // Possible fucniton in ILinearAlgebraProvider may be AddSparseVectorToScaledSparseVector(T[] y, int[] yIndices, T alpha, T[] x, int[] xIndices); - // But it require to develop value setting algorithm and due to "lock" it will be even more greedy then implemented below - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, result)) { - // Adding the same instance of sparse vector. That means if we modify "this" then "other" will be modified too. - // To avoid such problem lets change values in internal storage of "this" - if (alpha == 1.0) - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += _nonZeroValues[i]; - } - } - else if (alpha == -1.0) - { - Clear(); // Vector is subtracted from itself - return; - } - else - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += alpha * _nonZeroValues[i]; - } - } + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += scalar); } else { - // "this" and "other" are different objects, so by modifying "this" the "other" object will not be changed - if (alpha == 1.0) + for (var index = 0; index < Count; index++) { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += other._nonZeroValues[i]; - } - } - else - { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += alpha * other._nonZeroValues[i]; - } + result.At(index, At(index) + scalar); } } } @@ -489,53 +338,26 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// /// Adds another vector to this vector and stores the result into the result vector. /// - /// The vector to add to this one. - /// The vector to store the result of the addition. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Add(Vector other, Vector result) + /// + /// The vector to add to this one. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) + if (ReferenceEquals(this, result)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) - { - var tmp = Add(other); - tmp.CopyTo(result); + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += _nonZeroValues[index]); } else { - var sparse = result as SparseVector; - if (sparse == null) - { - base.Add(other, result); - } - else + for (var index = 0; index < Count; index++) { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Add(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(1.0, sparseother); - } + result.At(index, At(index) + other.At(index)); } } } @@ -585,131 +407,40 @@ namespace MathNet.Numerics.LinearAlgebra.Double return leftSide.Add(rightSide); } - /// - /// Subtracts a scalar from each element of the vector. - /// - /// The scalar to subtract. - /// A new vector containing the subtraction of this vector and the scalar. - public override Vector Subtract(double scalar) - { - if (scalar == 0.0) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] -= scalar; - } - - return copy; - } - /// /// Subtracts a scalar from each element of the vector and stores the result in the result vector. /// - /// The scalar to subtract. - /// The vector to store the result of the subtraction. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Subtract(double scalar, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Subtract(scalar, result); - } - - /// - /// Subtracts another vector from this vector. - /// - /// The vector to subtract from this one. - /// A new vector containing the subtraction of the the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Subtract(Vector other) + /// + /// The scalar to subtract. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(double scalar, Vector result) { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Subtract(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(-1.0, sparseVector); - return copy; + DoAdd(-scalar, result); } /// /// Subtracts another vector to this vector and stores the result into the result vector. /// - /// The vector to subtract from this one. - /// The vector to store the result of the subtraction. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Subtract(Vector other, Vector result) + /// + /// The vector to subtract from this one. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) + if (ReferenceEquals(this, other)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); + result.Clear(); + return; } - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) + for (var index = 0; index < Count; index++) { - var tmp = Subtract(other); - tmp.CopyTo(result); - } - else - { - var sparse = result as SparseVector; - if (sparse == null) - { - base.Subtract(other, result); - } - else - { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Subtract(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(-1.0, sparseother); - } - } + result.At(index, At(index) - other.At(index)); } } @@ -777,6 +508,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double 0, NonZerosCount, index => result._nonZeroValues[index] = -_nonZeroValues[index]); + Buffer.BlockCopy(_nonZeroIndices, 0, result._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); } @@ -806,30 +538,81 @@ namespace MathNet.Numerics.LinearAlgebra.Double } /// - /// Computes the dot product between this vector and another vector. + /// Multiplies a scalar to each element of the vector and stores the result in the result vector. /// - /// The other vector to add. - /// The result of the addition. - /// If is not of the same size. - /// If is . - public override double DotProduct(Vector other) + /// + /// The scalar to multiply. + /// + /// + /// The vector to store the result of the multiplication. + /// + protected override void DoMultiply(double scalar, Vector result) { - if (other == null) + if (scalar == 1.0) { - throw new ArgumentNullException("other"); + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + return; } - if (Count != other.Count) + if (scalar == 0) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + result.Clear(); + return; } - double result = 0; + var sparseResult = result as SparseVector; + if (sparseResult == null) + { + result.Clear(); + for (var index = 0; index < NonZerosCount; index++) + { + result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); + } + } + else + { + if (!ReferenceEquals(this, result)) + { + sparseResult.NonZerosCount = NonZerosCount; + sparseResult._nonZeroIndices = new int[NonZerosCount]; + Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, _nonZeroIndices.Length * Constants.SizeOfInt); + sparseResult._nonZeroValues = new double[_nonZeroValues.Length]; + } - // base implementation iterates though all elements, but we need only take non-zeros - for (var i = 0; i < NonZerosCount; i++) + Control.LinearAlgebraProvider.ScaleArray(scalar, _nonZeroValues, sparseResult._nonZeroValues); + } + } + + /// + /// Computes the dot product between this vector and another vector. + /// + /// + /// The other vector to add. + /// + /// s + /// The result of the addition. + /// + protected override double DoDotProduct(Vector other) + { + var result = 0.0; + + if (ReferenceEquals(this, other)) + { + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * _nonZeroValues[i]; + } + } + else { - result += _nonZeroValues[i] * other[_nonZeroIndices[i]]; + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); + } } return result; @@ -972,7 +755,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double var result = new SparseVector(length); for (var i = index; i < index + length; i++) { - result[i - index] = this[i]; + result.At(i - index, At(i)); } return result; @@ -998,7 +781,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double for (var i = 0; i < values.Length; i++) { - this[i] = values[i]; + At(i, values[i]); } } @@ -1083,35 +866,51 @@ namespace MathNet.Numerics.LinearAlgebra.Double } /// - /// Pointwise multiplies this vector with another vector. + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. /// /// The vector to pointwise multiply with this one. - /// A new vector which is the pointwise multiplication of the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector PointwiseMultiply(Vector other) + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Vector other, Vector result) { - if (other == null) + if (ReferenceEquals(this, other)) { - throw new ArgumentNullException("other"); + for (var i = 0; i < NonZerosCount; i++) + { + _nonZeroValues[i] *= _nonZeroValues[i]; + } } - - if (Count != other.Count) + else { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, other.At(index) * _nonZeroValues[i]); + } } + } - var copy = new SparseVector(Count); - for (var i = 0; i < _nonZeroIndices.Length; i++) + /// + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. + /// + /// The vector to pointwise multiply with this one. + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseDivide(Vector other, Vector result) + { + if (ReferenceEquals(this, other)) { - var d = _nonZeroValues[i] * other[_nonZeroIndices[i]]; - if (d != 0.0) + for (var i = 0; i < NonZerosCount; i++) { - copy[_nonZeroIndices[i]] = d; + _nonZeroValues[i] /= _nonZeroValues[i]; + } + } + else + { + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, _nonZeroValues[i] / other.At(index)); } } - - return copy; } /// @@ -1122,7 +921,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// Matrix M[i,j] = u[i]*v[j] /// If the u vector is . /// If the v vector is . - public static Matrix /*SparseMatrix*/ OuterProduct(SparseVector u, SparseVector v) + public static Matrix OuterProduct(SparseVector u, SparseVector v) { if (u == null) { @@ -1361,13 +1160,25 @@ namespace MathNet.Numerics.LinearAlgebra.Double #endregion + /// + /// Gets the value at the given index. + /// + /// Value real index in array + /// The value at the given index. + internal protected override double At(int index) + { + // Search if item idex exists in NonZeroIndices array in range "0 - real nonzero values count" + var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); + return itemIndex >= 0 ? _nonZeroValues[itemIndex] : 0.0; + } + /// /// Delete, Add or Update the value in NonZeroValues and NonZeroIndices /// /// Value real index in array /// The value to set. /// This method assume that index is between 0 and Array Size - private void SetValue(int index, double value) + internal protected override void At(int index, double value) { // Search if "index" already exists in range "0 - real nonzero values count" var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); @@ -1562,5 +1373,22 @@ namespace MathNet.Numerics.LinearAlgebra.Double yield return new KeyValuePair(_nonZeroIndices[i], _nonZeroValues[i]); } } + + /// + /// Returns the data contained in the vector as an array. + /// + /// + /// The vector's data as an array. + /// + public override double[] ToArray() + { + var ret = new double[Count]; + for (var i = 0; i < NonZerosCount; i++) + { + ret[_nonZeroIndices[i]] = _nonZeroValues[i]; + } + + return ret; + } } } diff --git a/src/Numerics/LinearAlgebra/Double/Vector.cs b/src/Numerics/LinearAlgebra/Double/Vector.cs index 7baefb6a..dff69988 100644 --- a/src/Numerics/LinearAlgebra/Double/Vector.cs +++ b/src/Numerics/LinearAlgebra/Double/Vector.cs @@ -62,10 +62,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// protected override void DoAdd(double scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + scalar); + } } /// @@ -79,10 +79,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// protected override void DoAdd(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + other.At(index)); + } } /// @@ -110,10 +110,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// protected override void DoSubtract(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] - other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) - other.At(index)); + } } /// @@ -127,10 +127,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// protected override void DoMultiply(double scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * scalar); + } } /// @@ -144,10 +144,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// protected override void DoDivide(double scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / scalar); + DoMultiply(1 / scalar, result); } /// @@ -157,10 +154,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The vector to store the result of the pointwise multiplication. protected override void DoPointwiseMultiply(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * other.At(index)); + } } /// @@ -170,10 +167,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The vector to store the result of the pointwise division. protected override void DoPointwiseDivide(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) / other.At(index)); + } } /// @@ -190,7 +187,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double return CommonParallel.Aggregate( 0, Count, - i => this[i] * other[i]); + i => At(i) * other.At(i)); } /// @@ -199,7 +196,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The value of the absolute minimum element. public override double AbsoluteMinimum() { - return Math.Abs(this[AbsoluteMinimumIndex()]); + return Math.Abs(At(AbsoluteMinimumIndex())); } /// @@ -209,10 +206,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double public override int AbsoluteMinimumIndex() { var index = 0; - var min = Math.Abs(this[index]); + var min = Math.Abs(At(index)); for (var i = 1; i < Count; i++) { - var test = Math.Abs(this[i]); + var test = Math.Abs(At(i)); if (test < min) { index = i; @@ -229,7 +226,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The value of the absolute maximum element. public override double AbsoluteMaximum() { - return Math.Abs(this[AbsoluteMaximumIndex()]); + return Math.Abs(At(AbsoluteMaximumIndex())); } /// @@ -239,10 +236,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double public override int AbsoluteMaximumIndex() { var index = 0; - var max = Math.Abs(this[index]); + var max = Math.Abs(At(index)); for (var i = 1; i < Count; i++) { - var test = Math.Abs(this[i]); + var test = Math.Abs(At(i)); if (test > max) { index = i; @@ -262,7 +259,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double return CommonParallel.Aggregate( 0, Count, - i => this[i]); + i => At(i)); } /// @@ -274,7 +271,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double return CommonParallel.Aggregate( 0, Count, - i => Math.Abs(this[i])); + i => Math.Abs(At(i))); } /// @@ -298,14 +295,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double return CommonParallel.Select( 0, Count, - (index, localData) => Math.Max(localData, Math.Abs(this[index])), + (index, localData) => Math.Max(localData, Math.Abs(At(index))), Math.Max); } var sum = CommonParallel.Aggregate( 0, Count, - index => Math.Pow(Math.Abs(this[index]), p)); + index => Math.Pow(Math.Abs(At(index)), p)); return Math.Pow(sum, 1.0 / p); } @@ -336,10 +333,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double public override Vector Negate() { var result = CreateVector(Count); - CommonParallel.For( - 0, - Count, - index => result[index] = -this[index]); + + for (var index = 0; index < Count; index++) + { + result.At(index, -At(index)); + } return result; } @@ -351,10 +349,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double public override int MaximumIndex() { var index = 0; - var max = this[index]; + var max = At(index); for (var i = 1; i < Count; i++) { - var test = this[i]; + var test = At(i); if (test > max) { index = i; @@ -372,10 +370,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double public override int MinimumIndex() { var index = 0; - var min = this[index]; + var min = At(index); for (var i = 1; i < Count; i++) { - var test = this[i]; + var test = At(i); if (test < min) { index = i; @@ -434,7 +432,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double var v = CreateVector(length); for (var index = 0; index < Count; index++) { - v[index] = randomDistribution.Sample(); + v.At(index, randomDistribution.Sample()); } return v; @@ -460,7 +458,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double var v = CreateVector(length); for (var index = 0; index < Count; index++) { - this[index] = randomDistribution.Sample(); + At(index, randomDistribution.Sample()); } return v; diff --git a/src/Numerics/LinearAlgebra/Generic/Vector.cs b/src/Numerics/LinearAlgebra/Generic/Vector.cs index a1c72a5b..7d9fcd76 100644 --- a/src/Numerics/LinearAlgebra/Generic/Vector.cs +++ b/src/Numerics/LinearAlgebra/Generic/Vector.cs @@ -93,10 +93,27 @@ namespace MathNet.Numerics.LinearAlgebra.Generic /// The value of the vector at the given . /// If is negative or /// greater than the size of the vector. - public abstract T this[int index] + public virtual T this[int index] { - get; - set; + get + { + if (index < 0 || index >= Count) + { + throw new ArgumentOutOfRangeException("index"); + } + + return At(index); + } + + set + { + if (index < 0 || index >= Count) + { + throw new ArgumentOutOfRangeException("index"); + } + + At(index, value); + } } /// @@ -715,7 +732,6 @@ namespace MathNet.Numerics.LinearAlgebra.Generic /// Pointwise divide this vector with another vector and stores the result into the result vector. /// /// The vector to pointwise divide this one by. - /// The vector to store the result of the pointwise division. protected abstract void DoPointwiseDivide(Vector other, Vector result); /// @@ -1207,7 +1223,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic var ret = new T[Count]; for (var i = 0; i < ret.Length; i++) { - ret[i] = this[i]; + ret[i] = At(i); } return ret; @@ -1534,5 +1550,15 @@ namespace MathNet.Numerics.LinearAlgebra.Generic { CommonParallel.For(0, Count, index => this[index] = default(T)); } + + /// Gets the value at the given . + /// The index of the value to get or set. + /// The value of the vector at the given . + internal protected abstract T At(int index); + + /// Sets the at the given . + /// The index of the value to get or set. + /// The value to set. + internal protected abstract void At(int index, T value); } } diff --git a/src/Numerics/LinearAlgebra/Single/DenseVector.cs b/src/Numerics/LinearAlgebra/Single/DenseVector.cs index 3f068bd5..b3a8f7fc 100644 --- a/src/Numerics/LinearAlgebra/Single/DenseVector.cs +++ b/src/Numerics/LinearAlgebra/Single/DenseVector.cs @@ -1393,5 +1393,21 @@ namespace MathNet.Numerics.LinearAlgebra.Single { Array.Clear(Data, 0, Data.Length); } + + /// Gets the value at the given . + /// The index of the value to get or set. + /// The value of the vector at the given . + internal protected override float At(int index) + { + return Data[index]; + } + + /// Sets the at the given . + /// The index of the value to get or set. + /// The value to set. + internal protected override void At(int index, float value) + { + Data[index] = value; + } } } diff --git a/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs index 51690d84..037dd6b8 100644 --- a/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs @@ -188,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// /// The matrix to copy. public SparseMatrix(Matrix matrix) - : base(matrix.RowCount, matrix.ColumnCount) + : this(matrix.RowCount, matrix.ColumnCount) { var sparseMatrix = matrix as SparseMatrix; diff --git a/src/Numerics/LinearAlgebra/Single/SparseVector.cs b/src/Numerics/LinearAlgebra/Single/SparseVector.cs index 4dbfd83d..142971aa 100644 --- a/src/Numerics/LinearAlgebra/Single/SparseVector.cs +++ b/src/Numerics/LinearAlgebra/Single/SparseVector.cs @@ -38,13 +38,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// /// A vector with sparse storage. /// + /// The sparse vector is not thread safe. public class SparseVector : Vector { - /// - /// Lock object for the indexer. - /// - private readonly object _lockObject = new object(); - /// /// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored. /// @@ -130,7 +126,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single { for (var i = 0; i < other.Count; i++) { - this[i] = other[i]; + this[i] = other.At(i); } } else @@ -168,9 +164,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// /// The array to create this vector from. /// The vector copy the array. Any changes to the vector will NOT change the array. - public SparseVector(float[] array) : this(array.Length) + public SparseVector(IList array) : this(array.Count) { - for (var i = 0; i < array.Length; i++) + for (var i = 0; i < array.Count; i++) { this[i] = array[i]; } @@ -187,7 +183,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single var matrix = new SparseMatrix(Count, 1); for (var i = 0; i < NonZerosCount; i++) { - matrix[_nonZeroIndices[i], 0] = _nonZeroValues[i]; + matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); } return matrix; @@ -202,7 +198,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single var matrix = new SparseMatrix(1, Count); for (var i = 0; i < NonZerosCount; i++) { - matrix[0, _nonZeroIndices[i]] = _nonZeroValues[i]; + matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); } return matrix; @@ -223,17 +219,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single throw new IndexOutOfRangeException(); } - lock (_lockObject) - { - // Search if item idex exists in NonZeroIndices array in range "0 - real nonzero values count" - var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); - if (itemIndex >= 0) - { - return _nonZeroValues[itemIndex]; - } - } - - return 0.0f; + return At(index); } set @@ -244,10 +230,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single throw new IndexOutOfRangeException(); } - lock (_lockObject) - { - SetValue(index, value); - } + At(index, value); } } @@ -324,10 +307,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single var otherVector = target as SparseVector; if (otherVector == null) { - CommonParallel.For( - 0, - Count, - index => target[index] = this[index]); + target.Clear(); + + for (var index = 0; index < NonZerosCount; index++) + { + target.At(_nonZeroIndices[index], _nonZeroValues[index]); + } } else { @@ -343,145 +328,39 @@ namespace MathNet.Numerics.LinearAlgebra.Single #region Operators and supplementary functions - /// - /// Adds a scalar to each element of the vector. - /// - /// The scalar to add. - /// A copy of the vector with the scalar added. - public override Vector Add(float scalar) - { - if (scalar == 0.0) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] += scalar; - } - - return copy; - } - /// /// Adds a scalar to each element of the vector and stores the result in the result vector. /// - /// The scalar to add. - /// The vector to store the result of the addition. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Add(float scalar, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Add(scalar, result); - } - - /// - /// Adds another vector to this vector. - /// - /// The vector to add to this one. - /// A new vector containing the sum of both vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Add(Vector other) - { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Add(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(1.0f, sparseVector); - return copy; - } - - /// - /// Adds the scaled sparse vector. - /// - /// The alpha. - /// The other. - private void AddScaledSparseVector(float alpha, SparseVector other) + /// + /// The scalar to add. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(float scalar, Vector result) { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) + if (scalar == 0.0f) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } - if (alpha == 0.0) - { return; } - // I don't use ILinearAlgebraProvider because we will get no benefit due to "lock" in this[index] - // Possible fucniton in ILinearAlgebraProvider may be AddSparseVectorToScaledSparseVector(T[] y, int[] yIndices, T alpha, T[] x, int[] xIndices); - // But it require to develop value setting algorithm and due to "lock" it will be even more greedy then implemented below - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, result)) { - // Adding the same instance of sparse vector. That means if we modify "this" then "other" will be modified too. - // To avoid such problem lets change values in internal storage of "this" - if (alpha == 1.0) - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += _nonZeroValues[i]; - } - } - else if (alpha == -1.0) - { - Clear(); // Vector is subtracted from itself - return; - } - else - { - for (var i = 0; i < NonZerosCount; i++) - { - _nonZeroValues[i] += alpha * _nonZeroValues[i]; - } - } + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += scalar); } else { - // "this" and "other" are different objects, so by modifying "this" the "other" object will not be changed - if (alpha == 1.0) - { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += other._nonZeroValues[i]; - } - } - else + for (var index = 0; index < Count; index++) { - for (var i = 0; i < other.NonZerosCount; i++) - { - this[other._nonZeroIndices[i]] += alpha * other._nonZeroValues[i]; - } + result.At(index, At(index) + scalar); } } } @@ -489,53 +368,26 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// /// Adds another vector to this vector and stores the result into the result vector. /// - /// The vector to add to this one. - /// The vector to store the result of the addition. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Add(Vector other, Vector result) + /// + /// The vector to add to this one. + /// + /// + /// The vector to store the result of the addition. + /// + protected override void DoAdd(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) + if (ReferenceEquals(this, result)) { - var tmp = Add(other); - tmp.CopyTo(result); + CommonParallel.For( + 0, + NonZerosCount, + index => _nonZeroValues[index] += _nonZeroValues[index]); } else { - var sparse = result as SparseVector; - if (sparse == null) + for (var index = 0; index < Count; index++) { - base.Add(other, result); - } - else - { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Add(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(1.0f, sparseother); - } + result.At(index, At(index) + other.At(index)); } } } @@ -585,131 +437,40 @@ namespace MathNet.Numerics.LinearAlgebra.Single return leftSide.Add(rightSide); } - /// - /// Subtracts a scalar from each element of the vector. - /// - /// The scalar to subtract. - /// A new vector containing the subtraction of this vector and the scalar. - public override Vector Subtract(float scalar) - { - if (scalar == 0.0) - { - return Clone(); - } - - var copy = (SparseVector)Clone(); - for (var i = 0; i < Count; i++) - { - copy[i] -= scalar; - } - - return copy; - } - /// /// Subtracts a scalar from each element of the vector and stores the result in the result vector. /// - /// The scalar to subtract. - /// The vector to store the result of the subtraction. - /// If the result vector is . - /// If this vector and are not the same size. - public override void Subtract(float scalar, Vector result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != result.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); - } - - base.Subtract(scalar, result); - } - - /// - /// Subtracts another vector from this vector. - /// - /// The vector to subtract from this one. - /// A new vector containing the subtraction of the the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector Subtract(Vector other) + /// + /// The scalar to subtract. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(float scalar, Vector result) { - if (other == null) - { - throw new ArgumentNullException("other"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - var sparseVector = other as SparseVector; - - if (sparseVector == null) - { - return base.Subtract(other); - } - - var copy = (SparseVector)Clone(); - copy.AddScaledSparseVector(-1.0f, sparseVector); - return copy; + DoAdd(-scalar, result); } /// /// Subtracts another vector to this vector and stores the result into the result vector. /// - /// The vector to subtract from this one. - /// The vector to store the result of the subtraction. - /// If the other vector is . - /// If the result vector is . - /// If this vector and are not the same size. - /// If this vector and are not the same size. - public override void Subtract(Vector other, Vector result) + /// + /// The vector to subtract from this one. + /// + /// + /// The vector to store the result of the subtraction. + /// + protected override void DoSubtract(Vector other, Vector result) { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (Count != other.Count) - { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); - } - - if (Count != result.Count) + if (ReferenceEquals(this, other)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); + result.Clear(); + return; } - if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) - { - var tmp = Subtract(other); - tmp.CopyTo(result); - } - else + for (var index = 0; index < Count; index++) { - var sparse = result as SparseVector; - if (sparse == null) - { - base.Subtract(other, result); - } - else - { - var sparseother = other as SparseVector; - if (sparseother == null) - { - base.Subtract(other, result); - } - else - { - CopyTo(result); - sparse.AddScaledSparseVector(-1.0f, sparseother); - } - } + result.At(index, At(index) - other.At(index)); } } @@ -784,52 +545,81 @@ namespace MathNet.Numerics.LinearAlgebra.Single } /// - /// Multiplies a scalar to each element of the vector. + /// Multiplies a scalar to each element of the vector and stores the result in the result vector. /// - /// The scalar to multiply. - /// A new vector that is the multiplication of the vector and the scalar. - public override Vector Multiply(float scalar) + /// + /// The scalar to multiply. + /// + /// + /// The vector to store the result of the multiplication. + /// + protected override void DoMultiply(float scalar, Vector result) { if (scalar == 1.0) { - return Clone(); + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + return; } if (scalar == 0) { - return new SparseVector(Count); + result.Clear(); + return; } - var copy = new SparseVector(this); - Control.LinearAlgebraProvider.ScaleArray(scalar, copy._nonZeroValues, copy._nonZeroValues); - return copy; + var sparseResult = result as SparseVector; + if (sparseResult == null) + { + result.Clear(); + for (var index = 0; index < NonZerosCount; index++) + { + result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); + } + } + else + { + if (!ReferenceEquals(this, result)) + { + sparseResult.NonZerosCount = NonZerosCount; + sparseResult._nonZeroIndices = new int[NonZerosCount]; + Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, _nonZeroIndices.Length * Constants.SizeOfInt); + sparseResult._nonZeroValues = new float[_nonZeroValues.Length]; + } + + Control.LinearAlgebraProvider.ScaleArray(scalar, _nonZeroValues, sparseResult._nonZeroValues); + } } /// /// Computes the dot product between this vector and another vector. /// - /// The other vector to add. - /// The result of the addition. - /// If is not of the same size. - /// If is . - public override float DotProduct(Vector other) + /// + /// The other vector to add. + /// + /// s + /// The result of the addition. + /// + protected override float DoDotProduct(Vector other) { - if (other == null) - { - throw new ArgumentNullException("other"); - } + var result = 0.0f; - if (Count != other.Count) + if (ReferenceEquals(this, other)) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * _nonZeroValues[i]; + } } - - float result = 0; - - // base implementation iterates though all elements, but we need only take non-zeros - for (var i = 0; i < NonZerosCount; i++) + else { - result += _nonZeroValues[i] * other[_nonZeroIndices[i]]; + for (var i = 0; i < NonZerosCount; i++) + { + result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); + } } return result; @@ -998,7 +788,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single for (var i = 0; i < values.Length; i++) { - this[i] = values[i]; + At(i, values[i]); } } @@ -1083,35 +873,51 @@ namespace MathNet.Numerics.LinearAlgebra.Single } /// - /// Pointwise multiplies this vector with another vector. + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. /// /// The vector to pointwise multiply with this one. - /// A new vector which is the pointwise multiplication of the two vectors. - /// If the other vector is . - /// If this vector and are not the same size. - public override Vector PointwiseMultiply(Vector other) + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Vector other, Vector result) { - if (other == null) + if (ReferenceEquals(this, other)) { - throw new ArgumentNullException("other"); + for (var i = 0; i < NonZerosCount; i++) + { + _nonZeroValues[i] *= _nonZeroValues[i]; + } } - - if (Count != other.Count) + else { - throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, other.At(index) * _nonZeroValues[i]); + } } + } - var copy = new SparseVector(Count); - for (var i = 0; i < _nonZeroIndices.Length; i++) + /// + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. + /// + /// The vector to pointwise multiply with this one. + /// The vector to store the result of the pointwise multiplication. + protected override void DoPointwiseDivide(Vector other, Vector result) + { + if (ReferenceEquals(this, other)) { - var d = _nonZeroValues[i] * other[_nonZeroIndices[i]]; - if (d != 0.0) + for (var i = 0; i < NonZerosCount; i++) { - copy[_nonZeroIndices[i]] = d; + _nonZeroValues[i] /= _nonZeroValues[i]; + } + } + else + { + for (var i = 0; i < NonZerosCount; i++) + { + var index = _nonZeroIndices[i]; + result.At(index, _nonZeroValues[i] / other.At(index)); } } - - return copy; } /// @@ -1122,7 +928,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// Matrix M[i,j] = u[i]*v[j] /// If the u vector is . /// If the v vector is . - public static Matrix /*SparseMatrix*/ OuterProduct(SparseVector u, SparseVector v) + public static Matrix OuterProduct(SparseVector u, SparseVector v) { if (u == null) { @@ -1361,13 +1167,25 @@ namespace MathNet.Numerics.LinearAlgebra.Single #endregion + /// + /// Gets the value at the given index. + /// + /// Value real index in array + /// The value at the given index. + internal protected override float At(int index) + { + // Search if item idex exists in NonZeroIndices array in range "0 - real nonzero values count" + var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); + return itemIndex >= 0 ? _nonZeroValues[itemIndex] : 0.0f; + } + /// /// Delete, Add or Update the value in NonZeroValues and NonZeroIndices /// /// Value real index in array /// The value to set. /// This method assume that index is between 0 and Array Size - private void SetValue(int index, float value) + internal protected override void At(int index, float value) { // Search if "index" already exists in range "0 - real nonzero values count" var itemIndex = Array.BinarySearch(_nonZeroIndices, 0, NonZerosCount, index); @@ -1562,5 +1380,22 @@ namespace MathNet.Numerics.LinearAlgebra.Single yield return new KeyValuePair(_nonZeroIndices[i], _nonZeroValues[i]); } } + + /// + /// Returns the data contained in the vector as an array. + /// + /// + /// The vector's data as an array. + /// + public override float[] ToArray() + { + var ret = new float[Count]; + for (var i = 0; i < NonZerosCount; i++) + { + ret[_nonZeroIndices[i]] = _nonZeroValues[i]; + } + + return ret; + } } } diff --git a/src/Numerics/LinearAlgebra/Single/Vector.cs b/src/Numerics/LinearAlgebra/Single/Vector.cs index 0248c1ac..e3ab2be0 100644 --- a/src/Numerics/LinearAlgebra/Single/Vector.cs +++ b/src/Numerics/LinearAlgebra/Single/Vector.cs @@ -63,10 +63,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// protected override void DoAdd(float scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + scalar); + } } /// @@ -80,10 +80,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// protected override void DoAdd(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] + other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) + other.At(index)); + } } /// @@ -111,10 +111,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// protected override void DoSubtract(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] - other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) - other.At(index)); + } } /// @@ -128,10 +128,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// protected override void DoMultiply(float scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * scalar); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * scalar); + } } /// @@ -145,10 +145,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// protected override void DoDivide(float scalar, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / scalar); + DoMultiply(1 / scalar, result); } /// @@ -158,10 +155,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// The vector to store the result of the pointwise multiplication. protected override void DoPointwiseMultiply(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] * other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) * other.At(index)); + } } /// @@ -171,10 +168,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// The vector to store the result of the pointwise division. protected override void DoPointwiseDivide(Vector other, Vector result) { - CommonParallel.For( - 0, - Count, - index => result[index] = this[index] / other[index]); + for (var index = 0; index < Count; index++) + { + result.At(index, At(index) / other.At(index)); + } } /// @@ -191,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single return CommonParallel.Aggregate( 0, Count, - i => this[i] * other[i]); + i => At(i) * other.At(i)); } /// @@ -200,7 +197,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// The value of the absolute minimum element. public override float AbsoluteMinimum() { - return Math.Abs(this[AbsoluteMinimumIndex()]); + return Math.Abs(At(AbsoluteMinimumIndex())); } /// @@ -210,10 +207,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single public override int AbsoluteMinimumIndex() { var index = 0; - var min = Math.Abs(this[index]); + var min = Math.Abs(At(index)); for (var i = 1; i < Count; i++) { - var test = Math.Abs(this[i]); + var test = Math.Abs(At(i)); if (test < min) { index = i; @@ -230,7 +227,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// The value of the absolute maximum element. public override float AbsoluteMaximum() { - return Math.Abs(this[AbsoluteMaximumIndex()]); + return Math.Abs(At(AbsoluteMaximumIndex())); } /// @@ -240,10 +237,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single public override int AbsoluteMaximumIndex() { var index = 0; - var max = Math.Abs(this[index]); + var max = Math.Abs(At(index)); for (var i = 1; i < Count; i++) { - var test = Math.Abs(this[i]); + var test = Math.Abs(At(i)); if (test > max) { index = i; @@ -263,7 +260,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single return CommonParallel.Aggregate( 0, Count, - i => this[i]); + i => At(i)); } /// @@ -275,7 +272,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single return CommonParallel.Aggregate( 0, Count, - i => Math.Abs(this[i])); + i => Math.Abs(At(i))); } /// @@ -285,7 +282,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// The p value. /// /// - /// Scalar ret = (sum(abs(this[i])^p))^(1/p) + /// Scalar ret = (sum(abs(At(i))^p))^(1/p) /// public override float Norm(double p) { @@ -299,14 +296,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single return CommonParallel.Select( 0, Count, - (index, localData) => Math.Max(localData, Math.Abs(this[index])), + (index, localData) => Math.Max(localData, Math.Abs(At(index))), Common.Max); } var sum = CommonParallel.Aggregate( 0, Count, - index => Math.Pow(Math.Abs(this[index]), p)); + index => Math.Pow(Math.Abs(At(index)), p)); return (float)Math.Pow(sum, 1.0 / p); } @@ -337,10 +334,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single public override Vector Negate() { var result = CreateVector(Count); - CommonParallel.For( - 0, - Count, - index => result[index] = -this[index]); + + for (var index = 0; index < Count; index++) + { + result.At(index, -At(index)); + } return result; } @@ -352,10 +350,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single public override int MaximumIndex() { var index = 0; - var max = this[index]; + var max = At(index); for (var i = 1; i < Count; i++) { - var test = this[i]; + var test = At(i); if (test > max) { index = i; @@ -373,10 +371,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single public override int MinimumIndex() { var index = 0; - var min = this[index]; + var min = At(index); for (var i = 1; i < Count; i++) { - var test = this[i]; + var test = At(i); if (test < min) { index = i; @@ -435,7 +433,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single var v = CreateVector(length); for (var index = 0; index < Count; index++) { - v[index] = Convert.ToSingle(randomDistribution.Sample()); + v.At(index, Convert.ToSingle(randomDistribution.Sample())); } return v; @@ -461,7 +459,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single var v = CreateVector(length); for (var index = 0; index < Count; index++) { - v[index] = Convert.ToSingle(randomDistribution.Sample()); + v.At(index, Convert.ToSingle(randomDistribution.Sample())); } return v; diff --git a/src/UnitTests/LinearAlgebraTests/Complex/UserDefinedVectorTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/UserDefinedVectorTests.cs index b8ada682..282c4d52 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex/UserDefinedVectorTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex/UserDefinedVectorTests.cs @@ -54,19 +54,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex _data = (Complex[])data.Clone(); } - public override Complex this[int index] - { - get - { - return _data[index]; - } - - set - { - _data[index] = value; - } - } - public override Matrix CreateMatrix(int rows, int columns) { return new UserDefinedMatrix(rows, columns); @@ -77,6 +64,15 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex return new UserDefinedVector(size); } + protected internal override Complex At(int index) + { + return _data[index]; + } + + protected internal override void At(int index, Complex value) + { + _data[index] = value; + } } public class UserDefinedVectorTests : VectorTests diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedVectorTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedVectorTests.cs index 822223f1..aaf815ec 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedVectorTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedVectorTests.cs @@ -47,19 +47,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 _data = (Complex32[])data.Clone(); } - public override Complex32 this[int index] - { - get - { - return _data[index]; - } - - set - { - _data[index] = value; - } - } - public override Matrix CreateMatrix(int rows, int columns) { return new UserDefinedMatrix(rows, columns); @@ -69,6 +56,16 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 { return new UserDefinedVector(size); } + + protected internal override Complex32 At(int index) + { + return _data[index]; + } + + protected internal override void At(int index, Complex32 value) + { + _data[index] = value; + } } public class UserDefinedVectorTests : VectorTests diff --git a/src/UnitTests/LinearAlgebraTests/Double/UserDefinedVectorTests.cs b/src/UnitTests/LinearAlgebraTests/Double/UserDefinedVectorTests.cs index 37c51450..1188561b 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/UserDefinedVectorTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/UserDefinedVectorTests.cs @@ -46,19 +46,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double _data = (double[])data.Clone(); } - public override double this[int index] - { - get - { - return _data[index]; - } - - set - { - _data[index] = value; - } - } - public override Matrix CreateMatrix(int rows, int columns) { return new UserDefinedMatrix(rows, columns); @@ -68,6 +55,16 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double { return new UserDefinedVector(size); } + + protected internal override double At(int index) + { + return _data[index]; + } + + protected internal override void At(int index, double value) + { + _data[index] = value; + } } public class UserDefinedVectorTests : VectorTests diff --git a/src/UnitTests/LinearAlgebraTests/Single/UserDefinedVectorTests.cs b/src/UnitTests/LinearAlgebraTests/Single/UserDefinedVectorTests.cs index 7b484eef..7bb6ceaa 100644 --- a/src/UnitTests/LinearAlgebraTests/Single/UserDefinedVectorTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Single/UserDefinedVectorTests.cs @@ -55,19 +55,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single _data = (float[])data.Clone(); } - public override float this[int index] - { - get - { - return _data[index]; - } - - set - { - _data[index] = value; - } - } - public override Matrix CreateMatrix(int rows, int columns) { return new UserDefinedMatrix(rows, columns); @@ -77,6 +64,16 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single { return new UserDefinedVector(size); } + + protected internal override float At(int index) + { + return _data[index]; + } + + protected internal override void At(int index, float value) + { + _data[index] = value; + } } public class UserDefinedVectorTests : VectorTests