package pl.edu.pw.mini.sg.efgame.gen

import org.apache.commons.math3.random.{ MersenneTwister, RandomGenerator }
import org.scalacheck.{ Gen, Prop, Properties }
import Prop.BooleanOperators


object GeneratorProperties extends Properties("Ef generator properties") {
  val bf = Gen.chooseNum(2.0, 100.0)

  property("leafProbability should be 1 for n=1 for any branching factor>=2") =
    Prop.forAll(bf)(bf => Math.abs(Generator.leafProbability(1, bf) - 1.0) < 1e-6)


  property("leaf probability should fulfil recurrence equation") = Prop.forAll(Gen.chooseNum(2, 200), bf)(
    (n, bf) => Math.abs(Generator.leafProbability(n, bf) - ((1 - Generator.leafProbability(n, bf))*Generator.leafProbability(n-1, bf)*bf)) < 1e-6
  )

  property("isCount should be 1 for lambda 0 for any n and any seed") = 
    Prop.forAll(
      Gen.posNum[Int], Gen.choose[Int](0, Int.MaxValue)
    )((n, seed) => {
      implicit val rng : RandomGenerator = new MersenneTwister(seed)
      Generator.isCount(n, 0.0) == 1
    })

  property("isCount should be n for lambda 1 for any n and any seed") =
    Prop.forAll(
      Gen.posNum[Int], Gen.choose[Int](0, Int.MaxValue)
    )((n, seed) => {
      implicit val rng : RandomGenerator = new MersenneTwister(seed)
      Generator.isCount(n, 1.0) == n
    })

  property("theFun should be monotonic with y for 0 < x < 1") =
    Prop.forAll(Gen.choose(1e-6, 1-(1e-6)), Gen.choose(1e-6, 0.5), Gen.choose(1e-6, 0.5))((x,y1,y2) =>
      (y1 != y2) ==> {
        if(y1 < y2) Generator.theFun(x,y1) > Generator.theFun(x, y2)
        else Generator.theFun(x,y2) > Generator.theFun(x, y1)
      }
    )

    property("theFun should be monotonic with x for 0 < y < 1") =
    Prop.forAll(Gen.choose(1e-6, 1-(1e-6)), Gen.choose(1e-6, 1-(1e-6)), Gen.choose(1e-6, 0.5))((x1,x2,y) =>
      (x1 != x2) ==> (
        if(x1 < x2) Generator.theFun(x1,y) < Generator.theFun(x2, y)
        else Generator.theFun(x2,y) < Generator.theFun(x1, y))
    )

  property("theFun should return 1 for exery x for y = 0") = Prop.forAll(Gen.choose(1e-9, 1.0))(x =>
    Math.abs(Generator.theFun(x, 0.0)  -1) < 1e-6
  )


  property("theFun should be in range [0,1]") = Prop.forAll(Gen.choose(1e-6, 1-(1e-6)), Gen.choose(1e-6, 0.5))(
    (x, y) => {
      val v = Generator.theFun(x,y)
      v <= 1 && v >= 0
    }
  )

}
