(self)
| 3111 | for e, a in zip(expected, actual))) |
| 3112 | |
| 3113 | def test_overlap(self): |
| 3114 | NormalDist = self.module.NormalDist |
| 3115 | |
| 3116 | # Match examples from Imman and Bradley |
| 3117 | for X1, X2, published_result in [ |
| 3118 | (NormalDist(0.0, 2.0), NormalDist(1.0, 2.0), 0.80258), |
| 3119 | (NormalDist(0.0, 1.0), NormalDist(1.0, 2.0), 0.60993), |
| 3120 | ]: |
| 3121 | self.assertAlmostEqual(X1.overlap(X2), published_result, places=4) |
| 3122 | self.assertAlmostEqual(X2.overlap(X1), published_result, places=4) |
| 3123 | |
| 3124 | # Check against integration of the PDF |
| 3125 | def overlap_numeric(X, Y, *, steps=8_192, z=5): |
| 3126 | 'Numerical integration cross-check for overlap() ' |
| 3127 | fsum = math.fsum |
| 3128 | center = (X.mean + Y.mean) / 2.0 |
| 3129 | width = z * max(X.stdev, Y.stdev) |
| 3130 | start = center - width |
| 3131 | dx = 2.0 * width / steps |
| 3132 | x_arr = [start + i*dx for i in range(steps)] |
| 3133 | xp = list(map(X.pdf, x_arr)) |
| 3134 | yp = list(map(Y.pdf, x_arr)) |
| 3135 | total = max(fsum(xp), fsum(yp)) |
| 3136 | return fsum(map(min, xp, yp)) / total |
| 3137 | |
| 3138 | for X1, X2 in [ |
| 3139 | # Examples from Imman and Bradley |
| 3140 | (NormalDist(0.0, 2.0), NormalDist(1.0, 2.0)), |
| 3141 | (NormalDist(0.0, 1.0), NormalDist(1.0, 2.0)), |
| 3142 | # Example from https://www.rasch.org/rmt/rmt101r.htm |
| 3143 | (NormalDist(0.0, 1.0), NormalDist(1.0, 2.0)), |
| 3144 | # Gender heights from http://www.usablestats.com/lessons/normal |
| 3145 | (NormalDist(70, 4), NormalDist(65, 3.5)), |
| 3146 | # Misc cases with equal standard deviations |
| 3147 | (NormalDist(100, 15), NormalDist(110, 15)), |
| 3148 | (NormalDist(-100, 15), NormalDist(110, 15)), |
| 3149 | (NormalDist(-100, 15), NormalDist(-110, 15)), |
| 3150 | # Misc cases with unequal standard deviations |
| 3151 | (NormalDist(100, 12), NormalDist(100, 15)), |
| 3152 | (NormalDist(100, 12), NormalDist(110, 15)), |
| 3153 | (NormalDist(100, 12), NormalDist(150, 15)), |
| 3154 | (NormalDist(100, 12), NormalDist(150, 35)), |
| 3155 | # Misc cases with small values |
| 3156 | (NormalDist(1.000, 0.002), NormalDist(1.001, 0.003)), |
| 3157 | (NormalDist(1.000, 0.002), NormalDist(1.006, 0.0003)), |
| 3158 | (NormalDist(1.000, 0.002), NormalDist(1.001, 0.099)), |
| 3159 | ]: |
| 3160 | self.assertAlmostEqual(X1.overlap(X2), overlap_numeric(X1, X2), places=5) |
| 3161 | self.assertAlmostEqual(X2.overlap(X1), overlap_numeric(X1, X2), places=5) |
| 3162 | |
| 3163 | # Error cases |
| 3164 | X = NormalDist() |
| 3165 | with self.assertRaises(TypeError): |
| 3166 | X.overlap() # too few arguments |
| 3167 | with self.assertRaises(TypeError): |
| 3168 | X.overlap(X, X) # too may arguments |
| 3169 | with self.assertRaises(TypeError): |
| 3170 | X.overlap(None) # right operand not a NormalDist |
nothing calls this directly
no test coverage detected