Let's see what we actually need here. Let's assume, we have an array of chances:
$chances = [0.8, 0.3, 0.15];
What we need is to get those results with the following calculations:
// 0.119
$chance0 = (1-$array[0]) * (1-$array[1]) * (1-$array[2]);
// 0.548
$chance1 = $array[0] * (1-$array[1]) * (1-$array[2]) + (1-$array[0]) * $array[1] * (1-$array[2]) + (1-$array[0]) * (1-$array[1]) * $array[2];
// 0.297
$chance2 = $array[0] * $array[1] * (1-$array[2]) + $array[0] * (1-$array[1]) * $array[2] + (1-$array[0]) * $array[1] * $array[2];
// 0.036
$chance3 = $array[0] * $array[1] * $array[2];
What we actually need, is based on an integer that represents a number of successful chances, get every non-repeating combination from a pool of numbers, and make the rest "inversive", i.e. make them (1 - chance)
To achieve that, I used this answer and modified the code a bit. From the mentioned answer, we get non-repeating combinations of chances (meaning, that in case we get 2 successful chances, 0.8
and 0.15
are same as 0.15
and 0.8
). Next, we use an array_diff
to see what is left and assume those are failing chances. But since those are failing chances, we need to "reverse" them, calling array_map
with the respective callback. The last thing is to calculate array_product
to get the chance of the event happening.
And finally we just array_sum
all the chances.
class Combinations implements Iterator
{
protected $c = null;
protected $s = null;
protected $n = 0;
protected $k = 0;
protected $pos = 0;
function __construct($s, $k) {
if(is_array($s)) {
$this->s = array_values($s);
$this->n = count($this->s);
} else {
$this->s = (string) $s;
$this->n = strlen($this->s);
}
$this->k = $k;
$this->rewind();
}
function key() {
return $this->pos;
}
function current() {
$r = array();
for($i = 0; $i < $this->k; $i++)
$r[] = $this->s[$this->c[$i]];
return is_array($this->s) ? $r : implode('', $r);
}
function next() {
if($this->_next())
$this->pos++;
else
$this->pos = -1;
}
function rewind() {
$this->c = range(0, $this->k);
$this->pos = 0;
}
function valid() {
return $this->pos >= 0;
}
protected function _next() {
$i = $this->k - 1;
while ($i >= 0 && $this->c[$i] == $this->n - $this->k + $i)
$i--;
if($i < 0)
return false;
$this->c[$i]++;
while($i++ < $this->k - 1)
$this->c[$i] = $this->c[$i - 1] + 1;
return true;
}
}
function getTotalChances($calculateFrom, $successCount)
{
$totalChance = [];
foreach(new Combinations($calculateFrom, $successCount) as $success)
{
$failure = array_map(function($element) {
return (1-$element);
}, array_diff($calculateFrom, $success));
$chance = array_product(array_merge($success, $failure));
$totalChance[] = $chance;
}
return(array_sum($totalChance));
}
$calculateFrom = [0.8, 0.3, 0.15];
var_dump(getTotalChances($calculateFrom, 2));
Now if you run the following, you will get what you need:
var_dump(getTotalChances($calculateFrom, 0)); // 0.119
var_dump(getTotalChances($calculateFrom, 1)); // 0.548
var_dump(getTotalChances($calculateFrom, 2)); // 0.297
var_dump(getTotalChances($calculateFrom, 3)); // 0.036