diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index f768bc42010646da75e6672c8d063d4f10533a33..fecaafdb8de298df504ca56eb2b3d7d2e9a1d65d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -494,6 +494,7 @@ public class BasePackage extends RBuiltinPackage { add(FileFunctions.ListFiles.class, FileFunctionsFactory.ListFilesNodeGen::create); add(FileFunctions.ListDirs.class, FileFunctionsFactory.ListDirsNodeGen::create); add(FileFunctions.Unlink.class, FileFunctionsFactory.UnlinkNodeGen::create); + add(FindInterval.class, FindIntervalNodeGen::create); add(ForceAndCall.class, ForceAndCallNodeGen::create); add(Formals.class, FormalsNodeGen::create); add(Format.class, FormatNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FindInterval.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FindInterval.java new file mode 100644 index 0000000000000000000000000000000000000000..45b4cb72d49b25c0f13931cb94260e37b6d50b62 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FindInterval.java @@ -0,0 +1,200 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 2002--2016, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ + +package com.oracle.truffle.r.nodes.builtin.base; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_ARITHMETIC; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; + +/** + * Note: R wrapper function {@code findInterval(x,vec,...)} has first two arguments swapped. + */ +@RBuiltin(name = "findInterval", kind = INTERNAL, parameterNames = {"xt", "x", "rightmost.closed", "all.inside", "left.open"}, behavior = PURE_ARITHMETIC) +public abstract class FindInterval extends RBuiltinNode.Arg5 { + + static { + Casts casts = new Casts(FindInterval.class); + casts.arg("xt").mustBe(doubleValue(), Message.INVALID_INPUT).asDoubleVector(); + casts.arg("x").mustBe(doubleValue(), Message.INVALID_INPUT).asDoubleVector(); + casts.arg("rightmost.closed").asLogicalVector().findFirst().mustNotBeNA().map(toBoolean()); + casts.arg("all.inside").asLogicalVector().findFirst().map(toBoolean()); + casts.arg("left.open").asLogicalVector().findFirst().map(toBoolean()); + } + + @Specialization(guards = {"xtAccess.supports(xt)", "xAccess.supports(x)"}) + RAbstractIntVector doFindInterval(RAbstractDoubleVector xt, RAbstractDoubleVector x, boolean right, boolean inside, boolean leftOpen, + @Cached("createEqualityProfile()") ValueProfile leftOpenProfile, + @Cached("create(xt)") VectorAccess xtAccess, + @Cached("create(xt)") VectorAccess xAccess, + @Cached("create()") VectorFactory vectorFactory) { + boolean leftOpenProfiled = leftOpenProfile.profile(leftOpen); + try (SequentialIterator xIter = xAccess.access(x)) { + int[] result = new int[xAccess.getLength(xIter)]; + int i = 0; + boolean complete = true; + int previous = 1; + while (xAccess.next(xIter)) { + if (xAccess.isNA(xIter)) { + previous = RRuntime.INT_NA; + complete = false; + } else { + try (RandomIterator xtIter = xtAccess.randomAccess(xt)) { + previous = findInterval2(xtAccess, xtIter, xAccess.getDouble(xIter), right, inside, leftOpenProfiled, previous); + } + } + result[i++] = previous; + } + return vectorFactory.createIntVector(result, complete); + } + } + + @Specialization(replaces = "doFindInterval") + RAbstractIntVector doFindIntervalGeneric(RAbstractDoubleVector xt, RAbstractDoubleVector x, boolean right, boolean inside, boolean leftOpen, + @Cached("createEqualityProfile()") ValueProfile leftOpenProfile, + @Cached("create()") VectorFactory factory) { + return doFindInterval(xt, x, right, inside, leftOpen, leftOpenProfile, xt.slowPathAccess(), x.slowPathAccess(), factory); + } + + // transcribed from appl/interv.c + + private int findInterval2(VectorAccess xtAccess, RandomIterator xtIter, double x, boolean right, boolean inside, boolean leftOpen, int iloIn) { + int n = xtAccess.getLength(xtIter); + if (n == 0) { + return 0; + } + + // Note: GNUR code is written with 1-based indexing (by shifting the pointer), we subtract + // one in each vector access + int ilo = iloIn; + if (ilo <= 0) { + double xt0 = xtAccess.getDouble(xtIter, 0); + if (xsmlr(leftOpen, x, xt0)) { + return leftBoundary(right, inside, x, xt0); + } + ilo = 1; + } + int ihi = ilo + 1; + if (ihi >= n) { + double xtLast = xtAccess.getDouble(xtIter, n - 1); + if (xgrtr(leftOpen, x, xtLast)) { + return rightBoundary(right, inside, x, xtLast, n); + } + if (n <= 1) { + /* x < xt[1] */ + return leftBoundary(right, inside, x, xtAccess.getDouble(xtIter, 0)); + } + ilo = n - 1; + ihi = n; + } + + if (xsmlr(leftOpen, x, xtAccess.getDouble(xtIter, ihi - 1))) { + if (xgrtr(leftOpen, x, xtAccess.getDouble(xtIter, ilo - 1))) { + /* `lucky': same interval as last time */ + return ilo; + } + /* **** now x < xt[ilo] . decrease ilo to capture x */ + int istep = 1; + boolean done = false; + while (true) { + ihi = ilo; + ilo = ihi - istep; + if (ilo <= 1) { + break; + } + double xtilo = xtAccess.getDouble(xtIter, ilo - 1); + if ((leftOpen && x > xtilo) || (!leftOpen && x >= xtilo)) { + done = true; + break; + } + istep *= 2; + } + if (!done) { + ilo = 1; + double xt0 = xtAccess.getDouble(xtIter, 0); + if (xsmlr(leftOpen, x, xt0)) { + return leftBoundary(right, inside, x, xt0); + } + } + } else { + /* **** now x >= xt[ihi] . increase ihi to capture x */ + int istep = 1; + boolean done = false; + while (true) { + ilo = ihi; + ihi = ilo + istep; + if (ihi >= n) { + break; + } + double xtihi = xtAccess.getDouble(xtIter, ihi - 1); + if ((leftOpen && x <= xtihi) || (!leftOpen && x < xtihi)) { + done = true; + break; + } + istep *= 2; + } + if (!done) { + double xtLast = xtAccess.getDouble(xtIter, n - 1); + if (xgrtr(leftOpen, x, xtLast)) { + return rightBoundary(right, inside, x, xtLast, n); + } + ihi = n; + } + } + + // L50 and L51 in the original GNUR source differ only by ">" vs ">=" depending on leftOpen + assert ilo <= ihi; + while (true) { + int middle = (ilo + ihi) / 2; + if (middle == ilo) { + return ilo; + } + /* note. it is assumed that middle = ilo in case ihi = ilo+1 . */ + double xtMiddle = xtAccess.getDouble(xtIter, middle - 1); + if ((!leftOpen && x >= xtMiddle) || (leftOpen && x > xtMiddle)) { + ilo = middle; + } else { + ihi = middle; + } + } + } + + private static int leftBoundary(boolean right, boolean inside, double x, double xt0) { + return ((inside || (right && x == xt0)) ? 1 : 0); + } + + private static int rightBoundary(boolean right, boolean inside, double x, double xtLast, int n) { + return ((inside || (right && x == xtLast)) ? (n - 1) : n); + } + + private static boolean xsmlr(boolean leftOpen, double x, double val) { + return x < val || (leftOpen && x <= val); + } + + private static boolean xgrtr(boolean leftOpen, double x, double val) { + return x > val || (!leftOpen && x >= val); + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 1baf7568d6d31e56b7361ec6b1a7c9ed1fc7a4e7..76a532dd74c87c148622624f11950246f18cd317 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -26275,21 +26275,37 @@ logical(0) #argv <- list(character(0), character(0)); .Internal(file.rename(argv[[1]], argv[[2]])) logical(0) -##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval1#Ignored.Unimplemented# -#argv <- list(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(3, 3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]])) -Error: 4 arguments passed to .Internal(findInterval) which requires 5 +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval1# +#argv <- list(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(3, 3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F)) + [1] 3 3 3 3 4 4 4 4 5 5 5 5 6 -##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval2#Ignored.Unimplemented# -#argv <- list(NA_real_, NA_real_, FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]])) -Error: 4 arguments passed to .Internal(findInterval) which requires 5 +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval1# +#argv <- list(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(3, 3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T)) + [1] 2 3 3 3 3 4 4 4 4 5 5 5 5 -##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval3#Ignored.Unimplemented# -#argv <- list(numeric(0), numeric(0), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]])) -Error: 4 arguments passed to .Internal(findInterval) which requires 5 +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval2# +#argv <- list(NA_real_, NA_real_, FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F)) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval2# +#argv <- list(NA_real_, NA_real_, FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T)) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval3# +#argv <- list(numeric(0), numeric(0), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F)) +integer(0) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval3# +#argv <- list(numeric(0), numeric(0), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T)) +integer(0) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval4# +#argv <- list(c(5, 10, 15), c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F)) + [1] 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 -##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval4#Ignored.Unimplemented# -#argv <- list(c(5, 10, 15), c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]])) -Error: 4 arguments passed to .Internal(findInterval) which requires 5 +##com.oracle.truffle.r.test.builtins.TestBuiltin_findInterval.testfindInterval4# +#argv <- list(c(5, 10, 15), c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T)) + [1] 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 ##com.oracle.truffle.r.test.builtins.TestBuiltin_floor.testFloor# #if (!any(R.version$engine == "FastR")) { 1+1i } else { { floor(1.1+1.9i); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_findInterval.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_findInterval.java index e726596d445fe8d08f199571f6cafc1c5f766b56..4a5bd037b74e825efd798f535eb8f199982546b5 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_findInterval.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_findInterval.java @@ -19,27 +19,25 @@ public class TestBuiltin_findInterval extends TestBase { @Test public void testfindInterval1() { - // FIXME RInternalError: not implemented: .Internal findInterval - assertEval(Ignored.Unimplemented, - "argv <- list(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(3, 3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))"); + assertEval("argv <- list(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(3, 3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T))"); + assertEval("argv <- list(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(3, 3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F))"); } @Test public void testfindInterval2() { - // FIXME RInternalError: not implemented: .Internal findInterval - assertEval(Ignored.Unimplemented, "argv <- list(NA_real_, NA_real_, FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))"); + assertEval("argv <- list(NA_real_, NA_real_, FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T))"); + assertEval("argv <- list(NA_real_, NA_real_, FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F))"); } @Test public void testfindInterval3() { - // FIXME RInternalError: not implemented: .Internal findInterval - assertEval(Ignored.Unimplemented, "argv <- list(numeric(0), numeric(0), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))"); + assertEval("argv <- list(numeric(0), numeric(0), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T))"); + assertEval("argv <- list(numeric(0), numeric(0), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F))"); } @Test public void testfindInterval4() { - // FIXME RInternalError: not implemented: .Internal findInterval - assertEval(Ignored.Unimplemented, - "argv <- list(c(5, 10, 15), c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))"); + assertEval("argv <- list(c(5, 10, 15), c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], T))"); + assertEval("argv <- list(c(5, 10, 15), c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), FALSE, FALSE); .Internal(findInterval(argv[[1]], argv[[2]], argv[[3]], argv[[4]], F))"); } } diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 768ff8b911ffa742dbf5b52e356063cc315be8b1..2fc42967eda91aaf0c1f6f4016805c22820b5a71 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -102,6 +102,7 @@ com.oracle.truffle.r.native/run/Rclasspath.sh,oracle_bash.copyright com.oracle.truffle.r.native/run/Rscript_exec.sh,oracle_bash.copyright com.oracle.truffle.r.native/run/Rscript.sh,oracle_bash.copyright com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FindInterval.java,gnu_r.core.copyright com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java,purdue.copyright com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java,gnu_r_ihaka.copyright com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseVariables.java,gnu_r.copyright