Вариант с рекурсией (все-таки отмеченное решение уже на 50 элементах заметно тормозит)
$array = array_fill(0, 50, 1);
$sum = 20;
function elements($array, $sum, &$result = [], $iteration = [])
{
// Если нужны все перестановки, то нужно закомментировать условие
if (!empty($result)) {
return;
}
if ($sum === 0) {
$result[] = $iteration;
return;
}
foreach ($array as $index => $value) {
if ($sum - $value < 0) {
continue;
}
$next = $array;
unset($next[$index]);
elements($next, $sum - $value, $result, array_merge($iteration, [$index]));
}
return;
}
elements($array, $sum, $result);
// Если вытащены все возможные перестановки, то разкомментировать
// Отсортируем, чтоб убрать повторяющиеся элементы
//foreach ($result as &$item) {
// sort($item);
//}
//unset($item);
//$result = array_unique($result, SORT_REGULAR);
foreach ($result as $item) {
echo 'Индексы элементов массива, составляющих сумму: ' . implode(' ', $item) . \PHP_EOL;
}