Package net.algart.arrays

Source Code of net.algart.arrays.ArraysSubMatrixCopier

/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2014 Daniel Alievsky, AlgART Laboratory (http://algart.net)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package net.algart.arrays;

import net.algart.math.IRange;

abstract class ArraysSubMatrixCopier {
    private static final boolean ENABLE_THIS_OPTIMIZATION = Arrays.SystemSettings.getBooleanProperty(
        "net.algart.arrays.enableSubMatrixCopierOptimization", true);
    private static final boolean ENABLE_CONTINUOUS_OPTIMIZATION_FOR_DEST = Arrays.SystemSettings.getBooleanProperty(
        "net.algart.arrays.enableSubMatrixCopierContinuousDestOptimization", true);
    private static final boolean ENABLE_CONTINUOUS_OPTIMIZATION_FOR_SRC = Arrays.SystemSettings.getBooleanProperty(
        "net.algart.arrays.enableSubMatrixCopierContinuousSrcOptimization", true);

    private static final boolean DEBUG_MODE = false;
    private static final boolean DEBUG_ALSO_ONE_DIMENSIONAL = false;

    private static final long MIN_ARRAY_LENGTH_FOR_COPY_SUB_MATRIX = DEBUG_MODE ? 1 : 1024;

    final Matrix<? extends UpdatableArray> dest;
    final Matrix<? extends Array> src;
    final Matrix.ContinuationMode destContinuationMode;
    final Matrix.ContinuationMode srcContinuationMode;
    final int n;
    final long[] destPosition;
    final long[] srcPosition;
    final long[] dimensions;
    final boolean isCopierToTiled;
    final Matrix<? extends Array> tileParent;
    final ArraysTileMatrixImpl.Indexer tilingIndexer;
    final long[] tileDimensions;
    final long[] tileStartIndexes;
    final long[] tileCounts;
    final Matrix<?> tileEnumerator; // - trivial virtual matrix to enumerate all tiles
    final boolean processingDeclined;
    boolean nothingToDo = false; // - correct only if !processingDeclined

    ArraysSubMatrixCopier(
        Matrix<? extends UpdatableArray> dest,
        Matrix<? extends Array> src,
        Matrix.ContinuationMode destContinuationMode,
        Matrix.ContinuationMode srcContinuationMode,
        long[] destPosition,
        long[] srcPosition,
        long[] dimensions,
        boolean isCopierToTiled)
    {
        assert src.dimCount() == dimensions.length;
        assert destPosition.length == dimensions.length;
        assert srcPosition.length == dimensions.length;
        assert dest.dimCount() == dimensions.length;
        assert destContinuationMode != null;
        assert srcContinuationMode != null;
        assert isCopierToTiled ? dest.isTiled() : src.isTiled();
        this.dest = dest;
        this.src = src;
        this.destContinuationMode = destContinuationMode;
        this.srcContinuationMode = srcContinuationMode;
        this.destPosition = destPosition;
        this.srcPosition = srcPosition;
        this.dimensions = dimensions;
        this.n = dimensions.length;
        this.isCopierToTiled = isCopierToTiled;
        this.tileParent = (isCopierToTiled ? dest : src).tileParent();
        // Overflows below are impossible: the position information is loaded either from subMatrix, or from Region
        boolean fullyInsideDest = true;
        for (int k = 0; k < n; k++) {
            assert this.dimensions[k] >= 0;
            if (this.destPosition[k] < 0) {
                this.srcPosition[k] -= this.destPosition[k];
                this.dimensions[k] += this.destPosition[k];
                this.destPosition[k] = 0;
                fullyInsideDest = false;
            }
            if (this.destPosition[k] > dest.dim(k) - this.dimensions[k]) {
                // must check this and correct dimensions also if there was this.destPosition[k] < 0!
                this.dimensions[k] = dest.dim(k) - this.destPosition[k];
                fullyInsideDest = false;
            }
            if (this.dimensions[k] <= 0) {
                this.dimensions[k] = 0; // to be on the safe side
                this.nothingToDo = true;
            }
        }
        // After this loop, there is also a guarantee that this.dimensions is a subregion of some correct Matrix
        assert fullyInsideDest || destContinuationMode != Matrix.ContinuationMode.NONE;
        // - if dest subMatrix must be inside the full matrix, it was already checked before this call
        this.processingDeclined = !fullyInsideDest && !destContinuationMode.isConstant();
        // - the loop above is not a correct solution for non-trivial continuation models
        if (this.nothingToDo || this.processingDeclined) {
            this.tilingIndexer = null;
            this.tileDimensions = null;
            this.tileStartIndexes = null;
            this.tileCounts = null;
            this.tileEnumerator = null;
        } else {
            Array a = (isCopierToTiled ? dest : src).array();
            this.tilingIndexer = a instanceof ArraysTileMatrixImpl.TileMatrixArray ?
                ((ArraysTileMatrixImpl.TileMatrixArray) a).indexer() :
                null; // - possible in non-standard implementations of Matrix interface
            this.tileDimensions = (isCopierToTiled ? dest : src).tileDimensions();
            this.tileStartIndexes = new long[n];
            this.tileCounts = new long[n];
            long[] positionInTiled = isCopierToTiled ? destPosition : srcPosition;
            for (int k = 0; k < n; k++) {
                assert this.tileDimensions[k] > 0 : "Illegal tiling (negative tile dimension)";
                assert dimensions[k] > 0; // because !processingDeclined
                assert dimensions[k] <= dest.dim(k); // because of the loop above
                long min = positionInTiled[k];
                long minIndex = min >= 0 ? min / this.tileDimensions[k] : (min + 1) / this.tileDimensions[k] - 1;
                long max = min + this.dimensions[k] - 1;
                long maxIndex = max >= 0 ? max / this.tileDimensions[k] : (max + 1) / this.tileDimensions[k] - 1;
                assert maxIndex <= maxIndex;
                this.tileStartIndexes[k] = minIndex;
                this.tileCounts[k] = maxIndex - minIndex + 1;
                assert this.tileCounts[k] <= dimensions[k]; // and, so, overflow in longMul below is impossible
            }
//            System.out.println(JArrays.toString(dimensions, ",", 100) + "; " + JArrays.toString(tileCounts,",",100)
//                + "; " + JArrays.toString(srcPosition, ",", 100) + "; " + JArrays.toString(destPosition,",",100)
//                + "; " + isCopierToTiled);
            this.tileEnumerator = Matrices.matrix(Arrays.nIntCopies(Arrays.longMul(tileCounts), 157), tileCounts);
        }
    }

    // for usage from AbstractArray.defaultCopy
    public static boolean copySubMatrixArray(
        ArrayContext context, // not used in the current version of this library
        UpdatableArray dest, Array src)
    {
        if (!ENABLE_THIS_OPTIMIZATION) {
            return false;
        }
        if (dest instanceof ArraysSubMatrixImpl.SubMatrixArray) {
            if (dest.length() < MIN_ARRAY_LENGTH_FOR_COPY_SUB_MATRIX || src.length() < dest.length()) {
                return false;
            }
            ArraysSubMatrixImpl.SubMatrixArray sma = (ArraysSubMatrixImpl.SubMatrixArray) dest;
            Matrix<? extends UpdatableArray> baseMatrix = sma.baseMatrix().cast(UpdatableArray.class);
            if (!baseMatrix.isTiled()) {
                return false;
            }
            if (!DEBUG_ALSO_ONE_DIMENSIONAL && baseMatrix.dimCount() == 1) {
                return false;
            }
            long[] dimensions = sma.dimensions();
            long[] destPosition = sma.from();
            long[] srcPosition = new long[dimensions.length]; // zero-filled
            return new ToTiled(
                baseMatrix, Matrices.matrixAtSubArray(src, 0, dimensions),
                sma.continuationMode(), Matrix.ContinuationMode.NONE,
                destPosition, srcPosition, dimensions).copySubMatrix(context);
        }
        if (src instanceof ArraysSubMatrixImpl.SubMatrixArray) {
            if (src.length() < MIN_ARRAY_LENGTH_FOR_COPY_SUB_MATRIX || dest.length() < src.length()) {
                return false;
            }
            ArraysSubMatrixImpl.SubMatrixArray sma = (ArraysSubMatrixImpl.SubMatrixArray) src;
            Matrix<? extends Array> baseMatrix = sma.baseMatrix();
            if (!baseMatrix.isTiled()) {
                return false;
            }
            if (!DEBUG_ALSO_ONE_DIMENSIONAL && baseMatrix.dimCount() == 1) {
                return false;
            }
            long[] dimensions = sma.dimensions();
            long[] srcPosition = sma.from();
            long[] destPosition = new long[dimensions.length]; // zero-filled
            return new FromTiled(
                Matrices.matrixAtSubArray(dest, 0, dimensions), baseMatrix,
                Matrix.ContinuationMode.NONE, sma.continuationMode(),
                destPosition, srcPosition, dimensions).copySubMatrix(context);
        }
        return false;
    }

    // for usage from copyRegion
    public static boolean copySubMatrixRegion(
        ArrayContext context,
        Matrix<? extends UpdatableArray> dest, Matrix<? extends Array> src,
        Matrix.ContinuationMode continuationMode,
        Matrices.Region destRegion, long... shifts)
    {
        if (!ENABLE_THIS_OPTIMIZATION) {
            return false;
        }
        if (!(destRegion instanceof Matrices.Hyperparallelepiped)) {
            return false;
        }
        final int n = destRegion.n();
        if (dest.dimCount() != n || src.dimCount() != n) {
            return false; // non-traditional use, not supported by copySubMatrix
        }
        if (!src.isTiled() && !dest.isTiled()) {
            return false;
        }
        if (!DEBUG_ALSO_ONE_DIMENSIONAL && n == 1) {
            return false;
        }
        long[] dimensions = new long[n];
        long[] destPosition = new long[n];
        long[] srcPosition = new long[n];
        for (int k = 0; k < n; k++) {
            IRange range = destRegion.coordRange(k);
            dimensions[k] = range.size();
            destPosition[k] = range.min();
            srcPosition[k] = shifts.length > k ? destPosition[k] - shifts[k] : destPosition[k];
        }
        if (dest.isTiled()) {
            return new ToTiled(dest, src, continuationMode, continuationMode,
                destPosition, srcPosition, dimensions).copySubMatrix(context);
        } else if (src.isTiled()) {
            return new FromTiled(dest, src, continuationMode, continuationMode,
                destPosition, srcPosition, dimensions).copySubMatrix(context);
        } else {
            throw new AssertionError("Mutable isTiled!");
        }
    }

    boolean copySubMatrix(ArrayContext context) {
        if (processingDeclined) { // must be checked before nothingToDo!
            return false;
        }
        if (nothingToDo) {
            return true;
        }
        final long tileCount = tileEnumerator.size();
        if (tileCount <= 1) {
            // no sense to optimize copying inside 1 tile: for example, copyRegion will probably work faster
            return false;
        }
        long[] positionInTiled = isCopierToTiled ? destPosition : srcPosition;
        long[] tileIndexes = new long[n];
        long[] tilePartPos = new long[n];
        long[] tilePartDim = new long[n];
        long[] work = new long[n];
        long readyCount = 0;
        long totalCount = Arrays.longMul(dimensions);
        for (long tileIndex = 0; tileIndex < tileCount; tileIndex++) {
            tileEnumerator.coordinates(tileIndex, tileIndexes);
            boolean continuousSubArray = true;
            // - this tile part corresponds to a continuous block in the parent array (which was tiled), if:
            // 1) it fully lies inside the matrix (in other case, subMatrix mechanism provides different schemes
            // for continuation depending on the continuation model: we do not try to optimize this case)
            // 2) it is the whole tile (100% of the matrix tile) or, maybe, a part along the high (last) coordinate,
            // but the full tile along all other coordinates; for example, for 2-dimensional matrix 8700x3400 and
            // tiles 1000x1000: (7000..7642)x(1000..2000) is not continuous, but (7000..7999)x(1100x1900) and
            // (8000..8699)x(1100x1900) are continuous
            long tileSize = 1;
            long dimMul = 1;
            long tilePosIndex = 0;
            for (int k = 0; k < n; k++) {
                long i = tileIndexes[k];
                long tileFrom = (i + tileStartIndexes[k]) * tileDimensions[k];
                long tileTo = tileFrom + tileDimensions[k];
                long partFrom = tileFrom;
                long partTo = tileTo;
                long dim = tileParent.dim(k);
                if (i == 0) {
                    // "(i + tileStartIndexes[k]) * tileDimensions[k]" can lead to negative overflow in this case
                    partFrom = positionInTiled[k];
                    if (k < n - 1 && partFrom != tileFrom) {
                        continuousSubArray = false;
                    }
                }
                if (i == tileCounts[k] - 1) {
                    // "tileFrom + tileDimensions[k]" can lead partTo positive overflow in this case
                    partTo = positionInTiled[k] + dimensions[k];
                    tileTo = tileTo < dim ? tileTo : dim; // stays unchanged in a case of overflow
                    if (k < n - 1 && partTo != tileTo) {
                        continuousSubArray = false;
                    }
                }
                if (partFrom > partTo)
                    throw new AssertionError("k=" + k + ", partFrom..partTo=" + partFrom + ".." + partTo + ", i=" + i
                    + ", tileStartIndexes[k]=" + tileStartIndexes[k]
                    + ", positionInTiled[k]=" + positionInTiled[k] + ", dimensions[k]=" + dimensions[k]
                    + ", tilePartDim[k]=" + tileDimensions[k]
                        + ", tilePartDim={" + JArrays.toString(tileDimensions, ",", 200) + "}");
                if (partFrom < 0 || partTo > dim) { // this tile part lies outside the tiled matrix
                    continuousSubArray = false;
                }
                tilePartPos[k] = partFrom;
                tilePartDim[k] = partTo - partFrom;
                tilePosIndex += partFrom * dimMul;
                dimMul *= dim;
                tileSize *= tilePartDim[k];
            }
            long translatedTilePosIndex = continuousSubArray ? tilingIndexer.translate(tilePosIndex) : -1;
            if (DEBUG_MODE && continuousSubArray) {
                assert tilePosIndex == tileParent.index(tilePartPos);
                assert tilePosIndex >= 0 && tilePosIndex + tileSize <= tileParent.size() :
                    tilePosIndex + "+" + tileSize + ", " + tileParent.size();
                assert translatedTilePosIndex >= 0 && translatedTilePosIndex + tileSize <= tileParent.size();
            }
            copyTileOrPartOfTile(tilePartPos, tilePartDim, work, translatedTilePosIndex, tileSize);
            if (context != null) {
                context.checkInterruptionAndUpdateProgress(dest.elementType(), readyCount, totalCount);
            }
            readyCount += tileSize;
            assert readyCount <= totalCount;
        }
        return true;
    }


    abstract void copyTileOrPartOfTile(
        long[] partPos, long[] partDim, long[] workMemory,
        long partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase, long partSize);

    private static class ToTiled extends ArraysSubMatrixCopier {
        private ToTiled(
            Matrix<? extends UpdatableArray> dest,
            Matrix<? extends Array> src,
            Matrix.ContinuationMode destContinuationMode,
            Matrix.ContinuationMode srcContinuationMode,
            long[] destPosition,
            long[] srcPosition,
            long[] dimensions)
        {
            super(dest, src, destContinuationMode, srcContinuationMode, destPosition, srcPosition, dimensions, true);
        }

        @Override
        void copyTileOrPartOfTile(
            long[] partPos, long[] partDim, long[] workMemoryForSrcPos,
            long partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase, long partSize)
        {
            for (int k = 0; k < partDim.length; k++) {
                workMemoryForSrcPos[k] = srcPosition[k] + partPos[k] - destPosition[k];
            }
//            System.out.print("Copying tile " + JArrays.toString(partDim, ",", 100) + " started at "
//                + JArrays.toString(partPos, ",", 100) + " to tiled, index "
//                + partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase + "... ");
            UpdatableArray destArray = ENABLE_CONTINUOUS_OPTIMIZATION_FOR_DEST
                && partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase != -1 ?
                (UpdatableArray) tileParent.array().subArr(
                    partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase, partSize) :
                dest.subMatr(partPos, partDim).array();
            Array srcArray = src.subMatr(workMemoryForSrcPos, partDim, srcContinuationMode).array();
            AbstractArray.defaultCopyWithoutOptimizations(destArray, srcArray);
//            System.out.println("done");
        }
    }

    private static class FromTiled extends ArraysSubMatrixCopier {
        private FromTiled(
            Matrix<? extends UpdatableArray> dest,
            Matrix<? extends Array> src,
            Matrix.ContinuationMode destContinuationMode,
            Matrix.ContinuationMode srcContinuationMode,
            long[] destPosition,
            long[] srcPosition,
            long[] dimensions)
        {
            super(dest, src, destContinuationMode, srcContinuationMode, destPosition, srcPosition, dimensions, false);
        }

        @Override
        void copyTileOrPartOfTile(
            long[] partPos, long[] partDim, long[] workMemoryForDestPos,
            long partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase, long partSize)
        {
            for (int k = 0; k < partDim.length; k++) {
                workMemoryForDestPos[k] = destPosition[k] + partPos[k] - srcPosition[k];
            }
//            System.out.print("Copying tile " + JArrays.toString(partDim, ",", 100) + " started at "
//                + JArrays.toString(partPos, ",", 100) + " from tiled, index "
//                + partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase + "... ");
            UpdatableArray destArray = dest.subMatr(workMemoryForDestPos, partDim).array();
            Array srcArray = ENABLE_CONTINUOUS_OPTIMIZATION_FOR_SRC
                && partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase != -1 ?
                tileParent.array().subArr(
                    partIndexInTheBaseIfItIsContinuousSubArrayOfTheBase, partSize) :
                src.subMatr(partPos, partDim, srcContinuationMode).array();
            AbstractArray.defaultCopyWithoutOptimizations(destArray, srcArray);
//            System.out.println("done");
        }
    }
}
TOP

Related Classes of net.algart.arrays.ArraysSubMatrixCopier

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.