How to manually define a custom operator
A custom operator is defined by its codename
, which is the key in Json-Logic-Typed format.
Example:
In the following example, the plus operator has +
as a codename and must declare an Operator
class/object that defines the computation performed by this operator.
{
"+": [
{"var": "some_value1", "type": {"codename": "int"}},
{"var": "some_value2", "type": {"codename": "int"}}
]
}
EvaluatorLogicConf
contains the information on how the implementation associates a class or object to a +
operator codename. To use, pass EvaluatorLogicConf
as an init parameter to EvaluatorLogic
.
Information provided to EvaluatorLogicConf
is a mapping of MethodConf
objects. MethodConf
holds an operator’s information for evaluation. There are 6 parameters:
operator
:String
codename.methodName
:String
name of method to invoke at evaluation.ownerMethodOpt
:Option[Operator]
Optional object. If defined, describes what the method to be invoked belongs to. If not defined, it means the method belongs to accumulator at evaluation.isReduceTypeOperator
:Boolean
true if operator is a reduce type (max, min, +, -, *, /, And, Or, …), false otherwise.isCompositionOperator
:Boolean
true if operator is a composition type (reduce, map, filter, all, none, some), false otherwise.isUnary
:Boolean
true if unary operator (logical negate, …), false otherwise.
You need to pass only your MethodConf
object to EvaluatorLogicConf.createConf
method.
val methodConf = MethodConf(...)
implicit val confEvaluator = EvaluatorLogicConf.createConf(methodConfsManualAdd = Map("expN" -> confMethod))
val evaluator = new EvaluatorLogic
evaluator.eval(...)
How to implement a custom operator
There are two distinct ways to define an operator.
First approach: implementing the Operator
trait
Example: Let’s implement an operator “expN” that takes two input \(X\), \(N\) and computes: \(\sum_{n=1}^{N} \frac{X^{n}}{n!}\)
The only thing left to do is manually pass the information about the “expN” operator as an MethodConf
object to the EvaluatorLogicConf.createConf
method.
class OperatorPlus2 {
def factorial(n: Int): Int = ...
def computePartialSum(x: Double, N: Long): Double = {
var sum = 0
for (i <- 0 to N) {
sum += math.pow(x, n) / factorial(n)
}
sum
}
}
val operatorPlus2 = new OperatorPlus2
val confMethod = ConfMethod(
"expN",
"computePartialSum",
Some(operatorPlus2),
false,
false,
false
)
implicit val confEvaluator = EvaluatorLogicConf.createConf(methodConfsManualAdd = Map("expN" -> confMethod))
val evaluator = new EvaluatorLogic
evaluating the following json
[{
"expN": [
{"var": "some_variable1", "type": {"codename": "int"}},
{"var": "some_variable2", "type": {"codename": "int"}}
]
},
{
"some_variable1": ...
"some_variable2": ...
}]
can be done using the evaluator:
val serializer = ...
val jsonLogicCore = serializer.serialize(json)
evalutor.eval(jsonLogicCore)
Second approach: method is defined in accumulator’s class definition
Example You may also define the operator secondAcc
, whose method belongs to evaluation accumulator
class A(num1: Int, num2: Double) {
def combine(that: A): A = new A(num1 + that.num1, num2 + that.num1 * that.num2)
}
val confMethod = ConfMethod(
"secondAcc",
"combine",
None,
true,
false,
false
)
implicit val confEvaluator = EvaluatorLogicConf.createConf(methodConfsManualAdd = Map("secondAcc" -> confMethod))
val evaluator = new EvaluatorLogic
Notice that method is not defined inside the Operator object, but inside accumulator’s class A
Define an operator: as a service
Please refer to Advanced: Define a Marshaller/Unmarshaller/Operator as a Java Service