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

net.maizegenetics.util.SuperByteMatrixMultiple Maven / Gradle / Ivy

/*
 *  SuperByteMatrixMultiple
 */
package net.maizegenetics.util;

import java.util.Arrays;
import java.util.Spliterator;
import static java.util.Spliterator.IMMUTABLE;
import static java.util.Spliterator.ORDERED;
import static java.util.Spliterator.SIZED;
import static java.util.Spliterator.SUBSIZED;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 *
 * @author Terry Casstevens
 */
public class SuperByteMatrixMultiple implements SuperByteMatrix {

    private final byte[][] myData;
    private final int myNumRows;
    private final int myNumColumns;
    private final int myNumRowsPerSingleDimArray;
    private final long myNumElements;
    private final int myNumElementsPerSingleDimArray;

    SuperByteMatrixMultiple(int rows, int columns) {

        myNumRows = rows;
        myNumColumns = columns;

        myNumElements = (long) myNumRows * (long) myNumColumns;
        myNumRowsPerSingleDimArray = Integer.MAX_VALUE / myNumColumns;
        myNumElementsPerSingleDimArray = myNumRowsPerSingleDimArray * myNumColumns;
        int numSingleDimArrays = (int) (myNumElements / (long) myNumElementsPerSingleDimArray);
        int numRemaining = (int) (myNumElements % (long) myNumElementsPerSingleDimArray);
        if (numRemaining != 0) {
            myData = new byte[numSingleDimArrays + 1][];
            for (int i = 0; i < numSingleDimArrays; i++) {
                myData[i] = new byte[myNumElementsPerSingleDimArray];
            }
            myData[numSingleDimArrays] = new byte[numRemaining];
        } else {
            myData = new byte[numSingleDimArrays][];
            for (int i = 0; i < numSingleDimArrays; i++) {
                myData[i] = new byte[myNumElementsPerSingleDimArray];
            }
        }

    }

    @Override
    public void set(int row, int column, byte value) {
        myData[getFirstIndex(row)][getSecondIndex(row, column)] = value;
    }

    @Override
    public void setAll(byte value) {
        int numSingleDimArrays = myData.length;
        for (int i = 0; i < numSingleDimArrays; i++) {
            Arrays.fill(myData[i], value);
        }
    }

    @Override
    public byte get(int row, int column) {
        return myData[getFirstIndex(row)][getSecondIndex(row, column)];
    }

    @Override
    public byte[] getAllColumns(int row) {

        if ((row < 0) || (row >= myNumRows)) {
            throw new IndexOutOfBoundsException("SuperByteMatrixMultiple: getAllColumns: row: " + row);
        }

        int start = getSecondIndex(row, 0);
        byte[] result = new byte[myNumColumns];
        System.arraycopy(myData[getFirstIndex(row)], start, result, 0, myNumColumns);
        return result;

    }

    @Override
    public byte[] getColumnRange(int row, int start, int end) {

        if ((row < 0) || (row >= myNumRows)) {
            throw new IndexOutOfBoundsException("SuperByteMatrixMultiple: getColumnRange: row: " + row);
        }

        if ((start < 0) || (start >= myNumColumns)) {
            throw new IndexOutOfBoundsException("SuperByteMatrixMultiple: getColumnRange: start: " + start);
        }

        if ((end < 0) || (end >= myNumColumns)) {
            throw new IndexOutOfBoundsException("SuperByteMatrixMultiple: getColumnRange: end: " + end);
        }

        if (end < start) {
            throw new IllegalArgumentException("SuperByteMatrixMultiple: getColumnRange: end: " + end + " less than start: " + start);
        }

        int startIndex = getSecondIndex(row, start);
        int numElements = end - start;
        byte[] result = new byte[numElements];
        System.arraycopy(myData[getFirstIndex(row)], startIndex, result, 0, numElements);
        return result;

    }

    @Override
    public byte[] getAllRows(int column) {

        if ((column < 0) || (column >= myNumColumns)) {
            throw new IndexOutOfBoundsException("SuperByteMatrixMultiple: getAllRows: column: " + column);
        }

        byte[] result = new byte[myNumRows];
        for (int row = 0; row < myNumRows; row++) {
            result[row] = get(row, column);
        }
        return result;

    }

    private int getFirstIndex(int row) {
        return row / myNumRowsPerSingleDimArray;
    }

    private int getSecondIndex(int row, int column) {
        return (row % myNumRowsPerSingleDimArray) * myNumColumns + column;
    }

    @Override
    public int getNumRows() {
        return myNumRows;
    }

    @Override
    public int getNumColumns() {
        return myNumColumns;
    }

    @Override
    public boolean isColumnInnerLoop() {
        return true;
    }

    @Override
    public void reorderRows(int[] newIndices) {

        if (newIndices.length != myNumRows) {
            throw new IllegalArgumentException("SuperByteMatrixMultiple: reorderRows: index array size: " + newIndices.length + " doesn't equal num rows in matrix: " + myNumRows);
        }

        int[] tempIndices = new int[newIndices.length];
        System.arraycopy(newIndices, 0, tempIndices, 0, myNumRows);

        int currentRow = 0;
        byte[] temp = new byte[myNumColumns];

        while (currentRow < myNumRows) {

            while (currentRow < myNumRows) {
                if ((tempIndices[currentRow] == currentRow) || (tempIndices[currentRow] == -1)) {
                    tempIndices[currentRow] = -1;
                } else {
                    break;
                }
                currentRow++;
            }

            if (currentRow < myNumRows) {

                System.arraycopy(myData[getFirstIndex(currentRow)], getSecondIndex(currentRow, 0), temp, 0, myNumColumns);

                int srcRow = tempIndices[currentRow];
                int destRow = currentRow;
                while (srcRow != currentRow) {
                    System.arraycopy(myData[getFirstIndex(srcRow)], getSecondIndex(srcRow, 0), myData[getFirstIndex(destRow)], getSecondIndex(destRow, 0), myNumColumns);
                    tempIndices[destRow] = -1;
                    destRow = srcRow;
                    srcRow = tempIndices[destRow];
                }

                System.arraycopy(temp, 0, myData[getFirstIndex(destRow)], getSecondIndex(destRow, 0), myNumColumns);
                tempIndices[destRow] = -1;

            }

        }

    }

    @Override
    public void reorderColumns(int[] newIndices) {

        if (newIndices.length != myNumColumns) {
            throw new IllegalArgumentException("SuperByteMatrixMultiple: reorderColumns: index array size: " + newIndices.length + " doesn't equal num columns in matrix: " + myNumColumns);
        }

        int[] tempIndices = new int[newIndices.length];
        System.arraycopy(newIndices, 0, tempIndices, 0, myNumColumns);

        int currentRow = 0;
        byte[] temp = new byte[myNumRows];

        while (currentRow < myNumColumns) {

            while (currentRow < myNumColumns) {
                if ((tempIndices[currentRow] == currentRow) || (tempIndices[currentRow] == -1)) {
                    tempIndices[currentRow] = -1;
                } else {
                    break;
                }
                currentRow++;
            }

            if (currentRow < myNumColumns) {

                for (int r = 0; r < myNumRows; r++) {
                    temp[r] = get(r, currentRow);
                }

                int srcColumn = tempIndices[currentRow];
                int destColumn = currentRow;
                while (srcColumn != currentRow) {
                    for (int r = 0; r < myNumRows; r++) {
                        set(r, destColumn, get(r, srcColumn));
                    }
                    tempIndices[destColumn] = -1;
                    destColumn = srcColumn;
                    srcColumn = tempIndices[destColumn];
                }

                for (int r = 0; r < myNumRows; r++) {
                    set(r, destColumn, temp[r]);
                }
                tempIndices[destColumn] = -1;

            }

        }

    }

    @Override
    public void setHetsTo(byte value) {
        for (byte[] current : myData) {
            for (int i = 0; i < current.length; i++) {
                if (((current[i] >>> 4) & 0xf) != (current[i] & 0xf)) {
                    current[i] = value;
                }
            }
        }
    }

    @Override
    public void arraycopy(int row, byte[] src, int startColumn) {
        System.arraycopy(src, 0, myData[getFirstIndex(row)], getSecondIndex(row, startColumn), src.length);
    }

    @Override
    public Stream stream() {
        return StreamSupport.stream(spliterator(), true);
    }

    @Override
    public Stream stream(int row) {
        long start = (long) row * (long) myNumColumns;
        return StreamSupport.stream(new SuperByteMatrixMultipleSpliterator<>(start, start + (long) myNumColumns), true);
    }

    public Spliterator spliterator() {
        return new SuperByteMatrixMultipleSpliterator<>(0, myNumElements);
    }

    class SuperByteMatrixMultipleSpliterator implements Spliterator {

        private long myCurrentIndex;
        private final long myFence;

        SuperByteMatrixMultipleSpliterator(long currentIndex, long fence) {
            myCurrentIndex = currentIndex;
            myFence = fence;
        }

        private int firstIndex(long index) {
            return (int) (index / myNumElementsPerSingleDimArray);
        }

        private int secondIndex(long index) {
            return (int) (index % myNumElementsPerSingleDimArray);
        }

        @Override
        public void forEachRemaining(Consumer action) {

            int firstIndex = firstIndex(myCurrentIndex);
            int secondIndex = secondIndex(myCurrentIndex);
            int fenceFirst = firstIndex(myFence);
            int fenceSecond = secondIndex(myFence);

            if (firstIndex == fenceFirst) {
                for (int i = secondIndex; i < fenceSecond; i++) {
                    action.accept(Byte.valueOf(myData[firstIndex][i]));
                }
            } else {
                for (int i = secondIndex; i < myNumElementsPerSingleDimArray; i++) {
                    action.accept(Byte.valueOf(myData[firstIndex][i]));
                }
                for (int i = firstIndex + 1; i < fenceFirst; i++) {
                    for (int j = 0; j < myNumElementsPerSingleDimArray; j++) {
                        action.accept(Byte.valueOf(myData[i][j]));
                    }
                }
                for (int i = 0; i < fenceSecond; i++) {
                    action.accept(Byte.valueOf(myData[fenceFirst][i]));
                }
            }

            myCurrentIndex = myFence;

        }

        @Override
        public boolean tryAdvance(Consumer action) {
            if (myCurrentIndex < myFence) {
                action.accept(Byte.valueOf(myData[firstIndex(myCurrentIndex)][secondIndex(myCurrentIndex)]));
                myCurrentIndex++;
                return true;
            } else {
                return false;
            }
        }

        @Override
        public Spliterator trySplit() {
            long lo = myCurrentIndex;
            long mid = (lo + myFence) >>> 1;
            if (lo < mid) {
                myCurrentIndex = mid;
                return new SuperByteMatrixMultipleSpliterator<>(lo, mid);
            } else {
                return null;
            }
        }

        @Override
        public long estimateSize() {
            return myFence - myCurrentIndex;
        }

        @Override
        public int characteristics() {
            return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy