blob: 0bea52cadd3eb402954e12b728b4b9dccbcbc252 [file] [log] [blame]
/*
* 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.wayang.core.util.mathex;
import org.apache.wayang.core.util.mathex.exceptions.EvaluationException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.ToDoubleFunction;
/**
* Default {@link Context} implementation that can be configured.
*/
public class DefaultContext implements Context {
private Context parentContext;
private Map<String, Double> variableValues = new HashMap<>();
private Map<String, ToDoubleFunction<double[]>> functions = new HashMap<>();
/**
* Creates a new instance.
*/
public DefaultContext() {
this(null);
}
/**
* Creates a new instance with a parent. If the new instance cannot serve a contextual information, it will
* ask the parent.
*
* @param parentContext the parent instance
*/
public DefaultContext(Context parentContext) {
this.parentContext = parentContext;
}
@Override
public double getVariable(String variableName) {
Double variableValue = this.variableValues.get(variableName);
if (variableValue == null && this.parentContext != null) {
variableValue = this.parentContext.getVariable(variableName);
}
if (variableValue == null) {
throw new EvaluationException(String.format("No variable named \"%s\".", variableName));
}
return variableValue;
}
@Override
public ToDoubleFunction<double[]> getFunction(String functionName) {
ToDoubleFunction<double[]> function = this.functions.get(functionName);
if (function == null && this.parentContext != null) {
function = this.parentContext.getFunction(functionName);
}
if (function == null) {
throw new EvaluationException(String.format("No function named \"%s\".", functionName));
}
return function;
}
/**
* Set the parent context.
*
* @param parentContext the parent context
*/
public void setParentContext(Context parentContext) {
this.parentContext = parentContext;
}
/**
* Register a variable.
*
* @param name the name of the variable
* @param value the value
*/
public void setVariable(String name, double value) {
this.variableValues.put(name, value);
}
/**
* Register a function.
*
* @param name the name of the function
* @param function the function
*/
public void setFunction(String name, ToDoubleFunction<double[]> function) {
this.functions.put(name, function);
}
/**
* Create an instance with standard variables and functions.
*
* @return the instance
*/
static Context createBaseContext() {
DefaultContext baseContext = new DefaultContext();
baseContext.setFunction("ln", args -> Math.log(args[0]));
baseContext.setFunction("ld", args -> Math.log(args[0]) / Math.log(2));
baseContext.setFunction("log", args -> Math.log(args[0]) / Math.log(args[1]));
baseContext.setFunction("max", args -> {
if (args.length == 0) throw new EvaluationException("max(...) requires at least one argument.");
double max = args[0];
for (int i = 0; i < args.length; i++) max = Math.max(max, args[i]);
return max;
});
baseContext.setFunction("min", args -> {
if (args.length == 0) throw new EvaluationException("min(...) requires at least one argument.");
double min = args[0];
for (int i = 0; i < args.length; i++) min = Math.min(min, args[i]);
return min;
});
baseContext.setFunction("abs", args -> Math.abs(args[0]));
baseContext.setVariable("pi", Math.PI);
baseContext.setVariable("e", Math.E);
return baseContext;
}
}