Browse Source

LA: migrate vectors to storage classes (major)

la-knuth
Christoph Ruegg 14 years ago
parent
commit
78a933aaf3
  1. 4
      src/Examples/LinearAlgebra/VectorDataAccessor.cs
  2. 9
      src/Numerics.IO/LinearAlgebra/IO/MatlabWriter.cs
  3. 75
      src/Numerics/LinearAlgebra/Complex/DenseMatrix.cs
  4. 248
      src/Numerics/LinearAlgebra/Complex/DenseVector.cs
  5. 4
      src/Numerics/LinearAlgebra/Complex/DiagonalMatrix.cs
  6. 4
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseCholesky.cs
  7. 2
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseEvd.cs
  8. 2
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseGramSchmidt.cs
  9. 4
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseLU.cs
  10. 2
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs
  11. 6
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseSvd.cs
  12. 1
      src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs
  13. 459
      src/Numerics/LinearAlgebra/Complex/SparseVector.cs
  14. 11
      src/Numerics/LinearAlgebra/Complex/Vector.cs
  15. 75
      src/Numerics/LinearAlgebra/Complex32/DenseMatrix.cs
  16. 257
      src/Numerics/LinearAlgebra/Complex32/DenseVector.cs
  17. 4
      src/Numerics/LinearAlgebra/Complex32/DiagonalMatrix.cs
  18. 4
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseCholesky.cs
  19. 2
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseEvd.cs
  20. 2
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseGramSchmidt.cs
  21. 4
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseLU.cs
  22. 2
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs
  23. 6
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseSvd.cs
  24. 1
      src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs
  25. 489
      src/Numerics/LinearAlgebra/Complex32/SparseVector.cs
  26. 11
      src/Numerics/LinearAlgebra/Complex32/Vector.cs
  27. 77
      src/Numerics/LinearAlgebra/Double/DenseMatrix.cs
  28. 268
      src/Numerics/LinearAlgebra/Double/DenseVector.cs
  29. 4
      src/Numerics/LinearAlgebra/Double/DiagonalMatrix.cs
  30. 4
      src/Numerics/LinearAlgebra/Double/Factorization/DenseCholesky.cs
  31. 2
      src/Numerics/LinearAlgebra/Double/Factorization/DenseGramSchmidt.cs
  32. 4
      src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs
  33. 2
      src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs
  34. 6
      src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs
  35. 1
      src/Numerics/LinearAlgebra/Double/SparseMatrix.cs
  36. 483
      src/Numerics/LinearAlgebra/Double/SparseVector.cs
  37. 11
      src/Numerics/LinearAlgebra/Double/Vector.cs
  38. 288
      src/Numerics/LinearAlgebra/Generic/Vector.cs
  39. 77
      src/Numerics/LinearAlgebra/Single/DenseMatrix.cs
  40. 268
      src/Numerics/LinearAlgebra/Single/DenseVector.cs
  41. 4
      src/Numerics/LinearAlgebra/Single/DiagonalMatrix.cs
  42. 4
      src/Numerics/LinearAlgebra/Single/Factorization/DenseCholesky.cs
  43. 2
      src/Numerics/LinearAlgebra/Single/Factorization/DenseGramSchmidt.cs
  44. 4
      src/Numerics/LinearAlgebra/Single/Factorization/DenseLU.cs
  45. 2
      src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs
  46. 6
      src/Numerics/LinearAlgebra/Single/Factorization/DenseSvd.cs
  47. 1
      src/Numerics/LinearAlgebra/Single/SparseMatrix.cs
  48. 503
      src/Numerics/LinearAlgebra/Single/SparseVector.cs
  49. 12
      src/Numerics/LinearAlgebra/Single/Vector.cs
  50. 8
      src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs
  51. 333
      src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs
  52. 16
      src/Numerics/LinearAlgebra/Storage/VectorStorage.cs
  53. 1
      src/Numerics/Numerics.csproj
  54. 3
      src/Portable/Portable.csproj
  55. 25
      src/UnitTests/LinearAlgebraTests/Complex/SparseVectorTest.cs
  56. 69
      src/UnitTests/LinearAlgebraTests/Complex/UserDefinedVector.cs
  57. 4
      src/UnitTests/LinearAlgebraTests/Complex/VectorTests.cs
  58. 25
      src/UnitTests/LinearAlgebraTests/Complex32/SparseVectorTest.cs
  59. 69
      src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedVector.cs
  60. 4
      src/UnitTests/LinearAlgebraTests/Complex32/VectorTests.cs
  61. 25
      src/UnitTests/LinearAlgebraTests/Double/SparseVectorTest.cs
  62. 69
      src/UnitTests/LinearAlgebraTests/Double/UserDefinedVector.cs
  63. 4
      src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs
  64. 26
      src/UnitTests/LinearAlgebraTests/Single/SparseVectorTest.cs
  65. 69
      src/UnitTests/LinearAlgebraTests/Single/UserDefinedVector.cs
  66. 4
      src/UnitTests/LinearAlgebraTests/Single/VectorTests.cs

4
src/Examples/LinearAlgebra/VectorDataAccessor.cs

@ -30,6 +30,8 @@ using MathNet.Numerics.LinearAlgebra.Double;
namespace Examples.LinearAlgebraExamples namespace Examples.LinearAlgebraExamples
{ {
using MathNet.Numerics.LinearAlgebra.Generic;
/// <summary> /// <summary>
/// Vector data access, copying and conversion examples /// Vector data access, copying and conversion examples
/// </summary> /// </summary>
@ -124,7 +126,7 @@ namespace Examples.LinearAlgebraExamples
Console.WriteLine(); Console.WriteLine();
// 8. Copy part of vector into another vector. If you need to copy all data then use CopoTy(vector) method. // 8. Copy part of vector into another vector. If you need to copy all data then use CopoTy(vector) method.
vectorA.CopyTo(cloneA, 3, 3, 4); vectorA.CopySubVectorTo(cloneA, 3, 3, 4);
Console.WriteLine(@"8. Copy part of vector into another vector"); Console.WriteLine(@"8. Copy part of vector into another vector");
Console.WriteLine(cloneA.ToString("#0.00\t", formatProvider)); Console.WriteLine(cloneA.ToString("#0.00\t", formatProvider));
Console.WriteLine(); Console.WriteLine();

9
src/Numerics.IO/LinearAlgebra/IO/MatlabWriter.cs

@ -37,6 +37,7 @@ namespace MathNet.Numerics.LinearAlgebra.IO
using Generic; using Generic;
using Matlab; using Matlab;
using Properties; using Properties;
using Storage;
/// <summary> /// <summary>
/// Writes matrices to a Matlab file. /// Writes matrices to a Matlab file.
@ -500,7 +501,7 @@ namespace MathNet.Numerics.LinearAlgebra.IO
int count = 0; int count = 0;
foreach (var column in matrix.ColumnEnumerator()) foreach (var column in matrix.ColumnEnumerator())
{ {
count += ((Double.SparseVector)column.Item2).NonZerosCount; count += ((SparseVectorStorage<double>)column.Item2.Storage).ValueCount;
dataWriter.Write(count); dataWriter.Write(count);
} }
@ -568,7 +569,7 @@ namespace MathNet.Numerics.LinearAlgebra.IO
int count = 0; int count = 0;
foreach (var column in matrix.ColumnEnumerator()) foreach (var column in matrix.ColumnEnumerator())
{ {
count += ((Single.SparseVector)column.Item2).NonZerosCount; count += ((SparseVectorStorage<float>)column.Item2.Storage).ValueCount;
dataWriter.Write(count); dataWriter.Write(count);
} }
@ -639,7 +640,7 @@ namespace MathNet.Numerics.LinearAlgebra.IO
int count = 0; int count = 0;
foreach (var column in matrix.ColumnEnumerator()) foreach (var column in matrix.ColumnEnumerator())
{ {
count += ((Complex.SparseVector)column.Item2).NonZerosCount; count += ((SparseVectorStorage<System.Numerics.Complex>)column.Item2.Storage).ValueCount;
dataWriter.Write(count); dataWriter.Write(count);
} }
@ -718,7 +719,7 @@ namespace MathNet.Numerics.LinearAlgebra.IO
int count = 0; int count = 0;
foreach (var column in matrix.ColumnEnumerator()) foreach (var column in matrix.ColumnEnumerator())
{ {
count += ((Complex32.SparseVector)column.Item2).NonZerosCount; count += ((SparseVectorStorage<Numerics.Complex32>)column.Item2.Storage).ValueCount;
dataWriter.Write(count); dataWriter.Write(count);
} }

75
src/Numerics/LinearAlgebra/Complex/DenseMatrix.cs

@ -39,8 +39,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
[Serializable] [Serializable]
public class DenseMatrix : Matrix public class DenseMatrix : Matrix
{ {
readonly DenseColumnMajorMatrixStorage<Complex> _storage;
/// <summary> /// <summary>
/// Number of rows. /// Number of rows.
/// </summary> /// </summary>
@ -59,15 +57,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// Gets the matrix's data. /// Gets the matrix's data.
/// </summary> /// </summary>
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
readonly Complex[] _data; readonly Complex[] _values;
internal DenseMatrix(DenseColumnMajorMatrixStorage<Complex> storage) internal DenseMatrix(DenseColumnMajorMatrixStorage<Complex> storage)
: base(storage) : base(storage)
{ {
_storage = storage; _rowCount = storage.RowCount;
_rowCount = _storage.RowCount; _columnCount = storage.ColumnCount;
_columnCount = _storage.ColumnCount; _values = storage.Data;
_data = _storage.Data;
} }
/// <summary> /// <summary>
@ -109,9 +106,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public DenseMatrix(int rows, int columns, Complex value) public DenseMatrix(int rows, int columns, Complex value)
: this(rows, columns) : this(rows, columns)
{ {
for (var i = 0; i < _data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
_data[i] = value; _values[i] = value;
} }
} }
@ -139,7 +136,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
for (var j = 0; j < _columnCount; j++) for (var j = 0; j < _columnCount; j++)
{ {
_data[(j * _rowCount) + i] = array[i, j]; _values[(j * _rowCount) + i] = array[i, j];
} }
} }
} }
@ -161,7 +158,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
public Complex[] Data public Complex[] Data
{ {
get { return _data; } get { return _values; }
} }
/// <summary> /// <summary>
@ -203,7 +200,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
var index = j * _rowCount; var index = j * _rowCount;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
ret._data[(i * _columnCount) + j] = _data[index + i]; ret._values[(i * _columnCount) + j] = _values[index + i];
} }
} }
@ -214,21 +211,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override Complex L1Norm() public override Complex L1Norm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override Complex FrobeniusNorm() public override Complex FrobeniusNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override Complex InfinityNorm() public override Complex InfinityNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _values);
} }
#region Static constructors for special matrices. #region Static constructors for special matrices.
@ -246,7 +243,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
var m = new DenseMatrix(order); var m = new DenseMatrix(order);
for (var i = 0; i < order; i++) for (var i = 0; i < order; i++)
{ {
m._data[(i * order) + i] = 1.0; m._values[(i * order) + i] = 1.0;
} }
return m; return m;
@ -268,7 +265,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult._values);
} }
} }
@ -292,14 +289,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0, 0.0,
denseResult.Data); denseResult.Values);
} }
} }
@ -323,14 +320,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0, 0.0,
denseResult._data); denseResult._values);
} }
} }
@ -354,14 +351,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0, 0.0,
denseResult._data); denseResult._values);
} }
} }
@ -385,14 +382,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0, 0.0,
denseResult.Data); denseResult.Values);
} }
} }
@ -416,14 +413,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0, 0.0,
denseResult._data); denseResult._values);
} }
} }
@ -441,7 +438,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(-1, _values, denseResult._values);
} }
} }
@ -461,7 +458,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -481,7 +478,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseDivideArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -502,7 +499,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
else else
{ {
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.AddArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -521,7 +518,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
else else
{ {
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.SubtractArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -537,7 +534,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
var index = j * _rowCount; var index = j * _rowCount;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
ret._data[(i * _columnCount) + j] = _data[index + i].Conjugate(); ret._values[(i * _columnCount) + j] = _values[index + i].Conjugate();
} }
} }
@ -559,7 +556,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
var sum = Complex.Zero; var sum = Complex.Zero;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
sum += _data[(i * _rowCount) + i]; sum += _values[(i * _rowCount) + i];
} }
return sum; return sum;

248
src/Numerics/LinearAlgebra/Complex/DenseVector.cs

@ -33,6 +33,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
using Generic; using Generic;
using NumberTheory; using NumberTheory;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -41,6 +42,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
[Serializable] [Serializable]
public class DenseVector : Vector public class DenseVector : Vector
{ {
/// <summary>
/// Number of elements
/// </summary>
readonly int _length;
/// <summary>
/// Gets the vector's data.
/// </summary>
readonly Complex[] _values;
internal DenseVector(DenseVectorStorage<Complex> storage)
: base(storage)
{
_length = storage.Length;
_values = storage.Data;
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class with a given size. /// Initializes a new instance of the <see cref="DenseVector"/> class with a given size.
/// </summary> /// </summary>
@ -50,9 +68,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public DenseVector(int size) : base(size) public DenseVector(int size)
: this(new DenseVectorStorage<Complex>(size))
{ {
Data = new Complex[size];
} }
/// <summary> /// <summary>
@ -68,11 +86,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public DenseVector(int size, Complex value) : this(size) public DenseVector(int size, Complex value)
: this(size)
{ {
for (var index = 0; index < Data.Length; index++) for (var index = 0; index < _values.Length; index++)
{ {
Data[index] = value; _values[index] = value;
} }
} }
@ -83,27 +102,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <param name="other"> /// <param name="other">
/// The vector to create the new vector from. /// The vector to create the new vector from.
/// </param> /// </param>
public DenseVector(Vector<Complex> other) : this(other.Count) public DenseVector(Vector<Complex> other)
{ : this(other.Count)
CommonParallel.For(
0,
Data.Length,
index => this[index] = other[index]);
}
/// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public DenseVector(DenseVector other) : this(other.Count)
{ {
CommonParallel.For( other.Storage.CopyTo(Storage, skipClearing: true);
0,
Data.Length,
index => Data[index] = other.Data[index]);
} }
/// <summary> /// <summary>
@ -112,20 +114,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector does not copy the array, but keeps a reference to it. Any /// <remarks>The vector does not copy the array, but keeps a reference to it. Any
/// changes to the vector will also change the array.</remarks> /// changes to the vector will also change the array.</remarks>
public DenseVector(Complex[] array) : base(array.Length) public DenseVector(Complex[] array)
: this(new DenseVectorStorage<Complex>(array.Length, array))
{ {
Data = array;
} }
/// <summary> /// <summary>
/// Gets the vector's internal data. /// Gets the vector's data.
/// </summary> /// </summary>
/// <value>The vector's internal data.</value> /// <value>The vector's data.</value>
/// <remarks>Changing values in the array also changes the corresponding value in vector. Use with care.</remarks> public Complex[] Values
internal Complex[] Data
{ {
get; get { return _values; }
private set;
} }
/// <summary> /// <summary>
@ -136,14 +136,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <returns> /// <returns>
/// A reference to the internal date of the given vector. /// A reference to the internal date of the given vector.
/// </returns> /// </returns>
public static implicit operator Complex[](DenseVector vector) public static explicit operator Complex[](DenseVector vector)
{ {
if (vector == null) if (vector == null)
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
return vector.Data; return vector.Values;
} }
/// <summary> /// <summary>
@ -169,10 +169,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <returns>This vector as a column matrix.</returns> /// <returns>This vector as a column matrix.</returns>
public override Matrix<Complex> ToColumnMatrix() public override Matrix<Complex> ToColumnMatrix()
{ {
var matrix = new DenseMatrix(Count, 1); var matrix = new DenseMatrix(_length, 1);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(i, 0, Data[i]); matrix.At(i, 0, _values[i]);
} }
return matrix; return matrix;
@ -184,33 +184,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <returns>This vector as a row matrix.</returns> /// <returns>This vector as a row matrix.</returns>
public override Matrix<Complex> ToRowMatrix() public override Matrix<Complex> ToRowMatrix()
{ {
var matrix = new DenseMatrix(1, Count); var matrix = new DenseMatrix(1, _length);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(0, i, Data[i]); matrix.At(0, i, _values[i]);
} }
return matrix; return matrix;
} }
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
/// <exception cref="IndexOutOfRangeException">If <paramref name="index"/> is negative or
/// greater than the size of the vector.</exception>
public override Complex this[int index]
{
get
{
return Data[index];
}
set
{
Data[index] = value;
}
}
/// <summary> /// <summary>
/// Creates a matrix with the given dimensions using the same storage type /// Creates a matrix with the given dimensions using the same storage type
/// as this vector. /// as this vector.
@ -244,49 +226,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
return new DenseVector(size); return new DenseVector(size);
} }
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<Complex> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as DenseVector;
if (otherVector == null)
{
CommonParallel.For(
0,
Data.Length,
index => target[index] = Data[index]);
}
else
{
Array.Copy(Data, 0, otherVector.Data, 0, Data.Length);
}
}
/// <summary> /// <summary>
/// Adds a scalar to each element of the vector and stores the result in the result vector. /// Adds a scalar to each element of the vector and stores the result in the result vector.
/// </summary> /// </summary>
@ -303,8 +242,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] + scalar); index => dense._values[index] = _values[index] + scalar);
} }
} }
@ -319,7 +258,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, Complex.One, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, Complex.One, odense.Values, rdense.Values);
} }
else else
{ {
@ -388,8 +327,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] - scalar); index => dense._values[index] = _values[index] - scalar);
} }
} }
@ -404,7 +343,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, -1.0, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, -1.0, odense.Values, rdense.Values);
} }
else else
{ {
@ -463,11 +402,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<Complex> Negate() public override Vector<Complex> Negate()
{ {
var result = new DenseVector(Count); var result = new DenseVector(_length);
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => result[index] = -Data[index]); index => result[index] = -_values[index]);
return result; return result;
} }
@ -487,7 +426,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, Data, denseResult.Data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult.Values);
} }
} }
@ -501,7 +440,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
var denseVector = other as DenseVector; var denseVector = other as DenseVector;
return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(Data, denseVector.Data); return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(_values, denseVector.Values);
} }
/// <summary> /// <summary>
@ -563,7 +502,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide");
} }
return Control.LinearAlgebraProvider.DotProduct(leftSide.Data, rightSide.Data); return Control.LinearAlgebraProvider.DotProduct(leftSide.Values, rightSide.Values);
} }
/// <summary> /// <summary>
@ -590,10 +529,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
var index = 0; var index = 0;
var min = Data[index].Magnitude; var min = _values[index].Magnitude;
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Data[i].Magnitude; var test = _values[i].Magnitude;
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -610,7 +549,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <returns>The value of the absolute minimum element.</returns> /// <returns>The value of the absolute minimum element.</returns>
public override Complex AbsoluteMinimum() public override Complex AbsoluteMinimum()
{ {
return Data[AbsoluteMinimumIndex()].Magnitude; return _values[AbsoluteMinimumIndex()].Magnitude;
} }
/// <summary> /// <summary>
@ -619,7 +558,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <returns>The value of the absolute maximum element.</returns> /// <returns>The value of the absolute maximum element.</returns>
public override Complex AbsoluteMaximum() public override Complex AbsoluteMaximum()
{ {
return Data[AbsoluteMaximumIndex()].Magnitude; return _values[AbsoluteMaximumIndex()].Magnitude;
} }
/// <summary> /// <summary>
@ -629,10 +568,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override int AbsoluteMaximumIndex() public override int AbsoluteMaximumIndex()
{ {
var index = 0; var index = 0;
var max = Data[index].Magnitude; var max = _values[index].Magnitude;
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Data[i].Magnitude; var test = _values[i].Magnitude;
if (test > max) if (test > max)
{ {
index = i; index = i;
@ -656,7 +595,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception> /// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
public override Vector<Complex> SubVector(int index, int length) public override Vector<Complex> SubVector(int index, int length)
{ {
if (index < 0 || index >= Count) if (index < 0 || index >= _length)
{ {
throw new ArgumentOutOfRangeException("index"); throw new ArgumentOutOfRangeException("index");
} }
@ -666,7 +605,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
if (index + length > Count) if (index + length > _length)
{ {
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
@ -675,8 +614,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
CommonParallel.For( CommonParallel.For(
index, index,
index + length, index + length,
i => result.Data[i - index] = Data[i]); i => result._values[i - index] = _values[i]);
return result; return result;
} }
@ -693,7 +632,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
throw new ArgumentNullException("values"); throw new ArgumentNullException("values");
} }
if (values.Length != Count) if (values.Length != _length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values");
} }
@ -701,7 +640,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
CommonParallel.For( CommonParallel.For(
0, 0,
values.Length, values.Length,
i => Data[i] = values[i]); i => _values[i] = values[i]);
} }
/// <summary> /// <summary>
@ -712,9 +651,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
var sum = Complex.Zero; var sum = Complex.Zero;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Data[i]; sum += _values[i];
} }
return sum; return sum;
@ -728,9 +667,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
var sum = Complex.Zero; var sum = Complex.Zero;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Data[i].Magnitude; sum += _values[i].Magnitude;
} }
return sum; return sum;
@ -752,8 +691,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] * other[index]); index => dense._values[index] = _values[index] * other[index]);
} }
} }
@ -774,8 +713,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] / other[index]); index => dense._values[index] = _values[index] / other[index]);
} }
} }
@ -807,7 +746,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
for (var j = 0; j < v.Count; j++) for (var j = 0; j < v.Count; j++)
{ {
matrix.At(i, j, u.Data[i] * v.Data[j]); matrix.At(i, j, u._values[i] * v._values[j]);
} }
}); });
return matrix; return matrix;
@ -845,19 +784,19 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
if (2.0 == p) if (2.0 == p)
{ {
return Data.Aggregate(Complex.Zero, SpecialFunctions.Hypotenuse).Magnitude; return _values.Aggregate(Complex.Zero, SpecialFunctions.Hypotenuse).Magnitude;
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(Data, (i, v) => v.Magnitude, Math.Max, 0d); return CommonParallel.Aggregate(_values, (i, v) => v.Magnitude, Math.Max, 0d);
} }
var sum = 0.0; var sum = 0.0;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Math.Pow(Data[i].Magnitude, p); sum += Math.Pow(_values[i].Magnitude, p);
} }
return Math.Pow(sum, 1.0 / p); return Math.Pow(sum, 1.0 / p);
@ -1022,14 +961,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
#endregion #endregion
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
}
/// <summary> /// <summary>
/// Conjugates vector and save result to <paramref name="target"/> /// Conjugates vector and save result to <paramref name="target"/>
/// </summary> /// </summary>
@ -1046,24 +977,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Count, _length,
index => denseTarget.Data[index] = Data[index].Conjugate()); index => denseTarget._values[index] = _values[index].Conjugate());
} }
} }
/// <summary>Gets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
internal protected override Complex At(int index)
{
return Data[index];
}
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <param name="value">The value to set.</param>
internal protected override void At(int index, Complex value)
{
Data[index] = value;
}
} }
} }

4
src/Numerics/LinearAlgebra/Complex/DiagonalMatrix.cs

@ -378,12 +378,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
return; return;
} }
if (_data.Length != denseSource.Data.Length) if (_data.Length != denseSource.Values.Length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source");
} }
Array.Copy(denseSource.Data, _data, denseSource.Data.Length); Array.Copy(denseSource.Values, _data, denseSource.Values.Length);
} }
/// <summary> /// <summary>

4
src/Numerics/LinearAlgebra/Complex/Factorization/DenseCholesky.cs

@ -169,11 +169,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); CommonParallel.For(0, dinput.Values.Length, index => dresult.Values[index] = dinput.Values[index]);
// Cholesky solve by overwriting result. // Cholesky solve by overwriting result.
var dfactor = (DenseMatrix)CholeskyFactor; var dfactor = (DenseMatrix)CholeskyFactor;
Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Data, 1); Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Values, 1);
} }
} }
} }

2
src/Numerics/LinearAlgebra/Complex/Factorization/DenseEvd.cs

@ -107,7 +107,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
var matrixH = matrix.ToArray(); var matrixH = matrix.ToArray();
NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Data, matrixH, order); NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Data, matrixH, order);
NonsymmetricReduceHessenberToRealSchur(((DenseVector)VectorEv).Data, ((DenseMatrix)MatrixEv).Data, matrixH, order); NonsymmetricReduceHessenberToRealSchur(((DenseVector)VectorEv).Values, ((DenseMatrix)MatrixEv).Data, matrixH, order);
} }
MatrixD.SetDiagonal(VectorEv); MatrixD.SetDiagonal(VectorEv);

2
src/Numerics/LinearAlgebra/Complex/Factorization/DenseGramSchmidt.cs

@ -217,7 +217,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment.");
} }
_provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Data, 1, dresult.Data); _provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Values, 1, dresult.Values);
} }
} }
} }

4
src/Numerics/LinearAlgebra/Complex/Factorization/DenseLU.cs

@ -170,11 +170,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); CommonParallel.For(0, dinput.Values.Length, index => dresult.Values[index] = dinput.Values[index]);
// LU solve by overwriting result. // LU solve by overwriting result.
var dfactors = (DenseMatrix)Factors; var dfactors = (DenseMatrix)Factors;
Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Values);
} }
/// <summary> /// <summary>

2
src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs

@ -188,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
} }
} }
} }

6
src/Numerics/LinearAlgebra/Complex/Factorization/DenseSvd.cs

@ -70,7 +70,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
VectorS = new DenseVector(nm); VectorS = new DenseVector(nm);
MatrixU = new DenseMatrix(matrix.RowCount); MatrixU = new DenseMatrix(matrix.RowCount);
MatrixVT = new DenseMatrix(matrix.ColumnCount); MatrixVT = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data);
} }
/// <summary> /// <summary>
@ -126,7 +126,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data);
} }
/// <summary> /// <summary>
@ -176,7 +176,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Values, 1, dresult.Values);
} }
} }
} }

1
src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs

@ -98,6 +98,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// The number of columns. /// The number of columns.
/// </param> /// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param> /// <param name="value">The value which we assign to each element of the matrix.</param>
[Obsolete("Use a dense matrix instead.")]
public SparseMatrix(int rows, int columns, Complex value) public SparseMatrix(int rows, int columns, Complex value)
: this(rows, columns) : this(rows, columns)
{ {

459
src/Numerics/LinearAlgebra/Complex/SparseVector.cs

@ -37,6 +37,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
using Generic; using Generic;
using NumberTheory; using NumberTheory;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -46,24 +47,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
[Serializable] [Serializable]
public class SparseVector : Vector public class SparseVector : Vector
{ {
/// <summary> readonly SparseVectorStorage<Complex> _storage;
/// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored.
/// </summary>
private Complex[] _nonZeroValues = new Complex[0];
/// <summary> internal SparseVector(SparseVectorStorage<Complex> storage)
/// The indices of the non-zero entries. : base(storage)
/// </summary>
private int[] _nonZeroIndices = new int[0];
/// <summary>
/// Gets the number of non zero elements in the vector.
/// </summary>
/// <value>The number of non zero elements.</value>
public int NonZerosCount
{ {
get; _storage = storage;
private set;
} }
#region Constructors #region Constructors
@ -77,7 +66,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size) : base(size) public SparseVector(int size)
: this(new SparseVectorStorage<Complex>(size))
{ {
} }
@ -94,58 +84,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size, Complex value) : this(size) [Obsolete("Use a dense vector instead.")]
public SparseVector(int size, Complex value)
: this(new SparseVectorStorage<Complex>(size))
{ {
if (value == Complex.Zero) if (value == Complex.Zero)
{ {
// Skip adding values
return; return;
} }
// We already know that this vector is "full", let's allocate all needed memory var valueCount = _storage.ValueCount = size;
_nonZeroValues = new Complex[size]; var indices = _storage.Indices = new int[valueCount];
_nonZeroIndices = new int[size]; var values = _storage.Values = new Complex[valueCount];
NonZerosCount = size;
CommonParallel.For( for (int i = 0; i < values.Length; i++)
0,
Count,
index =>
{
_nonZeroValues[index] = value;
_nonZeroIndices[index] = index;
});
}
/// <summary>
/// Initializes a new instance of the <see cref="SparseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public SparseVector(Vector<Complex> other) : this(other.Count)
{
var vector = other as SparseVector;
if (vector == null)
{ {
for (var i = 0; i < other.Count; i++) values[i] = value;
{ indices[i] = i;
this[i] = other.At(i);
}
}
else
{
_nonZeroValues = new Complex[vector.NonZerosCount];
_nonZeroIndices = new int[vector.NonZerosCount];
NonZerosCount = vector.NonZerosCount;
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
if (vector.NonZerosCount != 0)
{
CommonParallel.For(0, vector.NonZerosCount, index => _nonZeroValues[index] = vector._nonZeroValues[index]);
Buffer.BlockCopy(vector._nonZeroIndices, 0, _nonZeroIndices, 0, vector.NonZerosCount * Constants.SizeOfInt);
}
} }
} }
@ -156,18 +111,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <param name="other"> /// <param name="other">
/// The vector to create the new vector from. /// The vector to create the new vector from.
/// </param> /// </param>
public SparseVector(SparseVector other) : this(other.Count) public SparseVector(Vector<Complex> other)
: this(new SparseVectorStorage<Complex>(other.Count))
{ {
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value other.Storage.CopyTo(Storage, skipClearing: true);
_nonZeroValues = new Complex[other.NonZerosCount];
_nonZeroIndices = new int[other.NonZerosCount];
NonZerosCount = other.NonZerosCount;
if (other.NonZerosCount != 0)
{
CommonParallel.For(0, other.NonZerosCount, index => _nonZeroValues[index] = other._nonZeroValues[index]);
Buffer.BlockCopy(other._nonZeroIndices, 0, _nonZeroIndices, 0, other.NonZerosCount * Constants.SizeOfInt);
}
} }
/// <summary> /// <summary>
@ -175,11 +122,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// </summary> /// </summary>
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks> /// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks>
public SparseVector(IList<Complex> array) : this(array.Count) public SparseVector(IList<Complex> array)
: this(new SparseVectorStorage<Complex>(array.Count))
{ {
for (var i = 0; i < array.Count; i++) for (var i = 0; i < array.Count; i++)
{ {
this[i] = array[i]; Storage.At(i, array[i]);
} }
} }
@ -192,9 +140,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Matrix<Complex> ToColumnMatrix() public override Matrix<Complex> ToColumnMatrix()
{ {
var matrix = new SparseMatrix(Count, 1); var matrix = new SparseMatrix(Count, 1);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); matrix.At(_storage.Indices[i], 0, _storage.Values[i]);
} }
return matrix; return matrix;
@ -207,9 +155,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Matrix<Complex> ToRowMatrix() public override Matrix<Complex> ToRowMatrix()
{ {
var matrix = new SparseMatrix(1, Count); var matrix = new SparseMatrix(1, Count);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); matrix.At(0, _storage.Indices[i], _storage.Values[i]);
} }
return matrix; return matrix;
@ -248,68 +196,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
return new SparseVector(size); return new SparseVector(size);
} }
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
NonZerosCount = 0;
}
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<Complex> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as SparseVector;
if (otherVector == null)
{
target.Clear();
for (var index = 0; index < NonZerosCount; index++)
{
target.At(_nonZeroIndices[index], _nonZeroValues[index]);
}
}
else
{
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
otherVector._nonZeroValues = new Complex[NonZerosCount];
otherVector._nonZeroIndices = new int[NonZerosCount];
otherVector.NonZerosCount = NonZerosCount;
if (NonZerosCount != 0)
{
Array.Copy(_nonZeroValues, 0, otherVector._nonZeroValues, 0, NonZerosCount);
Buffer.BlockCopy(_nonZeroIndices, 0, otherVector._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt);
}
}
}
/// <summary> /// <summary>
/// Conjugates vector and save result to <paramref name="target"/> /// Conjugates vector and save result to <paramref name="target"/>
/// </summary> /// </summary>
@ -341,14 +227,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
else else
{ {
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value // Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
otherVector._nonZeroValues = new Complex[NonZerosCount]; otherVector._storage.Values = new Complex[_storage.ValueCount];
otherVector._nonZeroIndices = new int[NonZerosCount]; otherVector._storage.Indices = new int[_storage.ValueCount];
otherVector.NonZerosCount = NonZerosCount; otherVector._storage.ValueCount = _storage.ValueCount;
if (NonZerosCount != 0) if (_storage.ValueCount != 0)
{ {
CommonParallel.For(0, NonZerosCount, index => otherVector._nonZeroValues[index] = _nonZeroValues[index].Conjugate()); CommonParallel.For(0, _storage.ValueCount, index => otherVector._storage.Values[index] = _storage.Values[index].Conjugate());
Buffer.BlockCopy(_nonZeroIndices, 0, otherVector._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); Buffer.BlockCopy(_storage.Indices, 0, otherVector._storage.Indices, 0, _storage.ValueCount * Constants.SizeOfInt);
} }
} }
} }
@ -390,15 +276,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
//populate the non zero values from this //populate the non zero values from this
for (int j = 0; j < NonZerosCount; j++) for (int j = 0; j < _storage.ValueCount; j++)
{ {
vnonZeroValues[_nonZeroIndices[j]] = _nonZeroValues[j] + scalar; vnonZeroValues[_storage.Indices[j]] = _storage.Values[j] + scalar;
} }
//assign this vectors arrary to the new arrays. //assign this vectors arrary to the new arrays.
_nonZeroValues = vnonZeroValues; _storage.Values = vnonZeroValues;
_nonZeroIndices = vnonZeroIndices; _storage.Indices = vnonZeroIndices;
NonZerosCount = Count; _storage.ValueCount = Count;
} }
else else
{ {
@ -439,22 +325,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] += otherSparse._nonZeroValues[j++]; _storage.Values[i++] += otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != Complex.Zero) if (otherValue != Complex.Zero)
{ {
InsertAtUnchecked(i++, otherSparse._nonZeroIndices[j], otherValue); InsertAtUnchecked(i++, otherSparse._storage.Indices[j], otherValue);
} }
j++; j++;
} }
@ -464,25 +350,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] + otherSparse.At(next)); result.At(next, _storage.Values[i] + otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) + otherSparse._nonZeroValues[j]); result.At(next, At(next) + otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -585,22 +471,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] -= otherSparse._nonZeroValues[j++]; _storage.Values[i++] -= otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != Complex.Zero) if (otherValue != Complex.Zero)
{ {
InsertAtUnchecked(i++, otherSparse._nonZeroIndices[j], -otherValue); InsertAtUnchecked(i++, otherSparse._storage.Indices[j], -otherValue);
} }
j++; j++;
} }
@ -610,25 +496,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] - otherSparse.At(next)); result.At(next, _storage.Values[i] - otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) - otherSparse._nonZeroValues[j]); result.At(next, At(next) - otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -687,23 +573,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<Complex> Negate() public override Vector<Complex> Negate()
{ {
var result = new SparseVector(Count) var result = new SparseVectorStorage<Complex>(Count);
{ var valueCount = result.ValueCount = _storage.ValueCount;
_nonZeroValues = new Complex[NonZerosCount], var indices = result.Indices = new int[valueCount];
_nonZeroIndices = new int[NonZerosCount], var values = result.Values = new Complex[valueCount];
NonZerosCount = NonZerosCount
};
if (NonZerosCount != 0) if (valueCount != 0)
{ {
CommonParallel.For( CommonParallel.For(0, valueCount, index => values[index] = -_storage.Values[index]);
0, Buffer.BlockCopy(_storage.Indices, 0, indices, 0, valueCount * Constants.SizeOfInt);
NonZerosCount,
index => result._nonZeroValues[index] = -_nonZeroValues[index]);
Buffer.BlockCopy(_nonZeroIndices, 0, result._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt);
} }
return result; return new SparseVector(result);
} }
/// <summary> /// <summary>
@ -724,7 +605,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
var copy = new SparseVector(this); var copy = new SparseVector(this);
Control.LinearAlgebraProvider.ScaleArray(scalar, copy._nonZeroValues, copy._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, copy._storage.Values, copy._storage.Values);
return copy; return copy;
} }
@ -759,23 +640,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
if (sparseResult == null) if (sparseResult == null)
{ {
result.Clear(); result.Clear();
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); result.At(_storage.Indices[index], scalar * _storage.Values[index]);
} }
} }
else else
{ {
if (!ReferenceEquals(this, result)) if (!ReferenceEquals(this, result))
{ {
sparseResult.NonZerosCount = NonZerosCount; sparseResult._storage.ValueCount = _storage.ValueCount;
sparseResult._nonZeroIndices = new int[NonZerosCount]; sparseResult._storage.Indices = new int[_storage.ValueCount];
Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); Buffer.BlockCopy(_storage.Indices, 0, sparseResult._storage.Indices, 0, _storage.ValueCount * Constants.SizeOfInt);
sparseResult._nonZeroValues = new Complex[NonZerosCount]; sparseResult._storage.Values = new Complex[_storage.ValueCount];
Array.Copy(_nonZeroValues, sparseResult._nonZeroValues, NonZerosCount); Array.Copy(_storage.Values, sparseResult._storage.Values, _storage.ValueCount);
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues, sparseResult._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._storage.Values, sparseResult._storage.Values);
} }
} }
@ -794,16 +675,16 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * _nonZeroValues[i]; result += _storage.Values[i] * _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); result += _storage.Values[i] * other.At(_storage.Indices[i]);
} }
} }
@ -895,17 +776,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <returns>The index of absolute minimum element.</returns> /// <returns>The index of absolute minimum element.</returns>
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
// No non-zero elements. Return 0 // No non-zero elements. Return 0
return 0; return 0;
} }
var index = 0; var index = 0;
var min = _nonZeroValues[index].Magnitude; var min = _storage.Values[index].Magnitude;
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
var test = _nonZeroValues[i].Magnitude; var test = _storage.Values[i].Magnitude;
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -913,7 +794,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -984,9 +865,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Complex Sum() public override Complex Sum()
{ {
var result = Complex.Zero; var result = Complex.Zero;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i]; result += _storage.Values[i];
} }
return result; return result;
@ -999,9 +880,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Complex SumMagnitudes() public override Complex SumMagnitudes()
{ {
double result = 0; double result = 0;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i].Magnitude; result += _storage.Values[i].Magnitude;
} }
return result; return result;
@ -1016,17 +897,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] *= _nonZeroValues[i]; _storage.Values[i] *= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, other.At(index) * _nonZeroValues[i]); result.At(index, other.At(index) * _storage.Values[i]);
} }
} }
} }
@ -1040,17 +921,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] /= _nonZeroValues[i]; _storage.Values[i] /= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, _nonZeroValues[i] / other.At(index)); result.At(index, _storage.Values[i] / other.At(index));
} }
} }
} }
@ -1076,13 +957,13 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
var matrix = new SparseMatrix(u.Count, v.Count); var matrix = new SparseMatrix(u.Count, v.Count);
for (var i = 0; i < u.NonZerosCount; i++) for (var i = 0; i < u._storage.ValueCount; i++)
{ {
for (var j = 0; j < v.NonZerosCount; j++) for (var j = 0; j < v._storage.ValueCount; j++)
{ {
if (u._nonZeroIndices[i] == v._nonZeroIndices[j]) if (u._storage.Indices[i] == v._storage.Indices[j])
{ {
matrix.At(i, j, u._nonZeroValues[i] * v._nonZeroValues[j]); matrix.At(i, j, u._storage.Values[i] * v._storage.Values[j]);
} }
} }
} }
@ -1118,25 +999,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
throw new ArgumentOutOfRangeException("p"); throw new ArgumentOutOfRangeException("p");
} }
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return 0.0; return 0.0;
} }
if (2.0 == p) if (2.0 == p)
{ {
return _nonZeroValues.Aggregate(Complex.Zero, SpecialFunctions.Hypotenuse).Magnitude; return _storage.Values.Aggregate(Complex.Zero, SpecialFunctions.Hypotenuse).Magnitude;
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(0, NonZerosCount, i => _nonZeroValues[i].Magnitude, Math.Max, 0d); return CommonParallel.Aggregate(0, _storage.ValueCount, i => _storage.Values[i].Magnitude, Math.Max, 0d);
} }
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
sum += Math.Pow(_nonZeroValues[index].Magnitude, p); sum += Math.Pow(_storage.Values[index].Magnitude, p);
} }
return Math.Pow(sum, 1.0 / p); return Math.Pow(sum, 1.0 / p);
@ -1302,97 +1183,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
#endregion #endregion
/// <summary>
/// Gets the value at the given index.
/// </summary>
/// <param name="index">Value real index in array</param>
/// <returns>The value at the given index.</returns>
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;
}
/// <summary>
/// Delete, Add or Update the value in NonZeroValues and NonZeroIndices
/// </summary>
/// <param name="index">Value real index in array</param>
/// <param name="value">The value to set.</param>
/// <remarks>This method assume that index is between 0 and Array Size</remarks>
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);
if (itemIndex >= 0)
{
// Item already exist at itemIndex
if (value == Complex.Zero)
{
RemoveAtUnchecked(itemIndex);
}
else
{
_nonZeroValues[itemIndex] = value;
}
}
else
{
if (value != Complex.Zero)
{
InsertAtUnchecked(~itemIndex, index, value);
}
}
}
private void InsertAtUnchecked(int itemIndex, int index, Complex value) private void InsertAtUnchecked(int itemIndex, int index, Complex value)
{ {
// Check if the storage needs to be increased // Check if the storage needs to be increased
if ((NonZerosCount == _nonZeroValues.Length) && (NonZerosCount < Count)) if ((_storage.ValueCount == _storage.Values.Length) && (_storage.ValueCount < Count))
{ {
// Value and Indices arrays are completely full so we increase the size // Value and Indices arrays are completely full so we increase the size
var size = Math.Min(_nonZeroValues.Length + GrowthSize(), Count); var size = Math.Min(_storage.Values.Length + GrowthSize(), Count);
Array.Resize(ref _nonZeroValues, size); Array.Resize(ref _storage.Values, size);
Array.Resize(ref _nonZeroIndices, size); Array.Resize(ref _storage.Indices, size);
} }
// Move all values (with a position larger than index) in the value array // Move all values (with a position larger than index) in the value array
// to the next position // to the next position
// Move all values (with a position larger than index) in the columIndices // Move all values (with a position larger than index) in the columIndices
// array to the next position // array to the next position
for (var i = NonZerosCount - 1; i > itemIndex - 1; i--) for (var i = _storage.ValueCount - 1; i > itemIndex - 1; i--)
{ {
_nonZeroValues[i + 1] = _nonZeroValues[i]; _storage.Values[i + 1] = _storage.Values[i];
_nonZeroIndices[i + 1] = _nonZeroIndices[i]; _storage.Indices[i + 1] = _storage.Indices[i];
} }
// Add the value and the column index // Add the value and the column index
_nonZeroValues[itemIndex] = value; _storage.Values[itemIndex] = value;
_nonZeroIndices[itemIndex] = index; _storage.Indices[itemIndex] = index;
// increase the number of non-zero numbers by one // increase the number of non-zero numbers by one
NonZerosCount += 1; _storage.ValueCount += 1;
}
private void RemoveAtUnchecked(int itemIndex)
{
// Value is zero. Let's delete it from Values and Indices array
for (var i = itemIndex + 1; i < NonZerosCount; i++)
{
_nonZeroValues[i - 1] = _nonZeroValues[i];
_nonZeroIndices[i - 1] = _nonZeroIndices[i];
}
NonZerosCount -= 1;
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((NonZerosCount > 1024) && (NonZerosCount < _nonZeroIndices.Length / 2))
{
Array.Resize(ref _nonZeroValues, NonZerosCount);
Array.Resize(ref _nonZeroIndices, NonZerosCount);
}
} }
/// <summary> /// <summary>
@ -1403,19 +1220,19 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
private int GrowthSize() private int GrowthSize()
{ {
int delta; int delta;
if (_nonZeroValues.Length > 1024) if (_storage.Values.Length > 1024)
{ {
delta = _nonZeroValues.Length / 4; delta = _storage.Values.Length / 4;
} }
else else
{ {
if (_nonZeroValues.Length > 256) if (_storage.Values.Length > 256)
{ {
delta = 512; delta = 512;
} }
else else
{ {
delta = _nonZeroValues.Length > 64 ? 128 : 32; delta = _storage.Values.Length > 64 ? 128 : 32;
} }
} }
@ -1428,7 +1245,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
if (Count > 20) if (Count > 20)
{ {
return String.Format("SparseVectorOfComplex({0},{1},{2})", Count, NonZerosCount, GetHashCode()); return String.Format("SparseVectorOfComplex({0},{1},{2})", Count, _storage.ValueCount, GetHashCode());
} }
return base.ToString(format, formatProvider); return base.ToString(format, formatProvider);
@ -1442,14 +1259,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
var hashNum = Math.Min(NonZerosCount, 20); var hashNum = Math.Min(_storage.ValueCount, 20);
long hash = 0; long hash = 0;
for (var i = 0; i < hashNum; i++) for (var i = 0; i < hashNum; i++)
{ {
#if PORTABLE #if PORTABLE
hash ^= Precision.DoubleToInt64Bits(this._nonZeroValues[i].GetHashCode()); hash ^= Precision.DoubleToInt64Bits(this._storage.Values[i].GetHashCode());
#else #else
hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= BitConverter.DoubleToInt64Bits(_storage.Values[i].GetHashCode());
#endif #endif
} }
@ -1493,27 +1310,27 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
if (_nonZeroValues[i++] != Complex.Zero) if (_storage.Values[i++] != Complex.Zero)
{ {
return false; return false;
} }
continue; continue;
} }
if (i >= NonZerosCount || j < otherSparse.NonZerosCount && otherSparse._nonZeroIndices[j] < _nonZeroIndices[i]) if (i >= _storage.ValueCount || j < otherSparse._storage.ValueCount && otherSparse._storage.Indices[j] < _storage.Indices[i])
{ {
if (otherSparse._nonZeroValues[j++] != Complex.Zero) if (otherSparse._storage.Values[j++] != Complex.Zero)
{ {
return false; return false;
} }
continue; continue;
} }
if (!_nonZeroValues[i].AlmostEqual(otherSparse._nonZeroValues[j])) if (!_storage.Values[i].AlmostEqual(otherSparse._storage.Values[j]))
{ {
return false; return false;
} }
@ -1541,9 +1358,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// </remarks> /// </remarks>
public override IEnumerable<Tuple<int, Complex>> GetIndexedEnumerator() public override IEnumerable<Tuple<int, Complex>> GetIndexedEnumerator()
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
yield return new Tuple<int, Complex>(_nonZeroIndices[i], _nonZeroValues[i]); yield return new Tuple<int, Complex>(_storage.Indices[i], _storage.Values[i]);
} }
} }
@ -1556,9 +1373,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Complex[] ToArray() public override Complex[] ToArray()
{ {
var ret = new Complex[Count]; var ret = new Complex[Count];
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
ret[_nonZeroIndices[i]] = _nonZeroValues[i]; ret[_storage.Indices[i]] = _storage.Values[i];
} }
return ret; return ret;

11
src/Numerics/LinearAlgebra/Complex/Vector.cs

@ -31,6 +31,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
using Distributions; using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -41,15 +42,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the Vector class. /// Initializes a new instance of the Vector class.
/// Constructs a <strong>Vector</strong> with the given size.
/// </summary> /// </summary>
/// <param name="size"> protected Vector(VectorStorage<Complex> storage)
/// The size of the <strong>Vector</strong> to construct. : base(storage)
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one.
/// </exception>
protected Vector(int size) : base(size)
{ {
} }

75
src/Numerics/LinearAlgebra/Complex32/DenseMatrix.cs

@ -39,8 +39,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
[Serializable] [Serializable]
public class DenseMatrix : Matrix public class DenseMatrix : Matrix
{ {
readonly DenseColumnMajorMatrixStorage<Complex32> _storage;
/// <summary> /// <summary>
/// Number of rows. /// Number of rows.
/// </summary> /// </summary>
@ -59,15 +57,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// Gets the matrix's data. /// Gets the matrix's data.
/// </summary> /// </summary>
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
readonly Complex32[] _data; readonly Complex32[] _values;
internal DenseMatrix(DenseColumnMajorMatrixStorage<Complex32> storage) internal DenseMatrix(DenseColumnMajorMatrixStorage<Complex32> storage)
: base(storage) : base(storage)
{ {
_storage = storage; _rowCount = storage.RowCount;
_rowCount = _storage.RowCount; _columnCount = storage.ColumnCount;
_columnCount = _storage.ColumnCount; _values = storage.Data;
_data = _storage.Data;
} }
/// <summary> /// <summary>
@ -109,9 +106,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public DenseMatrix(int rows, int columns, Complex32 value) public DenseMatrix(int rows, int columns, Complex32 value)
: this(rows, columns) : this(rows, columns)
{ {
for (var i = 0; i < _data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
_data[i] = value; _values[i] = value;
} }
} }
@ -139,7 +136,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
for (var j = 0; j < _columnCount; j++) for (var j = 0; j < _columnCount; j++)
{ {
_data[(j * _rowCount) + i] = array[i, j]; _values[(j * _rowCount) + i] = array[i, j];
} }
} }
} }
@ -161,7 +158,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
public Complex32[] Data public Complex32[] Data
{ {
get { return _data; } get { return _values; }
} }
/// <summary> /// <summary>
@ -203,7 +200,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
var index = j * _rowCount; var index = j * _rowCount;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
ret._data[(i * _columnCount) + j] = _data[index + i]; ret._values[(i * _columnCount) + j] = _values[index + i];
} }
} }
@ -214,21 +211,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override Complex32 L1Norm() public override Complex32 L1Norm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override Complex32 FrobeniusNorm() public override Complex32 FrobeniusNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override Complex32 InfinityNorm() public override Complex32 InfinityNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _values);
} }
#region Static constructors for special matrices. #region Static constructors for special matrices.
@ -246,7 +243,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
var m = new DenseMatrix(order); var m = new DenseMatrix(order);
for (var i = 0; i < order; i++) for (var i = 0; i < order; i++)
{ {
m._data[(i * order) + i] = 1.0f; m._values[(i * order) + i] = 1.0f;
} }
return m; return m;
@ -268,7 +265,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult._values);
} }
} }
@ -292,14 +289,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0f, 0.0f,
denseResult.Data); denseResult.Values);
} }
} }
@ -323,14 +320,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0f, 0.0f,
denseResult._data); denseResult._values);
} }
} }
@ -354,14 +351,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0f, 0.0f,
denseResult._data); denseResult._values);
} }
} }
@ -385,14 +382,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0f, 0.0f,
denseResult.Data); denseResult.Values);
} }
} }
@ -416,14 +413,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0f, 0.0f,
denseResult._data); denseResult._values);
} }
} }
@ -441,7 +438,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(-1, _values, denseResult._values);
} }
} }
@ -461,7 +458,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -481,7 +478,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseDivideArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -502,7 +499,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
else else
{ {
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.AddArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -521,7 +518,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
else else
{ {
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.SubtractArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -537,7 +534,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
var index = j * _rowCount; var index = j * _rowCount;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
ret._data[(i * _columnCount) + j] = _data[index + i].Conjugate(); ret._values[(i * _columnCount) + j] = _values[index + i].Conjugate();
} }
} }
@ -559,7 +556,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
var sum = Complex32.Zero; var sum = Complex32.Zero;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
sum += _data[(i * _rowCount) + i]; sum += _values[(i * _rowCount) + i];
} }
return sum; return sum;

257
src/Numerics/LinearAlgebra/Complex32/DenseVector.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
using NumberTheory; using NumberTheory;
using Numerics; using Numerics;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -42,6 +43,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
[Serializable] [Serializable]
public class DenseVector : Vector public class DenseVector : Vector
{ {
/// <summary>
/// Number of elements
/// </summary>
readonly int _length;
/// <summary>
/// Gets the vector's data.
/// </summary>
readonly Complex32[] _values;
internal DenseVector(DenseVectorStorage<Complex32> storage)
: base(storage)
{
_length = storage.Length;
_values = storage.Data;
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class with a given size. /// Initializes a new instance of the <see cref="DenseVector"/> class with a given size.
/// </summary> /// </summary>
@ -51,9 +69,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public DenseVector(int size) : base(size) public DenseVector(int size)
: this(new DenseVectorStorage<Complex32>(size))
{ {
Data = new Complex32[size];
} }
/// <summary> /// <summary>
@ -69,11 +87,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public DenseVector(int size, Complex32 value) : this(size) public DenseVector(int size, Complex32 value)
: this(size)
{ {
for (var index = 0; index < Data.Length; index++) for (var index = 0; index < _values.Length; index++)
{ {
Data[index] = value; _values[index] = value;
} }
} }
@ -84,27 +103,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <param name="other"> /// <param name="other">
/// The vector to create the new vector from. /// The vector to create the new vector from.
/// </param> /// </param>
public DenseVector(Vector<Complex32> other) : this(other.Count) public DenseVector(Vector<Complex32> other)
: this(other.Count)
{ {
CommonParallel.For( other.Storage.CopyTo(Storage, skipClearing: true);
0,
Data.Length,
index => this[index] = other[index]);
}
/// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public DenseVector(DenseVector other) : this(other.Count)
{
CommonParallel.For(
0,
Data.Length,
index => Data[index] = other.Data[index]);
} }
/// <summary> /// <summary>
@ -113,20 +115,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector does not copy the array, but keeps a reference to it. Any /// <remarks>The vector does not copy the array, but keeps a reference to it. Any
/// changes to the vector will also change the array.</remarks> /// changes to the vector will also change the array.</remarks>
public DenseVector(Complex32[] array) : base(array.Length) public DenseVector(Complex32[] array)
: this(new DenseVectorStorage<Complex32>(array.Length, array))
{ {
Data = array;
} }
/// <summary> /// <summary>
/// Gets the vector's internal data. /// Gets the vector's data.
/// </summary> /// </summary>
/// <value>The vector's internal data.</value> /// <value>The vector's data.</value>
/// <remarks>Changing values in the array also changes the corresponding value in vector. Use with care.</remarks> public Complex32[] Values
internal Complex32[] Data
{ {
get; get { return _values; }
private set;
} }
/// <summary> /// <summary>
@ -137,14 +137,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <returns> /// <returns>
/// A reference to the internal date of the given vector. /// A reference to the internal date of the given vector.
/// </returns> /// </returns>
public static implicit operator Complex32[](DenseVector vector) public static explicit operator Complex32[](DenseVector vector)
{ {
if (vector == null) if (vector == null)
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
return vector.Data; return vector.Values;
} }
/// <summary> /// <summary>
@ -170,10 +170,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <returns>This vector as a column matrix.</returns> /// <returns>This vector as a column matrix.</returns>
public override Matrix<Complex32> ToColumnMatrix() public override Matrix<Complex32> ToColumnMatrix()
{ {
var matrix = new DenseMatrix(Count, 1); var matrix = new DenseMatrix(_length, 1);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(i, 0, Data[i]); matrix.At(i, 0, _values[i]);
} }
return matrix; return matrix;
@ -185,33 +185,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <returns>This vector as a row matrix.</returns> /// <returns>This vector as a row matrix.</returns>
public override Matrix<Complex32> ToRowMatrix() public override Matrix<Complex32> ToRowMatrix()
{ {
var matrix = new DenseMatrix(1, Count); var matrix = new DenseMatrix(1, _length);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(0, i, Data[i]); matrix.At(0, i, _values[i]);
} }
return matrix; return matrix;
} }
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
/// <exception cref="IndexOutOfRangeException">If <paramref name="index"/> is negative or
/// greater than the size of the vector.</exception>
public override Complex32 this[int index]
{
get
{
return Data[index];
}
set
{
Data[index] = value;
}
}
/// <summary> /// <summary>
/// Creates a matrix with the given dimensions using the same storage type /// Creates a matrix with the given dimensions using the same storage type
/// as this vector. /// as this vector.
@ -245,49 +227,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
return new DenseVector(size); return new DenseVector(size);
} }
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<Complex32> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as DenseVector;
if (otherVector == null)
{
CommonParallel.For(
0,
Data.Length,
index => target[index] = Data[index]);
}
else
{
Array.Copy(Data, 0, otherVector.Data, 0, Data.Length);
}
}
/// <summary> /// <summary>
/// Adds a scalar to each element of the vector and stores the result in the result vector. /// Adds a scalar to each element of the vector and stores the result in the result vector.
/// </summary> /// </summary>
@ -304,8 +243,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] + scalar); index => dense._values[index] = _values[index] + scalar);
} }
} }
@ -320,7 +259,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, Complex32.One, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, Complex32.One, odense.Values, rdense.Values);
} }
else else
{ {
@ -389,8 +328,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] - scalar); index => dense._values[index] = _values[index] - scalar);
} }
} }
@ -405,7 +344,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, -1.0f, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, -1.0f, odense.Values, rdense.Values);
} }
else else
{ {
@ -464,11 +403,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<Complex32> Negate() public override Vector<Complex32> Negate()
{ {
var result = new DenseVector(Count); var result = new DenseVector(_length);
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => result[index] = -Data[index]); index => result[index] = -_values[index]);
return result; return result;
} }
@ -488,7 +427,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, Data, denseResult.Data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult.Values);
} }
} }
@ -502,7 +441,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
var denseVector = other as DenseVector; var denseVector = other as DenseVector;
return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(Data, denseVector.Data); return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(_values, denseVector.Values);
} }
/// <summary> /// <summary>
@ -564,7 +503,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide");
} }
return Control.LinearAlgebraProvider.DotProduct(leftSide.Data, rightSide.Data); return Control.LinearAlgebraProvider.DotProduct(leftSide.Values, rightSide.Values);
} }
/// <summary> /// <summary>
@ -591,10 +530,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
var index = 0; var index = 0;
var min = Data[index].Magnitude; var min = _values[index].Magnitude;
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Data[i].Magnitude; var test = _values[i].Magnitude;
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -611,7 +550,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <returns>The value of the absolute minimum element.</returns> /// <returns>The value of the absolute minimum element.</returns>
public override Complex32 AbsoluteMinimum() public override Complex32 AbsoluteMinimum()
{ {
return Data[AbsoluteMinimumIndex()].Magnitude; return _values[AbsoluteMinimumIndex()].Magnitude;
} }
/// <summary> /// <summary>
@ -620,7 +559,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <returns>The value of the absolute maximum element.</returns> /// <returns>The value of the absolute maximum element.</returns>
public override Complex32 AbsoluteMaximum() public override Complex32 AbsoluteMaximum()
{ {
return Data[AbsoluteMaximumIndex()].Magnitude; return _values[AbsoluteMaximumIndex()].Magnitude;
} }
/// <summary> /// <summary>
@ -630,10 +569,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override int AbsoluteMaximumIndex() public override int AbsoluteMaximumIndex()
{ {
var index = 0; var index = 0;
var max = Data[index].Magnitude; var max = _values[index].Magnitude;
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Data[i].Magnitude; var test = _values[i].Magnitude;
if (test > max) if (test > max)
{ {
index = i; index = i;
@ -657,7 +596,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception> /// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
public override Vector<Complex32> SubVector(int index, int length) public override Vector<Complex32> SubVector(int index, int length)
{ {
if (index < 0 || index >= Count) if (index < 0 || index >= _length)
{ {
throw new ArgumentOutOfRangeException("index"); throw new ArgumentOutOfRangeException("index");
} }
@ -667,7 +606,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
if (index + length > Count) if (index + length > _length)
{ {
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
@ -676,8 +615,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
CommonParallel.For( CommonParallel.For(
index, index,
index + length, index + length,
i => result.Data[i - index] = Data[i]); i => result._values[i - index] = _values[i]);
return result; return result;
} }
@ -694,7 +633,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
throw new ArgumentNullException("values"); throw new ArgumentNullException("values");
} }
if (values.Length != Count) if (values.Length != _length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values");
} }
@ -702,7 +641,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
CommonParallel.For( CommonParallel.For(
0, 0,
values.Length, values.Length,
i => Data[i] = values[i]); i => _values[i] = values[i]);
} }
/// <summary> /// <summary>
@ -713,9 +652,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
var sum = Complex32.Zero; var sum = Complex32.Zero;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Data[i]; sum += _values[i];
} }
return sum; return sum;
@ -729,9 +668,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
var sum = Complex32.Zero; var sum = Complex32.Zero;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Data[i].Magnitude; sum += _values[i].Magnitude;
} }
return sum; return sum;
@ -753,8 +692,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] * other[index]); index => dense._values[index] = _values[index] * other[index]);
} }
} }
@ -775,8 +714,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] / other[index]); index => dense._values[index] = _values[index] / other[index]);
} }
} }
@ -808,7 +747,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
for (var j = 0; j < v.Count; j++) for (var j = 0; j < v.Count; j++)
{ {
matrix.At(i, j, u.Data[i] * v.Data[j]); matrix.At(i, j, u._values[i] * v._values[j]);
} }
}); });
return matrix; return matrix;
@ -832,9 +771,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
var v = (DenseVector)CreateVector(length); var v = (DenseVector)CreateVector(length);
for (var index = 0; index < v.Data.Length; index++) for (var index = 0; index < v._values.Length; index++)
{ {
v.Data[index] = new Complex32((float)randomDistribution.Sample(), (float)randomDistribution.Sample()); v._values[index] = new Complex32((float)randomDistribution.Sample(), (float)randomDistribution.Sample());
} }
return v; return v;
@ -858,9 +797,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
var v = (DenseVector)CreateVector(length); var v = (DenseVector)CreateVector(length);
for (var index = 0; index < v.Data.Length; index++) for (var index = 0; index < v._values.Length; index++)
{ {
v.Data[index] = new Complex32(randomDistribution.Sample(), randomDistribution.Sample()); v._values[index] = new Complex32(randomDistribution.Sample(), randomDistribution.Sample());
} }
return v; return v;
@ -898,19 +837,19 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
if (2.0 == p) if (2.0 == p)
{ {
return Data.Aggregate(Complex32.Zero, SpecialFunctions.Hypotenuse).Magnitude; return _values.Aggregate(Complex32.Zero, SpecialFunctions.Hypotenuse).Magnitude;
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(Data, (i, v) => v.Magnitude, Math.Max, 0f); return CommonParallel.Aggregate(_values, (i, v) => v.Magnitude, Math.Max, 0f);
} }
var sum = 0.0; var sum = 0.0;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Math.Pow(Data[i].Magnitude, p); sum += Math.Pow(_values[i].Magnitude, p);
} }
return (float)Math.Pow(sum, 1.0 / p); return (float)Math.Pow(sum, 1.0 / p);
@ -1075,14 +1014,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
#endregion #endregion
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
}
/// <summary> /// <summary>
/// Conjugates vector and save result to <paramref name="target"/> /// Conjugates vector and save result to <paramref name="target"/>
/// </summary> /// </summary>
@ -1099,25 +1030,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Count, _length,
index => denseTarget.Data[index] = Data[index].Conjugate()); index => denseTarget._values[index] = _values[index].Conjugate());
} }
} }
/// <summary>Gets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
internal protected override Complex32 At(int index)
{
return Data[index];
}
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <param name="value">The value to set.</param>
internal protected override void At(int index, Complex32 value)
{
Data[index] = value;
}
} }
} }

4
src/Numerics/LinearAlgebra/Complex32/DiagonalMatrix.cs

@ -378,12 +378,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
return; return;
} }
if (_data.Length != denseSource.Data.Length) if (_data.Length != denseSource.Values.Length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source");
} }
Array.Copy(denseSource.Data, _data, denseSource.Data.Length); Array.Copy(denseSource.Values, _data, denseSource.Values.Length);
} }
/// <summary> /// <summary>

4
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseCholesky.cs

@ -169,11 +169,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); CommonParallel.For(0, dinput.Values.Length, index => dresult.Values[index] = dinput.Values[index]);
// Cholesky solve by overwriting result. // Cholesky solve by overwriting result.
var dfactor = (DenseMatrix)CholeskyFactor; var dfactor = (DenseMatrix)CholeskyFactor;
Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Data, 1); Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Values, 1);
} }
} }
} }

2
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseEvd.cs

@ -108,7 +108,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
var matrixH = matrix.ToArray(); var matrixH = matrix.ToArray();
NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Data, matrixH, order); NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Data, matrixH, order);
NonsymmetricReduceHessenberToRealSchur(((LinearAlgebra.Complex.DenseVector)VectorEv).Data, ((DenseMatrix)MatrixEv).Data, matrixH, order); NonsymmetricReduceHessenberToRealSchur(((LinearAlgebra.Complex.DenseVector)VectorEv).Values, ((DenseMatrix)MatrixEv).Data, matrixH, order);
} }
for (var i = 0; i < VectorEv.Count; i++) for (var i = 0; i < VectorEv.Count; i++)

2
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseGramSchmidt.cs

@ -217,7 +217,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment.");
} }
_provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Data, 1, dresult.Data); _provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Values, 1, dresult.Values);
} }
} }
} }

4
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseLU.cs

@ -170,11 +170,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); CommonParallel.For(0, dinput.Values.Length, index => dresult.Values[index] = dinput.Values[index]);
// LU solve by overwriting result. // LU solve by overwriting result.
var dfactors = (DenseMatrix)Factors; var dfactors = (DenseMatrix)Factors;
Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Values);
} }
/// <summary> /// <summary>

2
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs

@ -188,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
} }
} }
} }

6
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseSvd.cs

@ -70,7 +70,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
VectorS = new DenseVector(nm); VectorS = new DenseVector(nm);
MatrixU = new DenseMatrix(matrix.RowCount); MatrixU = new DenseMatrix(matrix.RowCount);
MatrixVT = new DenseMatrix(matrix.ColumnCount); MatrixVT = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data);
} }
/// <summary> /// <summary>
@ -126,7 +126,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data);
} }
/// <summary> /// <summary>
@ -176,7 +176,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Values, 1, dresult.Values);
} }
} }
} }

1
src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs

@ -98,6 +98,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// The number of columns. /// The number of columns.
/// </param> /// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param> /// <param name="value">The value which we assign to each element of the matrix.</param>
[Obsolete("Use a dense matrix instead.")]
public SparseMatrix(int rows, int columns, Complex32 value) public SparseMatrix(int rows, int columns, Complex32 value)
: this(rows, columns) : this(rows, columns)
{ {

489
src/Numerics/LinearAlgebra/Complex32/SparseVector.cs

@ -37,6 +37,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
using NumberTheory; using NumberTheory;
using Numerics; using Numerics;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -46,24 +47,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
[Serializable] [Serializable]
public class SparseVector : Vector public class SparseVector : Vector
{ {
/// <summary> readonly SparseVectorStorage<Complex32> _storage;
/// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored.
/// </summary>
private Complex32[] _nonZeroValues = new Complex32[0];
/// <summary>
/// The indices of the non-zero entries.
/// </summary>
private int[] _nonZeroIndices = new int[0];
/// <summary> internal SparseVector(SparseVectorStorage<Complex32> storage)
/// Gets the number of non zero elements in the vector. : base(storage)
/// </summary>
/// <value>The number of non zero elements.</value>
public int NonZerosCount
{ {
get; _storage = storage;
private set;
} }
#region Constructors #region Constructors
@ -77,7 +66,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size) : base(size) public SparseVector(int size)
: this(new SparseVectorStorage<Complex32>(size))
{ {
} }
@ -94,58 +84,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size, Complex32 value) : this(size) [Obsolete("Use a dense vector instead.")]
public SparseVector(int size, Complex32 value)
: this(new SparseVectorStorage<Complex32>(size))
{ {
if (value == Complex32.Zero) if (value == Complex32.Zero)
{ {
// Skip adding values
return; return;
} }
// We already know that this vector is "full", let's allocate all needed memory var valueCount = _storage.ValueCount = size;
_nonZeroValues = new Complex32[size]; var indices = _storage.Indices = new int[valueCount];
_nonZeroIndices = new int[size]; var values = _storage.Values = new Complex32[valueCount];
NonZerosCount = size;
CommonParallel.For( for (int i = 0; i < values.Length; i++)
0,
Count,
index =>
{
_nonZeroValues[index] = value;
_nonZeroIndices[index] = index;
});
}
/// <summary>
/// Initializes a new instance of the <see cref="SparseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public SparseVector(Vector<Complex32> other) : this(other.Count)
{
var vector = other as SparseVector;
if (vector == null)
{ {
for (var i = 0; i < other.Count; i++) values[i] = value;
{ indices[i] = i;
this[i] = other.At(i);
}
}
else
{
_nonZeroValues = new Complex32[vector.NonZerosCount];
_nonZeroIndices = new int[vector.NonZerosCount];
NonZerosCount = vector.NonZerosCount;
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
if (vector.NonZerosCount != 0)
{
CommonParallel.For(0, vector.NonZerosCount, index => _nonZeroValues[index] = vector._nonZeroValues[index]);
Buffer.BlockCopy(vector._nonZeroIndices, 0, _nonZeroIndices, 0, vector.NonZerosCount * Constants.SizeOfInt);
}
} }
} }
@ -156,18 +111,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <param name="other"> /// <param name="other">
/// The vector to create the new vector from. /// The vector to create the new vector from.
/// </param> /// </param>
public SparseVector(SparseVector other) : this(other.Count) public SparseVector(Vector<Complex32> other)
: this(new SparseVectorStorage<Complex32>(other.Count))
{ {
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value other.Storage.CopyTo(Storage, skipClearing: true);
_nonZeroValues = new Complex32[other.NonZerosCount];
_nonZeroIndices = new int[other.NonZerosCount];
NonZerosCount = other.NonZerosCount;
if (other.NonZerosCount != 0)
{
CommonParallel.For(0, other.NonZerosCount, index => _nonZeroValues[index] = other._nonZeroValues[index]);
Buffer.BlockCopy(other._nonZeroIndices, 0, _nonZeroIndices, 0, other.NonZerosCount * Constants.SizeOfInt);
}
} }
/// <summary> /// <summary>
@ -175,11 +122,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// </summary> /// </summary>
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks> /// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks>
public SparseVector(IList<Complex32> array) : this(array.Count) public SparseVector(IList<Complex32> array)
: this(new SparseVectorStorage<Complex32>(array.Count))
{ {
for (var i = 0; i < array.Count; i++) for (var i = 0; i < array.Count; i++)
{ {
this[i] = array[i]; Storage.At(i, array[i]);
} }
} }
@ -192,9 +140,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Matrix<Complex32> ToColumnMatrix() public override Matrix<Complex32> ToColumnMatrix()
{ {
var matrix = new SparseMatrix(Count, 1); var matrix = new SparseMatrix(Count, 1);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); matrix.At(_storage.Indices[i], 0, _storage.Values[i]);
} }
return matrix; return matrix;
@ -207,44 +155,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Matrix<Complex32> ToRowMatrix() public override Matrix<Complex32> ToRowMatrix()
{ {
var matrix = new SparseMatrix(1, Count); var matrix = new SparseMatrix(1, Count);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); matrix.At(0, _storage.Indices[i], _storage.Values[i]);
} }
return matrix; return matrix;
} }
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
/// <exception cref="IndexOutOfRangeException">If <paramref name="index"/> is negative or
/// greater than the size of the vector.</exception>
public override Complex32 this[int index]
{
get
{
// If index is out of bounds
if ((index < 0) || (index >= Count))
{
throw new IndexOutOfRangeException();
}
return At(index);
}
set
{
// If index is out of bounds
if ((index < 0) || (index >= Count))
{
throw new IndexOutOfRangeException();
}
At(index, value);
}
}
/// <summary> /// <summary>
/// Creates a matrix with the given dimensions using the same storage type /// Creates a matrix with the given dimensions using the same storage type
/// as this vector. /// as this vector.
@ -278,68 +196,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
return new SparseVector(size); return new SparseVector(size);
} }
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
NonZerosCount = 0;
}
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<Complex32> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as SparseVector;
if (otherVector == null)
{
target.Clear();
for (var index = 0; index < NonZerosCount; index++)
{
target.At(_nonZeroIndices[index], _nonZeroValues[index]);
}
}
else
{
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
otherVector._nonZeroValues = new Complex32[NonZerosCount];
otherVector._nonZeroIndices = new int[NonZerosCount];
otherVector.NonZerosCount = NonZerosCount;
if (NonZerosCount != 0)
{
Array.Copy(_nonZeroValues, 0, otherVector._nonZeroValues, 0, NonZerosCount);
Buffer.BlockCopy(_nonZeroIndices, 0, otherVector._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt);
}
}
}
/// <summary> /// <summary>
/// Conjugates vector and save result to <paramref name="target"/> /// Conjugates vector and save result to <paramref name="target"/>
/// </summary> /// </summary>
@ -371,14 +227,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
else else
{ {
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value // Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
otherVector._nonZeroValues = new Complex32[NonZerosCount]; otherVector._storage.Values = new Complex32[_storage.ValueCount];
otherVector._nonZeroIndices = new int[NonZerosCount]; otherVector._storage.Indices = new int[_storage.ValueCount];
otherVector.NonZerosCount = NonZerosCount; otherVector._storage.ValueCount = _storage.ValueCount;
if (NonZerosCount != 0) if (_storage.ValueCount != 0)
{ {
CommonParallel.For(0, NonZerosCount, index => otherVector._nonZeroValues[index] = _nonZeroValues[index].Conjugate()); CommonParallel.For(0, _storage.ValueCount, index => otherVector._storage.Values[index] = _storage.Values[index].Conjugate());
Buffer.BlockCopy(_nonZeroIndices, 0, otherVector._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); Buffer.BlockCopy(_storage.Indices, 0, otherVector._storage.Indices, 0, _storage.ValueCount * Constants.SizeOfInt);
} }
} }
} }
@ -420,15 +276,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
//populate the non zero values from this //populate the non zero values from this
for (int j = 0; j < NonZerosCount; j++) for (int j = 0; j < _storage.ValueCount; j++)
{ {
vnonZeroValues[_nonZeroIndices[j]] = _nonZeroValues[j] + scalar; vnonZeroValues[_storage.Indices[j]] = _storage.Values[j] + scalar;
} }
//assign this vectors arrary to the new arrays. //assign this vectors arrary to the new arrays.
_nonZeroValues = vnonZeroValues; _storage.Values = vnonZeroValues;
_nonZeroIndices = vnonZeroIndices; _storage.Indices = vnonZeroIndices;
NonZerosCount = Count; _storage.ValueCount = Count;
} }
else else
{ {
@ -469,22 +325,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] += otherSparse._nonZeroValues[j++]; _storage.Values[i++] += otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != Complex32.Zero) if (otherValue != Complex32.Zero)
{ {
InsertAtUnchecked(i++, otherSparse._nonZeroIndices[j], otherValue); InsertAtUnchecked(i++, otherSparse._storage.Indices[j], otherValue);
} }
j++; j++;
} }
@ -494,25 +350,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] + otherSparse.At(next)); result.At(next, _storage.Values[i] + otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) + otherSparse._nonZeroValues[j]); result.At(next, At(next) + otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -615,22 +471,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] -= otherSparse._nonZeroValues[j++]; _storage.Values[i++] -= otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != Complex32.Zero) if (otherValue != Complex32.Zero)
{ {
InsertAtUnchecked(i++, otherSparse._nonZeroIndices[j], -otherValue); InsertAtUnchecked(i++, otherSparse._storage.Indices[j], -otherValue);
} }
j++; j++;
} }
@ -640,25 +496,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] - otherSparse.At(next)); result.At(next, _storage.Values[i] - otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) - otherSparse._nonZeroValues[j]); result.At(next, At(next) - otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -717,23 +573,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<Complex32> Negate() public override Vector<Complex32> Negate()
{ {
var result = new SparseVector(Count) var result = new SparseVectorStorage<Complex32>(Count);
{ var valueCount = result.ValueCount = _storage.ValueCount;
_nonZeroValues = new Complex32[NonZerosCount], var indices = result.Indices = new int[valueCount];
_nonZeroIndices = new int[NonZerosCount], var values = result.Values = new Complex32[valueCount];
NonZerosCount = NonZerosCount
};
if (NonZerosCount != 0) if (valueCount != 0)
{ {
CommonParallel.For( CommonParallel.For(0, valueCount, index => values[index] = -_storage.Values[index]);
0, Buffer.BlockCopy(_storage.Indices, 0, indices, 0, valueCount * Constants.SizeOfInt);
NonZerosCount,
index => result._nonZeroValues[index] = -_nonZeroValues[index]);
Buffer.BlockCopy(_nonZeroIndices, 0, result._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt);
} }
return result; return new SparseVector(result);
} }
/// <summary> /// <summary>
@ -754,7 +605,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
var copy = new SparseVector(this); var copy = new SparseVector(this);
Control.LinearAlgebraProvider.ScaleArray(scalar, copy._nonZeroValues, copy._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, copy._storage.Values, copy._storage.Values);
return copy; return copy;
} }
@ -789,23 +640,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
if (sparseResult == null) if (sparseResult == null)
{ {
result.Clear(); result.Clear();
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); result.At(_storage.Indices[index], scalar * _storage.Values[index]);
} }
} }
else else
{ {
if (!ReferenceEquals(this, result)) if (!ReferenceEquals(this, result))
{ {
sparseResult.NonZerosCount = NonZerosCount; sparseResult._storage.ValueCount = _storage.ValueCount;
sparseResult._nonZeroIndices = new int[NonZerosCount]; sparseResult._storage.Indices = new int[_storage.ValueCount];
Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); Buffer.BlockCopy(_storage.Indices, 0, sparseResult._storage.Indices, 0, _storage.ValueCount * Constants.SizeOfInt);
sparseResult._nonZeroValues = new Complex32[NonZerosCount]; sparseResult._storage.Values = new Complex32[_storage.ValueCount];
Array.Copy(_nonZeroValues, sparseResult._nonZeroValues, NonZerosCount); Array.Copy(_storage.Values, sparseResult._storage.Values, _storage.ValueCount);
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues, sparseResult._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._storage.Values, sparseResult._storage.Values);
} }
} }
@ -824,16 +675,16 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * _nonZeroValues[i]; result += _storage.Values[i] * _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); result += _storage.Values[i] * other.At(_storage.Indices[i]);
} }
} }
@ -925,17 +776,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <returns>The index of absolute minimum element.</returns> /// <returns>The index of absolute minimum element.</returns>
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
// No non-zero elements. Return 0 // No non-zero elements. Return 0
return 0; return 0;
} }
var index = 0; var index = 0;
var min = _nonZeroValues[index].Magnitude; var min = _storage.Values[index].Magnitude;
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
var test = _nonZeroValues[i].Magnitude; var test = _storage.Values[i].Magnitude;
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -943,7 +794,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -1014,9 +865,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Complex32 Sum() public override Complex32 Sum()
{ {
var result = Complex32.Zero; var result = Complex32.Zero;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i]; result += _storage.Values[i];
} }
return result; return result;
@ -1029,9 +880,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Complex32 SumMagnitudes() public override Complex32 SumMagnitudes()
{ {
var result = 0.0f; var result = 0.0f;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i].Magnitude; result += _storage.Values[i].Magnitude;
} }
return result; return result;
@ -1046,17 +897,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] *= _nonZeroValues[i]; _storage.Values[i] *= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, other.At(index) * _nonZeroValues[i]); result.At(index, other.At(index) * _storage.Values[i]);
} }
} }
} }
@ -1070,17 +921,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] /= _nonZeroValues[i]; _storage.Values[i] /= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, _nonZeroValues[i] / other.At(index)); result.At(index, _storage.Values[i] / other.At(index));
} }
} }
} }
@ -1106,13 +957,13 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
var matrix = new SparseMatrix(u.Count, v.Count); var matrix = new SparseMatrix(u.Count, v.Count);
for (var i = 0; i < u.NonZerosCount; i++) for (var i = 0; i < u._storage.ValueCount; i++)
{ {
for (var j = 0; j < v.NonZerosCount; j++) for (var j = 0; j < v._storage.ValueCount; j++)
{ {
if (u._nonZeroIndices[i] == v._nonZeroIndices[j]) if (u._storage.Indices[i] == v._storage.Indices[j])
{ {
matrix.At(i, j, u._nonZeroValues[i] * v._nonZeroValues[j]); matrix.At(i, j, u._storage.Values[i] * v._storage.Values[j]);
} }
} }
} }
@ -1148,25 +999,25 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
throw new ArgumentOutOfRangeException("p"); throw new ArgumentOutOfRangeException("p");
} }
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return Complex32.Zero; return Complex32.Zero;
} }
if (2.0 == p) if (2.0 == p)
{ {
return _nonZeroValues.Aggregate(Complex32.Zero, SpecialFunctions.Hypotenuse).Magnitude; return _storage.Values.Aggregate(Complex32.Zero, SpecialFunctions.Hypotenuse).Magnitude;
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(0, NonZerosCount, i => _nonZeroValues[i].Magnitude, Math.Max, 0f); return CommonParallel.Aggregate(0, _storage.ValueCount, i => _storage.Values[i].Magnitude, Math.Max, 0f);
} }
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
sum += Math.Pow(_nonZeroValues[index].Magnitude, p); sum += Math.Pow(_storage.Values[index].Magnitude, p);
} }
return (float)Math.Pow(sum, 1.0 / p); return (float)Math.Pow(sum, 1.0 / p);
@ -1332,97 +1183,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
#endregion #endregion
/// <summary>
/// Gets the value at the given index.
/// </summary>
/// <param name="index">Value real index in array</param>
/// <returns>The value at the given index.</returns>
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;
}
/// <summary>
/// Delete, Add or Update the value in NonZeroValues and NonZeroIndices
/// </summary>
/// <param name="index">Value real index in array</param>
/// <param name="value">The value to set.</param>
/// <remarks>This method assume that index is between 0 and Array Size</remarks>
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);
if (itemIndex >= 0)
{
// Item already exist at itemIndex
if (value == Complex32.Zero)
{
RemoveAtUnchecked(itemIndex);
}
else
{
_nonZeroValues[itemIndex] = value;
}
}
else
{
if (value != Complex32.Zero)
{
InsertAtUnchecked(~itemIndex, index, value);
}
}
}
private void InsertAtUnchecked(int itemIndex, int index, Complex32 value) private void InsertAtUnchecked(int itemIndex, int index, Complex32 value)
{ {
// Check if the storage needs to be increased // Check if the storage needs to be increased
if ((NonZerosCount == _nonZeroValues.Length) && (NonZerosCount < Count)) if ((_storage.ValueCount == _storage.Values.Length) && (_storage.ValueCount < Count))
{ {
// Value and Indices arrays are completely full so we increase the size // Value and Indices arrays are completely full so we increase the size
var size = Math.Min(_nonZeroValues.Length + GrowthSize(), Count); var size = Math.Min(_storage.Values.Length + GrowthSize(), Count);
Array.Resize(ref _nonZeroValues, size); Array.Resize(ref _storage.Values, size);
Array.Resize(ref _nonZeroIndices, size); Array.Resize(ref _storage.Indices, size);
} }
// Move all values (with a position larger than index) in the value array // Move all values (with a position larger than index) in the value array
// to the next position // to the next position
// Move all values (with a position larger than index) in the columIndices // Move all values (with a position larger than index) in the columIndices
// array to the next position // array to the next position
for (var i = NonZerosCount - 1; i > itemIndex - 1; i--) for (var i = _storage.ValueCount - 1; i > itemIndex - 1; i--)
{ {
_nonZeroValues[i + 1] = _nonZeroValues[i]; _storage.Values[i + 1] = _storage.Values[i];
_nonZeroIndices[i + 1] = _nonZeroIndices[i]; _storage.Indices[i + 1] = _storage.Indices[i];
} }
// Add the value and the column index // Add the value and the column index
_nonZeroValues[itemIndex] = value; _storage.Values[itemIndex] = value;
_nonZeroIndices[itemIndex] = index; _storage.Indices[itemIndex] = index;
// increase the number of non-zero numbers by one // increase the number of non-zero numbers by one
NonZerosCount += 1; _storage.ValueCount += 1;
}
private void RemoveAtUnchecked(int itemIndex)
{
// Value is zero. Let's delete it from Values and Indices array
for (var i = itemIndex + 1; i < NonZerosCount; i++)
{
_nonZeroValues[i - 1] = _nonZeroValues[i];
_nonZeroIndices[i - 1] = _nonZeroIndices[i];
}
NonZerosCount -= 1;
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((NonZerosCount > 1024) && (NonZerosCount < _nonZeroIndices.Length / 2))
{
Array.Resize(ref _nonZeroValues, NonZerosCount);
Array.Resize(ref _nonZeroIndices, NonZerosCount);
}
} }
/// <summary> /// <summary>
@ -1433,19 +1220,19 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
private int GrowthSize() private int GrowthSize()
{ {
int delta; int delta;
if (_nonZeroValues.Length > 1024) if (_storage.Values.Length > 1024)
{ {
delta = _nonZeroValues.Length / 4; delta = _storage.Values.Length / 4;
} }
else else
{ {
if (_nonZeroValues.Length > 256) if (_storage.Values.Length > 256)
{ {
delta = 512; delta = 512;
} }
else else
{ {
delta = _nonZeroValues.Length > 64 ? 128 : 32; delta = _storage.Values.Length > 64 ? 128 : 32;
} }
} }
@ -1458,7 +1245,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
if (Count > 20) if (Count > 20)
{ {
return String.Format("SparseVectorOfComplex32({0},{1},{2})", Count, NonZerosCount, GetHashCode()); return String.Format("SparseVectorOfComplex32({0},{1},{2})", Count, _storage.ValueCount, GetHashCode());
} }
return base.ToString(format, formatProvider); return base.ToString(format, formatProvider);
@ -1472,14 +1259,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
var hashNum = Math.Min(NonZerosCount, 20); var hashNum = Math.Min(_storage.ValueCount, 20);
long hash = 0; long hash = 0;
for (var i = 0; i < hashNum; i++) for (var i = 0; i < hashNum; i++)
{ {
#if PORTABLE #if PORTABLE
hash ^= Precision.DoubleToInt64Bits(this._nonZeroValues[i].GetHashCode()); hash ^= Precision.DoubleToInt64Bits(this._storage.Values[i].GetHashCode());
#else #else
hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= BitConverter.DoubleToInt64Bits(_storage.Values[i].GetHashCode());
#endif #endif
} }
@ -1523,27 +1310,27 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
if (_nonZeroValues[i++] != Complex32.Zero) if (_storage.Values[i++] != Complex32.Zero)
{ {
return false; return false;
} }
continue; continue;
} }
if (i >= NonZerosCount || j < otherSparse.NonZerosCount && otherSparse._nonZeroIndices[j] < _nonZeroIndices[i]) if (i >= _storage.ValueCount || j < otherSparse._storage.ValueCount && otherSparse._storage.Indices[j] < _storage.Indices[i])
{ {
if (otherSparse._nonZeroValues[j++] != Complex32.Zero) if (otherSparse._storage.Values[j++] != Complex32.Zero)
{ {
return false; return false;
} }
continue; continue;
} }
if (!_nonZeroValues[i].AlmostEqual(otherSparse._nonZeroValues[j])) if (!_storage.Values[i].AlmostEqual(otherSparse._storage.Values[j]))
{ {
return false; return false;
} }
@ -1571,9 +1358,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// </remarks> /// </remarks>
public override IEnumerable<Tuple<int, Complex32>> GetIndexedEnumerator() public override IEnumerable<Tuple<int, Complex32>> GetIndexedEnumerator()
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
yield return new Tuple<int, Complex32>(_nonZeroIndices[i], _nonZeroValues[i]); yield return new Tuple<int, Complex32>(_storage.Indices[i], _storage.Values[i]);
} }
} }
@ -1586,9 +1373,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Complex32[] ToArray() public override Complex32[] ToArray()
{ {
var ret = new Complex32[Count]; var ret = new Complex32[Count];
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
ret[_nonZeroIndices[i]] = _nonZeroValues[i]; ret[_storage.Indices[i]] = _storage.Values[i];
} }
return ret; return ret;

11
src/Numerics/LinearAlgebra/Complex32/Vector.cs

@ -30,6 +30,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
using Distributions; using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
using Complex32 = Numerics.Complex32; using Complex32 = Numerics.Complex32;
@ -41,15 +42,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the Vector class. /// Initializes a new instance of the Vector class.
/// Constructs a <strong>Vector</strong> with the given size.
/// </summary> /// </summary>
/// <param name="size"> protected Vector(VectorStorage<Complex32> storage)
/// The size of the <strong>Vector</strong> to construct. : base(storage)
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one.
/// </exception>
protected Vector(int size) : base(size)
{ {
} }

77
src/Numerics/LinearAlgebra/Double/DenseMatrix.cs

@ -39,8 +39,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
[Serializable] [Serializable]
public class DenseMatrix : Matrix public class DenseMatrix : Matrix
{ {
readonly DenseColumnMajorMatrixStorage<double> _storage;
/// <summary> /// <summary>
/// Number of rows. /// Number of rows.
/// </summary> /// </summary>
@ -59,15 +57,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// Gets the matrix's data. /// Gets the matrix's data.
/// </summary> /// </summary>
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
readonly double[] _data; readonly double[] _values;
internal DenseMatrix(DenseColumnMajorMatrixStorage<double> storage) internal DenseMatrix(DenseColumnMajorMatrixStorage<double> storage)
: base(storage) : base(storage)
{ {
_storage = storage; _rowCount = storage.RowCount;
_rowCount = _storage.RowCount; _columnCount = storage.ColumnCount;
_columnCount = _storage.ColumnCount; _values = storage.Data;
_data = _storage.Data;
} }
/// <summary> /// <summary>
@ -109,9 +106,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public DenseMatrix(int rows, int columns, double value) public DenseMatrix(int rows, int columns, double value)
: this(rows, columns) : this(rows, columns)
{ {
for (var i = 0; i < _data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
_data[i] = value; _values[i] = value;
} }
} }
@ -139,7 +136,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
for (var j = 0; j < _columnCount; j++) for (var j = 0; j < _columnCount; j++)
{ {
_data[(j * _rowCount) + i] = array[i, j]; _values[(j * _rowCount) + i] = array[i, j];
} }
} }
} }
@ -161,7 +158,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
public double[] Data public double[] Data
{ {
get { return _data; } get { return _values; }
} }
/// <summary> /// <summary>
@ -203,7 +200,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
var index = j * _rowCount; var index = j * _rowCount;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
ret._data[(i * _columnCount) + j] = _data[index + i]; ret._values[(i * _columnCount) + j] = _values[index + i];
} }
} }
@ -214,21 +211,21 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override double L1Norm() public override double L1Norm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override double FrobeniusNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override double InfinityNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _values);
} }
#region Static constructors for special matrices. #region Static constructors for special matrices.
@ -246,7 +243,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
var m = new DenseMatrix(order); var m = new DenseMatrix(order);
for (var i = 0; i < order; i++) for (var i = 0; i < order; i++)
{ {
m._data[(i * order) + i] = 1.0; m._values[(i * order) + i] = 1.0;
} }
return m; return m;
@ -271,7 +268,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.AddArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -290,7 +287,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.SubtractArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -308,7 +305,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult._values);
} }
} }
@ -332,14 +329,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0, 0.0,
denseResult.Data); denseResult.Values);
} }
} }
@ -363,14 +360,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0, 0.0,
denseResult._data); denseResult._values);
} }
} }
@ -394,14 +391,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0, 0.0,
denseResult._data); denseResult._values);
} }
} }
@ -425,14 +422,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0, 0.0,
denseResult.Data); denseResult.Values);
} }
} }
@ -456,14 +453,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0, 1.0,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0, 0.0,
denseResult._data); denseResult._values);
} }
} }
@ -481,7 +478,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(-1, _values, denseResult._values);
} }
} }
@ -501,7 +498,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -521,7 +518,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseDivideArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -547,8 +544,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
CommonParallel.For( CommonParallel.For(
0, 0,
_data.Length, _values.Length,
index => denseResult._data[index] %= divisor); index => denseResult._values[index] %= divisor);
} }
} }
@ -567,7 +564,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
var sum = 0.0; var sum = 0.0;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
sum += _data[(i * _rowCount) + i]; sum += _values[(i * _rowCount) + i];
} }
return sum; return sum;

268
src/Numerics/LinearAlgebra/Double/DenseVector.cs

@ -33,6 +33,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
using Generic; using Generic;
using NumberTheory; using NumberTheory;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -41,6 +42,23 @@ namespace MathNet.Numerics.LinearAlgebra.Double
[Serializable] [Serializable]
public class DenseVector : Vector public class DenseVector : Vector
{ {
/// <summary>
/// Number of elements
/// </summary>
readonly int _length;
/// <summary>
/// Gets the vector's data.
/// </summary>
readonly double[] _values;
internal DenseVector(DenseVectorStorage<double> storage)
: base(storage)
{
_length = storage.Length;
_values = storage.Data;
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class with a given size. /// Initializes a new instance of the <see cref="DenseVector"/> class with a given size.
/// </summary> /// </summary>
@ -51,9 +69,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public DenseVector(int size) public DenseVector(int size)
: base(size) : this(new DenseVectorStorage<double>(size))
{ {
Data = new double[size];
} }
/// <summary> /// <summary>
@ -72,9 +89,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public DenseVector(int size, double value) public DenseVector(int size, double value)
: this(size) : this(size)
{ {
for (var index = 0; index < Data.Length; index++) for (var index = 0; index < _values.Length; index++)
{ {
Data[index] = value; _values[index] = value;
} }
} }
@ -88,31 +105,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public DenseVector(Vector<double> other) public DenseVector(Vector<double> other)
: this(other.Count) : this(other.Count)
{ {
var vector = other as DenseVector; other.Storage.CopyTo(Storage, skipClearing: true);
if (vector == null)
{
CommonParallel.For(
0,
Data.Length,
index => this[index] = other[index]);
}
else
{
Buffer.BlockCopy(vector.Data, 0, Data, 0, Data.Length * Constants.SizeOfDouble);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public DenseVector(DenseVector other)
: this(other.Count)
{
Buffer.BlockCopy(other.Data, 0, Data, 0, Data.Length * Constants.SizeOfDouble);
} }
/// <summary> /// <summary>
@ -121,20 +114,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector does not copy the array, but keeps a reference to it. Any /// <remarks>The vector does not copy the array, but keeps a reference to it. Any
/// changes to the vector will also change the array.</remarks> /// changes to the vector will also change the array.</remarks>
public DenseVector(double[] array) : base(array.Length) public DenseVector(double[] array)
: this(new DenseVectorStorage<double>(array.Length, array))
{ {
Data = array;
} }
/// <summary> /// <summary>
/// Gets the vector's internal data. /// Gets the vector's data.
/// </summary> /// </summary>
/// <value>The vector's internal data.</value> /// <value>The vector's data.</value>
/// <remarks>Changing values in the array also changes the corresponding value in vector. Use with care.</remarks> public double[] Values
internal double[] Data
{ {
get; get { return _values; }
private set;
} }
/// <summary> /// <summary>
@ -145,14 +136,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns> /// <returns>
/// A reference to the internal date of the given vector. /// A reference to the internal date of the given vector.
/// </returns> /// </returns>
public static implicit operator double[](DenseVector vector) public static explicit operator double[](DenseVector vector)
{ {
if (vector == null) if (vector == null)
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
return vector.Data; return vector.Values;
} }
/// <summary> /// <summary>
@ -178,10 +169,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>This vector as a column matrix.</returns> /// <returns>This vector as a column matrix.</returns>
public override Matrix<double> ToColumnMatrix() public override Matrix<double> ToColumnMatrix()
{ {
var matrix = new DenseMatrix(Count, 1); var matrix = new DenseMatrix(_length, 1);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(i, 0, Data[i]); matrix.At(i, 0, _values[i]);
} }
return matrix; return matrix;
@ -193,33 +184,15 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>This vector as a row matrix.</returns> /// <returns>This vector as a row matrix.</returns>
public override Matrix<double> ToRowMatrix() public override Matrix<double> ToRowMatrix()
{ {
var matrix = new DenseMatrix(1, Count); var matrix = new DenseMatrix(1, _length);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(0, i, Data[i]); matrix.At(0, i, _values[i]);
} }
return matrix; return matrix;
} }
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
/// <exception cref="IndexOutOfRangeException">If <paramref name="index"/> is negative or
/// greater than the size of the vector.</exception>
public override double this[int index]
{
get
{
return Data[index];
}
set
{
Data[index] = value;
}
}
/// <summary> /// <summary>
/// Creates a matrix with the given dimensions using the same storage type /// Creates a matrix with the given dimensions using the same storage type
/// as this vector. /// as this vector.
@ -253,49 +226,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
return new DenseVector(size); return new DenseVector(size);
} }
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<double> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as DenseVector;
if (otherVector == null)
{
CommonParallel.For(
0,
Data.Length,
index => target[index] = Data[index]);
}
else
{
Buffer.BlockCopy(Data, 0, otherVector.Data, 0, Data.Length * Constants.SizeOfDouble);
}
}
/// <summary> /// <summary>
/// Adds a scalar to each element of the vector and stores the result in the result vector. /// Adds a scalar to each element of the vector and stores the result in the result vector.
/// </summary> /// </summary>
@ -312,8 +242,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] + scalar); index => dense._values[index] = _values[index] + scalar);
} }
} }
@ -328,7 +258,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, 1.0, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, 1.0, odense.Values, rdense.Values);
} }
else else
{ {
@ -397,8 +327,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] - scalar); index => dense._values[index] = _values[index] - scalar);
} }
} }
@ -413,7 +343,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, -1.0, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, -1.0, odense.Values, rdense.Values);
} }
else else
{ {
@ -472,11 +402,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<double> Negate() public override Vector<double> Negate()
{ {
var result = new DenseVector(Count); var result = new DenseVector(_length);
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => result[index] = -Data[index]); index => result[index] = -_values[index]);
return result; return result;
} }
@ -496,7 +426,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, Data, denseResult.Data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult.Values);
} }
} }
@ -510,7 +440,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
var denseVector = other as DenseVector; var denseVector = other as DenseVector;
return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(Data, denseVector.Data); return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(_values, denseVector.Values);
} }
/// <summary> /// <summary>
@ -572,7 +502,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide");
} }
return Control.LinearAlgebraProvider.DotProduct(leftSide.Data, rightSide.Data); return Control.LinearAlgebraProvider.DotProduct(leftSide.Values, rightSide.Values);
} }
/// <summary> /// <summary>
@ -602,16 +532,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double
var denseResult = result as DenseVector; var denseResult = result as DenseVector;
if (denseResult == null) if (denseResult == null)
{ {
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
result.At(index, Data[index] % divisor); result.At(index, _values[index] % divisor);
} }
} }
else else
{ {
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
denseResult.Data[index] = Data[index] % divisor; denseResult._values[index] = _values[index] % divisor;
} }
} }
} }
@ -640,10 +570,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
var index = 0; var index = 0;
var min = Math.Abs(Data[index]); var min = Math.Abs(_values[index]);
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Math.Abs(Data[i]); var test = Math.Abs(_values[i]);
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -660,7 +590,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>The value of the absolute minimum element.</returns> /// <returns>The value of the absolute minimum element.</returns>
public override double AbsoluteMinimum() public override double AbsoluteMinimum()
{ {
return Math.Abs(Data[AbsoluteMinimumIndex()]); return Math.Abs(_values[AbsoluteMinimumIndex()]);
} }
/// <summary> /// <summary>
@ -669,7 +599,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>The value of the absolute maximum element.</returns> /// <returns>The value of the absolute maximum element.</returns>
public override double AbsoluteMaximum() public override double AbsoluteMaximum()
{ {
return Math.Abs(Data[AbsoluteMaximumIndex()]); return Math.Abs(_values[AbsoluteMaximumIndex()]);
} }
/// <summary> /// <summary>
@ -679,10 +609,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override int AbsoluteMaximumIndex() public override int AbsoluteMaximumIndex()
{ {
var index = 0; var index = 0;
var max = Math.Abs(Data[index]); var max = Math.Abs(_values[index]);
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Math.Abs(Data[i]); var test = Math.Abs(_values[i]);
if (test > max) if (test > max)
{ {
index = i; index = i;
@ -706,7 +636,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception> /// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
public override Vector<double> SubVector(int index, int length) public override Vector<double> SubVector(int index, int length)
{ {
if (index < 0 || index >= Count) if (index < 0 || index >= _length)
{ {
throw new ArgumentOutOfRangeException("index"); throw new ArgumentOutOfRangeException("index");
} }
@ -716,7 +646,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
if (index + length > Count) if (index + length > _length)
{ {
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
@ -725,8 +655,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
CommonParallel.For( CommonParallel.For(
index, index,
index + length, index + length,
i => result.Data[i - index] = Data[i]); i => result._values[i - index] = _values[i]);
return result; return result;
} }
@ -743,7 +673,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
throw new ArgumentNullException("values"); throw new ArgumentNullException("values");
} }
if (values.Length != Count) if (values.Length != _length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values");
} }
@ -751,7 +681,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
CommonParallel.For( CommonParallel.For(
0, 0,
values.Length, values.Length,
i => Data[i] = values[i]); i => _values[i] = values[i]);
} }
/// <summary> /// <summary>
@ -761,13 +691,13 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override int MaximumIndex() public override int MaximumIndex()
{ {
var index = 0; var index = 0;
var max = Data[0]; var max = _values[0];
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
if (max < Data[i]) if (max < _values[i])
{ {
index = i; index = i;
max = Data[i]; max = _values[i];
} }
} }
@ -781,13 +711,13 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override int MinimumIndex() public override int MinimumIndex()
{ {
var index = 0; var index = 0;
var min = Data[0]; var min = _values[0];
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
if (min > Data[i]) if (min > _values[i])
{ {
index = i; index = i;
min = Data[i]; min = _values[i];
} }
} }
@ -802,9 +732,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
sum += Data[index]; sum += _values[index];
} }
return sum; return sum;
@ -818,9 +748,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
sum += Math.Abs(Data[index]); sum += Math.Abs(_values[index]);
} }
return sum; return sum;
@ -842,8 +772,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] * other[index]); index => dense._values[index] = _values[index] * other[index]);
} }
} }
@ -864,8 +794,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] / other[index]); index => dense._values[index] = _values[index] / other[index]);
} }
} }
@ -897,7 +827,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
for (var j = 0; j < v.Count; j++) for (var j = 0; j < v.Count; j++)
{ {
matrix.At(i, j, u.Data[i] * v.Data[j]); matrix.At(i, j, u._values[i] * v._values[j]);
} }
}); });
return matrix; return matrix;
@ -937,18 +867,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double
if (2.0 == p) if (2.0 == p)
{ {
return Data.Aggregate(0.0, SpecialFunctions.Hypotenuse); return _values.Aggregate(0.0, SpecialFunctions.Hypotenuse);
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(Data, (i, v) => Math.Abs(v), Math.Max, 0d); return CommonParallel.Aggregate(_values, (i, v) => Math.Abs(v), Math.Max, 0d);
} }
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
sum += Math.Pow(Math.Abs(Data[index]), p); sum += Math.Pow(Math.Abs(_values[index]), p);
} }
return Math.Pow(sum, 1.0 / p); return Math.Pow(sum, 1.0 / p);
@ -1114,29 +1044,5 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
#endregion #endregion
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
}
/// <summary>Gets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
internal protected override double At(int index)
{
return Data[index];
}
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <param name="value">The value to set.</param>
internal protected override void At(int index, double value)
{
Data[index] = value;
}
} }
} }

4
src/Numerics/LinearAlgebra/Double/DiagonalMatrix.cs

@ -377,12 +377,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double
return; return;
} }
if (_data.Length != denseSource.Data.Length) if (_data.Length != denseSource.Values.Length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source");
} }
Buffer.BlockCopy(denseSource.Data, 0, _data, 0, denseSource.Data.Length * Constants.SizeOfDouble); Buffer.BlockCopy(denseSource.Values, 0, _data, 0, denseSource.Values.Length * Constants.SizeOfDouble);
} }
/// <summary> /// <summary>

4
src/Numerics/LinearAlgebra/Double/Factorization/DenseCholesky.cs

@ -167,11 +167,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
Buffer.BlockCopy(dinput.Data, 0, dresult.Data, 0, dinput.Data.Length * Constants.SizeOfDouble); Buffer.BlockCopy(dinput.Values, 0, dresult.Values, 0, dinput.Values.Length * Constants.SizeOfDouble);
// Cholesky solve by overwriting result. // Cholesky solve by overwriting result.
var dfactor = (DenseMatrix)CholeskyFactor; var dfactor = (DenseMatrix)CholeskyFactor;
Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Data, 1); Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Values, 1);
} }
} }
} }

2
src/Numerics/LinearAlgebra/Double/Factorization/DenseGramSchmidt.cs

@ -216,7 +216,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment.");
} }
_provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Data, 1, dresult.Data); _provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Values, 1, dresult.Values);
} }
} }
} }

4
src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs

@ -168,11 +168,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
Buffer.BlockCopy(dinput.Data, 0, dresult.Data, 0, dinput.Data.Length * Constants.SizeOfDouble); Buffer.BlockCopy(dinput.Values, 0, dresult.Values, 0, dinput.Values.Length * Constants.SizeOfDouble);
// LU solve by overwriting result. // LU solve by overwriting result.
var dfactors = (DenseMatrix)Factors; var dfactors = (DenseMatrix)Factors;
Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Values);
} }
/// <summary> /// <summary>

2
src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs

@ -188,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
} }
} }
} }

6
src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs

@ -69,7 +69,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
VectorS = new DenseVector(nm); VectorS = new DenseVector(nm);
MatrixU = new DenseMatrix(matrix.RowCount); MatrixU = new DenseMatrix(matrix.RowCount);
MatrixVT = new DenseMatrix(matrix.ColumnCount); MatrixVT = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data);
} }
/// <summary> /// <summary>
@ -125,7 +125,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data);
} }
/// <summary> /// <summary>
@ -175,7 +175,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Values, 1, dresult.Values);
} }
} }
} }

1
src/Numerics/LinearAlgebra/Double/SparseMatrix.cs

@ -97,6 +97,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// The number of columns. /// The number of columns.
/// </param> /// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param> /// <param name="value">The value which we assign to each element of the matrix.</param>
[Obsolete("Use a dense matrix instead.")]
public SparseMatrix(int rows, int columns, double value) public SparseMatrix(int rows, int columns, double value)
: this(rows, columns) : this(rows, columns)
{ {

483
src/Numerics/LinearAlgebra/Double/SparseVector.cs

@ -37,6 +37,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
using Generic; using Generic;
using NumberTheory; using NumberTheory;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -46,24 +47,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double
[Serializable] [Serializable]
public class SparseVector : Vector public class SparseVector : Vector
{ {
/// <summary> readonly SparseVectorStorage<double> _storage;
/// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored.
/// </summary>
private double[] _nonZeroValues = new double[0];
/// <summary>
/// The indices of the non-zero entries.
/// </summary>
private int[] _nonZeroIndices = new int[0];
/// <summary> internal SparseVector(SparseVectorStorage<double> storage)
/// Gets the number of non zero elements in the vector. : base(storage)
/// </summary>
/// <value>The number of non zero elements.</value>
public int NonZerosCount
{ {
get; _storage = storage;
private set;
} }
#region Constructors #region Constructors
@ -77,7 +66,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size) : base(size) public SparseVector(int size)
: this(new SparseVectorStorage<double>(size))
{ {
} }
@ -94,55 +84,23 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size, double value) : this(size) [Obsolete("Use a dense vector instead.")]
public SparseVector(int size, double value)
: this(new SparseVectorStorage<double>(size))
{ {
if (value == 0.0) if (value == 0.0)
{ {
// Skip adding values
return; return;
} }
// We already know that this vector is "full", let's allocate all needed memory var valueCount = _storage.ValueCount = size;
_nonZeroValues = new double[size]; var indices = _storage.Indices = new int[valueCount];
_nonZeroIndices = new int[size]; var values = _storage.Values = new double[valueCount];
NonZerosCount = size;
CommonParallel.For(
0,
Count,
index =>
{
_nonZeroValues[index] = value;
_nonZeroIndices[index] = index;
});
}
/// <summary> for (int i = 0; i < values.Length; i++)
/// Initializes a new instance of the <see cref="SparseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public SparseVector(Vector<double> other) : this(other.Count)
{
var vector = other as SparseVector;
if (vector == null)
{ {
for (var i = 0; i < other.Count; i++) values[i] = value;
{ indices[i] = i;
this[i] = other.At(i);
}
}
else
{
_nonZeroValues = new double[vector.NonZerosCount];
_nonZeroIndices = new int[vector.NonZerosCount];
NonZerosCount = vector.NonZerosCount;
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
Buffer.BlockCopy(vector._nonZeroValues, 0, _nonZeroValues, 0, vector.NonZerosCount * Constants.SizeOfDouble);
Buffer.BlockCopy(vector._nonZeroIndices, 0, _nonZeroIndices, 0, vector.NonZerosCount * Constants.SizeOfInt);
} }
} }
@ -153,15 +111,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <param name="other"> /// <param name="other">
/// The vector to create the new vector from. /// The vector to create the new vector from.
/// </param> /// </param>
public SparseVector(SparseVector other) : this(other.Count) public SparseVector(Vector<double> other)
: this(new SparseVectorStorage<double>(other.Count))
{ {
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value other.Storage.CopyTo(Storage, skipClearing: true);
_nonZeroValues = new double[other.NonZerosCount];
_nonZeroIndices = new int[other.NonZerosCount];
NonZerosCount = other.NonZerosCount;
Buffer.BlockCopy(other._nonZeroValues, 0, _nonZeroValues, 0, other.NonZerosCount * Constants.SizeOfDouble);
Buffer.BlockCopy(other._nonZeroIndices, 0, _nonZeroIndices, 0, other.NonZerosCount * Constants.SizeOfInt);
} }
/// <summary> /// <summary>
@ -169,11 +122,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// </summary> /// </summary>
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks> /// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks>
public SparseVector(IList<double> array) : this(array.Count) public SparseVector(IList<double> array)
: this(new SparseVectorStorage<double>(array.Count))
{ {
for (var i = 0; i < array.Count; i++) for (var i = 0; i < array.Count; i++)
{ {
this[i] = array[i]; Storage.At(i, array[i]);
} }
} }
@ -185,10 +139,13 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>This vector as a column matrix.</returns> /// <returns>This vector as a column matrix.</returns>
public override Matrix<double> ToColumnMatrix() public override Matrix<double> ToColumnMatrix()
{ {
var indices = _storage.Indices;
var values = _storage.Values;
var matrix = new SparseMatrix(Count, 1); var matrix = new SparseMatrix(Count, 1);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); matrix.At(indices[i], 0, values[i]);
} }
return matrix; return matrix;
@ -200,10 +157,13 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>This vector as a row matrix.</returns> /// <returns>This vector as a row matrix.</returns>
public override Matrix<double> ToRowMatrix() public override Matrix<double> ToRowMatrix()
{ {
var indices = _storage.Indices;
var values = _storage.Values;
var matrix = new SparseMatrix(1, Count); var matrix = new SparseMatrix(1, Count);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); matrix.At(0, indices[i], values[i]);
} }
return matrix; return matrix;
@ -242,68 +202,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
return new SparseVector(size); return new SparseVector(size);
} }
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
NonZerosCount = 0;
}
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<double> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as SparseVector;
if (otherVector == null)
{
target.Clear();
for (var index = 0; index < NonZerosCount; index++)
{
target.At(_nonZeroIndices[index], _nonZeroValues[index]);
}
}
else
{
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
otherVector._nonZeroValues = new double[NonZerosCount];
otherVector._nonZeroIndices = new int[NonZerosCount];
otherVector.NonZerosCount = NonZerosCount;
if (NonZerosCount != 0)
{
Buffer.BlockCopy(_nonZeroValues, 0, otherVector._nonZeroValues, 0, NonZerosCount*Constants.SizeOfDouble);
Buffer.BlockCopy(_nonZeroIndices, 0, otherVector._nonZeroIndices, 0, NonZerosCount*Constants.SizeOfInt);
}
}
}
#region Operators and supplementary functions #region Operators and supplementary functions
/// <summary> /// <summary>
@ -340,16 +238,19 @@ namespace MathNet.Numerics.LinearAlgebra.Double
vnonZeroValues[index] = scalar; vnonZeroValues[index] = scalar;
} }
var indices = _storage.Indices;
var values = _storage.Values;
//populate the non zero values from this //populate the non zero values from this
for (int j = 0; j < NonZerosCount; j++) for (int j = 0; j < _storage.ValueCount; j++)
{ {
vnonZeroValues[_nonZeroIndices[j]] = _nonZeroValues[j] + scalar; vnonZeroValues[indices[j]] = values[j] + scalar;
} }
//assign this vectors arrary to the new arrays. //assign this vectors arrary to the new arrays.
_nonZeroValues = vnonZeroValues; _storage.Values = vnonZeroValues;
_nonZeroIndices = vnonZeroIndices; _storage.Indices = vnonZeroIndices;
NonZerosCount = Count; _storage.ValueCount = Count;
} }
else else
{ {
@ -390,22 +291,22 @@ namespace MathNet.Numerics.LinearAlgebra.Double
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] += otherSparse._nonZeroValues[j++]; _storage.Values[i++] += otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != 0.0) if (otherValue != 0.0)
{ {
InsertAtIndexUnchecked(i++, otherSparse._nonZeroIndices[j], otherValue); InsertAtIndexUnchecked(i++, otherSparse._storage.Indices[j], otherValue);
} }
j++; j++;
} }
@ -415,25 +316,25 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] + otherSparse.At(next)); result.At(next, _storage.Values[i] + otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) + otherSparse._nonZeroValues[j]); result.At(next, At(next) + otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -536,22 +437,22 @@ namespace MathNet.Numerics.LinearAlgebra.Double
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] -= otherSparse._nonZeroValues[j++]; _storage.Values[i++] -= otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != 0.0) if (otherValue != 0.0)
{ {
InsertAtIndexUnchecked(i++, otherSparse._nonZeroIndices[j], -otherValue); InsertAtIndexUnchecked(i++, otherSparse._storage.Indices[j], -otherValue);
} }
j++; j++;
} }
@ -561,25 +462,25 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] - otherSparse.At(next)); result.At(next, _storage.Values[i] - otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) - otherSparse._nonZeroValues[j]); result.At(next, At(next) - otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -638,24 +539,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<double> Negate() public override Vector<double> Negate()
{ {
var result = new SparseVector(Count) var result = new SparseVectorStorage<double>(Count);
{ var valueCount = result.ValueCount = _storage.ValueCount;
_nonZeroValues = new double[NonZerosCount], var indices = result.Indices = new int[valueCount];
_nonZeroIndices = new int[NonZerosCount], var values = result.Values = new double[valueCount];
NonZerosCount = NonZerosCount
};
if (NonZerosCount != 0) if (valueCount != 0)
{ {
CommonParallel.For( CommonParallel.For(0, valueCount, index => values[index] = -_storage.Values[index]);
0, Buffer.BlockCopy(_storage.Indices, 0, indices, 0, valueCount * Constants.SizeOfInt);
NonZerosCount,
index => result._nonZeroValues[index] = -_nonZeroValues[index]);
Buffer.BlockCopy(_nonZeroIndices, 0, result._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt);
} }
return result; return new SparseVector(result);
} }
/// <summary> /// <summary>
@ -676,7 +571,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
var copy = new SparseVector(this); var copy = new SparseVector(this);
Control.LinearAlgebraProvider.ScaleArray(scalar, copy._nonZeroValues, copy._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, copy._storage.Values, copy._storage.Values);
return copy; return copy;
} }
@ -711,23 +606,23 @@ namespace MathNet.Numerics.LinearAlgebra.Double
if (sparseResult == null) if (sparseResult == null)
{ {
result.Clear(); result.Clear();
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); result.At(_storage.Indices[index], scalar * _storage.Values[index]);
} }
} }
else else
{ {
if (!ReferenceEquals(this, result)) if (!ReferenceEquals(this, result))
{ {
sparseResult.NonZerosCount = NonZerosCount; sparseResult._storage.ValueCount = _storage.ValueCount;
sparseResult._nonZeroIndices = new int[NonZerosCount]; sparseResult._storage.Indices = new int[_storage.ValueCount];
Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); Buffer.BlockCopy(_storage.Indices, 0, sparseResult._storage.Indices, 0, _storage.ValueCount * Constants.SizeOfInt);
sparseResult._nonZeroValues = new double[NonZerosCount]; sparseResult._storage.Values = new double[_storage.ValueCount];
Buffer.BlockCopy(_nonZeroValues, 0, sparseResult._nonZeroValues, 0, NonZerosCount * Constants.SizeOfDouble); Buffer.BlockCopy(_storage.Values, 0, sparseResult._storage.Values, 0, _storage.ValueCount * Constants.SizeOfDouble);
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues, sparseResult._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._storage.Values, sparseResult._storage.Values);
} }
} }
@ -746,16 +641,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * _nonZeroValues[i]; result += _storage.Values[i] * _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); result += _storage.Values[i] * other.At(_storage.Indices[i]);
} }
} }
@ -850,17 +745,17 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
if (ReferenceEquals(this, result)) if (ReferenceEquals(this, result))
{ {
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
_nonZeroValues[index] %= divisor; _storage.Values[index] %= divisor;
} }
} }
else else
{ {
result.Clear(); result.Clear();
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
result.At(_nonZeroIndices[index], _nonZeroValues[index] % divisor); result.At(_storage.Indices[index], _storage.Values[index] % divisor);
} }
} }
} }
@ -888,17 +783,17 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>The index of absolute minimum element.</returns> /// <returns>The index of absolute minimum element.</returns>
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
// No non-zero elements. Return 0 // No non-zero elements. Return 0
return 0; return 0;
} }
var index = 0; var index = 0;
var min = Math.Abs(_nonZeroValues[index]); var min = Math.Abs(_storage.Values[index]);
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
var test = Math.Abs(_nonZeroValues[i]); var test = Math.Abs(_storage.Values[i]);
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -906,7 +801,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -976,23 +871,23 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>The index of absolute maximum element.</returns> /// <returns>The index of absolute maximum element.</returns>
public override int MaximumIndex() public override int MaximumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return 0; return 0;
} }
var index = 0; var index = 0;
var max = _nonZeroValues[0]; var max = _storage.Values[0];
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
if (max < _nonZeroValues[i]) if (max < _storage.Values[i])
{ {
index = i; index = i;
max = _nonZeroValues[i]; max = _storage.Values[i];
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -1001,23 +896,23 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <returns>The index of minimum element.</returns> /// <returns>The index of minimum element.</returns>
public override int MinimumIndex() public override int MinimumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return 0; return 0;
} }
var index = 0; var index = 0;
var min = _nonZeroValues[0]; var min = _storage.Values[0];
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
if (min > _nonZeroValues[i]) if (min > _storage.Values[i])
{ {
index = i; index = i;
min = _nonZeroValues[i]; min = _storage.Values[i];
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -1027,9 +922,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override double Sum() public override double Sum()
{ {
double result = 0; double result = 0;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i]; result += _storage.Values[i];
} }
return result; return result;
@ -1042,9 +937,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override double SumMagnitudes() public override double SumMagnitudes()
{ {
double result = 0; double result = 0;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += Math.Abs(_nonZeroValues[i]); result += Math.Abs(_storage.Values[i]);
} }
return result; return result;
@ -1059,17 +954,17 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] *= _nonZeroValues[i]; _storage.Values[i] *= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, other.At(index) * _nonZeroValues[i]); result.At(index, other.At(index) * _storage.Values[i]);
} }
} }
} }
@ -1083,17 +978,17 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] /= _nonZeroValues[i]; _storage.Values[i] /= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, _nonZeroValues[i] / other.At(index)); result.At(index, _storage.Values[i] / other.At(index));
} }
} }
} }
@ -1119,11 +1014,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
var matrix = new SparseMatrix(u.Count, v.Count); var matrix = new SparseMatrix(u.Count, v.Count);
for (var i = 0; i < u.NonZerosCount; i++) for (var i = 0; i < u._storage.ValueCount; i++)
{ {
for (var j = 0; j < v.NonZerosCount; j++) for (var j = 0; j < v._storage.ValueCount; j++)
{ {
matrix.At(i, j, u._nonZeroValues[i] * v._nonZeroValues[j]); matrix.At(i, j, u._storage.Values[i] * v._storage.Values[j]);
} }
} }
@ -1158,25 +1053,25 @@ namespace MathNet.Numerics.LinearAlgebra.Double
throw new ArgumentOutOfRangeException("p"); throw new ArgumentOutOfRangeException("p");
} }
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return 0.0; return 0.0;
} }
if (2.0 == p) if (2.0 == p)
{ {
return _nonZeroValues.Aggregate(0.0, SpecialFunctions.Hypotenuse); return _storage.Values.Aggregate(0.0, SpecialFunctions.Hypotenuse);
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(0, NonZerosCount, i => Math.Abs(_nonZeroValues[i]), Math.Max, 0d); return CommonParallel.Aggregate(0, _storage.ValueCount, i => Math.Abs(_storage.Values[i]), Math.Max, 0d);
} }
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
sum += Math.Pow(Math.Abs(_nonZeroValues[index]), p); sum += Math.Pow(Math.Abs(_storage.Values[index]), p);
} }
return Math.Pow(sum, 1.0 / p); return Math.Pow(sum, 1.0 / p);
@ -1343,97 +1238,33 @@ namespace MathNet.Numerics.LinearAlgebra.Double
#endregion #endregion
/// <summary>
/// Gets the value at the given index.
/// </summary>
/// <param name="index">Value real index in array</param>
/// <returns>The value at the given index.</returns>
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;
}
/// <summary>
/// Delete, Add or Update the value in NonZeroValues and NonZeroIndices
/// </summary>
/// <param name="index">Value real index in array</param>
/// <param name="value">The value to set.</param>
/// <remarks>This method assume that index is between 0 and Array Size</remarks>
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);
if (itemIndex >= 0)
{
// Item already exist at itemIndex
if (value == 0.0)
{
RemoveAtIndexUnchecked(itemIndex);
}
else
{
_nonZeroValues[itemIndex] = value;
}
}
else
{
if (value != 0.0)
{
InsertAtIndexUnchecked(~itemIndex, index, value);
}
}
}
private void InsertAtIndexUnchecked(int itemIndex, int index, double value) private void InsertAtIndexUnchecked(int itemIndex, int index, double value)
{ {
// Check if the storage needs to be increased // Check if the storage needs to be increased
if ((NonZerosCount == _nonZeroValues.Length) && (NonZerosCount < Count)) if ((_storage.ValueCount == _storage.Values.Length) && (_storage.ValueCount < Count))
{ {
// Value and Indices arrays are completely full so we increase the size // Value and Indices arrays are completely full so we increase the size
var size = Math.Min(_nonZeroValues.Length + GrowthSize(), Count); var size = Math.Min(_storage.Values.Length + GrowthSize(), Count);
Array.Resize(ref _nonZeroValues, size); Array.Resize(ref _storage.Values, size);
Array.Resize(ref _nonZeroIndices, size); Array.Resize(ref _storage.Indices, size);
} }
// Move all values (with a position larger than index) in the value array // Move all values (with a position larger than index) in the value array
// to the next position // to the next position
// Move all values (with a position larger than index) in the columIndices // Move all values (with a position larger than index) in the columIndices
// array to the next position // array to the next position
for (var i = NonZerosCount - 1; i > itemIndex - 1; i--) for (var i = _storage.ValueCount - 1; i > itemIndex - 1; i--)
{ {
_nonZeroValues[i + 1] = _nonZeroValues[i]; _storage.Values[i + 1] = _storage.Values[i];
_nonZeroIndices[i + 1] = _nonZeroIndices[i]; _storage.Indices[i + 1] = _storage.Indices[i];
} }
// Add the value and the column index // Add the value and the column index
_nonZeroValues[itemIndex] = value; _storage.Values[itemIndex] = value;
_nonZeroIndices[itemIndex] = index; _storage.Indices[itemIndex] = index;
// increase the number of non-zero numbers by one // increase the number of non-zero numbers by one
NonZerosCount += 1; _storage.ValueCount += 1;
}
private void RemoveAtIndexUnchecked(int itemIndex)
{
// Value is zero. Let's delete it from Values and Indices array
for (var i = itemIndex + 1; i < NonZerosCount; i++)
{
_nonZeroValues[i - 1] = _nonZeroValues[i];
_nonZeroIndices[i - 1] = _nonZeroIndices[i];
}
NonZerosCount -= 1;
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((NonZerosCount > 1024) && (NonZerosCount < _nonZeroIndices.Length / 2))
{
Array.Resize(ref _nonZeroValues, NonZerosCount);
Array.Resize(ref _nonZeroIndices, NonZerosCount);
}
} }
/// <summary> /// <summary>
@ -1444,19 +1275,19 @@ namespace MathNet.Numerics.LinearAlgebra.Double
private int GrowthSize() private int GrowthSize()
{ {
int delta; int delta;
if (_nonZeroValues.Length > 1024) if (_storage.Values.Length > 1024)
{ {
delta = _nonZeroValues.Length / 4; delta = _storage.Values.Length / 4;
} }
else else
{ {
if (_nonZeroValues.Length > 256) if (_storage.Values.Length > 256)
{ {
delta = 512; delta = 512;
} }
else else
{ {
delta = _nonZeroValues.Length > 64 ? 128 : 32; delta = _storage.Values.Length > 64 ? 128 : 32;
} }
} }
@ -1469,7 +1300,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
if (Count > 20) if (Count > 20)
{ {
return String.Format("SparseVectorOfDouble({0},{1},{2})", Count, NonZerosCount, GetHashCode()); return String.Format("SparseVectorOfDouble({0},{1},{2})", Count, _storage.ValueCount, GetHashCode());
} }
return base.ToString(format, formatProvider); return base.ToString(format, formatProvider);
@ -1483,14 +1314,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
var hashNum = Math.Min(NonZerosCount, 20); var hashNum = Math.Min(_storage.ValueCount, 20);
long hash = 0; long hash = 0;
for (var i = 0; i < hashNum; i++) for (var i = 0; i < hashNum; i++)
{ {
#if PORTABLE #if PORTABLE
hash ^= Precision.DoubleToInt64Bits(this._nonZeroValues[i].GetHashCode()); hash ^= Precision.DoubleToInt64Bits(this._storage.Values[i].GetHashCode());
#else #else
hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= BitConverter.DoubleToInt64Bits(_storage.Values[i].GetHashCode());
#endif #endif
} }
@ -1534,27 +1365,27 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
if (_nonZeroValues[i++] != 0d) if (_storage.Values[i++] != 0d)
{ {
return false; return false;
} }
continue; continue;
} }
if (i >= NonZerosCount || j < otherSparse.NonZerosCount && otherSparse._nonZeroIndices[j] < _nonZeroIndices[i]) if (i >= _storage.ValueCount || j < otherSparse._storage.ValueCount && otherSparse._storage.Indices[j] < _storage.Indices[i])
{ {
if (otherSparse._nonZeroValues[j++] != 0d) if (otherSparse._storage.Values[j++] != 0d)
{ {
return false; return false;
} }
continue; continue;
} }
if (!_nonZeroValues[i].AlmostEqual(otherSparse._nonZeroValues[j])) if (!_storage.Values[i].AlmostEqual(otherSparse._storage.Values[j]))
{ {
return false; return false;
} }
@ -1582,9 +1413,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// </remarks> /// </remarks>
public override IEnumerable<Tuple<int, double>> GetIndexedEnumerator() public override IEnumerable<Tuple<int, double>> GetIndexedEnumerator()
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
yield return new Tuple<int, double>(_nonZeroIndices[i], _nonZeroValues[i]); yield return new Tuple<int, double>(_storage.Indices[i], _storage.Values[i]);
} }
} }
@ -1597,9 +1428,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override double[] ToArray() public override double[] ToArray()
{ {
var ret = new double[Count]; var ret = new double[Count];
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
ret[_nonZeroIndices[i]] = _nonZeroValues[i]; ret[_storage.Indices[i]] = _storage.Values[i];
} }
return ret; return ret;

11
src/Numerics/LinearAlgebra/Double/Vector.cs

@ -30,6 +30,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
using Distributions; using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -40,15 +41,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the Vector class. /// Initializes a new instance of the Vector class.
/// Constructs a <strong>Vector</strong> with the given size.
/// </summary> /// </summary>
/// <param name="size"> protected Vector(VectorStorage<double> storage)
/// The size of the <strong>Vector</strong> to construct. : base(storage)
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one.
/// </exception>
protected Vector(int size) : base(size)
{ {
} }

288
src/Numerics/LinearAlgebra/Generic/Vector.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
using Distributions; using Distributions;
using Numerics; using Numerics;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -60,60 +61,152 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
private static readonly T One = Common.SetOne<T>(); private static readonly T One = Common.SetOne<T>();
/// <summary> /// <summary>
/// Initializes a new instance of the Vector class. /// Initializes a new instance of the Vector class.
/// Constructs a <strong>Vector</strong> with the given size.
/// </summary> /// </summary>
/// <param name="size"> protected Vector(VectorStorage<T> storage)
/// The size of the <strong>Vector</strong> to construct.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// If <paramref name="size"/> is less than one.
/// </exception>
protected Vector(int size)
{ {
if (size < 1) Storage = storage;
{ Count = storage.Length;
throw new ArgumentOutOfRangeException("size", Resources.ArgumentMustBePositive);
}
Count = size;
} }
/// <summary> /// <summary>
/// Gets he number of elements in the vector. /// Gets the raw vector data storage.
/// </summary> /// </summary>
public int Count public VectorStorage<T> Storage { get; private set; }
{
get; /// <summary>
private set; /// Gets the number of items.
} /// </summary>
public int Count { get; private set; }
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary> /// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param> /// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns> /// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative or /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative or
/// greater than the size of the vector.</exception> /// greater than the size of the vector.</exception>
public virtual T this[int index] public T this[int index]
{ {
get get { return Storage[index]; }
set { Storage[index] = value;}
}
/// <summary>Gets the value at the given <paramref name="index"/> without range checking..</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
public T At(int index)
{
return Storage.At(index);
}
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/> without range checking..</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <param name="value">The value to set.</param>
public void At(int index, T value)
{
Storage.At(index, value);
}
/// <summary>
/// Resets all values to zero.
/// </summary>
public void Clear()
{
Storage.Clear();
}
/// <summary>
/// Sets all values of a subvector to zero.
/// </summary>
public void ClearSubVector(int index, int count)
{
if (count < 1)
{ {
if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("count", Resources.ArgumentMustBePositive);
{ }
throw new ArgumentOutOfRangeException("index");
}
return At(index); if (index + count > Count || index < 0)
{
throw new ArgumentOutOfRangeException("index");
} }
set Storage.Clear(index, count);
}
/// <summary>
/// Returns a deep-copy clone of the vector.
/// </summary>
/// <returns>
/// A deep-copy clone of the vector.
/// </returns>
public Vector<T> Clone()
{
var result = CreateVector(Count);
Storage.CopyTo(result.Storage, skipClearing: true);
return result;
}
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public void CopyTo(Vector<T> target)
{
if (target == null)
{ {
if (index < 0 || index >= Count) throw new ArgumentNullException("target");
{ }
throw new ArgumentOutOfRangeException("index");
} if (ReferenceEquals(this, target) || ReferenceEquals(Storage, target.Storage))
{
return;
}
At(index, value); if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
Storage.CopyTo(target.Storage);
}
/// <summary>
/// Copies the requested elements from this vector to another.
/// </summary>
/// <param name="destination">
/// The vector to copy the elements to.
/// </param>
/// <param name="sourceIndex">
/// The element to start copying from.
/// </param>
/// <param name="targetIndex">
/// The element to start copying to.
/// </param>
/// <param name="count">
/// The number of elements to copy.
/// </param>
public void CopySubVectorTo(Vector<T> destination, int sourceIndex, int targetIndex, int count)
{
if (destination == null)
{
throw new ArgumentNullException("destination");
} }
// TODO: refactor range checks
Storage.CopySubVectorTo(destination.Storage, sourceIndex, targetIndex, count);
}
[Obsolete("Use CopySubVectorTo instead.")]
public void CopyTo(Vector<T> destination, int sourceIndex, int targetIndex, int count)
{
CopySubVectorTo(destination, sourceIndex, targetIndex, count);
} }
/// <summary> /// <summary>
@ -1166,115 +1259,6 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
#region Copying and Conversion #region Copying and Conversion
/// <summary>
/// Returns a deep-copy clone of the vector.
/// </summary>
/// <returns>
/// A deep-copy clone of the vector.
/// </returns>
public Vector<T> Clone()
{
var retrunVector = CreateVector(Count);
CopyTo(retrunVector);
return retrunVector;
}
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public virtual void CopyTo(Vector<T> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
CommonParallel.For(
0,
Count,
index => target[index] = this[index]);
}
/// <summary>
/// Copies the requested elements from this vector to another.
/// </summary>
/// <param name="destination">
/// The vector to copy the elements to.
/// </param>
/// <param name="offset">
/// The element to start copying from.
/// </param>
/// <param name="destinationOffset">
/// The element to start copying to.
/// </param>
/// <param name="count">
/// The number of elements to copy.
/// </param>
public virtual void CopyTo(Vector<T> destination, int offset, int destinationOffset, int count)
{
if (destination == null)
{
throw new ArgumentNullException("destination");
}
if (offset >= Count)
{
throw new ArgumentOutOfRangeException("offset");
}
if (offset + count > Count)
{
throw new ArgumentOutOfRangeException("count");
}
if (destinationOffset >= destination.Count)
{
throw new ArgumentOutOfRangeException("destinationOffset");
}
if (destinationOffset + count > destination.Count)
{
throw new ArgumentOutOfRangeException("count");
}
if (ReferenceEquals(this, destination))
{
var tmpVector = destination.CreateVector(destination.Count);
CopyTo(tmpVector);
CommonParallel.For(
0,
count,
index => destination[destinationOffset + index] = tmpVector[offset + index]);
}
else
{
CommonParallel.For(
0,
count,
index => destination[destinationOffset + index] = this[offset + index]);
}
}
/// <summary> /// <summary>
/// Returns the data contained in the vector as an array. /// Returns the data contained in the vector as an array.
/// </summary> /// </summary>
@ -1605,23 +1589,5 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
} }
#endregion #endregion
/// <summary>
/// Resets all values to zero.
/// </summary>
public virtual void Clear()
{
CommonParallel.For(0, Count, index => this[index] = default(T));
}
/// <summary>Gets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
internal protected abstract T At(int index);
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <param name="value">The value to set.</param>
internal protected abstract void At(int index, T value);
} }
} }

77
src/Numerics/LinearAlgebra/Single/DenseMatrix.cs

@ -39,8 +39,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single
[Serializable] [Serializable]
public class DenseMatrix : Matrix public class DenseMatrix : Matrix
{ {
readonly DenseColumnMajorMatrixStorage<float> _storage;
/// <summary> /// <summary>
/// Number of rows. /// Number of rows.
/// </summary> /// </summary>
@ -59,15 +57,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// Gets the matrix's data. /// Gets the matrix's data.
/// </summary> /// </summary>
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
readonly float[] _data; readonly float[] _values;
internal DenseMatrix(DenseColumnMajorMatrixStorage<float> storage) internal DenseMatrix(DenseColumnMajorMatrixStorage<float> storage)
: base(storage) : base(storage)
{ {
_storage = storage; _rowCount = storage.RowCount;
_rowCount = _storage.RowCount; _columnCount = storage.ColumnCount;
_columnCount = _storage.ColumnCount; _values = storage.Data;
_data = _storage.Data;
} }
/// <summary> /// <summary>
@ -109,9 +106,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public DenseMatrix(int rows, int columns, float value) public DenseMatrix(int rows, int columns, float value)
: this(rows, columns) : this(rows, columns)
{ {
for (var i = 0; i < _data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
_data[i] = value; _values[i] = value;
} }
} }
@ -139,7 +136,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
for (var j = 0; j < _columnCount; j++) for (var j = 0; j < _columnCount; j++)
{ {
_data[(j * _rowCount) + i] = array[i, j]; _values[(j * _rowCount) + i] = array[i, j];
} }
} }
} }
@ -161,7 +158,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <value>The matrix's data.</value> /// <value>The matrix's data.</value>
public float[] Data public float[] Data
{ {
get { return _data; } get { return _values; }
} }
/// <summary> /// <summary>
@ -203,7 +200,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
var index = j * _rowCount; var index = j * _rowCount;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
ret._data[(i * _columnCount) + j] = _data[index + i]; ret._values[(i * _columnCount) + j] = _values[index + i];
} }
} }
@ -214,21 +211,21 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override float L1Norm() public override float L1Norm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override float FrobeniusNorm() public override float FrobeniusNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _values);
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override float InfinityNorm() public override float InfinityNorm()
{ {
return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _data); return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _values);
} }
#region Static constructors for special matrices. #region Static constructors for special matrices.
@ -246,7 +243,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
var m = new DenseMatrix(order); var m = new DenseMatrix(order);
for (var i = 0; i < order; i++) for (var i = 0; i < order; i++)
{ {
m._data[(i * order) + i] = 1.0f; m._values[(i * order) + i] = 1.0f;
} }
return m; return m;
@ -271,7 +268,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
else else
{ {
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.AddArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -290,7 +287,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
else else
{ {
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.SubtractArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -308,7 +305,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult._values);
} }
} }
@ -332,14 +329,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0f, 0.0f,
denseResult.Data); denseResult.Values);
} }
} }
@ -363,14 +360,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0f, 0.0f,
denseResult._data); denseResult._values);
} }
} }
@ -394,14 +391,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0f, 0.0f,
denseResult._data); denseResult._values);
} }
} }
@ -425,14 +422,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseRight.Data, denseRight.Values,
denseRight.Count, denseRight.Count,
1, 1,
0.0f, 0.0f,
denseResult.Data); denseResult.Values);
} }
} }
@ -456,14 +453,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.Transpose,
Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f, 1.0f,
_data, _values,
_rowCount, _rowCount,
_columnCount, _columnCount,
denseOther._data, denseOther._values,
denseOther._rowCount, denseOther._rowCount,
denseOther._columnCount, denseOther._columnCount,
0.0f, 0.0f,
denseResult._data); denseResult._values);
} }
} }
@ -481,7 +478,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); Control.LinearAlgebraProvider.ScaleArray(-1, _values, denseResult._values);
} }
} }
@ -501,7 +498,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -521,7 +518,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
else else
{ {
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); Control.LinearAlgebraProvider.PointWiseDivideArrays(_values, denseOther._values, denseResult._values);
} }
} }
@ -547,8 +544,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
CommonParallel.For( CommonParallel.For(
0, 0,
_data.Length, _values.Length,
index => denseResult._data[index] %= divisor); index => denseResult._values[index] %= divisor);
} }
} }
@ -567,7 +564,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
var sum = 0.0f; var sum = 0.0f;
for (var i = 0; i < _rowCount; i++) for (var i = 0; i < _rowCount; i++)
{ {
sum += _data[(i * _rowCount) + i]; sum += _values[(i * _rowCount) + i];
} }
return sum; return sum;

268
src/Numerics/LinearAlgebra/Single/DenseVector.cs

@ -33,6 +33,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
using Generic; using Generic;
using NumberTheory; using NumberTheory;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -41,6 +42,23 @@ namespace MathNet.Numerics.LinearAlgebra.Single
[Serializable] [Serializable]
public class DenseVector : Vector public class DenseVector : Vector
{ {
/// <summary>
/// Number of elements
/// </summary>
readonly int _length;
/// <summary>
/// Gets the vector's data.
/// </summary>
readonly float[] _values;
internal DenseVector(DenseVectorStorage<float> storage)
: base(storage)
{
_length = storage.Length;
_values = storage.Data;
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class with a given size. /// Initializes a new instance of the <see cref="DenseVector"/> class with a given size.
/// </summary> /// </summary>
@ -51,9 +69,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public DenseVector(int size) public DenseVector(int size)
: base(size) : this(new DenseVectorStorage<float>(size))
{ {
Data = new float[size];
} }
/// <summary> /// <summary>
@ -72,9 +89,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public DenseVector(int size, float value) public DenseVector(int size, float value)
: this(size) : this(size)
{ {
for (var index = 0; index < Data.Length; index++) for (var index = 0; index < _values.Length; index++)
{ {
Data[index] = value; _values[index] = value;
} }
} }
@ -88,31 +105,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public DenseVector(Vector<float> other) public DenseVector(Vector<float> other)
: this(other.Count) : this(other.Count)
{ {
var vector = other as DenseVector; other.Storage.CopyTo(Storage, skipClearing: true);
if (vector == null)
{
CommonParallel.For(
0,
Data.Length,
index => this[index] = other[index]);
}
else
{
Buffer.BlockCopy(vector.Data, 0, Data, 0, Data.Length * Constants.SizeOfFloat);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="DenseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public DenseVector(DenseVector other)
: this(other.Count)
{
Buffer.BlockCopy(other.Data, 0, Data, 0, Data.Length * Constants.SizeOfFloat);
} }
/// <summary> /// <summary>
@ -121,20 +114,18 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector does not copy the array, but keeps a reference to it. Any /// <remarks>The vector does not copy the array, but keeps a reference to it. Any
/// changes to the vector will also change the array.</remarks> /// changes to the vector will also change the array.</remarks>
public DenseVector(float[] array) : base(array.Length) public DenseVector(float[] array)
: this(new DenseVectorStorage<float>(array.Length, array))
{ {
Data = array;
} }
/// <summary> /// <summary>
/// Gets the vector's internal data. /// Gets the vector's data.
/// </summary> /// </summary>
/// <value>The vector's internal data.</value> /// <value>The vector's data.</value>
/// <remarks>Changing values in the array also changes the corresponding value in vector. Use with care.</remarks> public float[] Values
internal float[] Data
{ {
get; get { return _values; }
private set;
} }
/// <summary> /// <summary>
@ -145,14 +136,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns> /// <returns>
/// A reference to the internal date of the given vector. /// A reference to the internal date of the given vector.
/// </returns> /// </returns>
public static implicit operator float[](DenseVector vector) public static explicit operator float[](DenseVector vector)
{ {
if (vector == null) if (vector == null)
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
return vector.Data; return vector.Values;
} }
/// <summary> /// <summary>
@ -178,10 +169,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>This vector as a column matrix.</returns> /// <returns>This vector as a column matrix.</returns>
public override Matrix<float> ToColumnMatrix() public override Matrix<float> ToColumnMatrix()
{ {
var matrix = new DenseMatrix(Count, 1); var matrix = new DenseMatrix(_length, 1);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(i, 0, Data[i]); matrix.At(i, 0, _values[i]);
} }
return matrix; return matrix;
@ -193,33 +184,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>This vector as a row matrix.</returns> /// <returns>This vector as a row matrix.</returns>
public override Matrix<float> ToRowMatrix() public override Matrix<float> ToRowMatrix()
{ {
var matrix = new DenseMatrix(1, Count); var matrix = new DenseMatrix(1, _length);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < _values.Length; i++)
{ {
matrix.At(0, i, Data[i]); matrix.At(0, i, _values[i]);
} }
return matrix; return matrix;
} }
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
/// <exception cref="IndexOutOfRangeException">If <paramref name="index"/> is negative or
/// greater than the size of the vector.</exception>
public override float this[int index]
{
get
{
return Data[index];
}
set
{
Data[index] = value;
}
}
/// <summary> /// <summary>
/// Creates a matrix with the given dimensions using the same storage type /// Creates a matrix with the given dimensions using the same storage type
/// as this vector. /// as this vector.
@ -253,49 +226,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single
return new DenseVector(size); return new DenseVector(size);
} }
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<float> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as DenseVector;
if (otherVector == null)
{
CommonParallel.For(
0,
Data.Length,
index => target[index] = Data[index]);
}
else
{
Buffer.BlockCopy(Data, 0, otherVector.Data, 0, Data.Length * Constants.SizeOfFloat);
}
}
/// <summary> /// <summary>
/// Adds a scalar to each element of the vector and stores the result in the result vector. /// Adds a scalar to each element of the vector and stores the result in the result vector.
/// </summary> /// </summary>
@ -312,8 +242,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] + scalar); index => dense._values[index] = _values[index] + scalar);
} }
} }
@ -328,7 +258,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, 1.0f, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, 1.0f, odense.Values, rdense.Values);
} }
else else
{ {
@ -397,8 +327,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] - scalar); index => dense._values[index] = _values[index] - scalar);
} }
} }
@ -413,7 +343,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
var odense = other as DenseVector; var odense = other as DenseVector;
if (rdense != null && odense != null) if (rdense != null && odense != null)
{ {
Control.LinearAlgebraProvider.AddVectorToScaledVector(Data, -1.0f, odense.Data, rdense.Data); Control.LinearAlgebraProvider.AddVectorToScaledVector(_values, -1.0f, odense.Values, rdense.Values);
} }
else else
{ {
@ -472,11 +402,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<float> Negate() public override Vector<float> Negate()
{ {
var result = new DenseVector(Count); var result = new DenseVector(_length);
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => result[index] = -Data[index]); index => result[index] = -_values[index]);
return result; return result;
} }
@ -496,7 +426,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, Data, denseResult.Data); Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult.Values);
} }
} }
@ -510,7 +440,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
var denseVector = other as DenseVector; var denseVector = other as DenseVector;
return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(Data, denseVector.Data); return denseVector == null ? base.DoDotProduct(other) : Control.LinearAlgebraProvider.DotProduct(_values, denseVector.Values);
} }
/// <summary> /// <summary>
@ -572,7 +502,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rightSide");
} }
return Control.LinearAlgebraProvider.DotProduct(leftSide.Data, rightSide.Data); return Control.LinearAlgebraProvider.DotProduct(leftSide.Values, rightSide.Values);
} }
/// <summary> /// <summary>
@ -602,16 +532,16 @@ namespace MathNet.Numerics.LinearAlgebra.Single
var denseResult = result as DenseVector; var denseResult = result as DenseVector;
if (denseResult == null) if (denseResult == null)
{ {
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
result.At(index, Data[index] % divisor); result.At(index, _values[index] % divisor);
} }
} }
else else
{ {
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
denseResult.Data[index] = Data[index] % divisor; denseResult._values[index] = _values[index] % divisor;
} }
} }
} }
@ -640,10 +570,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
var index = 0; var index = 0;
var min = Math.Abs(Data[index]); var min = Math.Abs(_values[index]);
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Math.Abs(Data[i]); var test = Math.Abs(_values[i]);
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -660,7 +590,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>The value of the absolute minimum element.</returns> /// <returns>The value of the absolute minimum element.</returns>
public override float AbsoluteMinimum() public override float AbsoluteMinimum()
{ {
return Math.Abs(Data[AbsoluteMinimumIndex()]); return Math.Abs(_values[AbsoluteMinimumIndex()]);
} }
/// <summary> /// <summary>
@ -669,7 +599,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>The value of the absolute maximum element.</returns> /// <returns>The value of the absolute maximum element.</returns>
public override float AbsoluteMaximum() public override float AbsoluteMaximum()
{ {
return Math.Abs(Data[AbsoluteMaximumIndex()]); return Math.Abs(_values[AbsoluteMaximumIndex()]);
} }
/// <summary> /// <summary>
@ -679,10 +609,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override int AbsoluteMaximumIndex() public override int AbsoluteMaximumIndex()
{ {
var index = 0; var index = 0;
var max = Math.Abs(Data[index]); var max = Math.Abs(_values[index]);
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
var test = Math.Abs(Data[i]); var test = Math.Abs(_values[i]);
if (test > max) if (test > max)
{ {
index = i; index = i;
@ -706,7 +636,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception> /// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
public override Vector<float> SubVector(int index, int length) public override Vector<float> SubVector(int index, int length)
{ {
if (index < 0 || index >= Count) if (index < 0 || index >= _length)
{ {
throw new ArgumentOutOfRangeException("index"); throw new ArgumentOutOfRangeException("index");
} }
@ -716,7 +646,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
if (index + length > Count) if (index + length > _length)
{ {
throw new ArgumentOutOfRangeException("length"); throw new ArgumentOutOfRangeException("length");
} }
@ -725,8 +655,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
CommonParallel.For( CommonParallel.For(
index, index,
index + length, index + length,
i => result.Data[i - index] = Data[i]); i => result._values[i - index] = _values[i]);
return result; return result;
} }
@ -743,7 +673,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
throw new ArgumentNullException("values"); throw new ArgumentNullException("values");
} }
if (values.Length != Count) if (values.Length != _length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "values");
} }
@ -751,7 +681,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
CommonParallel.For( CommonParallel.For(
0, 0,
values.Length, values.Length,
i => Data[i] = values[i]); i => _values[i] = values[i]);
} }
/// <summary> /// <summary>
@ -761,13 +691,13 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override int MaximumIndex() public override int MaximumIndex()
{ {
var index = 0; var index = 0;
var max = Data[0]; var max = _values[0];
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
if (max < Data[i]) if (max < _values[i])
{ {
index = i; index = i;
max = Data[i]; max = _values[i];
} }
} }
@ -781,13 +711,13 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override int MinimumIndex() public override int MinimumIndex()
{ {
var index = 0; var index = 0;
var min = Data[0]; var min = _values[0];
for (var i = 1; i < Count; i++) for (var i = 1; i < _length; i++)
{ {
if (min > Data[i]) if (min > _values[i])
{ {
index = i; index = i;
min = Data[i]; min = _values[i];
} }
} }
@ -802,9 +732,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
var sum = 0.0f; var sum = 0.0f;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Data[i]; sum += _values[i];
} }
return sum; return sum;
@ -818,9 +748,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
var sum = 0.0f; var sum = 0.0f;
for (var i = 0; i < Count; i++) for (var i = 0; i < _length; i++)
{ {
sum += Math.Abs(Data[i]); sum += Math.Abs(_values[i]);
} }
return sum; return sum;
@ -842,8 +772,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] * other[index]); index => dense._values[index] = _values[index] * other[index]);
} }
} }
@ -864,8 +794,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
CommonParallel.For( CommonParallel.For(
0, 0,
Data.Length, _values.Length,
index => dense.Data[index] = Data[index] / other[index]); index => dense._values[index] = _values[index] / other[index]);
} }
} }
@ -897,7 +827,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
for (var j = 0; j < v.Count; j++) for (var j = 0; j < v.Count; j++)
{ {
matrix.At(i, j, u.Data[i] * v.Data[j]); matrix.At(i, j, u._values[i] * v._values[j]);
} }
}); });
return matrix; return matrix;
@ -937,19 +867,19 @@ namespace MathNet.Numerics.LinearAlgebra.Single
if (2.0 == p) if (2.0 == p)
{ {
return Data.Aggregate(0f, SpecialFunctions.Hypotenuse); return _values.Aggregate(0f, SpecialFunctions.Hypotenuse);
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(Data, (i, v) => Math.Abs(v), Math.Max, 0f); return CommonParallel.Aggregate(_values, (i, v) => Math.Abs(v), Math.Max, 0f);
} }
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < Count; index++) for (var index = 0; index < _length; index++)
{ {
sum += Math.Pow(Math.Abs(Data[index]), p); sum += Math.Pow(Math.Abs(_values[index]), p);
} }
return (float)Math.Pow(sum, 1.0 / p); return (float)Math.Pow(sum, 1.0 / p);
@ -1115,29 +1045,5 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
#endregion #endregion
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
}
/// <summary>Gets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
internal protected override float At(int index)
{
return Data[index];
}
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <param name="value">The value to set.</param>
internal protected override void At(int index, float value)
{
Data[index] = value;
}
} }
} }

4
src/Numerics/LinearAlgebra/Single/DiagonalMatrix.cs

@ -377,12 +377,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single
return; return;
} }
if (_data.Length != denseSource.Data.Length) if (_data.Length != denseSource.Values.Length)
{ {
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source");
} }
Buffer.BlockCopy(denseSource.Data, 0, _data, 0, denseSource.Data.Length * Constants.SizeOfFloat); Buffer.BlockCopy(denseSource.Values, 0, _data, 0, denseSource.Values.Length * Constants.SizeOfFloat);
} }
/// <summary> /// <summary>

4
src/Numerics/LinearAlgebra/Single/Factorization/DenseCholesky.cs

@ -167,11 +167,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
Buffer.BlockCopy(dinput.Data, 0, dresult.Data, 0, dinput.Data.Length * Constants.SizeOfFloat); Buffer.BlockCopy(dinput.Values, 0, dresult.Values, 0, dinput.Values.Length * Constants.SizeOfFloat);
// Cholesky solve by overwriting result. // Cholesky solve by overwriting result.
var dfactor = (DenseMatrix)CholeskyFactor; var dfactor = (DenseMatrix)CholeskyFactor;
Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Data, 1); Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Values, 1);
} }
} }
} }

2
src/Numerics/LinearAlgebra/Single/Factorization/DenseGramSchmidt.cs

@ -216,7 +216,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do GramSchmidt factorization for dense vectors at the moment.");
} }
_provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Data, 1, dresult.Data); _provider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixQ.RowCount, MatrixQ.ColumnCount, null, dinput.Values, 1, dresult.Values);
} }
} }
} }

4
src/Numerics/LinearAlgebra/Single/Factorization/DenseLU.cs

@ -168,11 +168,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
} }
// Copy the contents of input to result. // Copy the contents of input to result.
Buffer.BlockCopy(dinput.Data, 0, dresult.Data, 0, dinput.Data.Length * Constants.SizeOfFloat); Buffer.BlockCopy(dinput.Values, 0, dresult.Values, 0, dinput.Values.Length * Constants.SizeOfFloat);
// LU solve by overwriting result. // LU solve by overwriting result.
var dfactors = (DenseMatrix)Factors; var dfactors = (DenseMatrix)Factors;
Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Values);
} }
/// <summary> /// <summary>

2
src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs

@ -187,7 +187,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
} }
} }
} }

6
src/Numerics/LinearAlgebra/Single/Factorization/DenseSvd.cs

@ -69,7 +69,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
VectorS = new DenseVector(nm); VectorS = new DenseVector(nm);
MatrixU = new DenseMatrix(matrix.RowCount); MatrixU = new DenseMatrix(matrix.RowCount);
MatrixVT = new DenseMatrix(matrix.ColumnCount); MatrixVT = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data);
} }
/// <summary> /// <summary>
@ -125,7 +125,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data);
} }
/// <summary> /// <summary>
@ -175,7 +175,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, 1, dresult.Data); Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Values, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Values, 1, dresult.Values);
} }
} }
} }

1
src/Numerics/LinearAlgebra/Single/SparseMatrix.cs

@ -97,6 +97,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// The number of columns. /// The number of columns.
/// </param> /// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param> /// <param name="value">The value which we assign to each element of the matrix.</param>
[Obsolete("Use a dense matrix instead.")]
public SparseMatrix(int rows, int columns, float value) public SparseMatrix(int rows, int columns, float value)
: this(rows, columns) : this(rows, columns)
{ {

503
src/Numerics/LinearAlgebra/Single/SparseVector.cs

@ -37,6 +37,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
using Generic; using Generic;
using NumberTheory; using NumberTheory;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -46,24 +47,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single
[Serializable] [Serializable]
public class SparseVector : Vector public class SparseVector : Vector
{ {
/// <summary> readonly SparseVectorStorage<float> _storage;
/// Gets the vector's internal data. The array containing the actual values; only the non-zero values are stored.
/// </summary>
private float[] _nonZeroValues = new float[0];
/// <summary> internal SparseVector(SparseVectorStorage<float> storage)
/// The indices of the non-zero entries. : base(storage)
/// </summary>
private int[] _nonZeroIndices = new int[0];
/// <summary>
/// Gets the number of non zero elements in the vector.
/// </summary>
/// <value>The number of non zero elements.</value>
public int NonZerosCount
{ {
get; _storage = storage;
private set;
} }
#region Constructors #region Constructors
@ -77,7 +66,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size) : base(size) public SparseVector(int size)
: this(new SparseVectorStorage<float>(size))
{ {
} }
@ -94,55 +84,23 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one. /// If <paramref name="size"/> is less than one.
/// </exception> /// </exception>
public SparseVector(int size, float value) : this(size) [Obsolete("Use a dense vector instead.")]
public SparseVector(int size, float value)
: this(new SparseVectorStorage<float>(size))
{ {
if (value == 0.0) if (value == 0.0)
{ {
// Skip adding values
return; return;
} }
// We already know that this vector is "full", let's allocate all needed memory var valueCount = _storage.ValueCount = size;
_nonZeroValues = new float[size]; var indices = _storage.Indices = new int[valueCount];
_nonZeroIndices = new int[size]; var values = _storage.Values = new float[valueCount];
NonZerosCount = size;
CommonParallel.For( for (int i = 0; i < values.Length; i++)
0,
Count,
index =>
{
_nonZeroValues[index] = value;
_nonZeroIndices[index] = index;
});
}
/// <summary>
/// Initializes a new instance of the <see cref="SparseVector"/> class by
/// copying the values from another.
/// </summary>
/// <param name="other">
/// The vector to create the new vector from.
/// </param>
public SparseVector(Vector<float> other) : this(other.Count)
{
var vector = other as SparseVector;
if (vector == null)
{ {
for (var i = 0; i < other.Count; i++) values[i] = value;
{ indices[i] = i;
this[i] = other.At(i);
}
}
else
{
_nonZeroValues = new float[vector.NonZerosCount];
_nonZeroIndices = new int[vector.NonZerosCount];
NonZerosCount = vector.NonZerosCount;
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
Buffer.BlockCopy(vector._nonZeroValues, 0, _nonZeroValues, 0, vector.NonZerosCount * Constants.SizeOfFloat);
Buffer.BlockCopy(vector._nonZeroIndices, 0, _nonZeroIndices, 0, vector.NonZerosCount * Constants.SizeOfInt);
} }
} }
@ -153,15 +111,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <param name="other"> /// <param name="other">
/// The vector to create the new vector from. /// The vector to create the new vector from.
/// </param> /// </param>
public SparseVector(SparseVector other) : this(other.Count) public SparseVector(Vector<float> other)
: this(new SparseVectorStorage<float>(other.Count))
{ {
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value other.Storage.CopyTo(Storage, skipClearing: true);
_nonZeroValues = new float[other.NonZerosCount];
_nonZeroIndices = new int[other.NonZerosCount];
NonZerosCount = other.NonZerosCount;
Buffer.BlockCopy(other._nonZeroValues, 0, _nonZeroValues, 0, other.NonZerosCount * Constants.SizeOfFloat);
Buffer.BlockCopy(other._nonZeroIndices, 0, _nonZeroIndices, 0, other.NonZerosCount * Constants.SizeOfInt);
} }
/// <summary> /// <summary>
@ -169,11 +122,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// </summary> /// </summary>
/// <param name="array">The array to create this vector from.</param> /// <param name="array">The array to create this vector from.</param>
/// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks> /// <remarks>The vector copy the array. Any changes to the vector will NOT change the array.</remarks>
public SparseVector(IList<float> array) : this(array.Count) public SparseVector(IList<float> array)
: this(new SparseVectorStorage<float>(array.Count))
{ {
for (var i = 0; i < array.Count; i++) for (var i = 0; i < array.Count; i++)
{ {
this[i] = array[i]; Storage.At(i, array[i]);
} }
} }
@ -186,9 +140,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override Matrix<float> ToColumnMatrix() public override Matrix<float> ToColumnMatrix()
{ {
var matrix = new SparseMatrix(Count, 1); var matrix = new SparseMatrix(Count, 1);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(_nonZeroIndices[i], 0, _nonZeroValues[i]); matrix.At(_storage.Indices[i], 0, _storage.Values[i]);
} }
return matrix; return matrix;
@ -201,44 +155,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override Matrix<float> ToRowMatrix() public override Matrix<float> ToRowMatrix()
{ {
var matrix = new SparseMatrix(1, Count); var matrix = new SparseMatrix(1, Count);
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
matrix.At(0, _nonZeroIndices[i], _nonZeroValues[i]); matrix.At(0, _storage.Indices[i], _storage.Values[i]);
} }
return matrix; return matrix;
} }
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
/// <param name="index">The index of the value to get or set.</param>
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
/// <exception cref="IndexOutOfRangeException">If <paramref name="index"/> is negative or
/// greater than the size of the vector.</exception>
public override float this[int index]
{
get
{
// If index is out of bounds
if ((index < 0) || (index >= Count))
{
throw new IndexOutOfRangeException();
}
return At(index);
}
set
{
// If index is out of bounds
if ((index < 0) || (index >= Count))
{
throw new IndexOutOfRangeException();
}
At(index, value);
}
}
/// <summary> /// <summary>
/// Creates a matrix with the given dimensions using the same storage type /// Creates a matrix with the given dimensions using the same storage type
/// as this vector. /// as this vector.
@ -272,68 +196,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single
return new SparseVector(size); return new SparseVector(size);
} }
/// <summary>
/// Resets all values to zero.
/// </summary>
public override void Clear()
{
NonZerosCount = 0;
}
/// <summary>
/// Copies the values of this vector into the target vector.
/// </summary>
/// <param name="target">
/// The vector to copy elements into.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="target"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="target"/> is not the same size as this vector.
/// </exception>
public override void CopyTo(Vector<float> target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (Count != target.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target");
}
if (ReferenceEquals(this, target))
{
return;
}
var otherVector = target as SparseVector;
if (otherVector == null)
{
target.Clear();
for (var index = 0; index < NonZerosCount; index++)
{
target.At(_nonZeroIndices[index], _nonZeroValues[index]);
}
}
else
{
// Lets copy only needed data. Portion of needed data is determined by NonZerosCount value
otherVector._nonZeroValues = new float[NonZerosCount];
otherVector._nonZeroIndices = new int[NonZerosCount];
otherVector.NonZerosCount = NonZerosCount;
if (NonZerosCount != 0)
{
Buffer.BlockCopy(_nonZeroValues, 0, otherVector._nonZeroValues, 0, NonZerosCount*Constants.SizeOfFloat);
Buffer.BlockCopy(_nonZeroIndices, 0, otherVector._nonZeroIndices, 0, NonZerosCount*Constants.SizeOfInt);
}
}
}
#region Operators and supplementary functions #region Operators and supplementary functions
/// <summary> /// <summary>
@ -371,15 +233,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
//populate the non zero values from this //populate the non zero values from this
for (int j = 0; j < NonZerosCount; j++) for (int j = 0; j < _storage.ValueCount; j++)
{ {
vnonZeroValues[_nonZeroIndices[j]] = _nonZeroValues[j] + scalar; vnonZeroValues[_storage.Indices[j]] = _storage.Values[j] + scalar;
} }
//assign this vectors arrary to the new arrays. //assign this vectors arrary to the new arrays.
_nonZeroValues = vnonZeroValues; _storage.Values = vnonZeroValues;
_nonZeroIndices = vnonZeroIndices; _storage.Indices = vnonZeroIndices;
NonZerosCount = Count; _storage.ValueCount = Count;
} }
else else
@ -421,22 +283,22 @@ namespace MathNet.Numerics.LinearAlgebra.Single
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] += otherSparse._nonZeroValues[j++]; _storage.Values[i++] += otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != 0.0) if (otherValue != 0.0)
{ {
InsertAtUnchecked(i++, otherSparse._nonZeroIndices[j], otherValue); InsertAtUnchecked(i++, otherSparse._storage.Indices[j], otherValue);
} }
j++; j++;
} }
@ -446,25 +308,25 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] + otherSparse.At(next)); result.At(next, _storage.Values[i] + otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) + otherSparse._nonZeroValues[j]); result.At(next, At(next) + otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -567,22 +429,22 @@ namespace MathNet.Numerics.LinearAlgebra.Single
if (ReferenceEquals(this, resultSparse)) if (ReferenceEquals(this, resultSparse))
{ {
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (i < NonZerosCount && j < otherSparse.NonZerosCount && _nonZeroIndices[i] == otherSparse._nonZeroIndices[j]) if (i < _storage.ValueCount && j < otherSparse._storage.ValueCount && _storage.Indices[i] == otherSparse._storage.Indices[j])
{ {
_nonZeroValues[i++] -= otherSparse._nonZeroValues[j++]; _storage.Values[i++] -= otherSparse._storage.Values[j++];
} }
else if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) else if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
i++; i++;
} }
else else
{ {
var otherValue = otherSparse._nonZeroValues[j]; var otherValue = otherSparse._storage.Values[j];
if (otherValue != 0.0) if (otherValue != 0.0)
{ {
InsertAtUnchecked(i++, otherSparse._nonZeroIndices[j], -otherValue); InsertAtUnchecked(i++, otherSparse._storage.Indices[j], -otherValue);
} }
j++; j++;
} }
@ -592,25 +454,25 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
result.Clear(); result.Clear();
int i = 0, j = 0, last = -1; int i = 0, j = 0, last = -1;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] <= otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] <= otherSparse._storage.Indices[j])
{ {
var next = _nonZeroIndices[i]; var next = _storage.Indices[i];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, _nonZeroValues[i] - otherSparse.At(next)); result.At(next, _storage.Values[i] - otherSparse.At(next));
} }
i++; i++;
} }
else else
{ {
var next = otherSparse._nonZeroIndices[j]; var next = otherSparse._storage.Indices[j];
if (next != last) if (next != last)
{ {
last = next; last = next;
result.At(next, At(next) - otherSparse._nonZeroValues[j]); result.At(next, At(next) - otherSparse._storage.Values[j]);
} }
j++; j++;
} }
@ -669,23 +531,18 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <remarks>Added as an alternative to the unary negation operator.</remarks> /// <remarks>Added as an alternative to the unary negation operator.</remarks>
public override Vector<float> Negate() public override Vector<float> Negate()
{ {
var result = new SparseVector(Count) var result = new SparseVectorStorage<float>(Count);
{ var valueCount = result.ValueCount = _storage.ValueCount;
_nonZeroValues = new float[NonZerosCount], var indices = result.Indices = new int[valueCount];
_nonZeroIndices = new int[NonZerosCount], var values = result.Values = new float[valueCount];
NonZerosCount = NonZerosCount
};
if (NonZerosCount != 0) if (valueCount != 0)
{ {
CommonParallel.For( CommonParallel.For(0, valueCount, index => values[index] = -_storage.Values[index]);
0, Buffer.BlockCopy(_storage.Indices, 0, indices, 0, valueCount * Constants.SizeOfInt);
NonZerosCount,
index => result._nonZeroValues[index] = -_nonZeroValues[index]);
Buffer.BlockCopy(_nonZeroIndices, 0, result._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt);
} }
return result; return new SparseVector(result);
} }
/// <summary> /// <summary>
@ -706,7 +563,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
var copy = new SparseVector(this); var copy = new SparseVector(this);
Control.LinearAlgebraProvider.ScaleArray(scalar, copy._nonZeroValues, copy._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, copy._storage.Values, copy._storage.Values);
return copy; return copy;
} }
@ -741,23 +598,23 @@ namespace MathNet.Numerics.LinearAlgebra.Single
if (sparseResult == null) if (sparseResult == null)
{ {
result.Clear(); result.Clear();
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
result.At(_nonZeroIndices[index], scalar * _nonZeroValues[index]); result.At(_storage.Indices[index], scalar * _storage.Values[index]);
} }
} }
else else
{ {
if (!ReferenceEquals(this, result)) if (!ReferenceEquals(this, result))
{ {
sparseResult.NonZerosCount = NonZerosCount; sparseResult._storage.ValueCount = _storage.ValueCount;
sparseResult._nonZeroIndices = new int[NonZerosCount]; sparseResult._storage.Indices = new int[_storage.ValueCount];
Buffer.BlockCopy(_nonZeroIndices, 0, sparseResult._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); Buffer.BlockCopy(_storage.Indices, 0, sparseResult._storage.Indices, 0, _storage.ValueCount * Constants.SizeOfInt);
sparseResult._nonZeroValues = new float[NonZerosCount]; sparseResult._storage.Values = new float[_storage.ValueCount];
Buffer.BlockCopy(_nonZeroValues, 0, sparseResult._nonZeroValues, 0, NonZerosCount * Constants.SizeOfFloat); Buffer.BlockCopy(_storage.Values, 0, sparseResult._storage.Values, 0, _storage.ValueCount * Constants.SizeOfFloat);
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues, sparseResult._nonZeroValues); Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._storage.Values, sparseResult._storage.Values);
} }
} }
@ -776,16 +633,16 @@ namespace MathNet.Numerics.LinearAlgebra.Single
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * _nonZeroValues[i]; result += _storage.Values[i] * _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i] * other.At(_nonZeroIndices[i]); result += _storage.Values[i] * other.At(_storage.Indices[i]);
} }
} }
@ -880,17 +737,17 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
if (ReferenceEquals(this, result)) if (ReferenceEquals(this, result))
{ {
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
_nonZeroValues[index] %= divisor; _storage.Values[index] %= divisor;
} }
} }
else else
{ {
result.Clear(); result.Clear();
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
result.At(_nonZeroIndices[index], _nonZeroValues[index] % divisor); result.At(_storage.Indices[index], _storage.Values[index] % divisor);
} }
} }
} }
@ -918,17 +775,17 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>The index of absolute minimum element.</returns> /// <returns>The index of absolute minimum element.</returns>
public override int AbsoluteMinimumIndex() public override int AbsoluteMinimumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
// No non-zero elements. Return 0 // No non-zero elements. Return 0
return 0; return 0;
} }
var index = 0; var index = 0;
var min = Math.Abs(_nonZeroValues[index]); var min = Math.Abs(_storage.Values[index]);
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
var test = Math.Abs(_nonZeroValues[i]); var test = Math.Abs(_storage.Values[i]);
if (test < min) if (test < min)
{ {
index = i; index = i;
@ -936,7 +793,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -1006,23 +863,23 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>The index of absolute maximum element.</returns> /// <returns>The index of absolute maximum element.</returns>
public override int MaximumIndex() public override int MaximumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return 0; return 0;
} }
var index = 0; var index = 0;
var max = _nonZeroValues[0]; var max = _storage.Values[0];
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
if (max < _nonZeroValues[i]) if (max < _storage.Values[i])
{ {
index = i; index = i;
max = _nonZeroValues[i]; max = _storage.Values[i];
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -1031,23 +888,23 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <returns>The index of minimum element.</returns> /// <returns>The index of minimum element.</returns>
public override int MinimumIndex() public override int MinimumIndex()
{ {
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return 0; return 0;
} }
var index = 0; var index = 0;
var min = _nonZeroValues[0]; var min = _storage.Values[0];
for (var i = 1; i < NonZerosCount; i++) for (var i = 1; i < _storage.ValueCount; i++)
{ {
if (min > _nonZeroValues[i]) if (min > _storage.Values[i])
{ {
index = i; index = i;
min = _nonZeroValues[i]; min = _storage.Values[i];
} }
} }
return _nonZeroIndices[index]; return _storage.Indices[index];
} }
/// <summary> /// <summary>
@ -1057,9 +914,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override float Sum() public override float Sum()
{ {
var result = 0.0f; var result = 0.0f;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += _nonZeroValues[i]; result += _storage.Values[i];
} }
return result; return result;
@ -1072,9 +929,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override float SumMagnitudes() public override float SumMagnitudes()
{ {
var result = 0.0f; var result = 0.0f;
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
result += Math.Abs(_nonZeroValues[i]); result += Math.Abs(_storage.Values[i]);
} }
return result; return result;
@ -1089,17 +946,17 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] *= _nonZeroValues[i]; _storage.Values[i] *= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, other.At(index) * _nonZeroValues[i]); result.At(index, other.At(index) * _storage.Values[i]);
} }
} }
} }
@ -1113,17 +970,17 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
if (ReferenceEquals(this, other)) if (ReferenceEquals(this, other))
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
_nonZeroValues[i] /= _nonZeroValues[i]; _storage.Values[i] /= _storage.Values[i];
} }
} }
else else
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
var index = _nonZeroIndices[i]; var index = _storage.Indices[i];
result.At(index, _nonZeroValues[i] / other.At(index)); result.At(index, _storage.Values[i] / other.At(index));
} }
} }
} }
@ -1149,13 +1006,13 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
var matrix = new SparseMatrix(u.Count, v.Count); var matrix = new SparseMatrix(u.Count, v.Count);
for (var i = 0; i < u.NonZerosCount; i++) for (var i = 0; i < u._storage.ValueCount; i++)
{ {
for (var j = 0; j < v.NonZerosCount; j++) for (var j = 0; j < v._storage.ValueCount; j++)
{ {
if (u._nonZeroIndices[i] == v._nonZeroIndices[j]) if (u._storage.Indices[i] == v._storage.Indices[j])
{ {
matrix.At(i, j, u._nonZeroValues[i] * v._nonZeroValues[j]); matrix.At(i, j, u._storage.Values[i] * v._storage.Values[j]);
} }
} }
} }
@ -1191,25 +1048,25 @@ namespace MathNet.Numerics.LinearAlgebra.Single
throw new ArgumentOutOfRangeException("p"); throw new ArgumentOutOfRangeException("p");
} }
if (NonZerosCount == 0) if (_storage.ValueCount == 0)
{ {
return 0.0f; return 0.0f;
} }
if (2.0 == p) if (2.0 == p)
{ {
return _nonZeroValues.Aggregate(0f, SpecialFunctions.Hypotenuse); return _storage.Values.Aggregate(0f, SpecialFunctions.Hypotenuse);
} }
if (Double.IsPositiveInfinity(p)) if (Double.IsPositiveInfinity(p))
{ {
return CommonParallel.Aggregate(0, NonZerosCount, i => Math.Abs(_nonZeroValues[i]), Math.Max, 0f); return CommonParallel.Aggregate(0, _storage.ValueCount, i => Math.Abs(_storage.Values[i]), Math.Max, 0f);
} }
var sum = 0.0; var sum = 0.0;
for (var index = 0; index < NonZerosCount; index++) for (var index = 0; index < _storage.ValueCount; index++)
{ {
sum += Math.Pow(Math.Abs(_nonZeroValues[index]), p); sum += Math.Pow(Math.Abs(_storage.Values[index]), p);
} }
return (float)Math.Pow(sum, 1.0 / p); return (float)Math.Pow(sum, 1.0 / p);
@ -1376,97 +1233,33 @@ namespace MathNet.Numerics.LinearAlgebra.Single
#endregion #endregion
/// <summary>
/// Gets the value at the given index.
/// </summary>
/// <param name="index">Value real index in array</param>
/// <returns>The value at the given index.</returns>
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;
}
/// <summary>
/// Delete, Add or Update the value in NonZeroValues and NonZeroIndices
/// </summary>
/// <param name="index">Value real index in array</param>
/// <param name="value">The value to set.</param>
/// <remarks>This method assume that index is between 0 and Array Size</remarks>
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);
if (itemIndex >= 0)
{
// Item already exist at itemIndex
if (value == 0.0)
{
RemoveAtUnchecked(itemIndex);
}
else
{
_nonZeroValues[itemIndex] = value;
}
}
else
{
if (value != 0.0)
{
InsertAtUnchecked(~itemIndex, index, value);
}
}
}
private void InsertAtUnchecked(int itemIndex, int index, float value) private void InsertAtUnchecked(int itemIndex, int index, float value)
{ {
// Check if the storage needs to be increased // Check if the storage needs to be increased
if ((NonZerosCount == _nonZeroValues.Length) && (NonZerosCount < Count)) if ((_storage.ValueCount == _storage.Values.Length) && (_storage.ValueCount < Count))
{ {
// Value and Indices arrays are completely full so we increase the size // Value and Indices arrays are completely full so we increase the size
var size = Math.Min(_nonZeroValues.Length + GrowthSize(), Count); var size = Math.Min(_storage.Values.Length + GrowthSize(), Count);
Array.Resize(ref _nonZeroValues, size); Array.Resize(ref _storage.Values, size);
Array.Resize(ref _nonZeroIndices, size); Array.Resize(ref _storage.Indices, size);
} }
// Move all values (with a position larger than index) in the value array // Move all values (with a position larger than index) in the value array
// to the next position // to the next position
// Move all values (with a position larger than index) in the columIndices // Move all values (with a position larger than index) in the columIndices
// array to the next position // array to the next position
for (var i = NonZerosCount - 1; i > itemIndex - 1; i--) for (var i = _storage.ValueCount - 1; i > itemIndex - 1; i--)
{ {
_nonZeroValues[i + 1] = _nonZeroValues[i]; _storage.Values[i + 1] = _storage.Values[i];
_nonZeroIndices[i + 1] = _nonZeroIndices[i]; _storage.Indices[i + 1] = _storage.Indices[i];
} }
// Add the value and the column index // Add the value and the column index
_nonZeroValues[itemIndex] = value; _storage.Values[itemIndex] = value;
_nonZeroIndices[itemIndex] = index; _storage.Indices[itemIndex] = index;
// increase the number of non-zero numbers by one // increase the number of non-zero numbers by one
NonZerosCount += 1; _storage.ValueCount += 1;
}
private void RemoveAtUnchecked(int itemIndex)
{
// Value is zero. Let's delete it from Values and Indices array
for (var i = itemIndex + 1; i < NonZerosCount; i++)
{
_nonZeroValues[i - 1] = _nonZeroValues[i];
_nonZeroIndices[i - 1] = _nonZeroIndices[i];
}
NonZerosCount -= 1;
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((NonZerosCount > 1024) && (NonZerosCount < _nonZeroIndices.Length / 2))
{
Array.Resize(ref _nonZeroValues, NonZerosCount);
Array.Resize(ref _nonZeroIndices, NonZerosCount);
}
} }
/// <summary> /// <summary>
@ -1477,19 +1270,19 @@ namespace MathNet.Numerics.LinearAlgebra.Single
private int GrowthSize() private int GrowthSize()
{ {
int delta; int delta;
if (_nonZeroValues.Length > 1024) if (_storage.Values.Length > 1024)
{ {
delta = _nonZeroValues.Length / 4; delta = _storage.Values.Length / 4;
} }
else else
{ {
if (_nonZeroValues.Length > 256) if (_storage.Values.Length > 256)
{ {
delta = 512; delta = 512;
} }
else else
{ {
delta = _nonZeroValues.Length > 64 ? 128 : 32; delta = _storage.Values.Length > 64 ? 128 : 32;
} }
} }
@ -1502,7 +1295,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
if (Count > 20) if (Count > 20)
{ {
return String.Format("SparseVectorOfSingle({0},{1},{2})", Count, NonZerosCount, GetHashCode()); return String.Format("SparseVectorOfSingle({0},{1},{2})", Count, _storage.ValueCount, GetHashCode());
} }
return base.ToString(format, formatProvider); return base.ToString(format, formatProvider);
@ -1516,14 +1309,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
var hashNum = Math.Min(NonZerosCount, 20); var hashNum = Math.Min(_storage.ValueCount, 20);
long hash = 0; long hash = 0;
for (var i = 0; i < hashNum; i++) for (var i = 0; i < hashNum; i++)
{ {
#if PORTABLE #if PORTABLE
hash ^= Precision.DoubleToInt64Bits(this._nonZeroValues[i].GetHashCode()); hash ^= Precision.DoubleToInt64Bits(this._storage.Values[i].GetHashCode());
#else #else
hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= BitConverter.DoubleToInt64Bits(_storage.Values[i].GetHashCode());
#endif #endif
} }
@ -1567,27 +1360,27 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
int i = 0, j = 0; int i = 0, j = 0;
while (i < NonZerosCount || j < otherSparse.NonZerosCount) while (i < _storage.ValueCount || j < otherSparse._storage.ValueCount)
{ {
if (j >= otherSparse.NonZerosCount || i < NonZerosCount && _nonZeroIndices[i] < otherSparse._nonZeroIndices[j]) if (j >= otherSparse._storage.ValueCount || i < _storage.ValueCount && _storage.Indices[i] < otherSparse._storage.Indices[j])
{ {
if (_nonZeroValues[i++] != 0f) if (_storage.Values[i++] != 0f)
{ {
return false; return false;
} }
continue; continue;
} }
if (i >= NonZerosCount || j < otherSparse.NonZerosCount && otherSparse._nonZeroIndices[j] < _nonZeroIndices[i]) if (i >= _storage.ValueCount || j < otherSparse._storage.ValueCount && otherSparse._storage.Indices[j] < _storage.Indices[i])
{ {
if (otherSparse._nonZeroValues[j++] != 0f) if (otherSparse._storage.Values[j++] != 0f)
{ {
return false; return false;
} }
continue; continue;
} }
if (!_nonZeroValues[i].AlmostEqual(otherSparse._nonZeroValues[j])) if (!_storage.Values[i].AlmostEqual(otherSparse._storage.Values[j]))
{ {
return false; return false;
} }
@ -1615,9 +1408,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// </remarks> /// </remarks>
public override IEnumerable<Tuple<int, float>> GetIndexedEnumerator() public override IEnumerable<Tuple<int, float>> GetIndexedEnumerator()
{ {
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
yield return new Tuple<int, float>(_nonZeroIndices[i], _nonZeroValues[i]); yield return new Tuple<int, float>(_storage.Indices[i], _storage.Values[i]);
} }
} }
@ -1630,9 +1423,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override float[] ToArray() public override float[] ToArray()
{ {
var ret = new float[Count]; var ret = new float[Count];
for (var i = 0; i < NonZerosCount; i++) for (var i = 0; i < _storage.ValueCount; i++)
{ {
ret[_nonZeroIndices[i]] = _nonZeroValues[i]; ret[_storage.Indices[i]] = _storage.Values[i];
} }
return ret; return ret;

12
src/Numerics/LinearAlgebra/Single/Vector.cs

@ -30,6 +30,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
using Distributions; using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Storage;
using Threading; using Threading;
/// <summary> /// <summary>
@ -40,16 +41,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the Vector class. /// Initializes a new instance of the Vector class.
/// Constructs a <strong>Vector</strong> with the given size.
/// </summary> /// </summary>
/// <param name="size"> protected Vector(VectorStorage<float> storage)
/// The size of the <strong>Vector</strong> to construct. : base(storage)
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="size"/> is less than one.
/// </exception>
protected Vector(int size)
: base(size)
{ {
} }

8
src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs

@ -90,7 +90,6 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
throw new ArgumentException(message, "target"); throw new ArgumentException(message, "target");
} }
//Buffer.BlockCopy(Data, 0, target.Data, 0, Data.Length * System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)));
Array.Copy(Data, 0, target.Data, 0, Data.Length); Array.Copy(Data, 0, target.Data, 0, Data.Length);
} }
@ -113,14 +112,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
void CopySubVectorTo(DenseVectorStorage<T> target, void CopySubVectorTo(DenseVectorStorage<T> target,
int sourceIndex, int targetIndex, int count) int sourceIndex, int targetIndex, int count)
{ {
if (ReferenceEquals(this, target))
{
throw new NotSupportedException();
}
ValidateSubVectorRange(target, sourceIndex, targetIndex, count); ValidateSubVectorRange(target, sourceIndex, targetIndex, count);
//Buffer.BlockCopy(Data, sourceIndex, target.Data, targetIndex, count * System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)));
Array.Copy(Data, sourceIndex, target.Data, targetIndex, count); Array.Copy(Data, sourceIndex, target.Data, targetIndex, count);
} }
} }

333
src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs

@ -0,0 +1,333 @@
using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Storage
{
[Serializable]
public class SparseVectorStorage<T> : VectorStorage<T>
where T : struct, IEquatable<T>, IFormattable
{
// [ruegg] public fields are OK here
readonly T _zero;
/// <summary>
/// Array that contains the indices of the non-zero values.
/// </summary>
public int[] Indices;
/// <summary>
/// Array that contains the non-zero elements of the vector.
/// </summary>
public T[] Values;
/// <summary>
/// Gets the number of non-zero elements in the vector.
/// </summary>
public int ValueCount;
internal SparseVectorStorage(int length, T zero = default(T))
: base(length)
{
_zero = zero;
Indices = new int[0];
Values = new T[0];
ValueCount = 0;
}
/// <summary>
/// Retrieves the requested element without range checking.
/// </summary>
public override T At(int index)
{
// Search if item idex exists in NonZeroIndices array in range "0 - nonzero values count"
var itemIndex = Array.BinarySearch(Indices, 0, ValueCount, index);
return itemIndex >= 0 ? Values[itemIndex] : _zero;
}
/// <summary>
/// Sets the element without range checking.
/// </summary>
public override void At(int index, T value)
{
// Search if "index" already exists in range "0 - nonzero values count"
var itemIndex = Array.BinarySearch(Indices, 0, ValueCount, index);
if (itemIndex >= 0)
{
// Non-zero item found in matrix
if (_zero.Equals(value))
{
// Delete existing item
RemoveAtIndexUnchecked(itemIndex);
}
else
{
// Update item
Values[itemIndex] = value;
}
}
else
{
// Item not found. Add new value
if (!_zero.Equals(value))
{
InsertAtIndexUnchecked(~itemIndex, index, value);
}
}
}
void InsertAtIndexUnchecked(int itemIndex, int index, T value)
{
// Check if the storage needs to be increased
if ((ValueCount == Values.Length) && (ValueCount < Length))
{
// Value and Indices arrays are completely full so we increase the size
var size = Math.Min(Values.Length + GrowthSize(), Length);
Array.Resize(ref Values, size);
Array.Resize(ref Indices, size);
}
// Move all values (with a position larger than index) in the value array to the next position
// Move all values (with a position larger than index) in the columIndices array to the next position
Array.Copy(Values, itemIndex, Values, itemIndex + 1, ValueCount - itemIndex);
Array.Copy(Indices, itemIndex, Indices, itemIndex + 1, ValueCount - itemIndex);
// Add the value and the column index
Values[itemIndex] = value;
Indices[itemIndex] = index;
// increase the number of non-zero numbers by one
ValueCount += 1;
}
void RemoveAtIndexUnchecked(int itemIndex)
{
// Value is zero. Let's delete it from Values and Indices array
Array.Copy(Values, itemIndex + 1, Values, itemIndex, ValueCount - itemIndex - 1);
Array.Copy(Indices, itemIndex + 1, Indices, itemIndex, ValueCount - itemIndex - 1);
ValueCount -= 1;
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((ValueCount > 1024) && (ValueCount < Indices.Length / 2))
{
Array.Resize(ref Values, ValueCount);
Array.Resize(ref Indices, ValueCount);
}
}
/// <summary>
/// Calculates the amount with which to grow the storage array's if they need to be
/// increased in size.
/// </summary>
/// <returns>The amount grown.</returns>
int GrowthSize()
{
int delta;
if (Values.Length > 1024)
{
delta = Values.Length / 4;
}
else
{
if (Values.Length > 256)
{
delta = 512;
}
else
{
delta = Values.Length > 64 ? 128 : 32;
}
}
return delta;
}
public override void Clear()
{
ValueCount = 0;
}
public override void Clear(int index, int count)
{
if (index == 0 && count == Length)
{
Clear();
return;
}
var first = Array.BinarySearch(Indices, 0, ValueCount, index);
var last = Array.BinarySearch(Indices, 0, ValueCount, index + count - 1);
if (first < 0) first = ~first;
if (last < 0) last = ~last - 1;
int itemCount = last - first + 1;
if (itemCount > 0)
{
Array.Copy(Values, first + count, Values, first, ValueCount - first - count);
Array.Copy(Indices, first + count, Indices, first, ValueCount - first - count);
ValueCount -= count;
}
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((ValueCount > 1024) && (ValueCount < Indices.Length / 2))
{
Array.Resize(ref Values, ValueCount);
Array.Resize(ref Indices, ValueCount);
}
}
/// <remarks>Parameters assumed to be validated already.</remarks>
public override void CopyTo(VectorStorage<T> target, bool skipClearing = false)
{
var sparseTarget = target as SparseVectorStorage<T>;
if (sparseTarget != null)
{
CopyTo(sparseTarget);
return;
}
// FALL BACK
if (!skipClearing)
{
target.Clear();
}
if (ValueCount != 0)
{
for (int i = 0; i < ValueCount; i++)
{
target.At(Indices[i], Values[i]);
}
}
}
void CopyTo(SparseVectorStorage<T> target)
{
if (ReferenceEquals(this, target))
{
return;
}
if (Length != target.Length)
{
var message = string.Format(Resources.ArgumentMatrixDimensions2, Length, target.Length);
throw new ArgumentException(message, "target");
}
target.ValueCount = ValueCount;
target.Values = new T[ValueCount];
target.Indices = new int[ValueCount];
if (ValueCount != 0)
{
Array.Copy(Values, target.Values, ValueCount);
Buffer.BlockCopy(Indices, 0, target.Indices, 0, ValueCount * Constants.SizeOfInt);
}
}
public override void CopySubVectorTo(VectorStorage<T> target,
int sourceIndex, int targetIndex, int count,
bool skipClearing = false)
{
ValidateSubVectorRange(target, sourceIndex, targetIndex, count);
var sparseTarget = target as SparseVectorStorage<T>;
if (sparseTarget != null)
{
CopySubVectorTo(sparseTarget, sourceIndex, targetIndex, count, skipClearing);
return;
}
// FALL BACK
var offset = targetIndex - sourceIndex;
var sourceFirst = Array.BinarySearch(Indices, 0, ValueCount, sourceIndex);
var sourceLast = Array.BinarySearch(Indices, 0, ValueCount, sourceIndex + count - 1);
if (sourceFirst < 0) sourceFirst = ~sourceFirst;
if (sourceLast < 0) sourceLast = ~sourceLast - 1;
if (!skipClearing)
{
target.Clear(targetIndex, count);
}
for (int i = sourceFirst; i <= sourceLast; i++)
{
target.At(Indices[i] + offset, Values[i]);
}
}
void CopySubVectorTo(SparseVectorStorage<T> target,
int sourceIndex, int targetIndex, int count,
bool skipClearing)
{
var offset = targetIndex - sourceIndex;
var sourceFirst = Array.BinarySearch(Indices, 0, ValueCount, sourceIndex);
var sourceLast = Array.BinarySearch(Indices, 0, ValueCount, sourceIndex + count - 1);
if (sourceFirst < 0) sourceFirst = ~sourceFirst;
if (sourceLast < 0) sourceLast = ~sourceLast - 1;
int sourceCount = sourceLast - sourceFirst + 1;
// special case when copying to itself
if (ReferenceEquals(this, target))
{
var values = new T[sourceCount];
var indices = new int[sourceCount];
Array.Copy(Values, sourceFirst, values, 0, sourceCount);
for (int i = 0; i < indices.Length; i++)
{
indices[i] = Indices[i + sourceFirst];
}
if (!skipClearing)
{
Clear(targetIndex, count);
}
for (int i = sourceFirst; i <= sourceLast; i++)
{
At(indices[i] + offset, values[i]);
}
return;
}
// special case for empty target - much faster
if (target.ValueCount == 0)
{
var values = new T[sourceCount];
var indices = new int[sourceCount];
Array.Copy(Values, sourceFirst, values, 0, sourceCount);
for (int i = 0; i < indices.Length; i++)
{
indices[i] = Indices[i + sourceFirst] + offset;
}
target.ValueCount = sourceCount;
target.Values = values;
target.Indices = indices;
return;
}
if (!skipClearing)
{
target.Clear(targetIndex, count);
}
for (int i = sourceFirst; i <= sourceLast; i++)
{
target.At(Indices[i] + offset, Values[i]);
}
}
}
}

16
src/Numerics/LinearAlgebra/Storage/VectorStorage.cs

@ -184,12 +184,22 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
throw new ArgumentNullException("target"); throw new ArgumentNullException("target");
} }
ValidateSubVectorRange(target, sourceIndex, targetIndex, count);
if (ReferenceEquals(this, target)) if (ReferenceEquals(this, target))
{ {
throw new NotSupportedException(); var tmp = new T[count];
} for (int i = 0; i < tmp.Length; i++)
{
tmp[i] = At(i + sourceIndex);
}
for (int i = 0; i < tmp.Length; i++)
{
At(i + targetIndex, tmp[i]);
}
ValidateSubVectorRange(target, sourceIndex, targetIndex, count); return;
}
for (int i = sourceIndex, ii = targetIndex; i < sourceIndex + count; i++, ii++) for (int i = sourceIndex, ii = targetIndex; i < sourceIndex + count; i++, ii++)
{ {

1
src/Numerics/Numerics.csproj

@ -124,6 +124,7 @@
<Compile Include="Distributions\Multivariate\InverseWishart.cs" /> <Compile Include="Distributions\Multivariate\InverseWishart.cs" />
<Compile Include="Distributions\Multivariate\MatrixNormal.cs" /> <Compile Include="Distributions\Multivariate\MatrixNormal.cs" />
<Compile Include="Distributions\Multivariate\Wishart.cs" /> <Compile Include="Distributions\Multivariate\Wishart.cs" />
<Compile Include="LinearAlgebra\Storage\SparseVectorStorage.cs" />
<Compile Include="LinearAlgebra\Storage\DenseVectorStorage.cs" /> <Compile Include="LinearAlgebra\Storage\DenseVectorStorage.cs" />
<Compile Include="LinearAlgebra\Storage\MatrixStorage.Validation.cs" /> <Compile Include="LinearAlgebra\Storage\MatrixStorage.Validation.cs" />
<Compile Include="LinearAlgebra\Complex32\ExtensionMethods.cs" /> <Compile Include="LinearAlgebra\Complex32\ExtensionMethods.cs" />

3
src/Portable/Portable.csproj

@ -906,6 +906,9 @@
<Compile Include="..\Numerics\LinearAlgebra\Storage\SparseCompressedRowMatrixStorage.cs"> <Compile Include="..\Numerics\LinearAlgebra\Storage\SparseCompressedRowMatrixStorage.cs">
<Link>LinearAlgebra\Storage\SparseCompressedRowMatrixStorage.cs</Link> <Link>LinearAlgebra\Storage\SparseCompressedRowMatrixStorage.cs</Link>
</Compile> </Compile>
<Compile Include="..\Numerics\LinearAlgebra\Storage\SparseVectorStorage.cs">
<Link>LinearAlgebra\Storage\SparseVectorStorage.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Storage\VectorStorage.cs"> <Compile Include="..\Numerics\LinearAlgebra\Storage\VectorStorage.cs">
<Link>LinearAlgebra\Storage\VectorStorage.cs</Link> <Link>LinearAlgebra\Storage\VectorStorage.cs</Link>
</Compile> </Compile>

25
src/UnitTests/LinearAlgebraTests/Complex/SparseVectorTest.cs

@ -35,6 +35,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
using System.Numerics; using System.Numerics;
using LinearAlgebra.Complex; using LinearAlgebra.Complex;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Storage;
using NUnit.Framework; using NUnit.Framework;
/// <summary> /// <summary>
@ -273,40 +274,41 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
public void CheckSparseMechanismBySettingValues() public void CheckSparseMechanismBySettingValues()
{ {
var vector = new SparseVector(10000); var vector = new SparseVector(10000);
var storage = (SparseVectorStorage<Complex>)vector.Storage;
// Add non-zero elements // Add non-zero elements
vector[200] = new Complex(1.5, 1); vector[200] = new Complex(1.5, 1);
Assert.AreEqual(new Complex(1.5, 1), vector[200]); Assert.AreEqual(new Complex(1.5, 1), vector[200]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[500] = new Complex(3.5, 1); vector[500] = new Complex(3.5, 1);
Assert.AreEqual(new Complex(3.5, 1), vector[500]); Assert.AreEqual(new Complex(3.5, 1), vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = new Complex(5.5, 1); vector[800] = new Complex(5.5, 1);
Assert.AreEqual(new Complex(5.5, 1), vector[800]); Assert.AreEqual(new Complex(5.5, 1), vector[800]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[0] = new Complex(7.5, 1); vector[0] = new Complex(7.5, 1);
Assert.AreEqual(new Complex(7.5, 1), vector[0]); Assert.AreEqual(new Complex(7.5, 1), vector[0]);
Assert.AreEqual(4, vector.NonZerosCount); Assert.AreEqual(4, storage.ValueCount);
// Remove non-zero elements // Remove non-zero elements
vector[200] = Complex.Zero; vector[200] = Complex.Zero;
Assert.AreEqual(Complex.Zero, vector[200]); Assert.AreEqual(Complex.Zero, vector[200]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[500] = Complex.Zero; vector[500] = Complex.Zero;
Assert.AreEqual(Complex.Zero, vector[500]); Assert.AreEqual(Complex.Zero, vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = Complex.Zero; vector[800] = Complex.Zero;
Assert.AreEqual(Complex.Zero, vector[800]); Assert.AreEqual(Complex.Zero, vector[800]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[0] = Complex.Zero; vector[0] = Complex.Zero;
Assert.AreEqual(Complex.Zero, vector[0]); Assert.AreEqual(Complex.Zero, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -325,11 +327,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
// Multiply by 0 // Multiply by 0
vector *= 0; vector *= 0;
var storage = (SparseVectorStorage<Complex>)vector.Storage;
Assert.AreEqual(Complex.Zero, vector[200]); Assert.AreEqual(Complex.Zero, vector[200]);
Assert.AreEqual(Complex.Zero, vector[500]); Assert.AreEqual(Complex.Zero, vector[500]);
Assert.AreEqual(Complex.Zero, vector[800]); Assert.AreEqual(Complex.Zero, vector[800]);
Assert.AreEqual(Complex.Zero, vector[0]); Assert.AreEqual(Complex.Zero, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -371,7 +375,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
Assert.AreEqual(Data[i] * zeroArray[i], result[i]); Assert.AreEqual(Data[i] * zeroArray[i], result[i]);
} }
Assert.AreEqual(2, result.NonZerosCount); var resultStorage = (SparseVectorStorage<Complex>)result.Storage;
Assert.AreEqual(2, resultStorage.ValueCount);
} }
/// <summary> /// <summary>

69
src/UnitTests/LinearAlgebraTests/Complex/UserDefinedVector.cs

@ -29,65 +29,56 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
using System.Numerics; using System.Numerics;
using LinearAlgebra.Complex; using LinearAlgebra.Complex;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Storage;
/// <summary> /// <summary>
/// User-defined vector implementation (internal class for testing purposes) /// User-defined vector implementation (internal class for testing purposes)
/// </summary> /// </summary>
internal class UserDefinedVector : Vector internal class UserDefinedVector : Vector
{ {
/// <summary> class UserDefinedVectorStorage : VectorStorage<Complex>
/// Values storage
/// </summary>
private readonly Complex[] _data;
/// <summary>
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// </summary>
/// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size) : base(size)
{ {
_data = new Complex[size]; public readonly Complex[] Data;
}
/// <summary> public UserDefinedVectorStorage(int size)
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array. : base(size)
/// </summary> {
/// <param name="data">The array to create this vector from.</param> Data = new Complex[size];
public UserDefinedVector(Complex[] data) : base(data.Length) }
{
_data = (Complex[])data.Clone();
}
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary> public UserDefinedVectorStorage(int size, Complex[] data)
/// <param name="index">The index of the value to get or set.</param> : base(size)
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
public override Complex this[int index]
{
get
{ {
return _data[index]; Data = data;
} }
set public override Complex At(int index)
{ {
_data[index] = value; return Data[index];
}
public override void At(int index, Complex value)
{
Data[index] = value;
} }
} }
/// <summary>Gets the value at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns> /// </summary>
protected internal override Complex At(int index) /// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size)
: base(new UserDefinedVectorStorage(size))
{ {
return this[index];
} }
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array.
/// <param name="value">The value to set.</param> /// </summary>
protected internal override void At(int index, Complex value) /// <param name="data">The array to create this vector from.</param>
public UserDefinedVector(Complex[] data)
: base(new UserDefinedVectorStorage(data.Length, (Complex[])data.Clone()))
{ {
this[index] = value;
} }
/// <summary> /// <summary>

4
src/UnitTests/LinearAlgebraTests/Complex/VectorTests.cs

@ -97,7 +97,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
var vector = CreateVector(Data); var vector = CreateVector(Data);
var other = CreateVector(Data.Length); var other = CreateVector(Data.Length);
vector.CopyTo(other, 2, 2, 2); vector.CopySubVectorTo(other, 2, 2, 2);
AssertHelpers.AreEqual(Complex.Zero, other[0]); AssertHelpers.AreEqual(Complex.Zero, other[0]);
AssertHelpers.AreEqual(Complex.Zero, other[1]); AssertHelpers.AreEqual(Complex.Zero, other[1]);
@ -113,7 +113,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
public void CanCopyPartialVectorToSelf() public void CanCopyPartialVectorToSelf()
{ {
var vector = CreateVector(Data); var vector = CreateVector(Data);
vector.CopyTo(vector, 0, 2, 2); vector.CopySubVectorTo(vector, 0, 2, 2);
AssertHelpers.AreEqual(new Complex(1, 1), vector[0]); AssertHelpers.AreEqual(new Complex(1, 1), vector[0]);
AssertHelpers.AreEqual(new Complex(2, 1), vector[1]); AssertHelpers.AreEqual(new Complex(2, 1), vector[1]);

25
src/UnitTests/LinearAlgebraTests/Complex32/SparseVectorTest.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
using System.Collections.Generic; using System.Collections.Generic;
using LinearAlgebra.Complex32; using LinearAlgebra.Complex32;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Storage;
using NUnit.Framework; using NUnit.Framework;
using Complex32 = Numerics.Complex32; using Complex32 = Numerics.Complex32;
@ -273,40 +274,41 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
public void CheckSparseMechanismBySettingValues() public void CheckSparseMechanismBySettingValues()
{ {
var vector = new SparseVector(10000); var vector = new SparseVector(10000);
var storage = (SparseVectorStorage<Complex32>)vector.Storage;
// Add non-zero elements // Add non-zero elements
vector[200] = new Complex32(1.5f, 1); vector[200] = new Complex32(1.5f, 1);
Assert.AreEqual(new Complex32(1.5f, 1), vector[200]); Assert.AreEqual(new Complex32(1.5f, 1), vector[200]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[500] = new Complex32(3.5f, 1); vector[500] = new Complex32(3.5f, 1);
Assert.AreEqual(new Complex32(3.5f, 1), vector[500]); Assert.AreEqual(new Complex32(3.5f, 1), vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = new Complex32(5.5f, 1); vector[800] = new Complex32(5.5f, 1);
Assert.AreEqual(new Complex32(5.5f, 1), vector[800]); Assert.AreEqual(new Complex32(5.5f, 1), vector[800]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[0] = new Complex32(7.5f, 1); vector[0] = new Complex32(7.5f, 1);
Assert.AreEqual(new Complex32(7.5f, 1), vector[0]); Assert.AreEqual(new Complex32(7.5f, 1), vector[0]);
Assert.AreEqual(4, vector.NonZerosCount); Assert.AreEqual(4, storage.ValueCount);
// Remove non-zero elements // Remove non-zero elements
vector[200] = Complex32.Zero; vector[200] = Complex32.Zero;
Assert.AreEqual(Complex32.Zero, vector[200]); Assert.AreEqual(Complex32.Zero, vector[200]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[500] = Complex32.Zero; vector[500] = Complex32.Zero;
Assert.AreEqual(Complex32.Zero, vector[500]); Assert.AreEqual(Complex32.Zero, vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = Complex32.Zero; vector[800] = Complex32.Zero;
Assert.AreEqual(Complex32.Zero, vector[800]); Assert.AreEqual(Complex32.Zero, vector[800]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[0] = Complex32.Zero; vector[0] = Complex32.Zero;
Assert.AreEqual(Complex32.Zero, vector[0]); Assert.AreEqual(Complex32.Zero, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -325,11 +327,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
// Multiply by 0 // Multiply by 0
vector *= 0; vector *= 0;
var storage = (SparseVectorStorage<Complex32>)vector.Storage;
Assert.AreEqual(Complex32.Zero, vector[200]); Assert.AreEqual(Complex32.Zero, vector[200]);
Assert.AreEqual(Complex32.Zero, vector[500]); Assert.AreEqual(Complex32.Zero, vector[500]);
Assert.AreEqual(Complex32.Zero, vector[800]); Assert.AreEqual(Complex32.Zero, vector[800]);
Assert.AreEqual(Complex32.Zero, vector[0]); Assert.AreEqual(Complex32.Zero, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -371,7 +375,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
Assert.AreEqual(Data[i] * zeroArray[i], result[i]); Assert.AreEqual(Data[i] * zeroArray[i], result[i]);
} }
Assert.AreEqual(2, result.NonZerosCount); var resultStorage = (SparseVectorStorage<Complex32>)result.Storage;
Assert.AreEqual(2, resultStorage.ValueCount);
} }
/// <summary> /// <summary>

69
src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedVector.cs

@ -28,6 +28,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
{ {
using LinearAlgebra.Complex32; using LinearAlgebra.Complex32;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Storage;
using Complex32 = Numerics.Complex32; using Complex32 = Numerics.Complex32;
/// <summary> /// <summary>
@ -35,59 +36,49 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
/// </summary> /// </summary>
internal class UserDefinedVector : Vector internal class UserDefinedVector : Vector
{ {
/// <summary> class UserDefinedVectorStorage : VectorStorage<Complex32>
/// Values storage
/// </summary>
private readonly Complex32[] _data;
/// <summary>
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// </summary>
/// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size) : base(size)
{ {
_data = new Complex32[size]; public readonly Complex32[] Data;
}
/// <summary> public UserDefinedVectorStorage(int size)
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array. : base(size)
/// </summary> {
/// <param name="data">The array to create this vector from.</param> Data = new Complex32[size];
public UserDefinedVector(Complex32[] data) : base(data.Length) }
{
_data = (Complex32[])data.Clone();
}
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary> public UserDefinedVectorStorage(int size, Complex32[] data)
/// <param name="index">The index of the value to get or set.</param> : base(size)
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
public override Complex32 this[int index]
{
get
{ {
return _data[index]; Data = data;
} }
set public override Complex32 At(int index)
{ {
_data[index] = value; return Data[index];
}
public override void At(int index, Complex32 value)
{
Data[index] = value;
} }
} }
/// <summary>Gets the value at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns> /// </summary>
protected internal override Complex32 At(int index) /// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size)
: base(new UserDefinedVectorStorage(size))
{ {
return this[index];
} }
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array.
/// <param name="value">The value to set.</param> /// </summary>
protected internal override void At(int index, Complex32 value) /// <param name="data">The array to create this vector from.</param>
public UserDefinedVector(Complex32[] data)
: base(new UserDefinedVectorStorage(data.Length, (Complex32[])data.Clone()))
{ {
this[index] = value;
} }
/// <summary> /// <summary>

4
src/UnitTests/LinearAlgebraTests/Complex32/VectorTests.cs

@ -97,7 +97,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
var vector = CreateVector(Data); var vector = CreateVector(Data);
var other = CreateVector(Data.Length); var other = CreateVector(Data.Length);
vector.CopyTo(other, 2, 2, 2); vector.CopySubVectorTo(other, 2, 2, 2);
AssertHelpers.AreEqual(Complex32.Zero, other[0]); AssertHelpers.AreEqual(Complex32.Zero, other[0]);
AssertHelpers.AreEqual(Complex32.Zero, other[1]); AssertHelpers.AreEqual(Complex32.Zero, other[1]);
@ -113,7 +113,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
public void CanCopyPartialVectorToSelf() public void CanCopyPartialVectorToSelf()
{ {
var vector = CreateVector(Data); var vector = CreateVector(Data);
vector.CopyTo(vector, 0, 2, 2); vector.CopySubVectorTo(vector, 0, 2, 2);
AssertHelpers.AreEqual(new Complex32(1, 1), vector[0]); AssertHelpers.AreEqual(new Complex32(1, 1), vector[0]);
AssertHelpers.AreEqual(new Complex32(2, 1), vector[1]); AssertHelpers.AreEqual(new Complex32(2, 1), vector[1]);

25
src/UnitTests/LinearAlgebraTests/Double/SparseVectorTest.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
using System.Collections.Generic; using System.Collections.Generic;
using LinearAlgebra.Double; using LinearAlgebra.Double;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Storage;
using NUnit.Framework; using NUnit.Framework;
/// <summary> /// <summary>
@ -272,40 +273,41 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
public void CheckSparseMechanismBySettingValues() public void CheckSparseMechanismBySettingValues()
{ {
var vector = new SparseVector(10000); var vector = new SparseVector(10000);
var storage = (SparseVectorStorage<double>)vector.Storage;
// Add non-zero elements // Add non-zero elements
vector[200] = 1.5; vector[200] = 1.5;
Assert.AreEqual(1.5, vector[200]); Assert.AreEqual(1.5, vector[200]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[500] = 3.5; vector[500] = 3.5;
Assert.AreEqual(3.5, vector[500]); Assert.AreEqual(3.5, vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = 5.5; vector[800] = 5.5;
Assert.AreEqual(5.5, vector[800]); Assert.AreEqual(5.5, vector[800]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[0] = 7.5; vector[0] = 7.5;
Assert.AreEqual(7.5, vector[0]); Assert.AreEqual(7.5, vector[0]);
Assert.AreEqual(4, vector.NonZerosCount); Assert.AreEqual(4, storage.ValueCount);
// Remove non-zero elements // Remove non-zero elements
vector[200] = 0; vector[200] = 0;
Assert.AreEqual(0, vector[200]); Assert.AreEqual(0, vector[200]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[500] = 0; vector[500] = 0;
Assert.AreEqual(0, vector[500]); Assert.AreEqual(0, vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = 0; vector[800] = 0;
Assert.AreEqual(0, vector[800]); Assert.AreEqual(0, vector[800]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[0] = 0; vector[0] = 0;
Assert.AreEqual(0, vector[0]); Assert.AreEqual(0, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -324,11 +326,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
// Multiply by 0 // Multiply by 0
vector *= 0; vector *= 0;
var storage = (SparseVectorStorage<double>)vector.Storage;
Assert.AreEqual(0, vector[200]); Assert.AreEqual(0, vector[200]);
Assert.AreEqual(0, vector[500]); Assert.AreEqual(0, vector[500]);
Assert.AreEqual(0, vector[800]); Assert.AreEqual(0, vector[800]);
Assert.AreEqual(0, vector[0]); Assert.AreEqual(0, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -370,7 +374,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
Assert.AreEqual(Data[i] * zeroArray[i], result[i]); Assert.AreEqual(Data[i] * zeroArray[i], result[i]);
} }
Assert.AreEqual(2, result.NonZerosCount); var resultStorage = (SparseVectorStorage<double>)result.Storage;
Assert.AreEqual(2, resultStorage.ValueCount);
} }
/// <summary> /// <summary>

69
src/UnitTests/LinearAlgebraTests/Double/UserDefinedVector.cs

@ -28,65 +28,56 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
{ {
using LinearAlgebra.Double; using LinearAlgebra.Double;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Storage;
/// <summary> /// <summary>
/// User-defined vector implementation (internal class for testing purposes) /// User-defined vector implementation (internal class for testing purposes)
/// </summary> /// </summary>
internal class UserDefinedVector : Vector internal class UserDefinedVector : Vector
{ {
/// <summary> class UserDefinedVectorStorage : VectorStorage<double>
/// Values storage
/// </summary>
private readonly double[] _data;
/// <summary>
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// </summary>
/// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size) : base(size)
{ {
_data = new double[size]; public readonly double[] Data;
}
/// <summary> public UserDefinedVectorStorage(int size)
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array. : base(size)
/// </summary> {
/// <param name="data">The array to create this vector from.</param> Data = new double[size];
public UserDefinedVector(double[] data) : base(data.Length) }
{
_data = (double[])data.Clone();
}
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary> public UserDefinedVectorStorage(int size, double[] data)
/// <param name="index">The index of the value to get or set.</param> : base(size)
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
public override double this[int index]
{
get
{ {
return _data[index]; Data = data;
} }
set public override double At(int index)
{ {
_data[index] = value; return Data[index];
}
public override void At(int index, double value)
{
Data[index] = value;
} }
} }
/// <summary>Gets the value at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns> /// </summary>
protected internal override double At(int index) /// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size)
: base(new UserDefinedVectorStorage(size))
{ {
return this[index];
} }
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array.
/// <param name="value">The value to set.</param> /// </summary>
protected internal override void At(int index, double value) /// <param name="data">The array to create this vector from.</param>
public UserDefinedVector(double[] data)
: base(new UserDefinedVectorStorage(data.Length, (double[])data.Clone()))
{ {
this[index] = value;
} }
/// <summary> /// <summary>

4
src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs

@ -95,7 +95,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
var vector = CreateVector(Data); var vector = CreateVector(Data);
var other = CreateVector(Data.Length); var other = CreateVector(Data.Length);
vector.CopyTo(other, 2, 2, 2); vector.CopySubVectorTo(other, 2, 2, 2);
Assert.AreEqual(0.0, other[0]); Assert.AreEqual(0.0, other[0]);
Assert.AreEqual(0.0, other[1]); Assert.AreEqual(0.0, other[1]);
@ -111,7 +111,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
public void CanCopyPartialVectorToSelf() public void CanCopyPartialVectorToSelf()
{ {
var vector = CreateVector(Data); var vector = CreateVector(Data);
vector.CopyTo(vector, 0, 2, 2); vector.CopySubVectorTo(vector, 0, 2, 2);
Assert.AreEqual(1.0, vector[0]); Assert.AreEqual(1.0, vector[0]);
Assert.AreEqual(2.0, vector[1]); Assert.AreEqual(2.0, vector[1]);

26
src/UnitTests/LinearAlgebraTests/Single/SparseVectorTest.cs

@ -34,7 +34,9 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
using System.Collections.Generic; using System.Collections.Generic;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Single; using LinearAlgebra.Single;
using LinearAlgebra.Storage;
using NUnit.Framework; using NUnit.Framework;
using Complex32 = Numerics.Complex32;
/// <summary> /// <summary>
/// Sparse vector tests. /// Sparse vector tests.
@ -272,40 +274,41 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
public void CheckSparseMechanismBySettingValues() public void CheckSparseMechanismBySettingValues()
{ {
var vector = new SparseVector(10000); var vector = new SparseVector(10000);
var storage = (SparseVectorStorage<float>)vector.Storage;
// Add non-zero elements // Add non-zero elements
vector[200] = 1.5f; vector[200] = 1.5f;
Assert.AreEqual(1.5f, vector[200]); Assert.AreEqual(1.5f, vector[200]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[500] = 3.5f; vector[500] = 3.5f;
Assert.AreEqual(3.5f, vector[500]); Assert.AreEqual(3.5f, vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = 5.5f; vector[800] = 5.5f;
Assert.AreEqual(5.5f, vector[800]); Assert.AreEqual(5.5f, vector[800]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[0] = 7.5f; vector[0] = 7.5f;
Assert.AreEqual(7.5f, vector[0]); Assert.AreEqual(7.5f, vector[0]);
Assert.AreEqual(4, vector.NonZerosCount); Assert.AreEqual(4, storage.ValueCount);
// Remove non-zero elements // Remove non-zero elements
vector[200] = 0; vector[200] = 0;
Assert.AreEqual(0, vector[200]); Assert.AreEqual(0, vector[200]);
Assert.AreEqual(3, vector.NonZerosCount); Assert.AreEqual(3, storage.ValueCount);
vector[500] = 0; vector[500] = 0;
Assert.AreEqual(0, vector[500]); Assert.AreEqual(0, vector[500]);
Assert.AreEqual(2, vector.NonZerosCount); Assert.AreEqual(2, storage.ValueCount);
vector[800] = 0; vector[800] = 0;
Assert.AreEqual(0, vector[800]); Assert.AreEqual(0, vector[800]);
Assert.AreEqual(1, vector.NonZerosCount); Assert.AreEqual(1, storage.ValueCount);
vector[0] = 0; vector[0] = 0;
Assert.AreEqual(0, vector[0]); Assert.AreEqual(0, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -324,11 +327,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
// Multiply by 0 // Multiply by 0
vector *= 0; vector *= 0;
var storage = (SparseVectorStorage<float>)vector.Storage;
Assert.AreEqual(0, vector[200]); Assert.AreEqual(0, vector[200]);
Assert.AreEqual(0, vector[500]); Assert.AreEqual(0, vector[500]);
Assert.AreEqual(0, vector[800]); Assert.AreEqual(0, vector[800]);
Assert.AreEqual(0, vector[0]); Assert.AreEqual(0, vector[0]);
Assert.AreEqual(0, vector.NonZerosCount); Assert.AreEqual(0, storage.ValueCount);
} }
/// <summary> /// <summary>
@ -370,7 +375,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
Assert.AreEqual(Data[i] * zeroArray[i], result[i]); Assert.AreEqual(Data[i] * zeroArray[i], result[i]);
} }
Assert.AreEqual(2, result.NonZerosCount); var resultStorage = (SparseVectorStorage<float>)result.Storage;
Assert.AreEqual(2, resultStorage.ValueCount);
} }
/// <summary> /// <summary>

69
src/UnitTests/LinearAlgebraTests/Single/UserDefinedVector.cs

@ -28,65 +28,56 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
{ {
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using LinearAlgebra.Single; using LinearAlgebra.Single;
using LinearAlgebra.Storage;
/// <summary> /// <summary>
/// User-defined vector implementation (internal class for testing purposes) /// User-defined vector implementation (internal class for testing purposes)
/// </summary> /// </summary>
internal class UserDefinedVector : Vector internal class UserDefinedVector : Vector
{ {
/// <summary> class UserDefinedVectorStorage : VectorStorage<float>
/// Values storage
/// </summary>
private readonly float[] _data;
/// <summary>
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// </summary>
/// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size) : base(size)
{ {
_data = new float[size]; public readonly float[] Data;
}
/// <summary> public UserDefinedVectorStorage(int size)
/// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array. : base(size)
/// </summary> {
/// <param name="data">The array to create this vector from.</param> Data = new float[size];
public UserDefinedVector(float[] data) : base(data.Length) }
{
_data = (float[])data.Clone();
}
/// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary> public UserDefinedVectorStorage(int size, float[] data)
/// <param name="index">The index of the value to get or set.</param> : base(size)
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns>
public override float this[int index]
{
get
{ {
return _data[index]; Data = data;
} }
set public override float At(int index)
{ {
_data[index] = value; return Data[index];
}
public override void At(int index, float value)
{
Data[index] = value;
} }
} }
/// <summary>Gets the value at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class with a given size.
/// <returns>The value of the vector at the given <paramref name="index"/>.</returns> /// </summary>
protected internal override float At(int index) /// <param name="size">The size of the vector.</param>
public UserDefinedVector(int size)
: base(new UserDefinedVectorStorage(size))
{ {
return this[index];
} }
/// <summary>Sets the <paramref name="value"/> at the given <paramref name="index"/>.</summary> /// <summary>
/// <param name="index">The index of the value to get or set.</param> /// Initializes a new instance of the <see cref="UserDefinedVector"/> class for an array.
/// <param name="value">The value to set.</param> /// </summary>
protected internal override void At(int index, float value) /// <param name="data">The array to create this vector from.</param>
public UserDefinedVector(float[] data)
: base(new UserDefinedVectorStorage(data.Length, (float[])data.Clone()))
{ {
this[index] = value;
} }
/// <summary> /// <summary>

4
src/UnitTests/LinearAlgebraTests/Single/VectorTests.cs

@ -95,7 +95,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
var vector = CreateVector(Data); var vector = CreateVector(Data);
var other = CreateVector(Data.Length); var other = CreateVector(Data.Length);
vector.CopyTo(other, 2, 2, 2); vector.CopySubVectorTo(other, 2, 2, 2);
Assert.AreEqual(0.0f, other[0]); Assert.AreEqual(0.0f, other[0]);
Assert.AreEqual(0.0f, other[1]); Assert.AreEqual(0.0f, other[1]);
@ -111,7 +111,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
public void CanCopyPartialVectorToSelf() public void CanCopyPartialVectorToSelf()
{ {
var vector = CreateVector(Data); var vector = CreateVector(Data);
vector.CopyTo(vector, 0, 2, 2); vector.CopySubVectorTo(vector, 0, 2, 2);
Assert.AreEqual(1.0f, vector[0]); Assert.AreEqual(1.0f, vector[0]);
Assert.AreEqual(2.0f, vector[1]); Assert.AreEqual(2.0f, vector[1]);

Loading…
Cancel
Save