| /* |
| * 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; |
| } |
| } |