336 lines
10 KiB
Java
336 lines
10 KiB
Java
package it.cavallium.warppi.math.rules.dsl;
|
|
|
|
import it.cavallium.warppi.math.Function;
|
|
import it.cavallium.warppi.math.MathContext;
|
|
import it.cavallium.warppi.math.MathematicalSymbols;
|
|
import it.cavallium.warppi.math.functions.*;
|
|
import it.cavallium.warppi.math.functions.Number;
|
|
import it.cavallium.warppi.math.functions.equations.Equation;
|
|
import it.cavallium.warppi.math.functions.equations.EquationsSystem;
|
|
import it.cavallium.warppi.math.functions.trigonometry.*;
|
|
import it.cavallium.warppi.math.rules.dsl.patterns.*;
|
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.util.*;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
class PatternTest {
|
|
private final MathContext mathContext = new MathContext();
|
|
|
|
@Test
|
|
void subFunctionPattern() {
|
|
final Pattern pattern = new SubFunctionPattern("x");
|
|
|
|
final Function func = new Sum(
|
|
mathContext,
|
|
new Number(mathContext, 1),
|
|
new Number(mathContext, 2)
|
|
);
|
|
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(func);
|
|
assertTrue(subFunctions.isPresent());
|
|
|
|
assertEquals(func, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
|
|
@Test
|
|
void undefinedSubFunction() {
|
|
final Pattern pattern = new SubFunctionPattern("x");
|
|
final Map<String, Function> subFunctions = Collections.singletonMap("y", new Number(mathContext, 1));
|
|
|
|
final var exception = assertThrows(UndefinedSubFunctionException.class, () ->
|
|
pattern.replace(mathContext, subFunctions)
|
|
);
|
|
assertEquals("x", exception.getSubFunctionName());
|
|
}
|
|
|
|
@Test
|
|
void sumPattern() {
|
|
final Pattern pattern = new SumPattern(
|
|
new SubFunctionPattern("x"),
|
|
new SubFunctionPattern("y")
|
|
);
|
|
|
|
final Function shouldNotMatch = new Subtraction(
|
|
mathContext,
|
|
new Number(mathContext, 1),
|
|
new Number(mathContext, 2)
|
|
);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Function shouldMatch = new Sum(
|
|
mathContext,
|
|
new Number(mathContext, 1),
|
|
new Number(mathContext, 2)
|
|
);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
|
|
@Test
|
|
void repeatedSubFunction() {
|
|
final Pattern pattern = new SumPattern(
|
|
new SubFunctionPattern("x"),
|
|
new SubFunctionPattern("x")
|
|
);
|
|
|
|
final Function shouldMatch = new Sum(
|
|
mathContext,
|
|
new Number(mathContext, 1),
|
|
new Number(mathContext, 1)
|
|
);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
|
|
final Function shouldNotMatch = new Sum(
|
|
mathContext,
|
|
new Number(mathContext, 1),
|
|
new Number(mathContext, 2)
|
|
);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
}
|
|
|
|
@Test
|
|
void numberPattern() {
|
|
final Pattern pattern = new NumberPattern(BigDecimal.valueOf(Math.PI));
|
|
|
|
final Function shouldNotMatch = new Number(mathContext, 2);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Function shouldMatch = new Number(mathContext, Math.PI);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
|
|
@Test
|
|
void negativePattern() {
|
|
final Pattern pattern = new NegativePattern(
|
|
new SubFunctionPattern("x")
|
|
);
|
|
|
|
final Function shouldNotMatch = new Number(mathContext, 1);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Function shouldMatch = new Negative(
|
|
mathContext,
|
|
new Variable(mathContext, 'x', Variable.V_TYPE.VARIABLE)
|
|
);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
|
|
@Test
|
|
void negativePatternForNumber() {
|
|
final Pattern pattern = new NegativePattern(
|
|
new NumberPattern(new BigDecimal(1))
|
|
);
|
|
|
|
final Function shouldNotMatch = new Number(mathContext, 1);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Function shouldMatch = new Number(mathContext, -1);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
|
|
@Test
|
|
void undefinedPattern() {
|
|
final Pattern pattern = new UndefinedPattern();
|
|
|
|
final Function shouldNotMatch = new Number(mathContext, 0);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Function shouldMatch = new Undefined(mathContext);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertTrue(pattern.replace(mathContext, subFunctions.get()) instanceof Undefined);
|
|
}
|
|
|
|
@Test
|
|
void equationsSystemPattern() {
|
|
final Pattern pattern = new EquationsSystemPattern(new Pattern[]{
|
|
new SubFunctionPattern("x"),
|
|
new SubFunctionPattern("y"),
|
|
new SubFunctionPattern("z")
|
|
});
|
|
|
|
final Function shouldNotMatch = new EquationsSystem(
|
|
mathContext,
|
|
new Function[]{
|
|
new Number(mathContext, 1),
|
|
new Number(mathContext, 2),
|
|
}
|
|
);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Function shouldMatch = new EquationsSystem(
|
|
mathContext,
|
|
new Function[]{
|
|
new Number(mathContext, 1),
|
|
new Number(mathContext, 2),
|
|
new Number(mathContext, 3)
|
|
}
|
|
);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
|
|
@Test
|
|
void rootPatternForRootSquare() {
|
|
final Pattern pattern = new RootPattern(
|
|
new SubFunctionPattern("x"),
|
|
new SubFunctionPattern("y")
|
|
);
|
|
|
|
final Function root = new Root(
|
|
mathContext,
|
|
new Number(mathContext, 2),
|
|
new Number(mathContext, 1)
|
|
);
|
|
final Optional<Map<String, Function>> rootSubFunctions = pattern.match(root);
|
|
assertTrue(rootSubFunctions.isPresent());
|
|
|
|
final Function rootSquare = new RootSquare(
|
|
mathContext,
|
|
new Number(mathContext, 1)
|
|
);
|
|
final Optional<Map<String, Function>> rootSquareSubFunctions = pattern.match(rootSquare);
|
|
assertTrue(rootSquareSubFunctions.isPresent());
|
|
assertEquals(rootSubFunctions.get(), rootSquareSubFunctions.get());
|
|
|
|
final Function replacement = pattern.replace(mathContext, rootSubFunctions.get());
|
|
assertTrue(replacement instanceof RootSquare);
|
|
assertEquals(rootSquare, replacement);
|
|
}
|
|
|
|
@Test
|
|
void constantPattern() {
|
|
final Pattern pattern = new ConstantPattern(MathematicalSymbols.PI);
|
|
|
|
final Function shouldNotMatch = new Variable(
|
|
mathContext,
|
|
MathematicalSymbols.EULER_NUMBER,
|
|
Variable.V_TYPE.CONSTANT
|
|
);
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Function shouldMatch = new Variable(
|
|
mathContext,
|
|
MathematicalSymbols.PI,
|
|
Variable.V_TYPE.CONSTANT
|
|
);
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
|
|
@Test
|
|
void otherBinaryPatterns() {
|
|
final Number one = new Number(mathContext, 1);
|
|
final Number two = new Number(mathContext, 2);
|
|
final SubFunctionPattern x = new SubFunctionPattern("x");
|
|
final SubFunctionPattern y = new SubFunctionPattern("y");
|
|
|
|
final Function shouldNotMatch = new Sum(mathContext, one, two);
|
|
|
|
@SuppressWarnings("SuspiciousNameCombination")
|
|
final List<ImmutablePair<Pattern, Function>> patternsAndMatchingFunctions = Arrays.asList(
|
|
new ImmutablePair<>(
|
|
new DivisionPattern(x, y),
|
|
new Division(mathContext, one, two)
|
|
),
|
|
new ImmutablePair<>(
|
|
new EquationPattern(x, y),
|
|
new Equation(mathContext, one, two)
|
|
),
|
|
new ImmutablePair<>(
|
|
new LogarithmPattern(x, y),
|
|
new Logarithm(mathContext, one, two)
|
|
),
|
|
new ImmutablePair<>(
|
|
new MultiplicationPattern(x, y),
|
|
new Multiplication(mathContext, one, two)
|
|
),
|
|
new ImmutablePair<>(
|
|
new PowerPattern(x, y),
|
|
new Power(mathContext, one, two)
|
|
),
|
|
new ImmutablePair<>(
|
|
new RootPattern(x, y),
|
|
new Root(mathContext, one, two)
|
|
),
|
|
new ImmutablePair<>(
|
|
new SubtractionPattern(x, y),
|
|
new Subtraction(mathContext, one, two)
|
|
),
|
|
new ImmutablePair<>(
|
|
new SumSubtractionPattern(x, y),
|
|
new SumSubtraction(mathContext, one, two)
|
|
)
|
|
);
|
|
|
|
testMultiplePatterns(shouldNotMatch, patternsAndMatchingFunctions);
|
|
}
|
|
|
|
@Test
|
|
void otherUnaryPatterns() {
|
|
final Number one = new Number(mathContext, 1);
|
|
final SubFunctionPattern x = new SubFunctionPattern("x");
|
|
|
|
final Function shouldNotMatch = new Negative(mathContext, one);
|
|
|
|
final List<ImmutablePair<Pattern, Function>> patternsAndMatchingFunctions = Arrays.asList(
|
|
new ImmutablePair<>(
|
|
new ArcCosinePattern(x),
|
|
new ArcCosine(mathContext, one)
|
|
),
|
|
new ImmutablePair<>(
|
|
new ArcSinePattern(x),
|
|
new ArcSine(mathContext, one)
|
|
),
|
|
new ImmutablePair<>(
|
|
new ArcTangentPattern(x),
|
|
new ArcTangent(mathContext, one)
|
|
),
|
|
new ImmutablePair<>(
|
|
new CosinePattern(x),
|
|
new Cosine(mathContext, one)
|
|
),
|
|
new ImmutablePair<>(
|
|
new SinePattern(x),
|
|
new Sine(mathContext, one)
|
|
),
|
|
new ImmutablePair<>(
|
|
new TangentPattern(x),
|
|
new Tangent(mathContext, one)
|
|
)
|
|
);
|
|
|
|
testMultiplePatterns(shouldNotMatch, patternsAndMatchingFunctions);
|
|
}
|
|
|
|
private void testMultiplePatterns(
|
|
final Function shouldNotMatch,
|
|
final List<ImmutablePair<Pattern, Function>> patternsAndMatchingFunctions
|
|
) {
|
|
for (final ImmutablePair<Pattern, Function> patternAndMatchingFunction : patternsAndMatchingFunctions) {
|
|
final Pattern pattern = patternAndMatchingFunction.getLeft();
|
|
final Function shouldMatch = patternAndMatchingFunction.getRight();
|
|
|
|
assertFalse(pattern.match(shouldNotMatch).isPresent());
|
|
|
|
final Optional<Map<String, Function>> subFunctions = pattern.match(shouldMatch);
|
|
assertTrue(subFunctions.isPresent());
|
|
assertEquals(shouldMatch, pattern.replace(mathContext, subFunctions.get()));
|
|
}
|
|
}
|
|
} |