Package r.builtins

Source Code of r.builtins.Outer$OuterBuiltIn

package r.builtins;

import java.util.*;

import r.*;
import r.builtins.LApply.CallableProvider;
import r.builtins.LApply.ValueProvider;
import r.data.*;
import r.data.internal.*;
import r.nodes.ast.*;
import r.nodes.exec.Constant;
import r.nodes.exec.*;
import r.nodes.exec.FunctionCall;
import r.runtime.*;

/**
* "outer"
*
* <pre>
* X, Y -- First and second arguments for function FUN. Typically a vector or array.
* FUN -- a function to use on the outer products, found via match.fun (except for the special case "*").
* ... -- optional arguments to be passed to FUN.
* </pre>
*/
final class Outer extends CallFactory {
    static final CallFactory _ = new Outer("outer", new String[]{"X", "Y", "FUN", "..."}, new String[]{"X", "Y"});

    private Outer(String name, String[] params, String[] required) {
        super(name, params, required);
    }

    private static final boolean EAGER = true; // NOTE: lazy is now only for integer, expand if needed, now is not faster than eager

    @Override public RNode create(ASTNode call, RSymbol[] names, RNode[] exprs) {
        ArgumentInfo ia = check(call, names, exprs);
        boolean product = false;
        if (ia.provided("FUN")) {
            RNode fnode = exprs[ia.position("FUN")];
            if (fnode instanceof Constant) {
                RAny value = ((Constant) fnode).execute(null);
                if (value instanceof RString) {
                    RString str = (RString) value;
                    if (str.size() == 1) {
                        if (str.getString(0).equals("*")) {
                            product = true;
                        }
                    }
                }
            }
        } else {
            product = true;
        }
        if (product) {
            return new MatrixOperation.OuterProduct(call, exprs[ia.position("X")], exprs[ia.position("Y")]);
        }

        int cnArgs = 2 + names.length - 3; // "-2" because both FUN, X, Y
        RSymbol[] cnNames = new RSymbol[cnArgs];
        RNode[] cnExprs = new RNode[cnArgs];
        cnNames[0] = null;
        ValueProvider xArgProvider = new ValueProvider(call);
        cnExprs[0] = xArgProvider;
        ValueProvider yArgProvider = new ValueProvider(call);
        cnExprs[1] = yArgProvider;
        ValueProvider[] constantArgProviders = new ValueProvider[cnArgs];
        int j = 0;
        for (int i = 0; i < names.length; i++) {
            if (ia.position("X") == i || ia.position("Y") == i || ia.position("FUN") == i) {
                continue;
            }
            cnNames[2 + j] = names[i];
            ValueProvider vp = new ValueProvider(call);
            cnExprs[2 + j] = vp;
            constantArgProviders[j] = vp;
            j++;
        }

        RNode funExpr = exprs[ia.position("FUN")];
        final CallableProvider callableProvider = new CallableProvider(funExpr.getAST(), funExpr);
        final RNode callNode = FunctionCall.getFunctionCall(call, callableProvider, cnNames, cnExprs);
        final int posX = ia.position("X");
        final int posY = ia.position("Y");
        final int posFUN = ia.position("FUN");

        return new OuterBuiltIn(call, names, exprs, callNode, callableProvider, xArgProvider, yArgProvider, constantArgProviders) {
            @Override public RAny doBuiltIn(Frame frame, RAny[] args) {
                RAny argx = null;
                RAny argy = null;
                RAny argfun = null;
                int k = 0;
                for (int i = 0; i < args.length; i++) {
                    if (i == posX) {
                        argx = args[i];
                    } else if (i == posY) {
                        argy = args[i];
                    } else if (i == posFUN) {
                        argfun = args[i];
                    } else {
                        constantArgProviders[k].setValue(args[i]);
                        k++;
                    }
                }
                return outer(frame, argx, argy, argfun);
            }
        };
    }

    public abstract static class OuterBuiltIn extends Builtin { // note: this class only exists so that we can call updateParent...
        @Child RNode callNode;
        CallableProvider callableProvider; // !!! not a child, just a shortcut into callNode
        ValueProvider xArgProvider; // !!! not a child
        ValueProvider yArgProvider; // !!! not a child
        ValueProvider[] constantArgProviders; // !!! not children

        public OuterBuiltIn(ASTNode ast, RSymbol[] argNames, RNode[] argExprs, RNode callNode, CallableProvider callableProvider, ValueProvider xArgProvider, ValueProvider yArgProvider, ValueProvider[] constantArgProviders) {
            super(ast, argNames, argExprs);
            this.callNode = adoptChild(callNode);
            this.callableProvider = callableProvider; // !!! no adopt
            this.xArgProvider = xArgProvider; // !!! no adopt
            this.yArgProvider = yArgProvider; // !!! no adopt
            this.constantArgProviders = constantArgProviders; // !!! no adopt
        }

        @Override
        protected <N extends RNode> N replaceChild(RNode oldNode, N newNode) {
            assert oldNode != null;
            if (callNode == oldNode) {
                callNode = newNode;
                return adoptInternal(newNode);
            }
            assert Utils.check(oldNode != callableProvider); // this not must not be rewritten
            assert Utils.check(oldNode != xArgProvider);
            assert Utils.check(oldNode != yArgProvider);
            return super.replaceChild(oldNode, newNode);
        }

        public RAny outer(Frame frame, RAny xarg, RAny yarg, RAny farg) {
            // LICENSE: transcribed code from GNU R, which is licensed under GPL

            if (!(xarg instanceof RArray && yarg instanceof RArray)) {
                Utils.nyi("unsupported type");
                return null;
            }

            RArray x = (RArray) xarg;
            RArray y = (RArray) yarg;

            int xsize = x.size();
            int ysize = y.size();

            RArray expy;
            RArray expx;

            if (EAGER) {
                x = x.materialize(); // FIXME: probably unnecessary (both x and y), could be done on-the-fly in the expansion methods
                y = y.materialize();
                if (y instanceof DoubleImpl) {
                    expy = expandYVector((DoubleImpl) y, ysize, xsize);
                } else if (y instanceof IntImpl) {
                    expy = expandYVector((IntImpl) y, ysize, xsize);
                } else {
                    expy = expandYVector(y, ysize, xsize);
                }

                if (xsize > 0) {
                    if (x instanceof DoubleImpl) {
                        expx = expandXVector((DoubleImpl) x, xsize, ysize);
                    } else if (x instanceof IntImpl) {
                        expx = expandXVector((IntImpl) x, xsize, ysize);
                    } else {
                        expx = expandXVector(x, xsize, ysize);
                    }
                } else {
                    expx = x;
                }
            } else {
                if (y instanceof RInt) {
                    expy = lazyExpandYVector((RInt) y, ysize, xsize);
                } else {
                    throw Utils.nyi();
                }
                if (xsize > 0) {
                    if (x instanceof RInt) {
                        expx = lazyExpandXVector((RInt) x, xsize, ysize);
                    } else {
                        throw Utils.nyi();
                    }
                } else {
                    expx = x;
                }
            }

            xArgProvider.setValue(expx);
            yArgProvider.setValue(expy);
            callableProvider.matchAndSet(frame, farg);
            RArray res = (RArray) callNode.execute(frame);

            int[] dimx = x.dimensions();
            int[] dimy = y.dimensions();

            int[] dim;
            if (dimx == null) {
                if (dimy == null) {
                    dim = new int[]{xsize, ysize};
                } else {
                    dim = new int[1 + dimy.length];
                    dim[0] = xsize;
                    System.arraycopy(dimy, 0, dim, 1, dimy.length);
                }
            } else {
                if (dimy == null) {
                    dim = new int[dimx.length + 1];
                    System.arraycopy(dimx, 0, dim, 0, dimx.length);
                    dim[dimx.length] = ysize;
                } else {
                    dim = new int[dimx.length + dimy.length];
                    System.arraycopy(dimx, 0, dim, 0, dimx.length);
                    System.arraycopy(dimy, 0, dim, dimx.length, dimy.length);
                }
            }
            return res.setDimensions(dim); // triggers materialization of the result
        }
    }

    public static RArray expandYVector(RArray y, int ysize, int count) {
        int size = ysize;
        int nsize = size * count;

        RArray res = Utils.createArray(y, nsize);
        int offset = 0;
        for (int elem = 0; elem < size; elem++) {
            Object v = y.get(elem);
            for (int i = 0; i < count; i++) {
                res.set(offset + i, v);
            }
            offset += count;
        }
        return res;
    }

    public static RDouble expandYVector(DoubleImpl yarg, int ysize, int count) {
        int size = ysize;
        int nsize = size * count;
        double[] y = yarg.getContent();

        double[] res = new double[nsize];
        int offset = 0;
        for (int elem = 0; elem < size; elem++) {
            double v = y[elem];
            Arrays.fill(res, offset, offset + count, v);
            offset += count;
        }
        return RDouble.RDoubleFactory.getFor(res);
    }

    public static RInt expandYVector(IntImpl yarg, int ysize, int count) {
        int size = ysize;
        int nsize = size * count;
        int[] y = yarg.getContent();

        int[] res = new int[nsize];
        int offset = 0;
        for (int elem = 0; elem < size; elem++) {
            int v = y[elem];
            Arrays.fill(res, offset, offset + count, v);
            offset += count;
        }
        return RInt.RIntFactory.getFor(res);
    }

    public static RInt lazyExpandYVector(RInt yarg, int ysize, final int count) {
        final int nsize = ysize * count;
        return TracingView.ViewTrace.trace(new View.RIntProxy<RInt>(yarg) {

            @Override public int getInt(int i) {
                int j = i / count;
                return orig.getInt(j);
            }

            @Override public int size() {
                return nsize;
            }

            @Override public int[] dimensions() {
                return null;
            }

            @Override public Names names() {
                return null;
            }

            @Override public Attributes attributes() {
                return null;
            }

            @Override
            public void accept(ValueVisitor v) {
                v.visit(this);
            }
        });
    }

    public static RArray expandXVector(RArray x, int xsize, int count) {
        int nsize = xsize * count;

        RArray res = Utils.createArray(x, nsize);
        int offset = 0;
        for (int rep = 0; rep < count; rep++) {
            for (int i = 0; i < xsize; i++) {
                res.set(offset + i, x.get(i));
            }
            offset += xsize;
        }
        return res;
    }

    public static RDouble expandXVector(DoubleImpl xarg, int xsize, int count) {
        int nsize = xsize * count;
        double[] x = xarg.getContent();
        double[] res = new double[nsize];
        int offset = 0;
        for (int rep = 0; rep < count; rep++) {
            System.arraycopy(x, 0, res, offset, xsize);
            offset += xsize;
        }
        return RDouble.RDoubleFactory.getFor(res);
    }

    public static RInt expandXVector(IntImpl xarg, int xsize, int count) {
        int nsize = xsize * count;
        int[] x = xarg.getContent();
        int[] res = new int[nsize];
        int offset = 0;
        for (int rep = 0; rep < count; rep++) {
            System.arraycopy(x, 0, res, offset, xsize);
            offset += xsize;
        }
        return RInt.RIntFactory.getFor(res);
    }

    // an attempt for performance improvement: but does not seem faster for now
    public static RInt expandXVectorCacheFriendly(IntImpl xarg, int xsize, int count) {
        int nsize = xsize * count;
        int[] x = xarg.getContent();
        int[] res = new int[nsize];
        int offset = 0;
        int rep = 0;
        int lastOffset = 0;
        if (rep < count) {
            System.arraycopy(x, 0, res, offset, xsize);
            lastOffset = offset;
            offset += xsize;
        }
        for (rep = 1; rep < count; rep++) {
            System.arraycopy(res, lastOffset, res, offset, xsize);
            lastOffset = offset;
            offset += xsize;
        }
        return RInt.RIntFactory.getFor(res);
    }

    public static RInt lazyExpandXVector(RInt xarg, int xsize, final int count) {
        final int nsize = xsize * count;
        return TracingView.ViewTrace.trace(new View.RIntProxy<RInt>(xarg) {

            @Override public int getInt(int i) {
                int j = i % count;
                return orig.getInt(j);
            }

            @Override public int size() {
                return nsize;
            }

            @Override public int[] dimensions() {
                return null;
            }

            @Override public Names names() {
                return null;
            }

            @Override public Attributes attributes() {
                return null;
            }

            @Override
            public void accept(ValueVisitor v) {
                v.visit(this);
            }
        });
    }

}
TOP

Related Classes of r.builtins.Outer$OuterBuiltIn

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.