All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ejml.sparse.csc.misc.ImplCommonOps_FSCC Maven / Gradle / Ivy

Go to download

A fast and easy to use dense and sparse matrix linear algebra library written in Java.

The newest version!
/*
 * Copyright (c) 2022, Peter Abeles. All Rights Reserved.
 *
 * This file is part of Efficient Java Matrix Library (EJML).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ejml.sparse.csc.misc;

import javax.annotation.Generated;
import org.ejml.UtilEjml;
import org.ejml.data.FGrowArray;
import org.ejml.data.FMatrixSparseCSC;
import org.ejml.data.IGrowArray;
import org.ejml.ops.IPredicateBinary;
import org.ejml.sparse.csc.CommonOps_FSCC;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;

import static org.ejml.UtilEjml.adjust;
import static org.ejml.sparse.csc.mult.ImplMultiplication_FSCC.multAddColA;

/**
 * Implementation class. Not recommended for direct use. Instead use {@link CommonOps_FSCC}
 * instead.
 *
 * @author Peter Abeles
 */
@Generated("org.ejml.sparse.csc.misc.ImplCommonOps_DSCC")
public class ImplCommonOps_FSCC {

    public static void select( FMatrixSparseCSC A, FMatrixSparseCSC output, IPredicateBinary selector ) {
        int selectCount = 0;

        // size estimation
        if (output != A) {
            output.growMaxLength(A.nz_length/2, false);
        }

        // selecting a subset doesn't change the order
        output.indicesSorted = A.indicesSorted;

        for (int col = 0; col < A.numCols; col++) {
            int start = A.col_idx[col];
            int end = A.col_idx[col + 1];

            output.col_idx[col] = selectCount;

            if (output.nz_rows.length < (selectCount + (end - start))) {
                int maxLength = Integer.max(output.nz_length*2 + 1, A.nz_length);
                output.growMaxLength(maxLength, true);
            }

            for (int i = start; i < end; i++) {
                int row = A.nz_rows[i];

                if (selector.apply(row, col)) {
                    output.nz_rows[selectCount] = row;
                    output.nz_values[selectCount] = A.nz_values[i];
                    selectCount++;
                }
            }
        }
        // writing last entry
        output.col_idx[output.numCols] = selectCount;

        output.nz_length = selectCount;
    }

    /**
     * Performs a matrix transpose.
     *
     * @param A Original matrix. Not modified.
     * @param C Storage for transposed 'A'. Reshaped.
     * @param gw (Optional) Storage for internal workspace. Can be null.
     */
    public static void transpose( FMatrixSparseCSC A, FMatrixSparseCSC C, @Nullable IGrowArray gw ) {
        int[] work = adjust(gw, A.numRows, A.numRows);
        C.reshape(A.numCols, A.numRows, A.nz_length);

        // compute the histogram for each row in 'a'
        for (int j = 0; j < A.nz_length; j++) {
            work[A.nz_rows[j]]++;
        }

        // construct col_idx in the transposed matrix
        C.histogramToStructure(work);
        System.arraycopy(C.col_idx, 0, work, 0, C.numCols);

        // fill in the row indexes
        int idx0 = A.col_idx[0];
        for (int j = 1; j <= A.numCols; j++) {
            final int col = j - 1;
            final int idx1 = A.col_idx[j];
            for (int i = idx0; i < idx1; i++) {
                int row = A.nz_rows[i];
                int index = work[row]++;
                C.nz_rows[index] = col;
                C.nz_values[index] = A.nz_values[i];
            }
            idx0 = idx1;
        }
    }

    /**
     * Performs matrix addition:
* C = αA + βB * * @param alpha scalar value multiplied against A * @param A Matrix * @param beta scalar value multiplied against B * @param B Matrix * @param C Output matrix. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void add( float alpha, FMatrixSparseCSC A, float beta, FMatrixSparseCSC B, FMatrixSparseCSC C, @Nullable IGrowArray gw, @Nullable FGrowArray gx ) { float[] x = adjust(gx, A.numRows); int[] w = adjust(gw, A.numRows, A.numRows); C.indicesSorted = false; C.nz_length = 0; for (int col = 0; col < A.numCols; col++) { C.col_idx[col] = C.nz_length; multAddColA(A, col, alpha, C, col + 1, x, w); multAddColA(B, col, beta, C, col + 1, x, w); // take the values in the dense vector 'x' and put them into 'C' int idxC0 = C.col_idx[col]; int idxC1 = C.col_idx[col + 1]; for (int i = idxC0; i < idxC1; i++) { C.nz_values[i] = x[C.nz_rows[i]]; } } C.col_idx[A.numCols] = C.nz_length; } /** * Adds the results of adding a column in A and B as a new column in C.
* C(:,end+1) = α*A(:,colA) + β*B(:,colB) * * @param alpha scalar * @param A matrix * @param colA column in A * @param beta scalar * @param B matrix * @param colB column in B * @param C Column in C * @param gw workspace */ public static void addColAppend( float alpha, FMatrixSparseCSC A, int colA, float beta, FMatrixSparseCSC B, int colB, FMatrixSparseCSC C, @Nullable IGrowArray gw ) { if (A.numRows != B.numRows || A.numRows != C.numRows) throw new IllegalArgumentException("Number of rows in A, B, and C do not match"); int idxA0 = A.col_idx[colA]; int idxA1 = A.col_idx[colA + 1]; int idxB0 = B.col_idx[colB]; int idxB1 = B.col_idx[colB + 1]; C.growMaxColumns(++C.numCols, true); C.growMaxLength(C.nz_length + idxA1 - idxA0 + idxB1 - idxB0, true); int[] w = adjust(gw, A.numRows); Arrays.fill(w, 0, A.numRows, -1); for (int i = idxA0; i < idxA1; i++) { int row = A.nz_rows[i]; C.nz_rows[C.nz_length] = row; C.nz_values[C.nz_length] = alpha*A.nz_values[i]; w[row] = C.nz_length++; } for (int i = idxB0; i < idxB1; i++) { int row = B.nz_rows[i]; if (w[row] != -1) { C.nz_values[w[row]] += beta*B.nz_values[i]; } else { C.nz_values[C.nz_length] = beta*B.nz_values[i]; C.nz_rows[C.nz_length++] = row; } } C.col_idx[C.numCols] = C.nz_length; } /** * Performs element-wise multiplication:
* C_ij = A_ij * B_ij * * @param A (Input) Matrix * @param B (Input) Matrix * @param C (Output) Matrix. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void elementMult( FMatrixSparseCSC A, FMatrixSparseCSC B, FMatrixSparseCSC C, @Nullable IGrowArray gw, @Nullable FGrowArray gx ) { float[] x = adjust(gx, A.numRows); int[] w = adjust(gw, A.numRows); Arrays.fill(w, 0, A.numRows, -1); // fill with -1. This will be a value less than column C.growMaxLength(Math.min(A.nz_length, B.nz_length), false); C.indicesSorted = false; // Hmm I think if B is storted then C will be sorted... C.nz_length = 0; for (int col = 0; col < A.numCols; col++) { int idxA0 = A.col_idx[col]; int idxA1 = A.col_idx[col + 1]; int idxB0 = B.col_idx[col]; int idxB1 = B.col_idx[col + 1]; // compute the maximum number of elements that there can be in this row int maxInRow = Math.min(idxA1 - idxA0, idxB1 - idxB0); // make sure there are enough non-zero elements in C if (C.nz_length + maxInRow > C.nz_values.length) C.growMaxLength(C.nz_values.length + maxInRow, true); // update the structure of C C.col_idx[col] = C.nz_length; // mark the rows that appear in A and save their value for (int i = idxA0; i < idxA1; i++) { int row = A.nz_rows[i]; w[row] = col; x[row] = A.nz_values[i]; } // If a row appears in A and B, multiply and set as an element in C for (int i = idxB0; i < idxB1; i++) { int row = B.nz_rows[i]; if (w[row] == col) { C.nz_values[C.nz_length] = x[row]*B.nz_values[i]; C.nz_rows[C.nz_length++] = row; } } } C.col_idx[C.numCols] = C.nz_length; } public static void removeZeros( FMatrixSparseCSC input, FMatrixSparseCSC output, float tol ) { output.reshape(input.numRows, input.numCols, input.nz_length); output.nz_length = 0; for (int i = 0; i < input.numCols; i++) { output.col_idx[i] = output.nz_length; int idx0 = input.col_idx[i]; int idx1 = input.col_idx[i + 1]; for (int j = idx0; j < idx1; j++) { float val = input.nz_values[j]; if (Math.abs(val) > tol) { output.nz_rows[output.nz_length] = input.nz_rows[j]; output.nz_values[output.nz_length++] = val; } } } output.col_idx[output.numCols] = output.nz_length; } public static void removeZeros( FMatrixSparseCSC A, float tol ) { int offset = 0; for (int i = 0; i < A.numCols; i++) { int idx0 = A.col_idx[i] + offset; int idx1 = A.col_idx[i + 1]; for (int j = idx0; j < idx1; j++) { float val = A.nz_values[j]; if (Math.abs(val) > tol) { A.nz_rows[j - offset] = A.nz_rows[j]; A.nz_values[j - offset] = val; } else { offset++; } } A.col_idx[i + 1] -= offset; } A.nz_length -= offset; } public static void duplicatesAdd( FMatrixSparseCSC A, @Nullable IGrowArray work ) { // Look up table from row to nz index int[] table = UtilEjml.adjustFill(work, A.numRows, -1); int offset = 0; for (int i = 0; i < A.numCols; i++) { int idx0 = A.col_idx[i] + offset; int idx1 = A.col_idx[i + 1]; // When a row is first encountered note the element it's at for (int j = idx0; j < idx1; j++) { int row = A.nz_rows[j]; if (table[row] == -1) table[row] = j; } // Set then add each element for (int j = idx0; j < idx1; j++) { int row = A.nz_rows[j]; // First or only time it's encountered, copy the value if (table[row] == j) { A.nz_rows[j - offset] = row; A.nz_values[j - offset] = A.nz_values[j]; table[row] = j - offset; // Update the table to include the offset location } else { // Each time it's encountered after this add the value and increase the offset A.nz_values[table[row]] += A.nz_values[j]; offset++; } } A.col_idx[i + 1] -= offset; // Need to do a second pass to undo the markings in the lookup table idx1 -= offset; for (int j = A.col_idx[i]; j < idx1; j++) { table[A.nz_rows[j]] = -1; } } A.nz_length -= offset; } /** * Given a symmetric matrix which is represented by a lower triangular matrix convert it back into * a full symmetric matrix * * @param A (Input) Lower triangular matrix * @param B (Output) Symmetric matrix. * @param gw (Optional) Workspace. Can be null. */ public static void symmLowerToFull( FMatrixSparseCSC A, FMatrixSparseCSC B, @Nullable IGrowArray gw ) { if (A.numCols != A.numRows) throw new IllegalArgumentException("Must be a lower triangular square matrix"); int N = A.numCols; int[] w = adjust(gw, N, N); B.reshape(N, N, A.nz_length*2); B.indicesSorted = false; //=== determine the row counts of the full matrix for (int col = 0; col < N; col++) { int idx0 = A.col_idx[col]; int idx1 = A.col_idx[col + 1]; // We know the length of the lower part of this column already w[col] += idx1 - idx0; // add elements to the top of the other columns along row with index 'col' for (int i = idx0; i < idx1; i++) { int row = A.nz_rows[i]; if (row > col) { w[row]++; } } } // Update the structure of B B.histogramToStructure(w); // Zero W again. It's being used to keep track of how many elements have been added to a column already Arrays.fill(w, 0, N, 0); // Fill in matrix for (int col = 0; col < N; col++) { int idx0 = A.col_idx[col]; int idx1 = A.col_idx[col + 1]; int lengthA = idx1 - idx0; int lengthB = B.col_idx[col + 1] - B.col_idx[col]; // Copy the non-zero values from A into B along the columns while taking in account the upper // elements already copied System.arraycopy(A.nz_values, idx0, B.nz_values, B.col_idx[col] + lengthB - lengthA, lengthA); System.arraycopy(A.nz_rows, idx0, B.nz_rows, B.col_idx[col] + lengthB - lengthA, lengthA); // Copy this column into the upper portion of B for (int i = idx0; i < idx1; i++) { int row = A.nz_rows[i]; if (row > col) { int indexB = B.col_idx[row] + w[row]++; B.nz_rows[indexB] = col; B.nz_values[indexB] = A.nz_values[i]; } } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy