From 9bff2987772443f0d5e450b2978fe8c93a0209a3 Mon Sep 17 00:00:00 2001
From: Regis Blanc <regwblanc@gmail.com>
Date: Wed, 8 Jul 2015 14:36:31 +0200
Subject: [PATCH] indepence of coins

---
 testcases/proof/proba/Coins.scala | 57 +++++++++++++++++++++++++++----
 1 file changed, 50 insertions(+), 7 deletions(-)

diff --git a/testcases/proof/proba/Coins.scala b/testcases/proof/proba/Coins.scala
index bc18f650e..a24211154 100644
--- a/testcases/proof/proba/Coins.scala
+++ b/testcases/proof/proba/Coins.scala
@@ -8,6 +8,7 @@ object Coins {
    */
   case class CoinDist(pHead: BigInt, pTail: BigInt)
 
+  case class CoinsJoinDist(hh: BigInt, ht: BigInt, th: BigInt, tt: BigInt)
 
   def isUniform(dist: CoinDist): Boolean = {
     require(isDist(dist))
@@ -17,6 +18,26 @@ object Coins {
   def isDist(dist: CoinDist): Boolean = 
     dist.pHead >= 0 && dist.pTail >= 0 && (dist.pHead > 0 || dist.pTail > 0)
 
+  def isDist(dist: CoinsJoinDist): Boolean =
+    dist.hh >= 0 && dist.ht >= 0 && dist.th >= 0 && dist.tt >= 0 &&
+    (dist.hh > 0 || dist.ht > 0 || dist.th > 0 || dist.tt > 0)
+
+  def join(c1: CoinDist, c2: CoinDist): CoinsJoinDist =
+    CoinsJoinDist(
+      c1.pHead*c2.pHead,
+      c1.pHead*c2.pTail,
+      c1.pTail*c2.pHead,
+      c1.pTail*c2.pTail)
+
+  def firstCoin(dist: CoinsJoinDist): CoinDist =
+    CoinDist(dist.hh + dist.ht, dist.th + dist.tt)
+
+  def secondCoin(dist: CoinsJoinDist): CoinDist =
+    CoinDist(dist.hh + dist.th, dist.ht + dist.tt)
+
+  def isIndependent(dist: CoinsJoinDist): Boolean =
+    join(firstCoin(dist), secondCoin(dist)) == dist
+
   //sum modulo: face is 0, tail is 1
   def sum(coin1: CoinDist, coin2: CoinDist): CoinDist = {
     require(isDist(coin1) && isDist(coin2))
@@ -26,6 +47,14 @@ object Coins {
     )
   }
 
+  def sum(dist: CoinsJoinDist): CoinDist = {
+    require(isDist(dist))
+    CoinDist(
+      dist.hh + dist.tt,
+      dist.ht + dist.th
+    )
+  }
+
   def sumIsUniform1(coin1: CoinDist, coin2: CoinDist): Boolean = {
     require(isDist(coin1) && isDist(coin2) && isUniform(coin1) && isUniform(coin2))
     val dist = sum(coin1, coin2)
@@ -38,6 +67,26 @@ object Coins {
     isUniform(dist)
   } holds
 
+  def sumUniform3(coin1: CoinDist, coin2: CoinDist, coin3: CoinDist): Boolean = {
+    require(isDist(coin1) && isDist(coin2) && isDist(coin3) && isUniform(coin1))
+    val dist = sum(sum(coin1, coin2), coin3)
+    isUniform(dist)
+  } holds
+
+  def sumUniformWithIndependence(dist: CoinsJoinDist): Boolean = {
+    require(isDist(dist) && isIndependent(dist) && (isUniform(firstCoin(dist)) || isUniform(secondCoin(dist))))
+    val res = sum(dist)
+    isUniform(res)
+  } holds
+
+  //should find counterexample, indepenence is required
+  def sumUniformWithoutIndependence(dist: CoinsJoinDist): Boolean = {
+    require(isDist(dist) && (isUniform(firstCoin(dist)) || isUniform(secondCoin(dist))))
+    val res = sum(dist)
+    isUniform(res)
+  } holds
+
+
   //sum of two non-uniform dices is potentially uniform (no result)
   def sumNonUniform1(coin1: CoinDist, coin2: CoinDist): Boolean = {
     require(isDist(coin1) && isDist(coin2) && !isUniform(coin1) && !isUniform(coin2))
@@ -52,12 +101,6 @@ object Coins {
   } //holds
 
 
-  def sumUniform3(coin1: CoinDist, coin2: CoinDist, coin3: CoinDist): Boolean = {
-    require(isDist(coin1) && isDist(coin2) && isDist(coin3) && isUniform(coin1))
-    val dist = sum(sum(coin1, coin2), coin3)
-    isUniform(dist)
-  } holds
-
   def sumIsCommutative(coin1: CoinDist, coin2: CoinDist, coin3: CoinDist): Boolean = {
     require(isDist(coin1) && isDist(coin2))
     sum(coin1, coin2) == sum(coin2, coin1)
@@ -66,6 +109,6 @@ object Coins {
   def sumIsAssociative(coin1: CoinDist, coin2: CoinDist, coin3: CoinDist): Boolean = {
     require(isDist(coin1) && isDist(coin2) && isDist(coin3))
     sum(sum(coin1, coin2), coin3) == sum(coin1, sum(coin2, coin3))
-  } holds
+  } //holds
 
 }
-- 
GitLab