package fj.data;
import fj.*;
import fj.test.Arbitrary;
import fj.test.Cogen;
import fj.test.Gen;
import fj.test.Property;
import org.junit.Assert;
import org.junit.Test;
import static fj.data.Option.some;
import static fj.data.Stream.unfold;
import static fj.data.test.PropertyAssert.assertResult;
import static fj.test.Arbitrary.*;
import static fj.test.Cogen.cogenInteger;
import static fj.test.Property.prop;
import static fj.test.Property.property;
import static fj.test.Variant.variant;
/**
* Created by mperry on 4/08/2014.
*/
public class TestRngState {
static List<Integer> expected1 = List.list(4,4,2,2,2,5,3,3,1,5);
static int size = 10;
static final Equal<List<Integer>> listIntEqual = Equal.listEqual(Equal.intEqual);
static Rng defaultRng() {
return new LcgRng(1);
}
static P2<Rng, Integer> num(Rng r) {
return r.range(1, 5);
}
static State<Rng, Integer> defaultState() {
return State.unit(s -> num(s));
}
static F<State<Rng, Integer>, State<Rng, Integer>> nextState() {
return s -> s.mapState(p2 -> num(p2._1()));
}
static P2<Rng, Integer> num(Rng r, int x) {
return r.range(x, x + 1);
}
@Test
public void testUnfold() {
Stream<Integer> s = unfold(r -> some(num(r).swap()), defaultRng());
Assert.assertTrue(listIntEqual.eq(s.take(size).toList(), expected1));
}
@Test
public void testTransitions() {
P2<List<State<Rng, Integer>>, State<Rng, Integer>> p = List.replicate(size, nextState()).foldLeft(
(P2<List<State<Rng, Integer>>, State<Rng, Integer>> p2, F<State<Rng, Integer>, State<Rng, Integer>> f) -> {
State<Rng, Integer> s = f.f(p2._2());
return P.p(p2._1().snoc(p2._2()), s);
}
, P.p(List.nil(), defaultState())
);
List<Integer> ints = p._1().map(s -> s.eval(defaultRng()));
Assert.assertTrue(listIntEqual.eq(ints, expected1));
}
@Test
public void testSequence() {
List<Integer> list = State.sequence(List.replicate(size, defaultState())).eval(defaultRng());
Assert.assertTrue(listIntEqual.eq(list, expected1));
}
@Test
public void testTraverse() {
List<Integer> list = State.traverse(List.range(1, 10), a -> (State.unit((Rng s) -> num(s, a)))).eval(defaultRng());
// System.out.println(list.toString());
List<Integer> expected = List.list(1,2,3,5,6,7,7,9,10);
Assert.assertTrue(listIntEqual.eq(list, expected));
}
public static Gen<State<LcgRng, Integer>> arbState() {
return Arbitrary.arbState(Arbitrary.arbLcgRng(), Cogen.cogenLcgRng(), arbInteger);
}
public static Gen<F<LcgRng, P2<LcgRng, Integer>>> arbStateF() {
return arbF(Cogen.cogenLcgRng(), arbP2(arbLcgRng(), arbInteger));
}
public static Cogen<State<LcgRng, Integer>> cogenState() {
return Cogen.cogenState(Arbitrary.arbLcgRng(), (LcgRng s, Integer j) -> (long) (j >= 0 ? 2 * j : -2 * j + 1));
}
public static Gen<F<Integer, State<LcgRng, Integer>>> arbBindable() {
return arbF(cogenInteger, arbState());
}
// Left identity: return i >>= f == f i
@Test
public void testLeftIdentity() {
Property p = property(
arbBindable(),
arbInteger,
arbLcgRng(),
(f, i, r) -> {
int a = State.<LcgRng, Integer>constant(i).flatMap(f).eval(r);
int b = f.f(i).eval(r);
// System.out.println(String.format("a=%d, b=%d", a, b));
return prop(a == b);
}
);
assertResult(p);
}
// Right identity: m >>= return == m
@Test
public void testRightIdentity() {
Property p = Property.property(
arbState(),
arbLcgRng(),
(s, r) -> {
int x = s.flatMap(a -> State.constant(a)).eval(r);
int y = s.eval(r);
// System.out.println(String.format("x=%d, y=%d", x, y));
return prop(x == y);
}
);
assertResult(p);
}
// Associativity: (m >>= f) >>= g == m >>= (\x -> f x >>= g)
@Test
public void testAssociativity() {
Property p = Property.property(
arbState(),
arbBindable(),
arbBindable(),
arbLcgRng(),
(s, f, g, r) -> {
int t = s.flatMap(f).flatMap(g).eval(r);
int u = s.flatMap(x -> f.f(x).flatMap(g)).eval(r);
// System.out.println(String.format("x=%d, y=%d", t, u));
return prop(t == u);
});
assertResult(p);
}
}