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

org.ojalgo.matrix.store.R064Store Maven / Gradle / Ivy

Go to download

oj! Algorithms - ojAlgo - is Open Source Java code that has to do with mathematics, linear algebra and optimisation.

There is a newer version: 55.0.1
Show newest version
/*
 * Copyright 1997-2024 Optimatika
 *
 * 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 org.ojalgo.matrix.store;

import static org.ojalgo.function.constant.PrimitiveMath.ONE;
import static org.ojalgo.function.constant.PrimitiveMath.ZERO;

import java.util.Arrays;

import org.ojalgo.ProgrammingError;
import org.ojalgo.array.Array1D;
import org.ojalgo.array.Array2D;
import org.ojalgo.array.ArrayC128;
import org.ojalgo.array.ArrayR064;
import org.ojalgo.array.BasicArray;
import org.ojalgo.array.operation.*;
import org.ojalgo.concurrent.DivideAndConquer;
import org.ojalgo.function.BinaryFunction;
import org.ojalgo.function.NullaryFunction;
import org.ojalgo.function.UnaryFunction;
import org.ojalgo.function.VoidFunction;
import org.ojalgo.function.constant.PrimitiveMath;
import org.ojalgo.function.special.MissingMath;
import org.ojalgo.machine.JavaType;
import org.ojalgo.machine.MemoryEstimator;
import org.ojalgo.matrix.decomposition.DecompositionStore;
import org.ojalgo.matrix.decomposition.EvD1D;
import org.ojalgo.matrix.operation.HouseholderLeft;
import org.ojalgo.matrix.operation.HouseholderRight;
import org.ojalgo.matrix.operation.MultiplyBoth;
import org.ojalgo.matrix.operation.MultiplyLeft;
import org.ojalgo.matrix.operation.MultiplyNeither;
import org.ojalgo.matrix.operation.MultiplyRight;
import org.ojalgo.matrix.transformation.Householder;
import org.ojalgo.matrix.transformation.HouseholderReference;
import org.ojalgo.matrix.transformation.Rotation;
import org.ojalgo.scalar.ComplexNumber;
import org.ojalgo.scalar.PrimitiveScalar;
import org.ojalgo.structure.Access1D;
import org.ojalgo.structure.Access2D;
import org.ojalgo.structure.Factory2D;
import org.ojalgo.structure.Mutate1D;
import org.ojalgo.type.math.MathType;

/**
 * A {@linkplain double} implementation of {@linkplain PhysicalStore}.
 *
 * @author apete
 */
public final class R064Store extends ArrayR064 implements PhysicalStore, DecompositionStore, Factory2D.Builder {

    public static final PhysicalStore.Factory FACTORY = new PrimitiveFactory<>() {

        @Override
        public R064Store copy(final Access2D source) {

            final int tmpRowDim = (int) source.countRows();
            final int tmpColDim = (int) source.countColumns();

            final R064Store retVal = new R064Store(tmpRowDim, tmpColDim);

            if (tmpColDim > FillMatchingSingle.THRESHOLD) {

                final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                    @Override
                    public void conquer(final int aFirst, final int aLimit) {
                        FillMatchingSingle.copy(retVal.data, tmpRowDim, aFirst, aLimit, source);
                    }

                };

                tmpConquerer.invoke(0, tmpColDim, FillMatchingSingle.THRESHOLD);

            } else {

                FillMatchingSingle.copy(retVal.data, tmpRowDim, 0, tmpColDim, source);
            }

            return retVal;
        }

        @Override
        public MathType getMathType() {
            return MathType.R064;
        }

        @Override
        public R064Store make(final int rows, final int columns) {
            return new R064Store(rows, columns);
        }

        @Override
        public R064Store make(final long rows, final long columns) {
            return new R064Store((int) rows, (int) columns);
        }

        @Override
        public R064Store transpose(final Access2D source) {

            final R064Store retVal = new R064Store((int) source.countColumns(), (int) source.countRows());

            final int tmpRowDim = retVal.getRowDim();
            final int tmpColDim = retVal.getColDim();

            if (tmpColDim > FillMatchingSingle.THRESHOLD) {

                final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                    @Override
                    public void conquer(final int first, final int limit) {
                        FillMatchingSingle.transpose(retVal.data, tmpRowDim, first, limit, source);
                    }

                };

                tmpConquerer.invoke(0, tmpColDim, FillMatchingSingle.THRESHOLD);

            } else {

                FillMatchingSingle.transpose(retVal.data, tmpRowDim, 0, tmpColDim, source);
            }

            return retVal;
        }

    };

    static final long ELEMENT_SIZE = JavaType.DOUBLE.memory();

    static final long SHALLOW_SIZE = MemoryEstimator.estimateObject(R064Store.class);

    /**
     * Extracts the argument of the ComplexNumber elements to a new primitive double valued matrix.
     */
    public static R064Store getComplexArgument(final Access2D arg) {

        final long numberOfRows = arg.countRows();
        final long numberOfColumns = arg.countColumns();

        final R064Store retVal = FACTORY.make(numberOfRows, numberOfColumns);

        Mutate1D.copyComplexArgument(arg, retVal);

        return retVal;
    }

    /**
     * Extracts the imaginary part of the ComplexNumber elements to a new primitive double valued matrix.
     */
    public static R064Store getComplexImaginary(final Access2D arg) {

        final long numberOfRows = arg.countRows();
        final long numberOfColumns = arg.countColumns();

        final R064Store retVal = FACTORY.make(numberOfRows, numberOfColumns);

        Mutate1D.copyComplexImaginary(arg, retVal);

        return retVal;
    }

    /**
     * Extracts the modulus of the ComplexNumber elements to a new primitive double valued matrix.
     */
    public static R064Store getComplexModulus(final Access2D arg) {

        final long numberOfRows = arg.countRows();
        final long numberOfColumns = arg.countColumns();

        final R064Store retVal = FACTORY.make(numberOfRows, numberOfColumns);

        Mutate1D.copyComplexModulus(arg, retVal);

        return retVal;
    }

    /**
     * Extracts the real part of the ComplexNumber elements to a new primitive double valued matrix.
     */
    public static R064Store getComplexReal(final Access2D arg) {

        final long numberOfRows = arg.countRows();
        final long numberOfColumns = arg.countColumns();

        final R064Store retVal = FACTORY.make(numberOfRows, numberOfColumns);

        Mutate1D.copyComplexReal(arg, retVal);

        return retVal;
    }

    public static R064Store wrap(final double... data) {
        return new R064Store(data);
    }

    public static R064Store wrap(final double[] data, final int structure) {
        return new R064Store(structure, data.length / structure, data);
    }

    static R064Store cast(final Access1D matrix) {
        if (matrix instanceof R064Store) {
            return (R064Store) matrix;
        } else if (matrix instanceof Access2D) {
            return FACTORY.copy((Access2D) matrix);
        } else {
            return FACTORY.column(matrix);
        }
    }

    static Householder.Primitive64 cast(final Householder transformation) {
        if (transformation instanceof Householder.Primitive64) {
            return (Householder.Primitive64) transformation;
        }
        if (transformation instanceof HouseholderReference) {
            return ((Householder.Primitive64) ((HouseholderReference) transformation).getWorker(FACTORY)).copy(transformation);
        }
        return new Householder.Primitive64(transformation);
    }

    static Rotation.Primitive cast(final Rotation transformation) {
        if (transformation instanceof Rotation.Primitive) {
            return (Rotation.Primitive) transformation;
        }
        return new Rotation.Primitive(transformation);
    }

    private final MultiplyBoth.Primitive multiplyBoth;
    private final MultiplyLeft.Primitive64 multiplyLeft;
    private final MultiplyNeither.Primitive64 multiplyNeither;
    private final MultiplyRight.Primitive64 multiplyRight;
    private final int myColDim;
    private final int myRowDim;
    private final Array2D myUtility;
    private transient double[] myWorkerColumn;

    @SuppressWarnings("unused")
    private R064Store(final double[] dataArray) {
        this(dataArray.length, 1, dataArray);
    }

    @SuppressWarnings("unused")
    private R064Store(final int numbRows) {
        this(numbRows, 1);
    }

    R064Store(final int numbRows, final int numbCols, final double[] dataArray) {

        super(dataArray);

        myRowDim = numbRows;
        myColDim = numbCols;

        myUtility = this.wrapInArray2D(myRowDim);

        multiplyBoth = MultiplyBoth.newPrimitive64(myRowDim, myColDim);
        multiplyLeft = MultiplyLeft.newPrimitive64(myRowDim, myColDim);
        multiplyRight = MultiplyRight.newPrimitive64(myRowDim, myColDim);
        multiplyNeither = MultiplyNeither.newPrimitive64(myRowDim, myColDim);
    }

    R064Store(final long numbRows, final long numbCols) {

        super(Math.toIntExact(numbRows * numbCols));

        myRowDim = Math.toIntExact(numbRows);
        myColDim = Math.toIntExact(numbCols);

        myUtility = this.wrapInArray2D(myRowDim);

        multiplyBoth = MultiplyBoth.newPrimitive64(myRowDim, myColDim);
        multiplyLeft = MultiplyLeft.newPrimitive64(myRowDim, myColDim);
        multiplyRight = MultiplyRight.newPrimitive64(myRowDim, myColDim);
        multiplyNeither = MultiplyNeither.newPrimitive64(myRowDim, myColDim);
    }

    @Override
    public void accept(final Access2D supplied) {
        for (long j = 0L; j < supplied.countColumns(); j++) {
            for (long i = 0L; i < supplied.countRows(); i++) {
                this.set(i, j, supplied.doubleValue(i, j));
            }
        }
    }

    @Override
    public void add(final long row, final long col, final Comparable addend) {
        myUtility.add(row, col, addend);
    }

    @Override
    public void add(final long row, final long col, final double addend) {
        myUtility.add(row, col, addend);
    }

    @Override
    public void applyCholesky(final int iterationPoint, final BasicArray multipliers) {

        final double[] tmpData = data;
        final double[] tmpColumn = ((ArrayR064) multipliers).data;

        if (myColDim - iterationPoint - 1 > ApplyCholesky.THRESHOLD) {

            final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                @Override
                protected void conquer(final int first, final int limit) {
                    ApplyCholesky.invoke(tmpData, myRowDim, first, limit, tmpColumn);
                }
            };

            tmpConquerer.invoke(iterationPoint + 1, myColDim, ApplyCholesky.THRESHOLD);

        } else {

            ApplyCholesky.invoke(tmpData, myRowDim, iterationPoint + 1, myColDim, tmpColumn);
        }
    }

    @Override
    public void applyLDL(final int iterationPoint, final BasicArray multipliers) {

        final double[] column = ((ArrayR064) multipliers).data;

        if (myColDim - iterationPoint - 1 > ApplyLDL.THRESHOLD) {

            final DivideAndConquer conquerer = new DivideAndConquer() {

                @Override
                protected void conquer(final int first, final int limit) {
                    ApplyLDL.invoke(data, myRowDim, first, limit, column, iterationPoint);
                }
            };

            conquerer.invoke(iterationPoint + 1, myColDim, ApplyLDL.THRESHOLD);

        } else {

            ApplyLDL.invoke(data, myRowDim, iterationPoint + 1, myColDim, column, iterationPoint);
        }
    }

    @Override
    public void applyLU(final int iterationPoint, final BasicArray multipliers) {

        final double[] column = ((ArrayR064) multipliers).data;

        if (myColDim - iterationPoint - 1 > ApplyLU.THRESHOLD) {

            final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                @Override
                protected void conquer(final int first, final int limit) {
                    ApplyLU.invoke(data, myRowDim, first, limit, column, iterationPoint);
                }
            };

            tmpConquerer.invoke(iterationPoint + 1, myColDim, ApplyLU.THRESHOLD);

        } else {

            ApplyLU.invoke(data, myRowDim, iterationPoint + 1, myColDim, column, iterationPoint);
        }
    }

    @Override
    public Array1D asList() {
        return myUtility.flatten();
    }

    @Override
    public R064Store build() {
        return this;
    }

    public void caxpy(final double aSclrA, final int aColX, final int aColY, final int aFirstRow) {
        AXPY.invoke(data, aColY * myRowDim + aFirstRow, aSclrA, data, aColX * myRowDim + aFirstRow, 0, myRowDim - aFirstRow);
    }

    @Override
    public Array1D computeInPlaceSchur(final PhysicalStore transformationCollector, final boolean eigenvalue) {

        // final PrimitiveDenseStore tmpThisCopy = this.copy();
        // final PrimitiveDenseStore tmpCollCopy = (PrimitiveDenseStore)
        // aTransformationCollector.copy();
        //
        // tmpThisCopy.computeInPlaceHessenberg(true);

        // Actual

        final double[] tmpData = data;

        final double[] tmpCollectorData = ((R064Store) transformationCollector).data;

        final double[] tmpVctrWork = new double[this.getMinDim()];
        EvD1D.orthes(tmpData, tmpCollectorData, tmpVctrWork);

        // BasicLogger.logDebug("Schur Step", this);
        // BasicLogger.logDebug("Hessenberg", tmpThisCopy);

        final double[][] tmpDiags = EvD1D.hqr2(tmpData, tmpCollectorData, eigenvalue);
        final double[] aRawReal = tmpDiags[0];
        final double[] aRawImag = tmpDiags[1];
        final int tmpLength = Math.min(aRawReal.length, aRawImag.length);

        final ArrayC128 retVal = ArrayC128.make(tmpLength);
        final ComplexNumber[] tmpRaw = retVal.data;

        for (int i = 0; i < tmpLength; i++) {
            tmpRaw[i] = ComplexNumber.of(aRawReal[i], aRawImag[i]);
        }

        return Array1D.C128.wrap(retVal);
    }

    @Override
    public MatrixStore conjugate() {
        return this.transpose();
    }

    @Override
    public R064Store copy() {
        return new R064Store(myRowDim, myColDim, this.copyOfData());
    }

    @Override
    public long countColumns() {
        return myColDim;
    }

    @Override
    public long countRows() {
        return myRowDim;
    }

    @Override
    public void divideAndCopyColumn(final int row, final int column, final BasicArray destination) {

        double[] destinationData = ((ArrayR064) destination).data;

        int index = row + column * myRowDim;
        double denominator = data[index];

        for (int i = row + 1; i < myRowDim; i++) {
            destinationData[i] = data[++index] /= denominator;
        }
    }

    @Override
    public double doubleValue(final int row, final int col) {
        return myUtility.doubleValue(row, col);
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (!super.equals(obj) || !(obj instanceof R064Store)) {
            return false;
        }
        R064Store other = (R064Store) obj;
        if (myColDim != other.myColDim || myRowDim != other.myRowDim) {
            return false;
        }
        return true;
    }

    @Override
    public void exchangeColumns(final long colA, final long colB) {
        myUtility.exchangeColumns(colA, colB);
    }

    @Override
    public void exchangeHermitian(final int indexA, final int indexB) {

        final int indexMin = Math.min(indexA, indexB);
        final int indexMax = Math.max(indexA, indexB);

        double tmpVal;

        for (int j = 0; j < indexMin; j++) {
            tmpVal = this.doubleValue(indexMin, j);
            this.set(indexMin, j, this.doubleValue(indexMax, j));
            this.set(indexMax, j, tmpVal);
        }

        tmpVal = this.doubleValue(indexMin, indexMin);
        this.set(indexMin, indexMin, this.doubleValue(indexMax, indexMax));
        this.set(indexMax, indexMax, tmpVal);

        for (int ij = indexMin + 1; ij < indexMax; ij++) {
            tmpVal = this.doubleValue(ij, indexMin);
            this.set(ij, indexMin, this.doubleValue(indexMax, ij));
            this.set(indexMax, ij, tmpVal);
        }

        for (int i = indexMax + 1; i < myRowDim; i++) {
            tmpVal = this.doubleValue(i, indexMin);
            this.set(i, indexMin, this.doubleValue(i, indexMax));
            this.set(i, indexMax, tmpVal);
        }

    }

    @Override
    public void exchangeRows(final long rowA, final long rowB) {
        myUtility.exchangeRows(rowA, rowB);
    }

    @Override
    public void fillCompatible(final Access2D left, final BinaryFunction operator, final Access2D right) {
        FillCompatible.invoke(data, myRowDim, left, operator, right);
    }

    @Override
    public void fillByMultiplying(final Access1D left, final Access1D right) {

        final int complexity = Math.toIntExact(left.count() / this.countRows());
        if (complexity != Math.toIntExact(right.count() / this.countColumns())) {
            ProgrammingError.throwForMultiplicationNotPossible();
        }

        if (left instanceof R064Store) {
            if (right instanceof R064Store) {
                multiplyNeither.invoke(data, R064Store.cast(left).data, complexity, R064Store.cast(right).data);
            } else {
                multiplyRight.invoke(data, R064Store.cast(left).data, complexity, right);
            }
        } else if (right instanceof R064Store) {
            multiplyLeft.invoke(data, left, complexity, R064Store.cast(right).data);
        } else {
            multiplyBoth.invoke(this, left, complexity, right);
        }
    }

    @Override
    public void fillColumn(final long row, final long col, final Access1D values) {
        myUtility.fillColumn(row, col, values);
    }

    @Override
    public void fillColumn(final long row, final long col, final Double value) {
        myUtility.fillColumn(row, col, value);
    }

    @Override
    public void fillColumn(final long row, final long col, final NullaryFunction supplier) {
        myUtility.fillColumn(row, col, supplier);
    }

    @Override
    public void fillDiagonal(final long row, final long col, final Double value) {
        myUtility.fillDiagonal(row, col, value);
    }

    @Override
    public void fillDiagonal(final long row, final long col, final NullaryFunction supplier) {
        myUtility.fillDiagonal(row, col, supplier);
    }

    @Override
    public void fillMatching(final Access1D values) {

        if (values instanceof TransjugatedStore) {
            final TransjugatedStore transposed = (TransjugatedStore) values;

            if (myColDim > FillMatchingSingle.THRESHOLD) {

                final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                    @Override
                    public void conquer(final int first, final int limit) {
                        FillMatchingSingle.transpose(data, myRowDim, first, limit, transposed.getOriginal());
                    }

                };

                tmpConquerer.invoke(0, myColDim, FillMatchingSingle.THRESHOLD);

            } else {

                FillMatchingSingle.transpose(data, myRowDim, 0, myColDim, transposed.getOriginal());
            }

        } else {

            super.fillMatching(values);
        }
    }

    @Override
    public void fillMatching(final Access1D left, final BinaryFunction function, final Access1D right) {

        int matchingCount = MissingMath.toMinIntExact(this.count(), left.count(), right.count());

        if (myColDim > FillMatchingDual.THRESHOLD) {

            final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                @Override
                protected void conquer(final int first, final int limit) {
                    OperationBinary.invoke(data, first, limit, 1, left, function, right);
                }

            };

            tmpConquerer.invoke(0, matchingCount, FillMatchingDual.THRESHOLD * FillMatchingDual.THRESHOLD);

        } else {

            OperationBinary.invoke(data, 0, matchingCount, 1, left, function, right);
        }
    }

    @Override
    public void fillMatching(final UnaryFunction function, final Access1D arguments) {

        int matchingCount = MissingMath.toMinIntExact(this.count(), arguments.count());

        if (myColDim > FillMatchingSingle.THRESHOLD) {

            final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                @Override
                protected void conquer(final int first, final int limit) {
                    OperationUnary.invoke(data, first, limit, 1, arguments, function);
                }

            };

            tmpConquerer.invoke(0, matchingCount, FillMatchingSingle.THRESHOLD * FillMatchingSingle.THRESHOLD);

        } else {

            OperationUnary.invoke(data, 0, matchingCount, 1, arguments, function);
        }
    }

    @Override
    public void fillRow(final long row, final long col, final Access1D values) {
        myUtility.fillRow(row, col, values);
    }

    @Override
    public void fillRow(final long row, final long col, final Double value) {
        myUtility.fillRow(row, col, value);
    }

    @Override
    public void fillRow(final long row, final long col, final NullaryFunction supplier) {
        myUtility.fillRow(row, col, supplier);
    }

    @Override
    public boolean generateApplyAndCopyHouseholderColumn(final int row, final int column, final Householder destination) {
        return GenerateApplyAndCopyHouseholderColumn.invoke(data, myRowDim, row, column, (Householder.Primitive64) destination);
    }

    @Override
    public boolean generateApplyAndCopyHouseholderRow(final int row, final int column, final Householder destination) {
        return GenerateApplyAndCopyHouseholderRow.invoke(data, myRowDim, row, column, (Householder.Primitive64) destination);
    }

    @Override
    public MatrixStore get() {
        return this;
    }

    @Override
    public Double get(final int row, final int col) {
        return myUtility.get(row, col);
    }

    @Override
    public int getColDim() {
        return myColDim;
    }

    @Override
    public int getMaxDim() {
        return Math.max(myRowDim, myColDim);
    }

    @Override
    public int getMinDim() {
        return Math.min(myRowDim, myColDim);
    }

    @Override
    public int getRowDim() {
        return myRowDim;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + myColDim;
        return prime * result + myRowDim;
    }

    @Override
    public void modifyAll(final UnaryFunction modifier) {

        if (myColDim > ModifyAll.THRESHOLD) {

            final DivideAndConquer conquerer = new DivideAndConquer() {

                @Override
                public void conquer(final int first, final int limit) {
                    R064Store.this.modify(myRowDim * first, myRowDim * limit, 1, modifier);
                }

            };

            conquerer.invoke(0, myColDim, ModifyAll.THRESHOLD);

        } else {

            this.modify(0, myRowDim * myColDim, 1, modifier);
        }
    }

    @Override
    public void modifyColumn(final long row, final long col, final UnaryFunction modifier) {
        myUtility.modifyColumn(row, col, modifier);
    }

    @Override
    public void modifyDiagonal(final long row, final long col, final UnaryFunction modifier) {
        myUtility.modifyDiagonal(row, col, modifier);
    }

    @Override
    public void modifyOne(final long row, final long col, final UnaryFunction modifier) {

        double tmpValue = this.doubleValue(row, col);

        tmpValue = modifier.invoke(tmpValue);

        this.set(row, col, tmpValue);
    }

    @Override
    public void modifyRow(final long row, final long col, final UnaryFunction modifier) {
        myUtility.modifyRow(row, col, modifier);
    }

    @Override
    public MatrixStore multiply(final MatrixStore right) {

        R064Store retVal = FACTORY.make(myRowDim, right.countColumns());

        if (right instanceof R064Store) {
            retVal.multiplyNeither.invoke(retVal.data, data, myColDim, R064Store.cast(right).data);
        } else {
            retVal.multiplyRight.invoke(retVal.data, data, myColDim, right);
        }

        return retVal;
    }

    @Override
    public Double multiplyBoth(final Access1D leftAndRight) {

        PhysicalStore tmpStep1 = FACTORY.make(1L, leftAndRight.count());
        PhysicalStore tmpStep2 = FACTORY.make(1L, 1L);

        tmpStep1.fillByMultiplying(leftAndRight, this);
        tmpStep2.fillByMultiplying(tmpStep1, leftAndRight);

        return tmpStep2.get(0L);
    }

    @Override
    public void negateColumn(final int column) {
        myUtility.modifyColumn(0, column, PrimitiveMath.NEGATE);
    }

    @Override
    public PhysicalStore.Factory physical() {
        return FACTORY;
    }

    @Override
    public TransformableRegion regionByColumns(final int... columns) {
        return new Subregion2D.ColumnsRegion<>(this, multiplyBoth, columns);
    }

    @Override
    public TransformableRegion regionByLimits(final int rowLimit, final int columnLimit) {
        return new Subregion2D.LimitRegion<>(this, multiplyBoth, rowLimit, columnLimit);
    }

    @Override
    public TransformableRegion regionByOffsets(final int rowOffset, final int columnOffset) {
        return new Subregion2D.OffsetRegion<>(this, multiplyBoth, rowOffset, columnOffset);
    }

    @Override
    public TransformableRegion regionByRows(final int... rows) {
        return new Subregion2D.RowsRegion<>(this, multiplyBoth, rows);
    }

    @Override
    public TransformableRegion regionByTransposing() {
        return new Subregion2D.TransposedRegion<>(this, multiplyBoth);
    }

    @Override
    public void rotateRight(final int low, final int high, final double cos, final double sin) {
        RotateRight.invoke(data, myRowDim, low, high, cos, sin);
    }

    @Override
    public void set(final int row, final int col, final double value) {
        myUtility.set(row, col, value);
    }

    @Override
    public void set(final long row, final long col, final Comparable value) {
        myUtility.set(row, col, value);
    }

    @Override
    public void setToIdentity(final int col) {
        myUtility.set(col, col, ONE);
        myUtility.fillColumn(col + 1, col, ZERO);
    }

    @Override
    public Array1D sliceColumn(final long row, final long col) {
        return myUtility.sliceColumn(row, col);
    }

    @Override
    public Array1D sliceDiagonal(final long row, final long col) {
        return myUtility.sliceDiagonal(row, col);
    }

    @Override
    public Array1D sliceRange(final long first, final long limit) {
        return myUtility.sliceRange(first, limit);
    }

    @Override
    public Array1D sliceRow(final long row, final long col) {
        return myUtility.sliceRow(row, col);
    }

    @Override
    public void substituteBackwards(final Access2D body, final boolean unitDiagonal, final boolean conjugated, final boolean hermitian) {

        final int tmpRowDim = myRowDim;
        final int tmpColDim = myColDim;

        if (tmpColDim > SubstituteBackwards.THRESHOLD) {

            final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                @Override
                public void conquer(final int first, final int limit) {
                    SubstituteBackwards.invoke(R064Store.this.data, tmpRowDim, first, limit, body, unitDiagonal, conjugated, hermitian);
                }

            };

            tmpConquerer.invoke(0, tmpColDim, SubstituteBackwards.THRESHOLD);

        } else {

            SubstituteBackwards.invoke(data, tmpRowDim, 0, tmpColDim, body, unitDiagonal, conjugated, hermitian);
        }
    }

    @Override
    public void substituteForwards(final Access2D body, final boolean unitDiagonal, final boolean conjugated, final boolean identity) {

        final int tmpRowDim = myRowDim;
        final int tmpColDim = myColDim;

        if (tmpColDim > SubstituteForwards.THRESHOLD) {

            final DivideAndConquer tmpConquerer = new DivideAndConquer() {

                @Override
                public void conquer(final int first, final int limit) {
                    SubstituteForwards.invoke(R064Store.this.data, tmpRowDim, first, limit, body, unitDiagonal, conjugated, identity);
                }

            };

            tmpConquerer.invoke(0, tmpColDim, SubstituteForwards.THRESHOLD);

        } else {

            SubstituteForwards.invoke(data, tmpRowDim, 0, tmpColDim, body, unitDiagonal, conjugated, identity);
        }
    }

    @Override
    public PrimitiveScalar toScalar(final int row, final int col) {
        return PrimitiveScalar.of(this.doubleValue(row, col));
    }

    @Override
    public String toString() {
        return Access2D.toString(this);
    }

    @Override
    public void transformLeft(final Householder transformation, final int firstColumn) {
        HouseholderLeft.call(data, myRowDim, firstColumn, R064Store.cast(transformation));
    }

    @Override
    public void transformLeft(final Rotation transformation) {

        final Rotation.Primitive tmpTransf = R064Store.cast(transformation);

        final int tmpLow = tmpTransf.low;
        final int tmpHigh = tmpTransf.high;

        if (tmpLow != tmpHigh) {
            if (!Double.isNaN(tmpTransf.cos) && !Double.isNaN(tmpTransf.sin)) {
                RotateLeft.invoke(data, myRowDim, tmpLow, tmpHigh, tmpTransf.cos, tmpTransf.sin);
            } else {
                myUtility.exchangeRows(tmpLow, tmpHigh);
            }
        } else if (!Double.isNaN(tmpTransf.cos)) {
            myUtility.modifyRow(tmpLow, 0L, PrimitiveMath.MULTIPLY.second(tmpTransf.cos));
        } else if (!Double.isNaN(tmpTransf.sin)) {
            myUtility.modifyRow(tmpLow, 0L, PrimitiveMath.DIVIDE.second(tmpTransf.sin));
        } else {
            myUtility.modifyRow(tmpLow, 0, PrimitiveMath.NEGATE);
        }
    }

    @Override
    public void transformRight(final Householder transformation, final int firstRow) {
        HouseholderRight.call(data, myRowDim, firstRow, R064Store.cast(transformation), this.getWorkerColumn());
    }

    @Override
    public void transformRight(final Rotation transformation) {

        final Rotation.Primitive tmpTransf = R064Store.cast(transformation);

        final int tmpLow = tmpTransf.low;
        final int tmpHigh = tmpTransf.high;

        if (tmpLow != tmpHigh) {
            if (!Double.isNaN(tmpTransf.cos) && !Double.isNaN(tmpTransf.sin)) {
                RotateRight.invoke(data, myRowDim, tmpLow, tmpHigh, tmpTransf.cos, tmpTransf.sin);
            } else {
                myUtility.exchangeColumns(tmpLow, tmpHigh);
            }
        } else if (!Double.isNaN(tmpTransf.cos)) {
            myUtility.modifyColumn(0L, tmpHigh, PrimitiveMath.MULTIPLY.second(tmpTransf.cos));
        } else if (!Double.isNaN(tmpTransf.sin)) {
            myUtility.modifyColumn(0L, tmpHigh, PrimitiveMath.DIVIDE.second(tmpTransf.sin));
        } else {
            myUtility.modifyColumn(0, tmpHigh, PrimitiveMath.NEGATE);
        }
    }

    @Override
    public void transformSymmetric(final Householder transformation) {
        HouseholderHermitian.invoke(data, R064Store.cast(transformation), this.getWorkerColumn());
    }

    @Override
    public void tred2(final BasicArray mainDiagonal, final BasicArray offDiagonal, final boolean yesvecs) {
        HouseholderHermitian.tred2j(data, ((ArrayR064) mainDiagonal).data, ((ArrayR064) offDiagonal).data, yesvecs);
    }

    @Override
    public void visitColumn(final long row, final long col, final VoidFunction visitor) {
        myUtility.visitColumn(row, col, visitor);
    }

    @Override
    public void visitDiagonal(final long row, final long col, final VoidFunction visitor) {
        myUtility.visitDiagonal(row, col, visitor);
    }

    @Override
    public void visitRow(final long row, final long col, final VoidFunction visitor) {
        myUtility.visitRow(row, col, visitor);
    }

    private double[] getWorkerColumn() {
        if (myWorkerColumn != null) {
            Arrays.fill(myWorkerColumn, ZERO);
        } else {
            myWorkerColumn = new double[myRowDim];
        }
        return myWorkerColumn;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy