From 7b8394410ca59f4337b2df3caee0f24f715b8c2d Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Wed, 21 Dec 2016 14:34:55 +0100
Subject: [PATCH] Externals for logis distribution: dlogis, qlogis, plogis

---
 .../oracle/truffle/r/library/stats/Logis.java | 137 ++++++++++++++++++
 .../foreign/CallAndExternalFunctions.java     |  10 +-
 mx.fastr/copyrights/overrides                 |   2 +-
 3 files changed, 147 insertions(+), 2 deletions(-)
 create mode 100644 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Logis.java

diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Logis.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Logis.java
new file mode 100644
index 0000000000..45328c4693
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Logis.java
@@ -0,0 +1,137 @@
+/*
+ * 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) 1998 Ross Ihaka
+ * Copyright (c) 1998--2008, The R Core Team
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+/*
+ *  Copyright (C) 1995, 1996    Robert Gentleman and Ross Ihaka
+ *  Copyright (C) 2000          The R Core Team
+ */
+package com.oracle.truffle.r.library.stats;
+
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_1;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_2;
+
+public final class Logis {
+    private Logis() {
+        // only static members
+    }
+
+    public static final class DLogis implements Function3_1 {
+        @Override
+        public double evaluate(double x, double location, double scale, boolean giveLog) {
+            if (Double.isNaN(x) || Double.isNaN(location) || Double.isNaN(scale)) {
+                return x + location + scale;
+            }
+            if (scale <= 0.0) {
+                return RMath.mlError();
+            }
+
+            x = TOMS708.fabs((x - location) / scale);
+            double e = Math.exp(-x);
+            double f = 1.0 + e;
+            return giveLog ? -(x + Math.log(scale * f * f)) : e / (scale * f * f);
+        }
+    }
+
+    public static final class QLogis implements Function3_2 {
+        @Override
+        public double evaluate(double p, double location, double scale, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(p) || Double.isNaN(location) || Double.isNaN(scale)) {
+                return p + location + scale;
+            }
+
+            try {
+                DPQ.rqp01boundaries(p, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, lowerTail, logP);
+            } catch (EarlyReturn e) {
+                return e.result;
+            }
+
+            if (scale < 0.) {
+                return RMath.mlError();
+            }
+            if (scale == 0.) {
+                return location;
+            }
+
+            /* p := logit(p) = Math.log( p / (1-p) ) : */
+            if (logP) {
+                if (lowerTail) {
+                    p = p - DPQ.rlog1exp(p);
+                } else {
+                    p = DPQ.rlog1exp(p) - p;
+                }
+            } else {
+                p = Math.log(lowerTail ? (p / (1. - p)) : ((1. - p) / p));
+            }
+
+            return location + scale * p;
+        }
+    }
+
+    public static final class PLogis implements Function3_2 {
+        @Override
+        public double evaluate(double x, double location, double scale, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(x) || Double.isNaN(location) || Double.isNaN(scale)) {
+                return x + location + scale;
+            }
+            if (scale <= 0.0) {
+                return RMath.mlError();
+            }
+
+            x = (x - location) / scale;
+            if (Double.isNaN(x)) {
+                return RMath.mlError();
+            }
+
+            try {
+                DPQ.rpboundsinf01(x, lowerTail, logP);
+            } catch (EarlyReturn earlyReturn) {
+                return earlyReturn.result;
+            }
+
+            if (logP) {
+                // Math.log(1 / (1 + Math.exp( +- x ))) = -Math.log(1 + Math.exp( +- x))
+                return -log1pexp(lowerTail ? -x : x);
+            } else {
+                return 1 / (1 + Math.exp(lowerTail ? -x : x));
+            }
+        }
+
+        private static double log1pexp(double x) {
+            if (x <= 18.) {
+                return RMath.log1p(Math.exp(x));
+            }
+            if (x > 33.3) {
+                return x;
+            }
+            // else: 18.0 < x <= 33.3 :
+            return x + Math.exp(-x);
+        }
+    }
+
+    public static final class RLogis extends RandFunction2_Double {
+        @Override
+        public double execute(double location, double scale, RandomNumberProvider rand) {
+            if (Double.isNaN(location) || !Double.isFinite(scale)) {
+                return RMath.mlError();
+            }
+
+            if (scale == 0. || !Double.isFinite(location)) {
+                return location;
+            } else {
+                double u = rand.unifRand();
+                return location + scale * Math.log(u / (1. - u));
+            }
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index 2c2f2c7983..001e044000 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -68,6 +68,9 @@ import com.oracle.truffle.r.library.stats.LogNormal;
 import com.oracle.truffle.r.library.stats.LogNormal.DLNorm;
 import com.oracle.truffle.r.library.stats.LogNormal.PLNorm;
 import com.oracle.truffle.r.library.stats.LogNormal.QLNorm;
+import com.oracle.truffle.r.library.stats.Logis;
+import com.oracle.truffle.r.library.stats.Logis.DLogis;
+import com.oracle.truffle.r.library.stats.Logis.RLogis;
 import com.oracle.truffle.r.library.stats.Pbeta;
 import com.oracle.truffle.r.library.stats.Pbinom;
 import com.oracle.truffle.r.library.stats.Pf;
@@ -78,7 +81,6 @@ import com.oracle.truffle.r.library.stats.RBeta;
 import com.oracle.truffle.r.library.stats.RChisq;
 import com.oracle.truffle.r.library.stats.RGamma;
 import com.oracle.truffle.r.library.stats.RHyper;
-import com.oracle.truffle.r.library.stats.RLogis;
 import com.oracle.truffle.r.library.stats.RMultinomNodeGen;
 import com.oracle.truffle.r.library.stats.RNbinomMu;
 import com.oracle.truffle.r.library.stats.RNchisq;
@@ -338,6 +340,12 @@ public class CallAndExternalFunctions {
                     return StatsFunctionsFactory.Function3_2NodeGen.create(new QLNorm());
                 case "plnorm":
                     return StatsFunctionsFactory.Function3_2NodeGen.create(new PLNorm());
+                case "dlogis":
+                    return StatsFunctionsFactory.Function3_1NodeGen.create(new DLogis());
+                case "qlogis":
+                    return StatsFunctionsFactory.Function3_2NodeGen.create(new Logis.QLogis());
+                case "plogis":
+                    return StatsFunctionsFactory.Function3_2NodeGen.create(new Logis.PLogis());
                 case "rmultinom":
                     return RMultinomNodeGen.create();
                 case "Approx":
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 0467373d31..1c597c2f2f 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -68,7 +68,7 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SNorm.java,g
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SExp.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNbinomMu.java,gnu_r_ihaka_core.copyright
-com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RLogis.java,gnu_r_ihaka_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Logis.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rf.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RChisq.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Exp.java,gnu_r_ihaka_core.copyright
-- 
GitLab