peopleprobs/probppl.go

143 lines
3.1 KiB
Go
Raw Normal View History

2024-02-25 13:35:47 +00:00
package main
import "fmt"
2024-02-25 20:31:22 +00:00
import "git.nunosempere.com/NunoSempere/probppl/choose"
2024-02-25 13:35:47 +00:00
import "math"
import rand "math/rand/v2"
type src = *rand.Rand
2024-02-25 20:31:22 +00:00
type pplKnownDistrib = map[int64]float64
2024-02-25 20:31:22 +00:00
func generatePeopleKnownDistribution(r src) map[int64]float64 {
mapping := make(map[int64]float64)
2024-02-25 19:32:12 +00:00
sum := 0.0
// Consider zero case separately
p0 := r.Float64()
mapping[0.0] = p0
sum += p0
// Consider successive exponents of 1.5
l := 1.0
m := 1.5
2024-02-25 20:47:45 +00:00
for i := 1; i < 20; i++ {
2024-02-25 19:32:12 +00:00
l = l * m
p := r.Float64()
2024-02-25 20:31:22 +00:00
mapping[int64(l)] = p
2024-02-25 19:32:12 +00:00
sum += p
}
for key, value := range mapping {
mapping[key] = value / sum
}
2024-02-25 19:32:12 +00:00
return mapping
}
2024-02-25 20:31:22 +00:00
func chooseWrapper(n int64, k int64) int64 {
if n < k {
return 0
} else {
return choose.Choose(n, k)
}
}
func getProbabilityOfKBirthdayMatchesGivenNPeopleKnown(n int64, k int64) float64 {
return float64(chooseWrapper(n, k)) * math.Pow(1.0/365.0, float64(k)) * math.Pow(1.0-(1.0/365.0), float64(n-k))
}
func getMatchesDrawGivenNPeopleKnown(n int64, r src) int64 {
p0 := getProbabilityOfKBirthdayMatchesGivenNPeopleKnown(n, 0)
p1 := getProbabilityOfKBirthdayMatchesGivenNPeopleKnown(n, 1)
p2 := getProbabilityOfKBirthdayMatchesGivenNPeopleKnown(n, 2)
p := r.Float64()
if p < p0 {
return 0
} else if p < (p0 + p1) {
return 1
} else if p < (p0 + p1 + p2) {
return 2
} else {
return 3 // stands for 'greater than 3'
}
}
/*
Draw 148 times
How many people do you know that were born in the same day of the year as you?
0: 46.6% | 69
1: 31.1% | 46
2: 12.8% | 19
3: 9.5% | 14
*/
func drawFromDistributionWithReplacement(d pplKnownDistrib, r src) int64 {
pp := r.Float64()
sum := 0.0
for i, p := range d {
sum += p
if p <= sum {
return int64(i)
}
}
fmt.Printf("%f, %f\n", sum, pp)
fmt.Println(d)
panic("Probabilities should sum up to 1")
}
2024-02-25 20:47:45 +00:00
func aboutEq(a int64, b int64) bool {
h := int64(3)
return ((-h) <= (a - b)) && ((a - b) <= h)
}
2024-02-25 20:31:22 +00:00
func draw148PplFromDistributionAndCheck(d pplKnownDistrib, r src) int64 {
count := make(map[int64]int64)
count[0] = 0
count[1] = 0
count[2] = 0
count[3] = 0
for i := 0; i < 148; i++ {
person_i_ppl_known := drawFromDistributionWithReplacement(d, r)
person_i_num_birthday_matches := getMatchesDrawGivenNPeopleKnown(person_i_ppl_known, r)
count[person_i_num_birthday_matches]++
}
2024-02-25 20:47:45 +00:00
// if (count[0] == 69) && (count[1] == 46) && (count[2] == 19) && (count[3] == 14) {
fmt.Println(count)
if aboutEq(count[0], 69) && aboutEq(count[1], 46) && aboutEq(count[2], 19) && aboutEq(count[3], 14) {
2024-02-25 20:31:22 +00:00
return 1
} else {
return 0
}
}
2024-02-25 20:47:45 +00:00
func getUnnormalizedBayesianUpdateForDistribution(d pplKnownDistrib, r src) int64 {
2024-02-25 20:31:22 +00:00
var sum int64 = 0
2024-02-25 20:47:45 +00:00
n := 1
2024-02-25 20:31:22 +00:00
for i := 0; i < n; i++ {
2024-02-25 20:47:45 +00:00
/* if i%1000 == 0 {
2024-02-25 20:33:05 +00:00
fmt.Println(i)
2024-02-25 20:47:45 +00:00
} */
draw_result := draw148PplFromDistributionAndCheck(d, r)
// fmt.Println(draw_result)
sum += draw_result
2024-02-25 20:31:22 +00:00
}
2024-02-25 20:47:45 +00:00
return sum // float64(sum) / float64(n)
2024-02-25 20:31:22 +00:00
}
2024-02-25 13:35:47 +00:00
func main() {
var r = rand.New(rand.NewPCG(uint64(1), uint64(2)))
2024-02-25 20:47:45 +00:00
for i := 0; i < 100; i++ {
people_known_distribution := generatePeopleKnownDistribution(r)
// fmt.Println(people_known_distribution)
result := getUnnormalizedBayesianUpdateForDistribution(people_known_distribution, r)
fmt.Println(result)
}
2024-02-25 13:35:47 +00:00
}