Repository: jena
Updated Branches:
  refs/heads/JENA-507 [created] 4a42ee2a1


Implement factorial and log functions (JENA-507)


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/33a8f8de
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/33a8f8de
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/33a8f8de

Branch: refs/heads/JENA-507
Commit: 33a8f8deea0e41c9fefafe2bcdaf19c49868e2a5
Parents: 66c27e4
Author: Rob Vesse <[email protected]>
Authored: Thu Oct 9 12:06:29 2014 +0100
Committer: Rob Vesse <[email protected]>
Committed: Thu Oct 9 12:06:29 2014 +0100

----------------------------------------------------------------------
 .../sparql/function/library/leviathan/cube.java |   2 +-
 .../function/library/leviathan/factorial.java   |  40 +++++++
 .../sparql/function/library/leviathan/log.java  |  44 ++++++++
 .../sparql/expr/TestLeviathanFunctions.java     | 105 +++++++++++++++----
 4 files changed, 170 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/33a8f8de/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/cube.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/cube.java
 
b/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/cube.java
index d94f928..0b78822 100644
--- 
a/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/cube.java
+++ 
b/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/cube.java
@@ -38,7 +38,7 @@ public class cube extends FunctionBase1 {
                 double dec = v.getDecimal().doubleValue() ;
                 return NodeValue.makeDecimal( Math.pow(dec, 3d)) ;
             case OP_FLOAT:
-                // TODO Should squaring a float keep it a float?
+                // TODO Should cubing a float keep it a float?
             case OP_DOUBLE:
                 return NodeValue.makeDouble( Math.pow(v.getDouble(), 3d) ) ;
             default:

http://git-wip-us.apache.org/repos/asf/jena/blob/33a8f8de/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/factorial.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/factorial.java
 
b/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/factorial.java
new file mode 100644
index 0000000..8fea35b
--- /dev/null
+++ 
b/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/factorial.java
@@ -0,0 +1,40 @@
+package com.hp.hpl.jena.sparql.function.library.leviathan;
+
+import java.math.BigInteger;
+
+import com.hp.hpl.jena.sparql.expr.ExprEvalException;
+import com.hp.hpl.jena.sparql.expr.NodeValue;
+import com.hp.hpl.jena.sparql.expr.nodevalue.XSDFuncOp;
+import com.hp.hpl.jena.sparql.function.FunctionBase1;
+
+public class factorial extends FunctionBase1 {
+
+    @Override
+    public NodeValue exec(NodeValue v) {
+        // Don't care about the return value, will just error if the thing 
isn't
+        // a numeric
+        XSDFuncOp.classifyNumeric("factorial", v);
+
+        BigInteger i = v.getInteger();
+
+        switch (i.compareTo(BigInteger.ZERO)) {
+        case 0:
+            // 0! is 1
+            return NodeValue.makeInteger(BigInteger.ONE);
+        case -1:
+            // Negative factorial is error
+            throw new ExprEvalException("Cannot evaluate a negative 
factorial");
+        case 1:
+            BigInteger res = i.add(BigInteger.ZERO);
+            i = i.subtract(BigInteger.ONE);
+            while (i.compareTo(BigInteger.ZERO) != 0) {
+                res = res.multiply(i);
+                i = i.subtract(BigInteger.ONE);
+            }
+            return NodeValue.makeInteger(res);
+        default:
+            throw new ExprEvalException("Unexpecte comparison result");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/33a8f8de/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/log.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/log.java
 
b/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/log.java
new file mode 100644
index 0000000..c45bd77
--- /dev/null
+++ 
b/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/library/leviathan/log.java
@@ -0,0 +1,44 @@
+package com.hp.hpl.jena.sparql.function.library.leviathan;
+
+import java.util.List;
+
+import com.hp.hpl.jena.query.QueryBuildException;
+import com.hp.hpl.jena.sparql.expr.ExprEvalException;
+import com.hp.hpl.jena.sparql.expr.ExprList;
+import com.hp.hpl.jena.sparql.expr.NodeValue;
+import com.hp.hpl.jena.sparql.expr.nodevalue.XSDFuncOp;
+import com.hp.hpl.jena.sparql.function.FunctionBase;
+import com.hp.hpl.jena.sparql.util.Utils;
+
+public class log extends FunctionBase {
+
+    @Override
+    public NodeValue exec(List<NodeValue> args) {
+        if (args.size() < 1 || args.size() > 2)
+            throw new ExprEvalException("Invalid number of arguments");
+
+        // Don't care about the return value, will just error if the thing 
isn't
+        // a numeric
+        NodeValue v = args.get(0);
+        XSDFuncOp.classifyNumeric("log", v);
+
+        if (args.size() == 1) {
+            // Log base 10
+            return NodeValue.makeDouble(Math.log10(v.getDouble()));
+        } else {
+            // Log with arbitrary base
+            // See 
http://en.wikipedia.org/wiki/List_of_logarithmic_identities#Changing_the_base
+            NodeValue base = args.get(1);
+            XSDFuncOp.classifyNumeric("log", base);
+
+            return NodeValue.makeDouble(Math.log10(v.getDouble()) / 
Math.log10(base.getDouble()));
+        }
+    }
+
+    @Override
+    public void checkBuild(String uri, ExprList args) {
+        if (args.size() < 1 || args.size() > 2)
+            throw new QueryBuildException("Function '" + Utils.className(this) 
+ "' takes one/two argument(s)");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/33a8f8de/jena-arq/src/test/java/com/hp/hpl/jena/sparql/expr/TestLeviathanFunctions.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/test/java/com/hp/hpl/jena/sparql/expr/TestLeviathanFunctions.java
 
b/jena-arq/src/test/java/com/hp/hpl/jena/sparql/expr/TestLeviathanFunctions.java
index 7c90c74..ba5c53c 100644
--- 
a/jena-arq/src/test/java/com/hp/hpl/jena/sparql/expr/TestLeviathanFunctions.java
+++ 
b/jena-arq/src/test/java/com/hp/hpl/jena/sparql/expr/TestLeviathanFunctions.java
@@ -18,20 +18,20 @@
 
 package com.hp.hpl.jena.sparql.expr;
 
-import org.apache.jena.atlas.junit.BaseTest ;
-import org.junit.AfterClass ;
-import org.junit.BeforeClass ;
-import org.junit.Test ;
-
-import com.hp.hpl.jena.graph.Node ;
-import com.hp.hpl.jena.shared.PrefixMapping ;
-import com.hp.hpl.jena.shared.impl.PrefixMappingImpl ;
-import com.hp.hpl.jena.sparql.ARQConstants ;
-import com.hp.hpl.jena.sparql.function.FunctionEnvBase ;
-import com.hp.hpl.jena.sparql.function.library.leviathan.LeviathanConstants ;
-import com.hp.hpl.jena.sparql.serializer.SerializationContext ;
-import com.hp.hpl.jena.sparql.util.ExprUtils ;
-import com.hp.hpl.jena.sparql.util.NodeFactoryExtra ;
+import org.apache.jena.atlas.junit.BaseTest;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.shared.PrefixMapping;
+import com.hp.hpl.jena.shared.impl.PrefixMappingImpl;
+import com.hp.hpl.jena.sparql.ARQConstants;
+import com.hp.hpl.jena.sparql.function.FunctionEnvBase;
+import com.hp.hpl.jena.sparql.function.library.leviathan.LeviathanConstants;
+import com.hp.hpl.jena.sparql.serializer.SerializationContext;
+import com.hp.hpl.jena.sparql.util.ExprUtils;
+import com.hp.hpl.jena.sparql.util.NodeFactoryExtra;
 
 public class TestLeviathanFunctions extends BaseTest {
 
@@ -90,24 +90,84 @@ public class TestLeviathanFunctions extends BaseTest {
     public void e_01() {
         test("lfn:e(2)", NodeFactoryExtra.doubleToNode(Math.exp(2d)));
     }
-    
+
     @Test
     public void pow_01() {
         test("lfn:pow(2, 4)", "16");
     }
-    
+
     @Test
     public void pow_02() {
         test("lfn:pow(0.5, 3)", "0.125");
     }
+
+    @Test
+    public void factorial_01() {
+        test("lfn:factorial(0)", "1");
+    }
+
+    @Test
+    public void factorial_02() {
+        test("lfn:factorial(1)", "1");
+    }
+
+    @Test
+    public void factorial_03() {
+        test("lfn:factorial(3)", "6");
+    }
+
+    @Test
+    public void factorial_04() {
+        test("lfn:factorial(5)", "120");
+    }
+
+    @Test(expected = ExprEvalException.class)
+    public void factorial_05() {
+        testError("lfn:factorial(-1)");
+    }
+
+    @Test(expected = ExprEvalException.class)
+    public void factorial_06() {
+        testError("lfn:factorial(5.4)");
+    }
+
+    @Test
+    public void log_01() {
+        test("lfn:log(1)", "0");
+    }
+
+    @Test
+    public void log_02() {
+        test("lfn:log(10)", "1");
+    }
+
+    @Test
+    public void log_03() {
+        test("lfn:log(-1)", NodeFactoryExtra.doubleToNode(Double.NaN));
+    }
+    
+    @Test
+    public void log_04() {
+        test("lfn:log(4, 2)", "2");
+    }
+    
+    @Test
+    public void log_05() {
+        test("lfn:log(4, 16)", "0.5");
+    }
     
-    private static void test(String string, String result) {
+    @Test
+    public void log_06() {
+        test("lfn:log(16, 4)", "2");
+    }
+
+    private static void test(String exprString, String result) {
         Node r = NodeFactoryExtra.parseNode(result);
-        test(string, r);
+        test(exprString, r);
     }
 
-    private static void test(String string, Node result) {
-        Expr expr = ExprUtils.parse(string, pmap);
+    private static void test(String exprString, Node result) {
+        Expr expr = ExprUtils.parse(exprString, pmap);
         NodeValue nv = expr.eval(null, new FunctionEnvBase());
         NodeValue nvr = NodeValue.makeNode(result);
 
@@ -116,4 +176,9 @@ public class TestLeviathanFunctions extends BaseTest {
         assertTrue("Not same value: Expected: " + nvr + " : Actual = " + nv, 
NodeValue.sameAs(nvr, nv));
     }
 
+    private static void testError(String exprString) {
+        Expr expr = ExprUtils.parse(exprString, pmap);
+        expr.eval(null, new FunctionEnvBase());
+    }
+
 }

Reply via email to