Repository: metron
Updated Branches:
  refs/heads/master 27ab28923 -> b2375a1f1


METRON-1038: Stellar should have a better collection of basic math operations 
closes apache/incubator-metron#650


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

Branch: refs/heads/master
Commit: b2375a1f1c66b19dc6a82cbcc8242741cdf65451
Parents: 27ab289
Author: cstella <ceste...@gmail.com>
Authored: Thu Aug 3 10:17:59 2017 +0100
Committer: cstella <ceste...@gmail.com>
Committed: Thu Aug 3 10:17:59 2017 +0100

----------------------------------------------------------------------
 metron-stellar/stellar-common/README.md         | 185 +++++++++++++------
 .../common/utils/math/MathOperation.java        |  45 +++++
 .../common/utils/math/MathOperations.java       |  83 +++++++++
 .../common/utils/math/StellarMathFunction.java  |  64 +++++++
 .../stellar/dsl/functions/MathFunctions.java    | 166 +++++++++++++++--
 .../dsl/functions/MathFunctionsTest.java        | 162 +++++++++++++++-
 6 files changed, 631 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/b2375a1f/metron-stellar/stellar-common/README.md
----------------------------------------------------------------------
diff --git a/metron-stellar/stellar-common/README.md 
b/metron-stellar/stellar-common/README.md
index 2b5d4b6..f12c77d 100644
--- a/metron-stellar/stellar-common/README.md
+++ b/metron-stellar/stellar-common/README.md
@@ -101,58 +101,65 @@ In the core language functions, we support basic 
functional programming primitiv
 
 ## Stellar Core Functions
 
-|                                                                              
                      |
-| ----------                                                                   
                      |
-| [ `ABS`](../../metron-analytics/metron-statistics#abs)                       
                      |
-| [ `APPEND_IF_MISSING`](#append_if_missing)                                   
                      |
-| [ `BIN`](../../metron-analytics/metron-statistics#bin)                       
                      |
-| [ `BLOOM_ADD`](#bloom_add)                                                   
                      |
-| [ `BLOOM_EXISTS`](#bloom_exists)                                             
                      |
-| [ `BLOOM_INIT`](#bloom_init)                                                 
                      |
-| [ `BLOOM_MERGE`](#bloom_merge)                                               
                      |
-| [ `CHOP`](#chop)                                                             
                      |
-| [ `CHOMP`](#chomp)                                                           
                      |
-| [ `COUNT_MATCHES`](#count_matches)                                           
                      |
-| [ `DAY_OF_MONTH`](#day_of_month)                                             
                      |
-| [ `DAY_OF_WEEK`](#day_of_week)                                               
                      |
-| [ `DAY_OF_YEAR`](#day_of_year)                                               
                      |
-| [ `DECODE`](#decode)                                                         
                      |
-| [ `DOMAIN_REMOVE_SUBDOMAINS`](#domain_remove_subdomains)                     
                      |
-| [ `DOMAIN_REMOVE_TLD`](#domain_remove_tld)                                   
                      |
-| [ `DOMAIN_TO_TLD`](#domain_to_tld)                                           
                      |
-| [ `ENCODE`](#encode)                                                         
                      |
-| [ `ENDS_WITH`](#ends_with)                                                   
                      |
-| [ `ENRICHMENT_EXISTS`](#enrichment_exists)                                   
                      |
-| [ `ENRICHMENT_GET`](#enrichment_get)                                         
                      |
-| [ `FILL_LEFT`](#fill_left)                                                   
                      |
-| [ `FILL_RIGHT`](#fill_right)                                                 
                      |
-| [ `FILTER`](#filter)                                                         
                      |
-| [ `FORMAT`](#format)                                                         
                      |
-| [ 
`HLLP_CARDINALITY`](../../metron-analytics/metron-statistics#hllp_cardinality)  
                 |
-| [ `HLLP_INIT`](../../metron-analytics/metron-statistics#hllp_init)           
                      |
-| [ `HLLP_MERGE`](../../metron-analytics/metron-statistics#hllp_merge)         
                      |
-| [ `HLLP_OFFER`](../../metron-analytics/metron-statistics#hllp_offer)         
                      |
-| [ `GEO_GET`](#geo_get)                                                       
                      |
-| [ `GET`](#get)                                                               
                      |
-| [ `GET_FIRST`](#get_first)                                                   
                      |
-| [ `GET_LAST`](#get_last)                                                     
                      |
-| [ `GET_SUPPORTED_ENCODINGS`](#get_supported_encodings)                       
                    |
-| [ `IN_SUBNET`](#in_subnet)                                                   
                      |
-| [ `IS_DATE`](#is_date)                                                       
                      |
-| [ `IS_ENCODING`](#is_encoding)                                               
                      |
-| [ `IS_DOMAIN`](#is_domain)                                                   
                      |
-| [ `IS_EMAIL`](#is_email)                                                     
                      |
-| [ `IS_EMPTY`](#is_empty)                                                     
                      |
-| [ `IS_INTEGER`](#is_integer)                                                 
                      |
-| [ `IS_IP`](#is_ip)                                                           
                      |
-| [ `IS_URL`](#is_url)                                                         
                      |
-| [ `JOIN`](#join)                                                             
                      |
-| [ `KAFKA_GET`](#kafka_get)                                                   
                      |
-| [ `KAFKA_PROPS`](#kafka_props)                                               
                      |
-| [ `KAFKA_PUT`](#kafka_put)                                                   
                      |
-| [ `KAFKA_TAIL`](#kafka_tail)                                                 
                      |
-| [ `LENGTH`](#length)                                                         
                      |
-| [ `LIST_ADD`](#list_add)                                                     
                      |
+|                                                                              
    |
+| ----------                                                                   
    |
+| [ `ABS`](../../metron-analytics/metron-statistics#abs)                       
    |
+| [ `APPEND_IF_MISSING`](#append_if_missing)                                   
    |
+| [ `BIN`](../../metron-analytics/metron-statistics#bin)                       
    |
+| [ `BLOOM_ADD`](#bloom_add)                                                   
    |
+| [ `BLOOM_EXISTS`](#bloom_exists)                                             
    |
+| [ `BLOOM_INIT`](#bloom_init)                                                 
    |
+| [ `BLOOM_MERGE`](#bloom_merge)                                               
    |
+| [ `CEILING`](#ceiling)                                                       
    |
+| [ `COS`](#cos)                                                               
    |
+| [ `CHOP`](#chop)                                                             
    |
+| [ `CHOMP`](#chomp)                                                           
    |
+| [ `COUNT_MATCHES`](#count_matches)                                           
    |
+| [ `DAY_OF_MONTH`](#day_of_month)                                             
    |
+| [ `DAY_OF_WEEK`](#day_of_week)                                               
    |
+| [ `DAY_OF_YEAR`](#day_of_year)                                               
    |
+| [ `DECODE`](#decode)                                                         
    |
+| [ `DOMAIN_REMOVE_SUBDOMAINS`](#domain_remove_subdomains)                     
    |
+| [ `DOMAIN_REMOVE_TLD`](#domain_remove_tld)                                   
    |
+| [ `DOMAIN_TO_TLD`](#domain_to_tld)                                           
    |
+| [ `ENCODE`](#encode)                                                         
    |
+| [ `ENDS_WITH`](#ends_with)                                                   
    |
+| [ `ENRICHMENT_EXISTS`](#enrichment_exists)                                   
    |
+| [ `ENRICHMENT_GET`](#enrichment_get)                                         
    |
+| [ `EXP`](#exp)                                                               
    |
+| [ `FILL_LEFT`](#fill_left)                                                   
    |
+| [ `FILL_RIGHT`](#fill_right)                                                 
    |
+| [ `FILTER`](#filter)                                                         
    |
+| [ `FLOOR`](#floor)                                                           
    |
+| [ `FORMAT`](#format)                                                         
    |
+| [ 
`HLLP_CARDINALITY`](../../metron-analytics/metron-statistics#hllp_cardinality) |
+| [ `HLLP_INIT`](../../metron-analytics/metron-statistics#hllp_init)           
    |
+| [ `HLLP_MERGE`](../../metron-analytics/metron-statistics#hllp_merge)         
    |
+| [ `HLLP_OFFER`](../../metron-analytics/metron-statistics#hllp_offer)         
    |
+| [ `GEO_GET`](#geo_get)                                                       
    |
+| [ `GET`](#get)                                                               
    |
+| [ `GET_FIRST`](#get_first)                                                   
    |
+| [ `GET_LAST`](#get_last)                                                     
    |
+| [ `GET_SUPPORTED_ENCODINGS`](#get_supported_encodings)                       
    |
+| [ `IN_SUBNET`](#in_subnet)                                                   
    |
+| [ `IS_DATE`](#is_date)                                                       
    |
+| [ `IS_ENCODING`](#is_encoding)                                               
    |
+| [ `IS_DOMAIN`](#is_domain)                                                   
    |
+| [ `IS_EMAIL`](#is_email)                                                     
    |
+| [ `IS_EMPTY`](#is_empty)                                                     
    |
+| [ `IS_INTEGER`](#is_integer)                                                 
    |
+| [ `IS_IP`](#is_ip)                                                           
    |
+| [ `IS_URL`](#is_url)                                                         
    |
+| [ `JOIN`](#join)                                                             
    |
+| [ `KAFKA_GET`](#kafka_get)                                                   
    |
+| [ `KAFKA_PROPS`](#kafka_props)                                               
    |
+| [ `KAFKA_PUT`](#kafka_put)                                                   
    |
+| [ `KAFKA_TAIL`](#kafka_tail)                                                 
    |
+| [ `LENGTH`](#length)                                                         
    |
+| [ `LIST_ADD`](#list_add)                                                     
                          |
+| [ `LOG2`](#log2)                                                             
                  |
+| [ `LOG10`](#log10)                                                           
                    |
+| [ `LN`](#ln)                                                                 
              |
 | [ `MAAS_GET_ENDPOINT`](#maas_get_endpoint)                                   
                      |
 | [ `MAAS_MODEL_APPLY`](#maas_model_apply)                                     
                      |
 | [ `MAP`](#map)                                                               
                      |
@@ -166,7 +173,10 @@ In the core language functions, we support basic 
functional programming primitiv
 | [ `REDUCE`](#reduce)                                                         
                      |
 | [ `REGEXP_MATCH`](#regexp_match)                                             
                      |
 | [ `REGEXP_GROUP_VAL`](#regexp_group_val)                                     
                              |
+| [ `ROUND`](#round)                                                           
        |
 | [ `SPLIT`](#split)                                                           
                      |
+| [ `SIN`](#sin)                                                               
                  |
+| [ `SQRT`](#sqrt)                                                             
                    |
 | [ `STARTS_WITH`](#starts_with)                                               
                      |
 | [ `STATS_ADD`](../../metron-analytics/metron-statistics#stats_add)           
                      |
 | [ `STATS_BIN`](../../metron-analytics/metron-statistics#stats_bin)           
                      |
@@ -190,6 +200,7 @@ In the core language functions, we support basic functional 
programming primitiv
 | [ `STRING_ENTROPY`](#string_entropy)                                         
                      |
 | [ `SYSTEM_ENV_GET`](#system_env_get)                                         
                      |
 | [ `SYSTEM_PROPERTY_GET`](#system_property_get)                               
                      |
+| [ `TAN`](#tan)                                                               
          |
 | [ `TO_DOUBLE`](#to_double)                                                   
                      |
 | [ `TO_EPOCH_TIMESTAMP`](#to_epoch_timestamp)                                 
                      |
 | [ `TO_FLOAT`](#to_float)                                                     
                      |
@@ -244,6 +255,18 @@ In the core language functions, we support basic 
functional programming primitiv
     * bloomfilters - A list of bloom filters to merge
   * Returns: Bloom Filter or null if the list is empty
 
+### `CEILING`
+  * Description: Returns the ceiling of a number.
+  * Input:
+    * number - The number to take the ceiling of
+  * Returns: The ceiling of the number passed in.
+
+### `COS`
+  * Description: Returns the cosine of a number.
+  * Input:
+    * number - The number to take the cosine of
+  * Returns: The cosine of the number passed in.
+
 ### `CHOP`
   * Description: Remove the last character from a String
   * Input:
@@ -347,6 +370,12 @@ In the core language functions, we support basic 
functional programming primitiv
     * column_family - The Column Family to use
   * Returns: A Map associated with the indicator and enrichment type.  Empty 
otherwise.
 
+### `EXP`
+  * Description: Returns Euler's number raised to the power of the argument.
+  * Input:
+    * number - The power to which e is raised.
+  * Returns: Euler's number raised to the power of the argument.
+
 ### `FILL_LEFT`
   * Description: Fills or pads a given string with a given character, to a 
given length on the left
   * Input:
@@ -370,6 +399,12 @@ In the core language functions, we support basic 
functional programming primitiv
     * predicate - The lambda expression to apply.  This expression is assumed 
to take one argument and return a boolean.
   * Returns: The input list filtered by the predicate.
 
+### `FLOOR`
+  * Description: Returns the floor of a number.
+  * Input:
+    * number - The number to take the floor of
+  * Returns: The floor of the number passed in.
+
 ### `FORMAT`
   * Description: Returns a formatted string using the specified format string 
and arguments. Uses Java's string formatting conventions.
   * Input:
@@ -510,11 +545,29 @@ In the core language functions, we support basic 
functional programming primitiv
     * list - List to add element to.
     * element - Element to add to list
   * Returns: Resulting list with the item added at the end.
-  
+
 ### `GET_SUPPORTED_ENCODINGS`
   * Description: Returns a list of the encodings that are currently supported.
   * Returns: A List of String
-        
+ 
+### `LOG2`
+  * Description: Returns the log (base `2`) of a number.
+  * Input:
+    * number - The number to take the log (base `2`) of
+  * Returns: The log (base `2`) of the number passed in.
+
+### `LOG10`
+  * Description: Returns the log (base `10`) of a number.
+  * Input:
+    * number - The number to take the log (base `10`) of
+  * Returns: The log (base `10`) of the number passed in.
+
+### `LN`
+  * Description: Returns the natural log of a number.
+  * Input:
+    * number - The number to take the natural log of
+  * Returns: The natural log of the number passed in.
+
 ### `MAAS_GET_ENDPOINT`
   * Description: Inspects ZooKeeper and returns a map containing the name, 
version and url for the model referred to by the input parameters.
   * Input:
@@ -621,6 +674,24 @@ In the core language functions, we support basic 
functional programming primitiv
     * group - The integer that selects what group to select, starting at 1
   * Returns: The value of the group, or null if not matched or no group at 
index.
 
+### `ROUND`
+  * Description: Rounds a number to the nearest integer.  This is half-up 
rounding.
+  * Input:
+    * number - The number to round
+  * Returns: The nearest integer (based on half-up rounding).
+
+### `SIN`
+  * Description: Returns the sine of a number.
+  * Input:
+    * number - The number to take the sine of
+  * Returns: The sine of the number passed in.
+
+### `SQRT`
+  * Description: Returns the square root of a number.
+  * Input:
+    * number - The number to take the square root of
+  * Returns: The square root of the number passed in.
+
 ### `STRING_ENTROPY`
   * Description: Computes the base-2 shannon entropy of a string.
   * Input:
@@ -653,6 +724,12 @@ In the core language functions, we support basic 
functional programming primitiv
     * key - Property to get the value for
   * Returns: String
 
+### `TAN`
+  * Description: Returns the tangent of a number.
+  * Input:
+    * number - The number to take the tangent of
+  * Returns: The tangent of the number passed in.
+
 ### `TO_DOUBLE`
   * Description: Transforms the first argument to a double precision number
   * Input:

http://git-wip-us.apache.org/repos/asf/metron/blob/b2375a1f/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperation.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperation.java
 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperation.java
new file mode 100644
index 0000000..803d130
--- /dev/null
+++ 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperation.java
@@ -0,0 +1,45 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.metron.stellar.common.utils.math;
+
+import java.util.function.Function;
+
+public class MathOperation {
+  private int maxArgs;
+  private int minArgs;
+  private Function<Number[], Number> operation;
+  public MathOperation(Function<Number[], Number> operation, int minArgs, int 
maxArgs) {
+    this.operation = operation;
+    this.maxArgs = maxArgs;
+    this.minArgs = minArgs;
+  }
+
+  public int getMaxArgs() {
+    return maxArgs;
+  }
+
+  public int getMinArgs() {
+    return minArgs;
+  }
+
+  public Function<Number[], Number> getOperation() {
+    return operation;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/b2375a1f/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperations.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperations.java
 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperations.java
new file mode 100644
index 0000000..bccdc00
--- /dev/null
+++ 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/MathOperations.java
@@ -0,0 +1,83 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.metron.stellar.common.utils.math;
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+public enum MathOperations implements Function<Number[], Number> {
+  ABS(d -> Math.abs(d)),
+  CEIL(d -> Math.ceil(d)),
+  COS(d -> Math.cos(d)),
+  FLOOR(d -> Math.floor(d)),
+  LOG10(d -> Math.log10(d)),
+  LOG2(d -> Math.log(d)/Math.log(2)),
+  LN(d -> Math.log(d)),
+  SIN(d -> Math.sin(d)),
+  SQRT(d -> Math.sqrt(d)),
+  TAN(d -> Math.tan(d)),
+  EXP(d -> Math.exp(d)),
+  ROUND(new MathOperation(d -> {
+    Double val = d[0].doubleValue();
+    return Double.isNaN(val)?Double.NaN:Math.round(d[0].doubleValue());
+  }, 1, 1)),
+  ;
+
+  private static class SingleOpFunc implements Function<Number[], Number> {
+    Function<Double, Number> f;
+    public SingleOpFunc(Function<Double, Number> f) {
+      this.f = f;
+    }
+    @Override
+    public Number apply(Number[] numbers) {
+      return f.apply(numbers[0].doubleValue());
+    }
+  }
+
+  private static class BinaryOpFunc implements Function<Number[], Number> {
+    BiFunction<Double, Double, Number> f;
+    public BinaryOpFunc(BiFunction<Double, Double, Number> f) {
+      this.f = f;
+    }
+    @Override
+    public Number apply(Number[] numbers) {
+      return f.apply(numbers[0].doubleValue(), numbers[1].doubleValue());
+    }
+  }
+
+  MathOperation op;
+  MathOperations(Function<Double, Number> singleArg) {
+    op = new MathOperation(new SingleOpFunc(singleArg), 1, 1);
+  }
+
+  MathOperations(BiFunction<Double, Double, Number> binaryArg) {
+    op = new MathOperation(new BinaryOpFunc(binaryArg), 2, 2);
+  }
+
+  MathOperations(MathOperation op)
+  {
+    this.op = op;
+  }
+
+  @Override
+  public Number apply(Number[] in) {
+      return op.getOperation().apply(in);
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/b2375a1f/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/StellarMathFunction.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/StellarMathFunction.java
 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/StellarMathFunction.java
new file mode 100644
index 0000000..0f9eb16
--- /dev/null
+++ 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/utils/math/StellarMathFunction.java
@@ -0,0 +1,64 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.metron.stellar.common.utils.math;
+
+import org.apache.metron.stellar.dsl.Context;
+import org.apache.metron.stellar.dsl.ParseException;
+import org.apache.metron.stellar.dsl.StellarFunction;
+
+import java.util.List;
+
+public class StellarMathFunction implements StellarFunction {
+  MathOperation _func;
+  public StellarMathFunction(MathOperations _func) {
+    this._func = _func.op;
+  }
+
+  public StellarMathFunction(MathOperation _func) {
+    this._func = _func;
+  }
+
+  @Override
+  public Object apply(List<Object> args, Context context) throws 
ParseException {
+    if(args.size() < _func.getMinArgs()) {
+      return Double.NaN;
+    }
+    Number[] nums = new Number[_func.getMaxArgs()];
+    for(int i = 0; i < _func.getMaxArgs();++i) {
+      nums[i] = (Number)args.get(i);
+      if(nums[i] == null) {
+        return Double.NaN;
+      }
+    }
+
+    Object ret = _func.getOperation().apply(nums);
+    return ret;
+  }
+
+  @Override
+  public void initialize(Context context) {
+
+  }
+
+  @Override
+  public boolean isInitialized() {
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/b2375a1f/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/MathFunctions.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/MathFunctions.java
 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/MathFunctions.java
index 5583ba2..a5ac366 100644
--- 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/MathFunctions.java
+++ 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/MathFunctions.java
@@ -19,15 +19,19 @@
  */
 package org.apache.metron.stellar.dsl.functions;
 
+import org.apache.metron.stellar.common.utils.math.MathOperations;
+import org.apache.metron.stellar.common.utils.math.StellarMathFunction;
 import org.apache.metron.stellar.dsl.Context;
 import org.apache.metron.stellar.dsl.ParseException;
 import org.apache.metron.stellar.dsl.Stellar;
 import org.apache.metron.stellar.dsl.StellarFunction;
 
 import java.util.List;
+import java.util.function.Function;
 
 public class MathFunctions {
 
+
   @Stellar(name="ABS"
           ,description="Returns the absolute value of a number."
           ,params = {
@@ -35,29 +39,159 @@ public class MathFunctions {
                     }
           , returns="The absolute value of the number passed in."
           )
-  public static class Abs implements StellarFunction {
+  public static class Abs extends StellarMathFunction{
+
+
+    public Abs() {
+      super(MathOperations.ABS);
+    }
+  }
+
+  @Stellar(name="LOG10"
+          ,description="Returns the log (base 10) of a number."
+          ,params = {
+                "number - The number to take the log (base 10) value of"
+                    }
+          , returns="The log (base 10) of the number passed in."
+          )
+  public static class Log10 extends StellarMathFunction {
+   public Log10() {
+      super(MathOperations.LOG10);
+    }
+
+  }
+
+  @Stellar(name="LOG2"
+          ,description="Returns the log (base 2) of a number."
+          ,params = {
+                "number - The number to take the log (base 2) value of"
+                    }
+          , returns="The log (base 2) of the number passed in."
+          )
+  public static class Log2 extends StellarMathFunction {
+   public Log2() {
+      super(MathOperations.LOG2);
+    }
 
-    @Override
-    public Object apply(List<Object> args, Context context) throws 
ParseException {
-      if(args.size() < 1) {
-        return Double.NaN;
-      }
-      Number n = (Number)args.get(0);
-      if(n == null) {
-        return Double.NaN;
-      }
-      return Math.abs(n.doubleValue());
+  }
+
+  @Stellar(name="LN"
+          ,description="Returns the natural log of a number."
+          ,params = {
+                "number - The number to take the natural log value of"
+                    }
+          , returns="The natural log of the number passed in."
+          )
+  public static class Ln extends StellarMathFunction {
+   public Ln() {
+      super(MathOperations.LN);
     }
 
-    @Override
-    public void initialize(Context context) {
+  }
 
+  @Stellar(name="SQRT"
+          ,description="Returns the square root of a number."
+          ,params = {
+                "number - The number to take the square root of"
+                    }
+          , returns="The square root of the number passed in."
+          )
+  public static class Sqrt extends StellarMathFunction {
+   public Sqrt() {
+      super(MathOperations.SQRT);
     }
 
-    @Override
-    public boolean isInitialized() {
-      return true;
+  }
+
+  @Stellar(name="CEILING"
+          ,description="Returns the ceiling of a number."
+          ,params = {
+                "number - The number to take the ceiling of"
+                    }
+          , returns="The ceiling of the number passed in."
+          )
+  public static class Ceil extends StellarMathFunction {
+   public Ceil() {
+      super(MathOperations.CEIL);
     }
+
   }
 
+  @Stellar(name="FLOOR"
+          ,description="Returns the floor of a number."
+          ,params = {
+                "number - The number to take the floor of"
+                    }
+          , returns="The floor of the number passed in."
+          )
+  public static class Floor extends StellarMathFunction {
+   public Floor() {
+      super(MathOperations.FLOOR);
+    }
+  }
+
+  @Stellar(name="SIN"
+          ,description="Returns the sine of a number."
+          ,params = {
+                "number - The number to take the sine of"
+                    }
+          , returns="The sine of the number passed in."
+          )
+  public static class Sin extends StellarMathFunction {
+   public Sin() {
+      super(MathOperations.SIN);
+    }
+  }
+
+  @Stellar(name="COS"
+          ,description="Returns the cosine of a number."
+          ,params = {
+                "number - The number to take the cosine of"
+                    }
+          , returns="The cosine of the number passed in."
+          )
+  public static class Cos extends StellarMathFunction {
+   public Cos() {
+      super(MathOperations.COS);
+    }
+  }
+
+  @Stellar(name="TAN"
+          ,description="Returns the tangent of a number."
+          ,params = {
+                "number - The number to take the tangent of"
+                    }
+          , returns="The tangent of the number passed in."
+          )
+  public static class Tan extends StellarMathFunction {
+   public Tan() {
+      super(MathOperations.TAN);
+    }
+  }
+
+  @Stellar(name="EXP"
+          ,description="Returns Euler's number raised to the power of the 
argument"
+          ,params = {
+                "number - The power to which e is raised."
+                    }
+          , returns="Euler's number raised to the power of the argument."
+          )
+  public static class Exp extends StellarMathFunction {
+   public Exp() {
+      super(MathOperations.EXP);
+    }
+  }
+
+  @Stellar(name="ROUND"
+          ,description="Rounds a number to the nearest integer. This is 
half-up rounding."
+          ,params = {
+                "number - The number to round"
+                    }
+          , returns="The nearest integer (based on half-up rounding)."
+          )
+  public static class Round extends StellarMathFunction {
+   public Round() {
+      super(MathOperations.ROUND);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/b2375a1f/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/MathFunctionsTest.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/MathFunctionsTest.java
 
b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/MathFunctionsTest.java
index d427fb4..cdb1c42 100644
--- 
a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/MathFunctionsTest.java
+++ 
b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/MathFunctionsTest.java
@@ -19,6 +19,7 @@
  */
 package org.apache.metron.stellar.dsl.functions;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import org.apache.metron.stellar.common.StellarProcessor;
 import org.apache.metron.stellar.dsl.Context;
@@ -26,9 +27,16 @@ import org.apache.metron.stellar.dsl.StellarFunctions;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.HashMap;
 import java.util.Map;
 
 public class MathFunctionsTest {
+
+  public static final double EPSILON = 1e-7;
+  public static Map<Double, Double> baseExpectations = new HashMap<Double, 
Double>() {{
+    put(Double.NaN, Double.NaN);
+  }};
+
   public static Object run(String rule, Map<String, Object> variables) {
     Context context = Context.EMPTY_CONTEXT();
     StellarProcessor processor = new StellarProcessor();
@@ -38,10 +46,156 @@ public class MathFunctionsTest {
 
   @Test
   public void testAbs() {
-    Assert.assertEquals((Double)run("ABS(value)", ImmutableMap.of("value", 
0)), 0, 1e-7);
-    Assert.assertTrue(Double.isNaN((Double)run("ABS(value)", 
ImmutableMap.of("value", Double.NaN))));
-    Assert.assertEquals((Double)run("ABS(value)", ImmutableMap.of("value", 
10.5)), 10.5, 1e-7);
-    Assert.assertEquals((Double)run("ABS(value)", ImmutableMap.of("value", 
-10.5)), 10.5, 1e-7);
+    assertValues("ABS",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 0d);
+             put(10.5d, 10.5d);
+             put(-10.5d, 10.5d);
+           }}
+    );
+  }
+
+  @Test
+  public void testSqrt() {
+    assertValues("SQRT",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 0d);
+             put(25d, 5d);
+             put(-10.5d, Double.NaN);
+           }}
+    );
+  }
+
+  @Test
+  public void testCeiling() {
+    assertValues("CEILING",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 0d);
+             put(10.5d, 11d);
+             put(-10.5d, -10d);
+           }}
+    );
+  }
+
+  @Test
+  public void testFloor() {
+    assertValues("FLOOR",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 0d);
+             put(10.5d, 10d);
+             put(-10.5d, -11d);
+           }}
+    );
+  }
+
+  @Test
+  public void testSin() {
+    assertValues("SIN",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 0d);
+             put(Math.PI/6, 0.5);
+             put(Math.PI/4, Math.sqrt(2)/2.0);
+             put(Math.PI/3, Math.sqrt(3)/2.0);
+             put(Math.PI/2, 1d);
+           }}
+    );
+  }
+
+  @Test
+  public void testCos() {
+    assertValues("COS",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 1d);
+             put(Math.PI/6, Math.sqrt(3)/2.0);
+             put(Math.PI/4, Math.sqrt(2)/2.0);
+             put(Math.PI/3, 0.5d);
+             put(Math.PI/2, 0d);
+           }}
+    );
+  }
+
+  @Test
+  public void testTan() {
+    assertValues("TAN",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 0d);
+             put(Math.PI/6, Math.sqrt(3)/3.0);
+             put(Math.PI/4, 1d);
+             put(Math.PI/3, Math.sqrt(3));
+             put(Math.PI/2, Math.sin(Math.PI/2)/Math.cos(Math.PI/2));
+           }}
+    );
+  }
+
+  @Test
+  public void testExp() {
+    assertValues("EXP",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 1d);
+             put(0.5d, Math.sqrt(Math.E));
+             put(-0.5d, 1/Math.sqrt(Math.E));
+             put(1d, Math.E);
+             put(2d, Math.E*Math.E);
+           }}
+    );
+  }
+
+  @Test
+  public void testRound() {
+    assertValues("ROUND",
+           new HashMap<Double, Double>(baseExpectations) {{
+             put(0d, 0d);
+             put(0.5d, 1d);
+             put(0.4d, 0d);
+             put(-0.5d, 0d);
+           }}
+    );
+  }
+
+  @Test
+  public void testNaturalLog() {
+    testLog("LN", Math.E);
+  }
+
+  @Test
+  public void testLog2() {
+    testLog("LOG2", 2);
+  }
+
+  @Test
+  public void testLog10() {
+    testLog("LOG10", 10);
+  }
+
+  public void assertValues(String func, Map<Double, Double> expected) {
+    for(Map.Entry<Double, Double> test : expected.entrySet()) {
+      for(String expr : ImmutableList.of(func + "(value)"
+                                        ,func + "(" + test.getKey() + ")"
+                                        )
+         )
+      {
+        if (Double.isNaN(test.getValue())) {
+          Assert.assertTrue(expr + " != NaN, where value == " + test.getKey(), 
Double.isNaN(toDouble(run(expr, ImmutableMap.of("value", test.getKey())))));
+        } else {
+          Assert.assertEquals(expr + " != " + test.getValue() + " (where value 
== " + test.getKey() + ")", test.getValue(), toDouble(run(expr, 
ImmutableMap.of("value", test.getKey()))), EPSILON);
+        }
+      }
+    }
+  }
+
+  public Double toDouble(Object n) {
+    return ((Number)n).doubleValue();
+  }
+
+  public void testLog(String logExpr, double base) {
+    Map<Double, Double> expectedValues = new HashMap<Double, 
Double>(baseExpectations) {{
+      put(base, 1d);
+      put(0d, Double.NEGATIVE_INFINITY);
+    }};
+    for(int i = 1;i <= 10;++i) {
+      expectedValues.put(Math.pow(base, i), (double)i);
+    }
+    assertValues(logExpr, expectedValues);
   }
 
 }

Reply via email to