Generating Probabilities for PC-PRB-302

First, we had a few conditions. The first being that all probabilities had to be simplified fractions with denominator less than some number, in my particular generator, it was $10$.

Second, any product of two probabilities had to also have a simplified denominator less than $10$.

Lastly, sometimes, we had to have two pairs of probabilities, both with one common term, (eg, two tuples like $(a, b)$ and $(b, c)$) such that both the simplified fractions of $ab$ and $bc$ had to have the same denominator.

To start things off, I made a few types.

type Fraction = (Integer, Integer)
type Probability = (Fraction, Fraction)
type Pair = (Probability, Probability)

I started off looking for all the simplified fractions that would be used.

allFractions :: [Fraction]
allFractions = liftM2 (,) [1..9] [2..9]

simplifiedFractions :: [Fraction]
simplifiedFractions = filter simplifiedLessThanOne allFractions
where
simplifiedLessThanOne (a,b) = a<b && gcd a b == 1

Then found all the pairs such that their products also had denominators smaller than $10$. But the code for this was a little fun.

allProbabilities :: [Probability]
allProbabilities = (\x -> liftM2 (,) x x) simplifiedFractions

goodProbabilities :: [Probability]
goodProbabilities = ourRulesFrom allProbabilities
where
productLessThanOne ((a,b),(c,d)) = a*c < b*d
--productDenomLessThanTen ((a,b),(c,d)) = b*d < 10*(gcd (a*c) (b*d))
ourRulesFrom = filter productLessThanOne

I would be done here, except sometimes I wanted two pairs of fractions with a common term and the products of both pairs to have a common denominator, or at least one is a multiple of the other.

allPairs :: [Pair]
allPairs = liftM2 (,) goodProbabilities goodProbabilities

pairsWithCommonTerm :: [Pair] -> [Pair]
pairsWithCommonTerm = filter onlyOneCommon
where
bothSame ((a,b),(c,d)) = (a == c && b == d) || (a == d && b == c)
bothDiff ((a,b),(c,d)) = (a /= c && b /= d) || (a /= d && b /= c)
onlyOneCommon x = not $bothSame x || bothDiff x pairsWithSameDenom :: [Pair] -> [Pair] pairsWithSameDenom = filter pairHasSameDenom where pairHasSameDenom (x,y) = a mod b == 0 where a = max x' y' b = min x' y' x' = timesDenom x y' = timesDenom y timesDenom = snd . times times = simplify . times' times' ((a,b),(c,d)) = (a*c, b*d) simplify (a,b) = (a div d, b div d) where d = gcd a b goodPairs :: [Pair] goodPairs = pairsWithCommonTerm . pairsWithSameDenom$ allPairs

Then just to finish testing I had this.

pick :: IO Pair
pick = runRVar (choice goodPairs) StdRandom

The output of pick is ultimately what I wanted to use in the generator.

But to have a little look further, I made another filter.

pairsTheSame :: Pair -> Pair -> Bool
pairsTheSame = same pSame
where
fSame :: Fraction -> Fraction -> Bool
fSame (a,b) (c,d) = a == c && b == d
same s (a,b) (c,d) = (s a c && s b d) || (s a d && s b c)
pSame :: Probability -> Probability -> Bool
pSame = same fSame

uniquePairs = nubBy pairsTheSame goodPairs

Fun. Now to do this all in java. :(