/// <summary> /// Performs the following operation for 0 <= i < <see cref="NumRows"/>, 0 <= j < <see cref="NumColumns"/>: /// this[i, j] = <paramref name="otherCoefficient"/> * <paramref name="otherMatrix"/>[i, j] + this[i, j]. /// The resulting matrix overwrites the entries of this <see cref="CscMatrix"/> instance. /// </summary> /// <param name="otherMatrix">A matrix with the same indexing arrays as this <see cref="CscMatrix"/> instance.</param> /// <param name="otherCoefficient">A scalar that multiplies each entry of <paramref name="otherMatrix"/>.</param> /// <exception cref="SparsityPatternModifiedException">Thrown if <paramref name="otherMatrix"/> has different /// indexing arrays than this instance.</exception> public void AxpyIntoThis(CscMatrix otherMatrix, double otherCoefficient) { //Preconditions.CheckSameMatrixDimensions(this, other); // no need if the indexing arrays are the same if (!HasSameIndexer(otherMatrix)) { throw new SparsityPatternModifiedException("Only allowed if the indexing arrays are the same"); } Blas.Daxpy(values.Length, otherCoefficient, otherMatrix.values, 0, 1, this.values, 0, 1); }
/// <summary> /// Performs the following operation for 0 <= i < <see cref="NumRows"/>, 0 <= j < <see cref="NumColumns"/>: /// result[i, j] = <paramref name="otherCoefficient"/> * <paramref name="otherMatrix"/>[i, j] + this[i, j]. /// The resulting matrix is written to a new <see cref="CscMatrix"/> and then returned. /// </summary> /// <param name="otherMatrix">A matrix with the same <see cref="NumRows"/> and <see cref="NumColumns"/> as this /// <see cref="CscMatrix"/> instance.</param> /// <param name="otherCoefficient">A scalar that multiplies each entry of <paramref name="otherMatrix"/>.</param> /// <exception cref="NonMatchingDimensionsException">Thrown if <paramref name="otherMatrix"/> has different /// <see cref="NumRows"/> or <see cref="NumColumns"/> than this instance.</exception> public CscMatrix Axpy(CscMatrix otherMatrix, double otherCoefficient) { // Conceptually it is not wrong to so this, even if the indexers are different, but how would I implement it. if (!HasSameIndexer(otherMatrix)) { throw new SparsityPatternModifiedException("Only allowed if the indexing arrays are the same"); } //TODO: Perhaps this should be done using mkl_malloc and BLAS copy. double[] resultValues = new double[values.Length]; Array.Copy(this.values, resultValues, values.Length); Blas.Daxpy(values.Length, otherCoefficient, otherMatrix.values, 0, 1, resultValues, 0, 1); // Do not copy the index arrays, since they are already spread around. TODO: is this a good idea? return(new CscMatrix(NumRows, NumColumns, resultValues, this.rowIndices, this.colOffsets)); }
/// <summary> /// Performs the operation: result = transpose(<paramref name="csc"/>) * <paramref name="other"/> * <paramref name="csc"/> /// in an efficient way, by appropriately selecting which methods should be called for these matrices and in what order. /// </summary> /// <param name="csc">The matrix that will be multiplied "outside".</param> /// <param name="other">The matrix that will be multiplied "inside". It must be square.</param> public static Matrix ThisTransposeTimesOtherTimesThis(this CscMatrix csc, Matrix other) { // As of 15 December 2018, right multiplying is more efficient than left multiplying, since the resulting matrix // of right multiplying is column major and we can leverage BLAS. Therefore we want the right multiplication to // happen for the larger matrix: transpose(csc) * matrix. if (other.NumColumns < csc.NumColumns) { Matrix temp = csc.MultiplyLeft(other, false, false); // temp is larger than other return(csc.MultiplyRight(temp, true, false)); } else { Matrix temp = csc.MultiplyRight(other, true, false); // other is larger than temp return(csc.MultiplyLeft(temp, false, false)); } }
private bool HasSameIndexer(CscMatrix other) { return((this.rowIndices == other.rowIndices) && (this.colOffsets == other.colOffsets)); }
/// <summary> /// Performs the matrix-vector multiplication: oper(<paramref name="matrix"/>) * <paramref name="vector"/>. /// To multiply <paramref name="matrix"/> * columnVector, set <paramref name="transposeThis"/> to false. /// To multiply rowVector * <paramref name="matrix"/>, set <paramref name="transposeThis"/> to true. /// </summary> /// <param name="matrix">The matrix to multiply.</param> /// <param name="vector">A vector with <see cref="IIndexable1D.Length"/> being equal to the /// <see cref="IIndexable2D.NumColumns"/> of oper(<paramref name="matrix"/>).</param> /// <param name="transposeThis">If true, oper(<paramref name="matrix"/>) = transpose(<paramref name="matrix"/>). /// Otherwise oper(<paramref name="matrix"/>) = <paramref name="matrix"/>.</param> /// <exception cref="NonMatchingDimensionsException">Thrown if the <see cref="IIndexable1D.Length"/> of /// <paramref name="vector"/> is different than the <see cref="NumColumns"/> of /// oper(<paramref name="matrix"/>).</exception> public static double[] MultiplyRight(this CscMatrix matrix, double[] vector, bool transposeThis) { //TODO: delete this once legacy vectors, matrices are no longer used. var asVector = Vector.CreateFromArray(vector, false); return(matrix.Multiply(asVector, transposeThis).RawData); }
/// <summary> /// Performs the operation: result = transpose(<paramref name="csc"/>) * <paramref name="other"/> * <paramref name="csc"/> /// in an efficient way, by appropriately selecting which methods should be called for these matrices and in what order. /// </summary> /// <param name="csc">The matrix that will be multiplied "outside".</param> /// <param name="other">The matrix that will be multiplied "inside". It must be square.</param> public static Matrix ThisTransposeTimesOtherTimesThis(this CscMatrix csc, SymmetricMatrix other) => throw new NotImplementedException("Placeholder for when SymmetricMatrix is fully implemented");