package jscl.math.function;
import jscl.AngleUnit;
import jscl.CustomFunctionCalculationException;
import jscl.JsclMathEngine;
import jscl.NumeralBase;
import jscl.math.Expression;
import jscl.text.ParseException;
import org.junit.Assert;
import org.junit.Test;
import java.util.Collections;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/**
* User: serso
* Date: 11/15/11
* Time: 5:35 PM
*/
public class CustomFunctionTest {
@Test
public void testLog() throws Exception {
JsclMathEngine mathEngine = JsclMathEngine.getInstance();
assertEquals("∞", Expression.valueOf("1/0").numeric().toString());
assertEquals("∞", Expression.valueOf("ln(10)/ln(1)").numeric().toString());
// logarithm
final CustomFunction.Builder jBuilder = new CustomFunction.Builder(true, "log", asList("a", "b"), "ln(b)/ln(a)");
Function function = mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder.create());
assertEquals("log(a, b)", function.toString());
assertEquals("ln(b)/ln(a)", ((CustomFunction) mathEngine.getFunctionsRegistry().get("log")).getContent());
assertEquals("∞", Expression.valueOf("log(1, 10)").numeric().toString());
assertEquals("3.321928094887363", Expression.valueOf("log(2, 10)").numeric().toString());
assertEquals("1.430676558073393", Expression.valueOf("log(5, 10)").numeric().toString());
assertEquals("0.960252567789128", Expression.valueOf("log(11, 10)").numeric().toString());
assertEquals("1/b*1/ln(a)", Expression.valueOf("∂(log(a, b), b)").expand().toString());
assertEquals("-1/a*(1/ln(a))^2*ln(b)", Expression.valueOf("∂(log(a, b), a)").expand().toString());
}
@Test
public void testDerivative() throws Exception {
JsclMathEngine mathEngine = JsclMathEngine.getInstance();
final CustomFunction.Builder jBuilder = new CustomFunction.Builder("t1", asList("a"), "sin(a)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder.create());
assertEquals("1", Expression.valueOf("t1(90)").numeric().toString());
assertEquals("cos(t)", Expression.valueOf("∂(t1(t), t)").expand().toString());
assertEquals("0", Expression.valueOf("∂(t1(t), t2)").expand().toString());
assertEquals("cos(a)", Expression.valueOf("∂(t1(a), a)").expand().toString());
assertEquals("1", Expression.valueOf("∂(t1(a), t1(a))").expand().toString());
final CustomFunction.Builder jBuilder1 = new CustomFunction.Builder("t2", asList("a", "b"), "b*sin(a)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder1.create());
assertEquals("y*cos(x)", Expression.valueOf("∂(t2(x, y), x)").expand().toString());
assertEquals("sin(x)", Expression.valueOf("∂(t2(x, y), y)").expand().toString());
}
@Test
public void testAntiDerivative() throws Exception {
JsclMathEngine mathEngine = JsclMathEngine.getInstance();
final CustomFunction.Builder jBuilder = new CustomFunction.Builder("t1", asList("a"), "sin(a)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder.create());
assertEquals("1", Expression.valueOf("t1(90)").numeric().toString());
try {
mathEngine.setAngleUnits(AngleUnit.rad);
assertEquals("-cos(t)", Expression.valueOf("∫(t1(t), t)").expand().toString());
assertEquals("t2*sin(t)", Expression.valueOf("∫(t1(t), t2)").expand().toString());
assertEquals("-cos(a)", Expression.valueOf("∫(t1(a), a)").expand().toString());
assertEquals("1/2*sin(a)^2", Expression.valueOf("∫(t1(a), t1(a))").expand().toString());
final CustomFunction.Builder jBuilder1 = new CustomFunction.Builder("t2", asList("a", "b"), "b*sin(a)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder1.create());
assertEquals("-y*cos(x)", Expression.valueOf("∫(t2(x, y), x)").expand().toString());
assertEquals("1/2*y^2*sin(x)", Expression.valueOf("∫(t2(x, y), y)").expand().toString());
} finally {
mathEngine.setAngleUnits(AngleUnit.deg);
}
}
@Test
public void testFunction() throws Exception {
JsclMathEngine mathEngine = JsclMathEngine.getInstance();
final CustomFunction.Builder jBuilder = new CustomFunction.Builder("testFunction", asList("a", "b", "c", "d"), "b*cos(a)/c+d");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder.create());
assertEquals("6.749543120264322", Expression.valueOf("testFunction(2, 3, 4, 6)").numeric().toString());
assertEquals("7.749543120264322", Expression.valueOf("testFunction(2, 3, 4, 7)").numeric().toString());
assertEquals("6.749543120264322", Expression.valueOf("testFunction(2*1, 3, 4, 6)").numeric().toString());
assertEquals("6.749543120264322", Expression.valueOf("testFunction(2*1, 3, 4, 3!)").numeric().toString());
assertEquals("6.749543120264322", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString());
assertEquals("testFunction(2, 3, 4, 3!)", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").simplify().toString());
assertEquals("3*cos(2)/4+3!", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").expand().toString());
assertEquals("3*(1/2*1/exp(2*i)+1/2*exp(2*i))/4+3!", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").elementary().toString());
assertEquals("sin(t)^2*testFunction(2, 3, 4, 3!)", Expression.valueOf("sin(t)*testFunction(2*1, 3, 2^2-1+e^0, 3!)*sin(t)").simplify().toString());
assertEquals("testFunction(2, 3, 4, 3!)^2", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)*testFunction(2, 3, 4, 3!)").simplify().toString());
try {
Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)*testFunction(2, 3, 4)");
Assert.fail();
} catch (ParseException e) {
// ok, not enough parameters
}
final ExtendedConstant.Builder a = new ExtendedConstant.Builder(new Constant("a"), 1000d);
mathEngine.getConstantsRegistry().addOrUpdate(a.create());
final CustomFunction.Builder jBuilder1 = new CustomFunction.Builder("testFunction2", asList("a", "b", "c", "d"), "b*cos(a)/c+d");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder1.create());
assertEquals("6.749543120264322", Expression.valueOf("testFunction2(2, 3, 4, 6)").numeric().toString());
assertEquals("7.749543120264322", Expression.valueOf("testFunction2(2, 3, 4, 7)").numeric().toString());
assertEquals("6.749543120264322", Expression.valueOf("testFunction2(2*1, 3, 4, 6)").numeric().toString());
assertEquals("6.749543120264322", Expression.valueOf("testFunction2(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString());
final CustomFunction.Builder jBuilder2 = new CustomFunction.Builder("testFunction3", asList("a", "b", "c", "d"), "testFunction2(a, b, c, d) - testFunction(a, b, c, d)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder2.create());
assertEquals("0", Expression.valueOf("testFunction3(2, 3, 4, 6)").numeric().toString());
assertEquals("0", Expression.valueOf("testFunction3(2, 3, 4, 7)").numeric().toString());
assertEquals("0", Expression.valueOf("testFunction3(2*1, 3, 4, 6)").numeric().toString());
assertEquals("0", Expression.valueOf("testFunction3(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString());
final CustomFunction.Builder jBuilder3 = new CustomFunction.Builder("testFunction4", asList("a", "b", "c", "d"), "testFunction2(a, b/2, c/3, d/4) - testFunction(a, b!, c, d)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder3.create());
assertEquals("-4.874771560132161", Expression.valueOf("testFunction4(2, 3, 4, 6)").numeric().toString());
assertEquals("-5.624771560132161", Expression.valueOf("testFunction4(2, 3, 4, 7)").numeric().toString());
assertEquals("-4.874771560132161", Expression.valueOf("testFunction4(2*1, 3, 4, 6)").numeric().toString());
assertEquals("-4.874771560132161", Expression.valueOf("testFunction4(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString());
final CustomFunction.Builder jBuilder4 = new CustomFunction.Builder("testFunction5", asList("a", "b"), "testFunction2(a, b/2, 2, 1) - testFunction(a, b!, 4!, 1)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder4.create());
assertEquals("0.499695413509548", Expression.valueOf("testFunction5(2, 3)").numeric().toString());
assertEquals("0.499695413509548", Expression.valueOf("testFunction5(2, 3)").numeric().toString());
assertEquals("0.499695413509548", Expression.valueOf("testFunction5(2*1, 3)").numeric().toString());
assertEquals("0", Expression.valueOf("testFunction5(2*1, 2^2-1+e^0)").numeric().toString());
try {
Expression.valueOf("testFunction5(2, 3.5)").numeric();
Assert.fail();
} catch (ArithmeticException e) {
}
final CustomFunction.Builder jBuilder5 = new CustomFunction.Builder("testFunction6", asList("a", "b"), "testFunction(a, b!, 4!, Π)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder5.create());
assertEquals("180.2498477067548", Expression.valueOf("testFunction6(2, 3)").numeric().toString());
final ExtendedConstant.Builder e = new ExtendedConstant.Builder(new Constant("e"), 181d);
mathEngine.getConstantsRegistry().addOrUpdate(e.create());
final CustomFunction.Builder jBuilder6 = new CustomFunction.Builder("testFunction7", asList("a", "b"), "testFunction(a, b!, 4!, e)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder6.create());
assertEquals("181.2498477067548", Expression.valueOf("testFunction7(2, 3)").numeric().toString());
final ExtendedConstant.Builder e1 = new ExtendedConstant.Builder(new Constant("e"), 181d);
mathEngine.getConstantsRegistry().addOrUpdate(e1.create());
final CustomFunction.Builder jBuilder7 = new CustomFunction.Builder("testFunction8", asList("a", "b"), "testFunction(sin(a), b!, 4!, e)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder7.create());
assertEquals("181.249999953623", Expression.valueOf("testFunction8(2, 3)").numeric().toString());
}
@Test
public void testFunction2() throws Exception {
JsclMathEngine mathEngine = JsclMathEngine.getInstance();
final CustomFunction.Builder jBuilder = new CustomFunction.Builder("f", asList("x", "y"), "z1/z2*√(x^2+y^2)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder.create());
final CustomFunction.Builder jBuilder1 = new CustomFunction.Builder("f2", asList("x", "y"), "√(x^2+y^2)");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder1.create());
final CustomFunction.Builder jBuilder2 = new CustomFunction.Builder("f3", asList("x", "y"), "x^2+y^2");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder2.create());
try {
assertEquals("1", Expression.valueOf("f(1, 1)").numeric().toString());
Assert.fail();
} catch (ArithmeticException e) {
//ok
}
assertEquals("1.414213562373095", Expression.valueOf("f2(1, 1)").numeric().toString());
assertEquals("5", Expression.valueOf("f2(4, 3)").numeric().toString());
assertEquals("2*z1", Expression.valueOf("∂(f3(z1, z2), z1)").expand().toString());
assertEquals("2*z2", Expression.valueOf("∂(f3(z1, z2), z2)").expand().toString());
// test symbols
final CustomFunction.Builder jBuilder3 = new CustomFunction.Builder("f4", asList("x", "y"), "2 000*x^2+y^2");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder3.create());
final CustomFunction.Builder jBuilder4 = new CustomFunction.Builder("f5", asList("x", "y"), "2'000* x ^2+y^2\r");
mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder4.create());
}
@Test
public void testNumbersAreReadInBinMode() throws Exception {
final JsclMathEngine me = JsclMathEngine.getInstance();
me.setNumeralBase(NumeralBase.bin);
final CustomFunction f = new CustomFunction.Builder("test", asList("x", "y"), "2000*x-0.001*y").create();
assertEquals(NumeralBase.bin, me.getNumeralBase());
me.setNumeralBase(NumeralBase.dec);
assertEquals("2000*x-0.001*y", f.getContent());
}
@Test
public void testInvalidFunctionShouldReturnNumeralBase() throws Exception {
final JsclMathEngine me = JsclMathEngine.getInstance();
me.setNumeralBase(NumeralBase.bin);
try {
new CustomFunction.Builder("test", Collections.<String>emptyList(), "2000*").create();
fail();
} catch (CustomFunctionCalculationException ignored) {
}
assertEquals(NumeralBase.bin, me.getNumeralBase());
me.setNumeralBase(NumeralBase.dec);
}
}