/// <summary> /// See <see cref="IVector.AxpyIntoThis(IVectorView, double)"/>. /// </summary> public void AxpyIntoThis(IVectorView otherVector, double otherCoefficient) { if (otherVector is Vector dense) { AxpyIntoThis(dense, otherCoefficient); } else { Preconditions.CheckVectorDimensions(this, otherVector); if (otherVector is SparseVector sparse) { if (sparse.RawIndices.Length != 0) { SparseBlas.Daxpyi(sparse.RawIndices.Length, otherCoefficient, sparse.RawValues, sparse.RawIndices, 0, data, 0); } } else { for (int i = 0; i < Length; ++i) { this.data[i] += otherCoefficient * otherVector[i]; } } } }
/// <summary> /// Performs the matrix-vector multiplication: <paramref name="rhsVector"/> = oper(this) * <paramref name="vector"/>. /// To multiply this * columnVector, set <paramref name="transposeThis"/> to false. /// To multiply rowVector * this, set <paramref name="transposeThis"/> to true. /// The resulting vector will overwrite the entries of <paramref name="rhsVector"/>. /// </summary> /// <param name="lhsVector"> /// The vector that will be multiplied by this matrix. It sits on the left hand side of the equation y = oper(A) * x. /// Constraints: <paramref name="lhsVector"/>.<see cref="IIndexable1D.Length"/> /// == oper(this).<see cref="IIndexable2D.NumColumns"/>. /// </param> /// <param name="rhsVector"> /// The vector that will be overwritten by the result of the multiplication. It sits on the right hand side of the /// equation y = oper(A) * x. Constraints: <paramref name="lhsVector"/>.<see cref="IIndexable1D.Length"/> /// == oper(this).<see cref="IIndexable2D.NumRows"/>. /// </param> /// <param name="transposeThis">If true, oper(this) = transpose(this). Otherwise oper(this) = this.</param> /// <exception cref="NonMatchingDimensionsException"> /// Thrown if the <see cref="IIndexable1D.Length"/> of <paramref name="lhsVector"/> or <paramref name="rhsVector"/> /// violate the described contraints. /// </exception> public void MultiplyIntoResult(Vector lhsVector, Vector rhsVector, bool transposeThis = false) { if (transposeThis) { Preconditions.CheckMultiplicationDimensions(NumRows, lhsVector.Length); Preconditions.CheckSystemSolutionDimensions(NumColumns, rhsVector.Length); } else { Preconditions.CheckMultiplicationDimensions(NumColumns, lhsVector.Length); Preconditions.CheckSystemSolutionDimensions(NumRows, rhsVector.Length); } SparseBlas.Dcscgemv(transposeThis, NumRows, NumColumns, values, colOffsets, rowIndices, lhsVector.RawData, 0, rhsVector.RawData, 0); }
/// <summary> /// See <see cref="IVectorView.Axpy(IVectorView, double)"/>. /// </summary> public IVector Axpy(IVectorView otherVector, double otherCoefficient) { if (otherVector is Vector dense) { return(Axpy(dense, otherCoefficient)); } else if (otherVector is SparseVector sparse) { Preconditions.CheckVectorDimensions(this, otherVector); double[] result = new double[data.Length]; Array.Copy(data, result, data.Length); SparseBlas.Daxpyi(sparse.RawIndices.Length, otherCoefficient, sparse.RawValues, sparse.RawIndices, 0, result, 0); return(Vector.CreateFromArray(result, false)); } else { return(otherVector.LinearCombination(otherCoefficient, this, 1.0)); // To avoid accessing zero entries } }
/// <summary> /// Performs the matrix-matrix multiplication: oper(this) * <paramref name="other"/>. /// </summary> /// <param name="other"> /// A matrix such that the <see cref="IIndexable2D.NumRows"/> of <paramref name="other"/> are equal to the /// <see cref="IIndexable2D.NumColumns"/> of oper(this). /// </param> /// <param name="transposeThis">If true, oper(this) = transpose(this). Otherwise oper(this) = this.</param> /// <exception cref="Exceptions.NonMatchingDimensionsException"> /// Thrown if <paramref name="otherMatrix"/> has different <see cref="IIndexable2D.NumRows"/> than the /// <see cref="IIndexable2D.NumColumns"/> of oper(this). /// </exception> public Matrix MultiplyRight(Matrix other, bool transposeThis) { int numRowsResult; if (transposeThis) { Preconditions.CheckMultiplicationDimensions(this.NumRows, other.NumRows); numRowsResult = this.NumColumns; } else { Preconditions.CheckMultiplicationDimensions(this.NumColumns, other.NumRows); numRowsResult = this.NumRows; } var result = Matrix.CreateZero(numRowsResult, other.NumColumns); SparseBlas.Dcscgemm(transposeThis, this.NumRows, other.NumColumns, this.NumColumns, values, colOffsets, rowIndices, other.RawData, result.RawData); return(result); }
/// <summary> /// See <see cref="IVectorView.DotProduct(IVectorView)"/>. /// </summary> public double DotProduct(IVectorView vector) { Preconditions.CheckVectorDimensions(this, vector); if (vector is Vector dense) { return(SparseBlas.Ddoti(values.Length, values, indices, 0, dense.RawData, 0)); } else if ((vector is SparseVector sparse) && HasSameIndexer(sparse)) { return(Blas.Ddot(values.Length, this.values, 0, 1, sparse.values, 0, 1)); } double sum = 0; for (int i = 0; i < values.Length; ++i) { sum += values[i] * vector[indices[i]]; } return(sum); }
/// <summary> /// See <see cref="IVectorView.Axpy(IVectorView, double)"/>. /// </summary> public IVector Axpy(IVectorView otherVector, double otherCoefficient) { Preconditions.CheckVectorDimensions(this, otherVector); if (otherVector is SparseVector otherSparse) // In case both matrices have the exact same index arrays { if (HasSameIndexer(otherSparse)) { // Do not copy the index arrays, since they are already spread around. TODO: is this a good idea? double[] result = new double[this.values.Length]; Array.Copy(this.values, result, this.values.Length); Blas.Daxpy(values.Length, otherCoefficient, otherSparse.values, 0, 1, result, 0, 1); return(new SparseVector(Length, result, indices)); } } else if (otherVector is Vector otherDense) { double[] result = otherDense.Scale(otherCoefficient).RawData; SparseBlas.Daxpyi(this.indices.Length, 1.0, this.values, this.indices, 0, result, 0); return(Vector.CreateFromArray(result, false)); } // All entries must be processed. TODO: optimizations may be possible (e.g. only access the nnz in this vector) return(DenseStrategies.LinearCombination(this, 1.0, otherVector, otherCoefficient)); }
/// <summary> /// See <see cref="IVector.AxpyIntoThis(IVectorView, double)"/>. /// </summary> public void AxpyIntoThis(IVectorView otherVector, double otherCoefficient) { if (otherVector is Vector dense) { AxpyIntoThis(dense, otherCoefficient); } else { Preconditions.CheckVectorDimensions(this, otherVector); if (otherVector is SparseVector sparse) { //TODO: should I check whether the sparse vector is all 0, in order to avoid the BLAS call? SparseBlas.Daxpyi(sparse.RawIndices.Length, otherCoefficient, sparse.RawValues, sparse.RawIndices, 0, data, 0); } else { for (int i = 0; i < Length; ++i) { this.data[i] += otherCoefficient * otherVector[i]; } } } }