/** * Sets the expression which should be evaluated when calculating new values for the given * parameter. These values are used to initialize the freeParameters. * * @param parameter The parameter whose initial value needs to be computed. * @param expressionString The formula for picking initial values. * @throws ParseException If the formula cannot be parsed or contains variable names. */ public void setParameterEstimationInitializationExpression( String startsWith, String parameter, String expressionString) throws ParseException { if (parameter == null) { throw new NullPointerException("Parameter was null."); } if (startsWith == null) { throw new NullPointerException("StartsWith expression was null."); } if (startsWith.contains(" ")) { throw new IllegalArgumentException("StartsWith expression contains spaces."); } if (expressionString == null) { throw new NullPointerException("Expression string was null."); } // Parse the expression. This could throw an ParseException, but that exception needs to handed // up the // chain, because the interface will need it. ExpressionParser parser = new ExpressionParser(); Expression expression = parser.parseExpression(expressionString); List<String> parameterNames = parser.getParameters(); if (parameterNames.size() > 0) { throw new IllegalArgumentException( "Initial distribution may not " + "contain parameters: " + expressionString); } parameterEstimationInitializationExpressions.put(parameter, expression); parameterEstimationInitializationExpressionStrings.put(parameter, expressionString); startsWithParametersTemplates.put(startsWith, expressionString); }
// Formulas that should and should not fail. @Test public void test4() { Map<String, Integer> formulasToOffsets = new LinkedHashMap<String, Integer>(); // -1 means it should parse. formulasToOffsets.put("X X", 2); formulasToOffsets.put("b11 b11", 4); formulasToOffsets.put("X + Y ++", 7); formulasToOffsets.put("b1*X1 *+ b2 * X2 +", 17); formulasToOffsets.put("cos()", 0); formulasToOffsets.put("2..3 * X", 0); formulasToOffsets.put("+X1", -1); formulasToOffsets.put("-X1", -1); formulasToOffsets.put("A / B", -1); formulasToOffsets.put("b1*X1 +@**!! b2 * X2", 7); formulasToOffsets.put("X7", 0); List<String> otherNodes = new ArrayList<String>(); otherNodes.add("X7"); ExpressionParser parser = new ExpressionParser(otherNodes, ExpressionParser.RestrictionType.MAY_NOT_CONTAIN); for (String formula : formulasToOffsets.keySet()) { try { parser.parseExpression(formula); assertEquals(formulasToOffsets.get(formula).intValue(), -1); } catch (ParseException e) { int offset = e.getErrorOffset(); assertEquals(formulasToOffsets.get(formula).intValue(), offset); } } }
public void test2() { final Map<String, Double> values = new HashMap<String, Double>(); values.put("b11", 1.0); values.put("X1", 2.0); values.put("X2", 3.0); values.put("B22", 4.0); values.put("B12", 5.0); values.put("X4", 6.0); values.put("b13", 7.0); values.put("X5", 8.0); values.put("b10", 9.0); values.put("X", 10.0); values.put("Y", 11.0); values.put("Z", 12.0); values.put("W", 13.0); values.put("T", 14.0); values.put("R", 15.0); values.put("s2", 0.0); values.put("s3", 1.0); Context context = new Context() { public Double getValue(String var) { return values.get(var); } }; List<String> formulas = new ArrayList<String>(); // formulas.add("ChiSquare(s3)"); formulas.add("Gamma(1, 1)"); formulas.add("Beta(3, 5)"); formulas.add("Poisson(5)"); formulas.add("Indicator(0.3)"); formulas.add("ExponentialPower(3)"); formulas.add("exp(Normal(s2, s3))"); // Log normal formulas.add("Normal(0, s3)"); formulas.add("abs(Normal(s2, s3) ^ 3)"); // Gaussian Power formulas.add("Discrete(3, 1, 5)"); formulas.add("0.3 * Normal(-2.0e2, 0.5) + 0.7 * Normal(2.0, 0.5)"); // Mixture of Gaussians formulas.add("StudentT(s3)"); formulas.add("s3"); // Single value. formulas.add("Hyperbolic(5, 3)"); formulas.add("Uniform(s2, s3)"); formulas.add("VonMises(s3)"); formulas.add("Split(0, 1, 5, 6)"); formulas.add("Mixture(0.5, N(-2, 0.5), 0.5, N(2, 0.5))"); // ExpressionParser parser = new ExpressionParser(); try { for (String formula : formulas) { Expression expression = parser.parseExpression(formula); double value = expression.evaluate(context); } } catch (ParseException e) { e.printStackTrace(); } }
public void setErrorsTemplate(String errorsTemplate) throws ParseException { if (errorsTemplate == null) { throw new NullPointerException(); } // Test to make sure it's parsable. ExpressionParser parser = new ExpressionParser(); parser.parseExpression(errorsTemplate); this.errorsTemplate = errorsTemplate; }
public void setParametersEstimationInitializationTemplate(String parametersTemplate) throws ParseException { if (parametersTemplate == null) { throw new NullPointerException(); } // Test to make sure it's parsable. ExpressionParser parser = new ExpressionParser(); parser.parseExpression(parametersTemplate); this.parametersEstimationInitializationTemplate = parametersTemplate; }
// Test distribution means. @Test public void test5() { final Map<String, Double> values = new HashMap<String, Double>(); Context context = new Context() { public Double getValue(String var) { return values.get(var); } }; Map<String, Double> formulas = new LinkedHashMap<String, Double>(); formulas.put("ChiSquare(1)", 1.0); formulas.put("Gamma(2, .5)", 1.0); formulas.put("Beta(1, 2)", 0.33); formulas.put("Normal(2, 3)", 2.0); formulas.put("N(2, 3)", 2.0); formulas.put("StudentT(5)", 0.0); formulas.put("U(0, 1)", 0.5); formulas.put("Uniform(0, 1)", 0.5); formulas.put("Split(0, 1, 5, 6)", 3.0); ExpressionParser parser = new ExpressionParser(); try { for (String formula : formulas.keySet()) { Expression expression = parser.parseExpression(formula); double sum = 0.0; int sampleSize = 10000; for (int i = 0; i < sampleSize; i++) { double value = expression.evaluate(context); sum += value; } double mean = sum / sampleSize; assertEquals(formulas.get(formula), mean, 0.1); } } catch (ParseException e) { e.printStackTrace(); } }
public void setParametersTemplate(String parametersTemplate) throws ParseException { if (parametersTemplate == null) { throw new NullPointerException(); } // Test to make sure it's parsable. ExpressionParser parser = new ExpressionParser(); Expression expression = parser.parseExpression(parametersTemplate); List<String> parameterNames = parser.getParameters(); if (!parameterNames.isEmpty()) { throw new IllegalArgumentException( "Initial distribution for a parameter may not " + "contain parameters: " + expression.toString()); } this.parametersTemplate = parametersTemplate; }
public void setStartsWithParametersTemplate(String startsWith, String parametersTemplate) throws ParseException { if (startsWith == null || startsWith.isEmpty()) { return; } if (parametersTemplate == null) { throw new NullPointerException(); } // Test to make sure it's parsable. ExpressionParser parser = new ExpressionParser(); parser.parseExpression(parametersTemplate); if (startsWith.contains(" ")) { throw new IllegalArgumentException("Starts with string contains spaces."); } // this.parametersTemplate = parametersTemplate; this.startsWithParametersTemplates.put(startsWith, parametersTemplate); }
public void setNodeExpression(Node node, String expressionString) throws ParseException { if (node == null) { throw new NullPointerException("Node was null."); } if (expressionString == null) { // return; throw new NullPointerException("Expression string was null."); } // Parse the expression. This could throw an ParseException, but that exception needs to handed // up the // chain, because the interface will need it. ExpressionParser parser = new ExpressionParser(); Expression expression = parser.parseExpression(expressionString); List<String> parameterNames = parser.getParameters(); // Make a list of parent names. List<Node> parents = this.graph.getParents(node); List<String> parentNames = new LinkedList<>(); for (Node parent : parents) { parentNames.add(parent.getName()); } // List<String> _params = new ArrayList<String>(parameterNames); // _params.retainAll(variableNames); // _params.removeAll(parentNames); // // if (!_params.isEmpty()) { // throw new IllegalArgumentException("Conditioning on a variable other than the // parents: " + node); // } // Make a list of parameter names, by removing from the parser's list of freeParameters any that // correspond // to parent variables. If there are any variable names (including error terms) that are not // among the list of // parents, that's a time to throw an exception. We must respect the graph! (We will not // complain if any parents // are missing.) parameterNames.removeAll(variableNames); for (Node variable : nodes) { if (parameterNames.contains(variable.getName())) { parameterNames.remove(variable.getName()); // throw new IllegalArgumentException("The list of parameter names may not // include variables: " + variable.getName()); } } // Remove old parameter references. List<String> parametersToRemove = new LinkedList<>(); for (String parameter : this.referencedParameters.keySet()) { Set<Node> nodes = this.referencedParameters.get(parameter); if (nodes.contains(node)) { nodes.remove(node); } if (nodes.isEmpty()) { parametersToRemove.add(parameter); } } for (String parameter : parametersToRemove) { this.referencedParameters.remove(parameter); this.parameterExpressions.remove(parameter); this.parameterExpressionStrings.remove(parameter); this.parameterEstimationInitializationExpressions.remove(parameter); this.parameterEstimationInitializationExpressionStrings.remove(parameter); } // Add new parameter references. for (String parameter : parameterNames) { if (this.referencedParameters.get(parameter) == null) { this.referencedParameters.put(parameter, new HashSet<Node>()); } Set<Node> nodes = this.referencedParameters.get(parameter); nodes.add(node); setSuitableParameterDistribution(parameter); } // Remove old node references. List<Node> nodesToRemove = new LinkedList<>(); for (Node _node : this.referencedNodes.keySet()) { Set<Node> nodes = this.referencedNodes.get(_node); if (nodes.contains(node)) { nodes.remove(node); } if (nodes.isEmpty()) { nodesToRemove.add(_node); } } for (Node _node : nodesToRemove) { this.referencedNodes.remove(_node); } // Add new freeParameters. for (String variableString : variableNames) { Node _node = getNode(variableString); if (this.referencedNodes.get(_node) == null) { this.referencedNodes.put(_node, new HashSet<Node>()); } for (String s : parentNames) { if (s.equals(variableString)) { Set<Node> nodes = this.referencedNodes.get(_node); nodes.add(node); } } } // Finally, save the parsed expression and the original string that the user entered. No need to // annoy // the user by changing spacing. nodeExpressions.put(node, expression); nodeExpressionStrings.put(node, expressionString); }
@Test public void test1() { final Map<String, Double> values = new HashMap<String, Double>(); values.put("b11", 1.0); values.put("X1", 2.0); values.put("X2", 3.0); values.put("B22", 4.0); values.put("B12", 5.0); values.put("X4", 6.0); values.put("b13", 7.0); values.put("X5", 8.0); values.put("b10", 9.0); values.put("X", 10.0); values.put("Y", 11.0); values.put("Z", 12.0); values.put("W", 13.0); values.put("T", 14.0); values.put("R", 15.0); Context context = new Context() { public Double getValue(String var) { return values.get(var); } }; Map<String, Double> formulasToEvaluations = new HashMap<String, Double>(); formulasToEvaluations.put("0", 0.0); formulasToEvaluations.put("b11*X1 + sin(X2) + B22*X2 + B12*X4+b13*X5", 100.14); formulasToEvaluations.put("X5*X4*X4", 288.0); formulasToEvaluations.put("sin(b10*X1)", -0.75097); formulasToEvaluations.put("((X + ((Y * (Z ^ W)) * T)) + R)", 16476953628377113.0); formulasToEvaluations.put("X + Y * Z ^ W * T + R", 16476953628377113.0); formulasToEvaluations.put("pow(2, 5)", 32.0); formulasToEvaluations.put("2^5", 32.0); formulasToEvaluations.put("exp(1)", 2.718); formulasToEvaluations.put("sqrt(2)", 1.414); formulasToEvaluations.put("cos(0)", 1.0); formulasToEvaluations.put("cos(3.14/2)", 0.0); formulasToEvaluations.put("sin(0)", 0.0); formulasToEvaluations.put("sin(3.14/2)", 1.0); formulasToEvaluations.put("tan(1)", 1.56); formulasToEvaluations.put("cosh(1)", 1.54); formulasToEvaluations.put("sinh(1)", 1.18); formulasToEvaluations.put("tanh(1)", 0.76); formulasToEvaluations.put("acos(1)", 0.0); formulasToEvaluations.put("asin(1)", 1.57); formulasToEvaluations.put("atan(1)", 0.78); formulasToEvaluations.put("ln(1)", 0.0); formulasToEvaluations.put("log10(10)", 1.0); formulasToEvaluations.put("ceil(2.5)", 3.0); formulasToEvaluations.put("floor(2.5)", 2.0); formulasToEvaluations.put("abs(-5)", 5.0); formulasToEvaluations.put("max(2, 5, 3, 1, 10, -3)", 10.0); formulasToEvaluations.put("min(2, 5, 3, 1, 10, -3)", -3.0); // Logical. formulasToEvaluations.put("AND(1, 1)", 1.0); formulasToEvaluations.put("AND(1, 0)", 0.0); formulasToEvaluations.put("AND(0, 1)", 0.0); formulasToEvaluations.put("AND(0, 0)", 0.0); formulasToEvaluations.put("AND(0, 0.5)", 0.0); formulasToEvaluations.put("1 AND 1", 1.0); formulasToEvaluations.put("OR(1, 1)", 1.0); formulasToEvaluations.put("OR(1, 0)", 1.0); formulasToEvaluations.put("OR(0, 1)", 1.0); formulasToEvaluations.put("OR(0, 0)", 0.0); formulasToEvaluations.put("OR(0, 0.5)", 0.0); formulasToEvaluations.put("1 OR 1", 1.0); formulasToEvaluations.put("XOR(1, 1)", 0.0); formulasToEvaluations.put("XOR(1, 0)", 1.0); formulasToEvaluations.put("XOR(0, 1)", 1.0); formulasToEvaluations.put("XOR(0, 0)", 0.0); formulasToEvaluations.put("XOR(0, 0.5)", 0.0); formulasToEvaluations.put("1 XOR 1", 0.0); formulasToEvaluations.put("1 AND 0 OR 1 XOR 1 + 1", 1.0); formulasToEvaluations.put("1 < 2", 1.0); formulasToEvaluations.put("1 < 0", 0.0); formulasToEvaluations.put("1 < 1", 0.0); formulasToEvaluations.put("1 <= 2", 1.0); formulasToEvaluations.put("1 <= 1", 1.0); formulasToEvaluations.put("1 <= -1", 0.0); formulasToEvaluations.put("1 = 2", 0.0); formulasToEvaluations.put("1 = 1", 1.0); formulasToEvaluations.put("1 = -1", 0.0); formulasToEvaluations.put("1 > 2", 0.0); formulasToEvaluations.put("1 > 1", 0.0); formulasToEvaluations.put("1 > -1", 1.0); formulasToEvaluations.put("1 >= 2", 0.0); formulasToEvaluations.put("1 >= 1", 1.0); formulasToEvaluations.put("1 >= -1", 1.0); formulasToEvaluations.put("IF(1 > 2, 1, 2)", 2.0); formulasToEvaluations.put("IF(1 < 2, 1, 2)", 1.0); formulasToEvaluations.put("IF(1 < 2 AND 3 < 4, 1, 2)", 1.0); ExpressionParser parser = new ExpressionParser(); try { for (String formula : formulasToEvaluations.keySet()) { Expression expression = parser.parseExpression(formula); double value = expression.evaluate(context); assertEquals(formulasToEvaluations.get(formula), value, 0.01); } } catch (ParseException e) { e.printStackTrace(); } }