Package r.nodes.exec

Source Code of r.nodes.exec.ReadArray

package r.nodes.exec;

import r.*;
import r.builtins.*;
import r.data.*;
import r.data.internal.*;
import r.errors.*;
import r.nodes.ast.*;
import r.nodes.exec.Selector.*;
import r.runtime.*;

/**
* A multi-dimensional read. arrayname '[' [first index] , [second index] { , [ other index]} [ , drop = ] ']' There are
* no node rewrites, but the selection operator nodes have their selector nodes which tend to be overwritten. The
* special case for matrices is determined statically when # of dimensions is 2.
*/
public abstract class ReadArray extends BaseR {

    final boolean subset;

    @Child RNode lhs;
    @Child OptionNode dropExpr;
    @Child OptionNode exactExpr;

    public ReadArray(ASTNode ast, boolean subset, RNode lhs, OptionNode dropExpr, OptionNode exactExpr) {
        super(ast);
        this.subset = subset;
        this.lhs = adoptChild(lhs);
        this.dropExpr = adoptChild(dropExpr);
        this.exactExpr = adoptChild(exactExpr);
    }

    public ReadArray(ReadArray other) {
        this(other.ast, other.subset, other.lhs, other.dropExpr, other.exactExpr);
    }

    @Override protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
        assert oldNode != null;
        if (lhs == oldNode) {
            lhs = newNode;
            return adoptInternal(newNode);
        }
        if (dropExpr == oldNode) {
            dropExpr = (r.nodes.exec.Selector.OptionNode) newNode;
            return adoptInternal(newNode);
        }
        if (exactExpr == oldNode) {
            exactExpr = (r.nodes.exec.Selector.OptionNode) newNode;
            return adoptInternal(newNode);
        }
        return super.replaceChild(oldNode, newNode);
    }

    // =================================================================================================================
    // Specialized forms
    // =================================================================================================================

    /**
     * Generalized selector operator that works with arrays of arbitraty number of dimensions. Uses the selector index
     * mechanism and reverse incrementing to create the selection result. At the moment does not perform any rewriting
     * as the matrix - array distinction is known static time from the parser.
     */
    public static class GenericRead extends ReadArray {

        final int[] offsets;
        final int[] selSizes;
        @Children final SelectorNode[] selectorExprs;
        final Selector[] selectorVals;

        public GenericRead(ASTNode ast, boolean subset, RNode lhs, SelectorNode[] selectorExprs, OptionNode dropExpr, OptionNode exactExpr) {
            super(ast, subset, lhs, dropExpr, exactExpr);
            this.selectorExprs = adoptChildren(selectorExprs);
            this.offsets = new int[selectorExprs.length + 1];
            this.selSizes = new int[selectorExprs.length];
            this.selectorVals = new Selector[selectorExprs.length];
        }

        @Override public Object execute(Frame frame) {
            RAny lhsVal = (RAny) lhs.execute(frame);
            for (int i = 0; i < selectorVals.length; ++i) {
                selectorVals[i] = selectorExprs[i].executeSelector(frame);
            }
            boolean dropVal = dropExpr.executeLogical(frame) != 0; // FIXME: what is the correct execution order of these args?
            int exactVal = exactExpr.executeLogical(frame);

            if (!(lhsVal instanceof RArray)) { throw RError.getObjectNotSubsettable(ast, lhsVal.typeOf()); }
            RArray array = (RArray) lhsVal;
            int[] dim = array.dimensions();
            if (dim == null || dim.length != selectorExprs.length) { throw RError.getIncorrectDimensions(getAST()); }
            return executeLoop(array, dropVal, exactVal);
        }

        @Override protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
            assert oldNode != null;
            if (selectorExprs != null) {
                for (int i = 0; i < selectorExprs.length; i++) {
                    if (selectorExprs[i] == oldNode) {
                        selectorExprs[i] = (r.nodes.exec.Selector.SelectorNode) newNode;
                        return adoptInternal(newNode);
                    }
                }
            }
            return super.replaceChild(oldNode, newNode);
        }

        /**
         * Execute method which evaluates the lhs, selectors and optional expressions, checks that the array selection
         * can proceed and then proceeds optionally replacing the falling selectors. The valued variant of execute is
         * called for the production of the result, on failure the responsible selector is replaced and the valued
         * variant is called again.
         */

        protected final Object executeLoop(RArray array, boolean dropVal, int exactVal) {
            while (true) {
                try {
                    return execute(array, dropVal, exactVal);
                } catch (SpecializationException e) {
                    Selector failedSelector = (Selector) e.getResult();
                    for (int i = 0; i < selectorVals.length; ++i) {
                        if (selectorVals[i] == failedSelector) {
                            RAny index = failedSelector.getIndex();
                            SelectorNode newSelector = Selector.createSelectorNode(ast, subset, index, selectorExprs[i], false, failedSelector.getTransition());
                            selectorExprs[i] = adoptChild(newSelector);
                            selectorVals[i] = newSelector.executeSelector(index);
                        }
                    }
                }
            }
        }

        /**
         * Returns the selection array or vector. The selSizes array contains sizes of the selectors (number of elements
         * that will be returned by it). The idx array contains the indices returned by the selectors (that is the
         * indices used to compute the source offset). The selIdx array contains the position in the selector (when this
         * is equal to the selector size the selector has overflown).
         */
        public Object execute(RArray source, boolean drop, @SuppressWarnings("unused") int exact) throws SpecializationException {
            int[] sourceDim = source.dimensions();
            boolean mayHaveNA = Selector.initialize(offsets, selectorVals, sourceDim, selSizes, ast);
            int[] destDim = Selector.calculateDestinationDimensions(selSizes, !subset || drop);
            int destSize = Selector.calculateSizeFromSelectorSizes(selSizes);

            RArray dest = Utils.createArray(source, destSize, destDim, null, null); // drop attributes
            if (destSize == 0) { return dest; }
            int offset = 0;
            for (;;) {
                int sourceOffset = offsets[0];
                if (sourceOffset == RInt.NA) {
                    Utils.setNA(dest, offset);
                } else {
                    dest.set(offset, source.getRef(sourceOffset));
                }
                offset++;
                if (offset < destSize) {
                    if (!mayHaveNA) {
                        Selector.advanceNoNA(offsets, sourceDim, selectorVals, ast);
                    } else {
                        Selector.advance(offsets, sourceDim, selectorVals, ast);
                    }
                } else {
                    break;
                }
            }
            return dest;
        }
    }

    // reading with the last dimension set only (e.g. x[,,i])
    public static class ArrayColumnSubset extends MatrixRead {

        @Child RNode columnExpr;
        final int nSelectors;

        public ArrayColumnSubset(ASTNode ast, RNode lhs, int nSelectors, RNode columnExpr, OptionNode dropExpr, OptionNode exactExpr) {
            super(ast, true, lhs, null, null, dropExpr, exactExpr);
            this.columnExpr = adoptChild(columnExpr);
            this.nSelectors = nSelectors;
            //assert Utils.check(nSelectors > 2);  // we could support 2 as well, but there is MatrixColumnSubset for that
        }

        @Override public Object execute(Frame frame) {

            RAny lhsVal = (RAny) lhs.execute(frame);
            RAny colVal = (RAny) columnExpr.execute(frame);
            boolean dropVal = dropExpr.executeLogical(frame) != RLogical.FALSE; // FIXME: what is the correct execution order of these args?
            int exactVal = exactExpr.executeLogical(frame);

            // TODO: GNU-R has different behavior when selecting from arrays that have some dimension zero

            if (!(lhsVal instanceof RArray)) { throw RError.getObjectNotSubsettable(ast, lhsVal.typeOf()); }
            RArray array = (RArray) lhsVal;
            int[] dim = array.dimensions();
            if (dim == null || dim.length != nSelectors) { throw RError.getIncorrectDimensions(getAST()); }
            int n = dim[nSelectors - 1]; // limit for the column (last dimension)

            try {
                int col;
                if (colVal instanceof ScalarIntImpl) {
                    col = ((ScalarIntImpl) colVal).getInt();
                } else if (colVal instanceof ScalarDoubleImpl) {
                    col = Convert.double2int(((ScalarDoubleImpl) colVal).getDouble());
                } else {
                    throw new SpecializationException(null);
                }
                if (col > n || col <= 0) { throw new SpecializationException(null); }

                int[] ndim;
                int m; // size of the result

                if (dropVal) {
                    boolean hasNonTrivialDimension = false;
                    boolean resultIsVector = true;
                    m = 1;
                    for (int i = 0; i < nSelectors - 1; i++) {
                        int d = dim[i];
                        if (d != 1) {
                            if (hasNonTrivialDimension) {
                                resultIsVector = false;
                            } else {
                                hasNonTrivialDimension = true;
                            }
                        }
                        m *= d;
                    }
                    if (resultIsVector) {
                        ndim = null;
                    } else {
                        ndim = new int[nSelectors - 1];
                        System.arraycopy(dim, 0, ndim, 0, ndim.length);
                    }
                } else {
                    ndim = new int[nSelectors];
                    ndim[nSelectors - 1] = 1;

                    m = 1;
                    for (int i = 0; i < ndim.length - 1; i++) {
                        int d = dim[i];
                        ndim[i] = d;
                        m *= d;
                    }
                }

                // note: also could be lazy here
                RArray res = Utils.createArray(array, m, ndim, null, null); // drop attributes
                int offset = (col - 1) * m; // note: col is 1-based
                for (int i = 0; i < m; i++) {
                    res.set(i, array.getRef(offset + i));
                }
                return res;
            } catch (SpecializationException e) {
                SelectorNode[] selectorExprs = new SelectorNode[nSelectors];
                for (int i = 0; i < nSelectors - 1; i++) {
                    selectorExprs[i] = Selector.createSelectorNode(ast, true, null);
                }
                selectorExprs[nSelectors - 1] = Selector.createSelectorNode(ast, true, columnExpr);
                GenericRead gr = new GenericRead(ast, true, lhs, selectorExprs, dropExpr, exactExpr);
                replace(gr, "install GenericRead from ArrayColumnSubset");
                for (int i = 0; i < nSelectors - 1; i++) {
                    gr.selectorVals[i] = selectorExprs[i].executeSelector(frame);
                }
                gr.selectorVals[nSelectors - 1] = selectorExprs[nSelectors - 1].executeSelector(colVal);
                return gr.executeLoop(array, dropVal, exactVal);
            }
        }

        @Override protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
            assert oldNode != null;
            if (columnExpr == oldNode) {
                columnExpr = newNode;
                return adoptInternal(newNode);
            }
            return super.replaceChild(oldNode, newNode);
        }
    }

    /**
     * Matrix specialization for the array selection.
     */
    public static class MatrixRead extends ReadArray {

        @Child SelectorNode selectorIExpr;
        @Child SelectorNode selectorJExpr;

        public MatrixRead(ASTNode ast, boolean subset, RNode lhs, SelectorNode selectorIExpr, SelectorNode selectorJExpr, OptionNode dropExpr, OptionNode exactExpr) {
            super(ast, subset, lhs, dropExpr, exactExpr);
            this.selectorIExpr = adoptChild(selectorIExpr);
            this.selectorJExpr = adoptChild(selectorJExpr);
        }

        @Override public Object execute(Frame frame) {
            RAny lhsVal = (RAny) lhs.execute(frame);
            Selector selectorI = selectorIExpr.executeSelector(frame);
            Selector selectorJ = selectorJExpr.executeSelector(frame);
            boolean dropVal = dropExpr.executeLogical(frame) != 0; // FIXME: what is the correct execution order of these args?
            int exactVal = exactExpr.executeLogical(frame);

            if (!(lhsVal instanceof RArray)) { throw RError.getObjectNotSubsettable(ast, lhsVal.typeOf()); }
            RArray array = (RArray) lhsVal;
            int[] dim = array.dimensions();
            if (dim == null || dim.length != 2) { throw RError.getIncorrectDimensions(getAST()); }
            return executeLoop(array, selectorI, selectorJ, dropVal, exactVal);
        }

        @Override protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
            assert oldNode != null;
            if (selectorIExpr == oldNode) {
                selectorIExpr = (r.nodes.exec.Selector.SelectorNode) newNode;
                return adoptInternal(newNode);
            }
            if (selectorJExpr == oldNode) {
                selectorJExpr = (r.nodes.exec.Selector.SelectorNode) newNode;
                return adoptInternal(newNode);
            }
            return super.replaceChild(oldNode, newNode);
        }

        public Object executeLoop(RArray array, Selector selectorI, Selector selectorJ, boolean dropVal, int exactVal) {
            Selector selI = selectorI;
            Selector selJ = selectorJ;
            for (;;) {
                try {
                    return execute(array, selI, selJ, dropVal, exactVal);
                } catch (SpecializationException e) {
                    Selector failedSelector = (Selector) e.getResult();
                    if (failedSelector == selI) {
                        RAny index = selI.getIndex();
                        selectorIExpr.replace(Selector.createSelectorNode(ast, subset, index, selectorIExpr.child, false, selectorI.getTransition()));
                        selI = selectorIExpr.executeSelector(index);
                    } else {
                        // failedSelector == selectorJ
                        RAny index = selJ.getIndex();
                        selectorJExpr.replace(Selector.createSelectorNode(ast, subset, index, selectorJExpr.child, false, selectorJ.getTransition()));
                        selJ = selectorJExpr.executeSelector(index);
                    }
                }
            }
        }

        public Object execute(RArray source, Selector selectorI, Selector selectorJ, boolean drop, @SuppressWarnings("unused") int exact) throws SpecializationException {
            assert Utils.check(subset);
            int[] ndim = source.dimensions();
            int m = ndim[0];
            int n = ndim[1];
            selectorI.start(m, ast);
            selectorJ.start(n, ast);
            int nm = selectorI.size();
            int nn = selectorJ.size();
            boolean mayHaveNA = selectorI.mayHaveNA() || selectorJ.mayHaveNA();
            int nsize = nm * nn;
            if ((nm != 1 && nn != 1) || !drop) {
                ndim = new int[]{nm, nn};
            } else {
                ndim = null;
            }
            RArray res = Utils.createArray(source, nsize, ndim, null, null); // drop attributes
            if (!mayHaveNA) {
                int resoffset = 0;
                for (int nj = 0; nj < nn; nj++) {
                    int j = selectorJ.nextIndex(ast);
                    int srcoffset = j * m;
                    for (int ni = 0; ni < nm; ni++) {
                        int i = selectorI.nextIndex(ast);
                        Object value = source.getRef(srcoffset + i); // FIXME: check overflow? (the same is at many locations, whenever indexing a matrix)
                        res.set(resoffset++, value);
                    }
                    selectorI.restart();
                }
            } else {
                for (int nj = 0; nj < nn; nj++) {
                    int j = selectorJ.nextIndex(ast);
                    if (j != RInt.NA) {
                        selectorI.restart();
                        for (int ni = 0; ni < nm; ni++) {
                            int offset = nj * nm + ni;
                            int i = selectorI.nextIndex(ast);
                            if (i != RInt.NA) {
                                Object value;
                                value = source.getRef(j * m + i); // FIXME: check overflow? (the same is at many locations, whenever indexing a matrix)
                                res.set(offset, value);
                            } else {
                                Utils.setNA(res, offset);
                            }
                        }
                    } else {
                        for (int ni = 0; ni < nm; ni++) {
                            Utils.setNA(res, nj * nm + ni);
                        }
                    }
                }
            }

            return res;
        }

    }

    public static class MatrixSubscript extends MatrixRead {

        public MatrixSubscript(ASTNode ast, RNode lhs, SelectorNode selectorIExpr, SelectorNode selectorJExpr, OptionNode dropExpr, OptionNode exactExpr) {
            super(ast, false, lhs, selectorIExpr, selectorJExpr, dropExpr, exactExpr);
        }

        @Override public Object execute(RArray base, Selector selectorI, Selector selectorJ, boolean drop, int exact) throws SpecializationException {
            int[] ndim = base.dimensions();
            int m = ndim[0];
            int n = ndim[1];
            selectorI.start(m, ast);
            selectorJ.start(n, ast);
            int i = selectorI.nextIndex(ast);
            int j = selectorJ.nextIndex(ast);
            assert Utils.check(i != RInt.NA && j != RInt.NA); // ensured by subscript selectors
            int offset = j * m + i;
            if (!(base instanceof RList)) {
                return base.boxedGet(offset);
            } else {
                return ((RList) base).getRAny(offset);
            }
        }
    }

    public static class MatrixColumnSubset extends MatrixRead {

        @Child RNode columnExpr;

        public MatrixColumnSubset(ASTNode ast, RNode lhs, RNode columnExpr, OptionNode dropExpr, OptionNode exactExpr) {
            super(ast, true, lhs, null, null, dropExpr, exactExpr);
            this.columnExpr = adoptChild(columnExpr);
        }

        @Override public Object execute(Frame frame) {

            RAny lhsVal = (RAny) lhs.execute(frame);
            RAny colVal = (RAny) columnExpr.execute(frame);
            boolean dropVal = dropExpr.executeLogical(frame) != RLogical.FALSE; // FIXME: what is the correct execution order of these args?
            int exactVal = exactExpr.executeLogical(frame);

            if (!(lhsVal instanceof RArray)) { throw RError.getObjectNotSubsettable(ast, lhsVal.typeOf()); }
            RArray array = (RArray) lhsVal;
            int[] dim = array.dimensions();
            if (dim == null || dim.length != 2) { throw RError.getIncorrectDimensions(getAST()); }
            int m = dim[0];
            int n = dim[1];

            try {
                int col;
                if (colVal instanceof ScalarIntImpl) {
                    col = ((ScalarIntImpl) colVal).getInt();
                } else if (colVal instanceof ScalarDoubleImpl) {
                    col = Convert.double2int(((ScalarDoubleImpl) colVal).getDouble());
                } else {
                    throw new SpecializationException(null);
                }
                if (col > n || col <= 0) { throw new SpecializationException(null); }

                int[] ndim;
                if (dropVal) {
                    ndim = null;
                } else {
                    ndim = new int[]{m, 1};
                }

                // note: also could be lazy here
                RArray res = Utils.createArray(array, m, ndim, null, null); // drop attributes
                int offset = (col - 1) * m; // note: col is 1-based
                for (int i = 0; i < m; i++) {
                    res.set(i, array.getRef(offset + i));
                }
                return res;
            } catch (SpecializationException e) {
                SelectorNode selIExpr = Selector.createSelectorNode(ast, true, null);
                SelectorNode selJExpr = Selector.createSelectorNode(ast, true, columnExpr);
                MatrixRead mr = new MatrixRead(ast, true, lhs, selIExpr, selJExpr, dropExpr, exactExpr);
                replace(mr, "install MatrixRead from MatrixColumnSubset");
                Selector selI = selIExpr.executeSelector(frame);
                Selector selJ = selJExpr.executeSelector(colVal);
                return mr.executeLoop(array, selI, selJ, dropVal, exactVal);
            }
        }

        @Override protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
            assert oldNode != null;
            if (columnExpr == oldNode) {
                columnExpr = newNode;
                return adoptInternal(newNode);
            }
            return super.replaceChild(oldNode, newNode);
        }
    }

    public static class MatrixRowSubset extends MatrixRead {

        @Child RNode rowExpr;

        public MatrixRowSubset(ASTNode ast, RNode lhs, RNode rowExpr, OptionNode dropExpr, OptionNode exactExpr) {
            super(ast, true, lhs, null, null, dropExpr, exactExpr);
            this.rowExpr = adoptChild(rowExpr);
        }

        @Override public Object execute(Frame frame) {

            RAny lhsVal = (RAny) lhs.execute(frame);
            RAny rowVal = (RAny) rowExpr.execute(frame);
            boolean dropVal = dropExpr.executeLogical(frame) != RLogical.FALSE; // FIXME: what is the correct execution order of these args?
            int exactVal = exactExpr.executeLogical(frame);

            if (!(lhsVal instanceof RArray)) { throw RError.getObjectNotSubsettable(ast, lhsVal.typeOf()); }
            RArray array = (RArray) lhsVal;
            int[] dim = array.dimensions();
            if (dim == null || dim.length != 2) { throw RError.getIncorrectDimensions(getAST()); }
            int m = dim[0];
            int n = dim[1];

            try {
                int row;
                if (rowVal instanceof ScalarIntImpl) {
                    row = ((ScalarIntImpl) rowVal).getInt();
                } else if (rowVal instanceof ScalarDoubleImpl) {
                    row = Convert.double2int(((ScalarDoubleImpl) rowVal).getDouble());
                } else {
                    throw new SpecializationException(null);
                }
                if (row > n || row <= 0) { throw new SpecializationException(null); }

                int[] ndim;
                if (dropVal) {
                    ndim = null;
                } else {
                    ndim = new int[]{1, n};
                }

                // note: also could be lazy here
                RArray res = Utils.createArray(array, n, ndim, null, null); // drop attributes
                int offset = row - 1;
                for (int i = 0; i < n; i++) {
                    res.set(i, array.getRef(offset));
                    offset += m;
                }
                return res;
            } catch (SpecializationException e) {
                SelectorNode selIExpr = Selector.createSelectorNode(ast, true, rowExpr);
                SelectorNode selJExpr = Selector.createSelectorNode(ast, true, null);
                MatrixRead nn = new MatrixRead(ast, true, lhs, selIExpr, selJExpr, dropExpr, exactExpr);
                replace(nn, "install MatrixRead from MatrixRowSubset");
                Selector selI = selIExpr.executeSelector(rowVal);
                Selector selJ = selJExpr.executeSelector(frame);
                return nn.executeLoop(array, selI, selJ, dropVal, exactVal);
            }
        }

        @Override protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
            assert oldNode != null;
            if (rowExpr == oldNode) {
                rowExpr = newNode;
                return adoptInternal(newNode);
            }
            return super.replaceChild(oldNode, newNode);
        }
    }

    // subset using two sequences, m[a:b, c:d], only simple cases (positive limits, within bounds)
    public static class MatrixSequenceSubset extends ReadArray {

        @Child RNode rowFromExpr;
        @Child RNode rowToExpr;
        @Child RNode colFromExpr;
        @Child RNode colToExpr;

        public MatrixSequenceSubset(ASTNode ast, RNode lhs, RNode rowFromExpr, RNode rowToExpr, RNode colFromExpr, RNode colToExpr, OptionNode dropExpr, OptionNode exactExpr) {
            super(ast, true, lhs, dropExpr, exactExpr);
            this.rowFromExpr = adoptChild(rowFromExpr);
            this.rowToExpr = adoptChild(rowToExpr);
            this.colFromExpr = adoptChild(colFromExpr);
            this.colToExpr = adoptChild(colToExpr);
        }

        private static int extractLimit(Object value) throws SpecializationException { // zero-based
            if (value instanceof ScalarDoubleImpl) {
                double d = ((ScalarDoubleImpl) value).getDouble();
                if (d > 0 && d <= Integer.MAX_VALUE) { return ((int) d) - 1; // truncate towards zero
                }
            } else if (value instanceof ScalarIntImpl) {
                int i = ((ScalarIntImpl) value).getInt();
                if (i > 0) { return i - 1; }
            }
            throw new SpecializationException(null);
        }

        @Override public Object execute(Frame frame) {

            RAny lhsVal = (RAny) lhs.execute(frame);
            Object rowFromVal = rowFromExpr.execute(frame);
            Object rowToVal = rowToExpr.execute(frame);
            Object colFromVal = colFromExpr.execute(frame);
            Object colToVal = colToExpr.execute(frame);
            boolean dropVal = dropExpr.executeLogical(frame) != RLogical.FALSE; // FIXME: what is the correct execution order of these args?
            int exactVal = exactExpr.executeLogical(frame);
            if (!(lhsVal instanceof RArray)) { throw RError.getObjectNotSubsettable(ast, lhsVal.typeOf()); }
            RArray array = (RArray) lhsVal;

            try {

                int rowFrom = extractLimit(rowFromVal); // zero-based
                int rowTo = extractLimit(rowToVal);
                int colFrom = extractLimit(colFromVal);
                int colTo = extractLimit(colToVal);

                int[] dim = array.dimensions();
                if (dim == null || dim.length != 2) { throw RError.getIncorrectDimensions(getAST()); }
                int m = dim[0];
                int n = dim[1];

                int rowStep;
                int rowSize;
                if (rowFrom <= rowTo) {
                    rowStep = 1;
                    if (rowTo > m) { throw new SpecializationException(null); }
                    rowSize = rowTo - rowFrom + 1;
                } else {
                    rowStep = -1;
                    if (rowFrom > m) { throw new SpecializationException(null); }
                    rowSize = rowFrom - rowTo + 1;
                }

                int colStep;
                int colSize;
                if (colFrom <= colTo) {
                    colStep = 1;
                    if (colTo > n) { throw new SpecializationException(null); }
                    colSize = colTo - colFrom + 1;
                } else {
                    colStep = -1;
                    if (colFrom > n) { throw new SpecializationException(null); }
                    colSize = colFrom - colTo + 1;
                }

                int[] ndim;
                if (!dropVal || (rowSize > 1 && colSize > 1)) {
                    ndim = new int[]{rowSize, colSize};
                } else {
                    ndim = null;
                }

                int size = rowSize * colSize;
                RArray res = Utils.createArray(array, size, ndim, null, null); // drop attributes

                if (colStep == 1 && rowStep == 1) {
                    int j = colFrom * m + rowFrom; // j - index to source matrix
                    int jmax = j + rowSize;
                    int jadvance = m - rowSize;
                    for (int i = 0; i < size; i++) {
                        res.set(i, array.getRef(j++)); // i - index to target matrix
                        if (j == jmax) {
                            j += jadvance;
                            jmax += m;
                        }
                    }
                } else {
                    int i = 0;
                    // NOTE: here we know that colFrom != colTo and rowFrom != rowTo
                    for (int col = colFrom; col != colTo + colStep; col += colStep) {
                        for (int row = rowFrom; row != rowTo + rowStep; row += rowStep) {
                            res.set(i++, array.getRef(col * m + row));
                        }
                    }
                }
                return res;
            } catch (SpecializationException e) {
                // FIXME: clean this up; does Colon need to be package-private?
                ASTNode rowAST = rowFromExpr.getAST().getParent();
                Builtin rowColon = (Builtin) Primitives.getCallFactory(RSymbol.getSymbol(":"), null).create(rowAST, rowFromExpr, rowToExpr);
                SelectorNode selIExpr = Selector.createSelectorNode(rowAST, true, rowColon);
                ASTNode colAST = colFromExpr.getAST().getParent();
                Builtin colColon = (Builtin) Primitives.getCallFactory(RSymbol.getSymbol(":"), null).create(colAST, colFromExpr, colToExpr);
                SelectorNode selJExpr = Selector.createSelectorNode(ast, true, colColon);
                MatrixRead nn = new MatrixRead(ast, true, lhs, selIExpr, selJExpr, dropExpr, exactExpr);
                replace(nn, "install MatrixRead from MatrixSequenceSubset");
                Selector selI = selIExpr.executeSelector(rowColon.doBuiltIn(frame, new RAny[]{(RAny) rowFromVal, (RAny) rowToVal}));
                Selector selJ = selJExpr.executeSelector(colColon.doBuiltIn(frame, new RAny[]{(RAny) colFromVal, (RAny) colToVal}));
                return nn.executeLoop(array, selI, selJ, dropVal, exactVal);
            }
        }

        @Override protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
            assert oldNode != null;
            if (rowFromExpr == oldNode) {
                rowFromExpr = newNode;
                return adoptInternal(newNode);
            }
            if (rowToExpr == oldNode) {
                rowToExpr = newNode;
                return adoptInternal(newNode);
            }
            if (colFromExpr == oldNode) {
                colFromExpr = newNode;
                return adoptInternal(newNode);
            }
            if (colToExpr == oldNode) {
                colToExpr = newNode;
                return adoptInternal(newNode);
            }
            return super.replaceChild(oldNode, newNode);
        }
    }
}
TOP

Related Classes of r.nodes.exec.ReadArray

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.