package com.github.liblevenshtein.transducer;
import java.util.Arrays;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.github.liblevenshtein.transducer.factory.PositionFactory;
import com.github.liblevenshtein.transducer.factory.PositionTransitionFactory;
import com.github.liblevenshtein.transducer.factory.StateFactory;
import static com.github.liblevenshtein.assertion.StateTransitionFunctionAssertions.assertThat;
/**
* These tests were taken from the transition tables on page 29 of "Fast String
* Correction with Levenshtein Automata".
*/
public class StateTransitionFunctionTest {
private static final int N = 1;
private static final int W = 5;
private final PositionFactory positionFactory = new PositionFactory();
private final StateFactory stateFactory = new StateFactory();
private final PositionTransitionFactory transitionFactory =
new PositionTransitionFactory.ForStandardPositions();
private final MergeFunction merge = new MergeFunction.ForStandardPositions();
private final UnsubsumeFunction unsubsume = new UnsubsumeFunction.ForStandardPositions();
private final SubsumesFunction subsumes = new SubsumesFunction.ForStandardAlgorithm();
private final StateTransitionFunction transition = new StateTransitionFunction();
@BeforeTest
public void setUp() {
transitionFactory.stateFactory(stateFactory);
transitionFactory.positionFactory(positionFactory);
unsubsume.subsumes(subsumes);
transition.comparator((a, b) -> {
final int i = a.numErrors() - b.numErrors();
if (0 != i) {
return i;
}
return a.termIndex() - b.termIndex();
});
transition.stateFactory(stateFactory);
transition.transitionFactory(transitionFactory);
transition.merge(merge);
transition.unsubsume(unsubsume);
transition.maxDistance(N);
}
@DataProvider(name = "is")
public Object[][] is() {
final Object[][] is = new Object[1 + W - 3][1];
for (int i = 0; i <= W - 3; ++i) {
is[i] = new Object[] {i};
}
return is;
}
@Test(dataProvider = "is")
public void testOfAgainstPrefixes(final int i) {
final boolean[] characteristicVector = new boolean[W];
Arrays.fill(characteristicVector, false);
characteristicVector[0] = false;
characteristicVector[1] = false;
characteristicVector[2] = false;
validate(a(i), c(i), characteristicVector);
validate(b(i), null, characteristicVector);
validate(c(i), null, characteristicVector);
validate(d(i), null, characteristicVector);
validate(e(i), null, characteristicVector);
characteristicVector[0] = true;
characteristicVector[1] = false;
characteristicVector[2] = false;
validate(a(i), a(1 + i), characteristicVector);
validate(b(i), b(1 + i), characteristicVector);
validate(c(i), b(1 + i), characteristicVector);
validate(d(i), b(1 + i), characteristicVector);
validate(e(i), b(1 + i), characteristicVector);
characteristicVector[0] = false;
characteristicVector[1] = true;
characteristicVector[2] = false;
validate(a(i), e(i), characteristicVector);
validate(b(i), null, characteristicVector);
validate(c(i), b(2 + i), characteristicVector);
validate(d(i), null, characteristicVector);
validate(e(i), b(2 + i), characteristicVector);
characteristicVector[0] = false;
characteristicVector[1] = false;
characteristicVector[2] = true;
validate(a(i), c(i), characteristicVector);
validate(b(i), null, characteristicVector);
validate(c(i), null, characteristicVector);
validate(d(i), b(3 + i), characteristicVector);
validate(e(i), b(3 + i), characteristicVector);
characteristicVector[0] = true;
characteristicVector[1] = true;
characteristicVector[2] = false;
validate(a(i), a(1 + i), characteristicVector);
validate(b(i), b(1 + i), characteristicVector);
validate(c(i), c(1 + i), characteristicVector);
validate(d(i), b(1 + i), characteristicVector);
validate(e(i), c(1 + i), characteristicVector);
characteristicVector[0] = true;
characteristicVector[1] = false;
characteristicVector[2] = true;
validate(a(i), a(1 + i), characteristicVector);
validate(b(i), b(1 + i), characteristicVector);
validate(c(i), b(1 + i), characteristicVector);
validate(d(i), d(1 + i), characteristicVector);
validate(e(i), d(1 + i), characteristicVector);
characteristicVector[0] = false;
characteristicVector[1] = true;
characteristicVector[2] = true;
validate(a(i), e(i), characteristicVector);
validate(b(i), null, characteristicVector);
validate(c(i), b(2 + i), characteristicVector);
validate(d(i), b(3 + i), characteristicVector);
validate(e(i), c(2 + i), characteristicVector);
characteristicVector[0] = true;
characteristicVector[1] = true;
characteristicVector[2] = true;
validate(a(i), a(1 + i), characteristicVector);
validate(b(i), b(1 + i), characteristicVector);
validate(c(i), c(1 + i), characteristicVector);
validate(d(i), d(1 + i), characteristicVector);
validate(e(i), e(1 + i), characteristicVector);
}
@Test
public void testOfAgainstSuffixes() {
final boolean[] characteristicVector = new boolean[W];
int i;
i = W - 2;
Arrays.fill(characteristicVector, false);
characteristicVector[0] = false;
characteristicVector[1] = false;
validate(a(i), c(i), characteristicVector);
validate(b(i), null, characteristicVector);
validate(c(i), null, characteristicVector);
validate(d(i), null, characteristicVector);
validate(e(i), null, characteristicVector);
characteristicVector[0] = true;
characteristicVector[1] = false;
validate(a(i), a(1 + i), characteristicVector);
validate(b(i), b(1 + i), characteristicVector);
validate(c(i), b(1 + i), characteristicVector);
validate(d(i), b(1 + i), characteristicVector);
validate(e(i), b(1 + i), characteristicVector);
characteristicVector[0] = false;
characteristicVector[1] = true;
validate(a(i), e(i), characteristicVector);
validate(b(i), null, characteristicVector);
validate(c(i), b(2 + i), characteristicVector);
validate(d(i), null, characteristicVector);
validate(e(i), b(2 + i), characteristicVector);
characteristicVector[0] = true;
characteristicVector[1] = true;
validate(a(i), a(1 + i), characteristicVector);
validate(b(i), b(1 + i), characteristicVector);
validate(c(i), c(1 + i), characteristicVector);
validate(d(i), b(1 + i), characteristicVector);
validate(e(i), c(1 + i), characteristicVector);
i = W - 1;
Arrays.fill(characteristicVector, false);
characteristicVector[0] = false;
validate(a(i), c(i), characteristicVector);
validate(b(i), null, characteristicVector);
validate(c(i), null, characteristicVector);
characteristicVector[0] = true;
validate(a(i), a(1 + i), characteristicVector);
validate(b(i), b(1 + i), characteristicVector);
validate(c(i), b(1 + i), characteristicVector);
i = W;
Arrays.fill(characteristicVector, false);
// [NOTE] :: In the paper, for the case when i = W, A(i) maps to B(i), but
// that isn't what I get with the transitions.
//
// [TODO] :: Verify that the mapping should indeed be A(i) to C(i), or
// figure out what I'm doing wrong ...
//
//validate(A(i), B(i), characteristicVector);
validate(a(i), c(i), characteristicVector);
validate(b(i), null, characteristicVector);
}
private void validate(
final State input,
final State expectedOutput,
final boolean... characteristicVector) {
assertThat(transition).transitionsTo(expectedOutput, input, characteristicVector);
}
private State a(final int i) {
if (0 <= i && i <= W) {
return stateFactory.build(
positionFactory.build(i, 0));
}
return null;
}
private State b(final int i) {
if (0 <= i && i <= W) {
return stateFactory.build(
positionFactory.build(i, 1));
}
return null;
}
private State c(final int i) {
// [NOTE] :: In the paper, this should not be defined when i = W, but from
// my experiments it seems to be the appropriate image of A(i) when i = W.
//
// [TODO] :: Verify whether this is the correct image of A(i) when i = W, or
// determine what I am doing wrong ...
//
//if (0 <= i && i <= W - 1) {
// return stateFactory.build(
// positionFactory.build(i, 1),
// positionFactory.build(1 + i, 1));
//}
return stateFactory.build(
positionFactory.build(i, 1),
positionFactory.build(1 + i, 1));
//return null;
}
private State d(final int i) {
if (0 <= i && i <= W - 2) {
return stateFactory.build(
positionFactory.build(i, 1),
positionFactory.build(2 + i, 1));
}
return null;
}
private State e(final int i) {
if (0 <= i && i <= W - 2) {
return stateFactory.build(
positionFactory.build(i, 1),
positionFactory.build(1 + i, 1),
positionFactory.build(2 + i, 1));
}
return null;
}
}