Массив#ошибка ассортимента товаров: слишком велик для продукта

#ruby-on-rails #ruby #algorithm

Вопрос:

У меня 93 массива. Каждый массив имеет в среднем около 18 значений, которые мне нужны, чтобы создать произведение этих массивов.

Итак, у меня есть мой массив двух измерений, в котором хранятся эти 93 массива.

Вот что я пытаюсь сделать

 DATASET.first.product(*DATASET[1..-1])  

Руби возвращается

 RangeError: too big to product  

Кто-нибудь знает какой-нибудь обходной путь, чтобы разобраться в этом? Какие-то способы их разделить?

Комментарии:

1. Хорошо, значит, такой продукт будет состоять из 18^93 подмассивов. Это огромная сумма! Зачем вам понадобилось такое чудовище?

2. Зачем вам нужен такой массив данных для тестирования свойств? 00

3. Для меня это звучит как проблема xy. Почему ты хочешь это сделать? Чего вы пытаетесь достичь с помощью сгенерированного массива?

4. @Max: Ой, я только что сделал это сам. Если бы вы преобразовали каждую частицу во Вселенной в хранилище, то объем данных, которые вам пришлось бы хранить в каждой частице , составлял бы 20 порядков величины всей информации, когда-либо созданной людьми. Таким образом, на самом деле это на 100 порядков больше.

5. Мне нравится, что Ruby выдает эту ошибку заранее, а не просто исчерпывает память.

Ответ №1:

То, чего ты хочешь, невозможно.

Произведение 93 массивов с ~18 элементами каждый представляет собой массив примерно с 549975033204266172374216967425209467080301768557741749051999338598022831065169332830885722071173603516904554174087168 элементами, каждый из которых представляет собой массив из 93 элементов.

Это означает, что вам нужно 549975033204266172374216967425209467080301768557741749051999338598022831065169332830885722071173603516904554174087168 * 93 * 64 бит памяти для его хранения, что примерно 409181424703974032246417423764355843507744515806959861294687507916928986312485983626178977220953161016576988305520852992 байт. Это примерно на 40 порядков больше, чем количество частиц во Вселенной. Другими словами, даже если бы вы преобразовали всю вселенную в оперативную память, вам все равно нужно было бы найти способ хранения порядка 827180612553027йобибайт на каждую частицу во Вселенной; это примерно в 600000000000000000000000000 раз превышает информационное содержание Всемирной паутины и в 10000000000000000000000 раз превышает информационное содержание темной паутины.

Кто-нибудь знает какой-нибудь обходной путь, чтобы разобраться в этом? Какие-то способы их разделить?

Даже если вы обрабатываете их по частям, это не меняет того факта, что вам все равно нужно обработать 51147678087996754030802177970544480438468064475869982661835938489616123289060747953272372152619145127072123538190106624 элементов. Даже если вы были в состоянии обработать один элемент на каждый процессор команд (что нереально, вы, вероятно, нужны десятки, если не сотни, инструкций), и даже если каждая команда занимает один такт (что нереально, в настоящее время основной ЦП, каждая инструкция занимает несколько тактов), и даже если у вас терагерцового процессора (что нереально, самый быстрый современные ЦП высотой 5 ГГц), и даже если ваш процессор был миллион ядер (что нереально, даже графические процессоры только пару тысяч очень простой ядер), и даже если ваша материнская плата имея миллион розеток (что нереально, основной платы только до 4 гнезд, и даже крупнейшие суперкомпьютеры только 10 миллионов ядер в сумме), и даже если бы у тебя был миллион из этих компьютеров в кластере, и даже если бы у тебя был миллион тех, скопления в сверхскопления, и даже если бы у тебя был миллион друзей, которые также имеют сверхскопление такой, он бы все равно займет у вас около 1621000000000000000000000000000000000000000000000000000000000000000000 лет, чтобы выполнить итерации через них.

Комментарии:

1. Слово предупреждения — не цитируйте этот ответ руководству, они только поймут, что для этого требуется больше оперативной памяти, и назначат вам крайний срок.

2. Конечно, есть некоторые физические аргументы, которые можно привести, почему даже попытка этого приведет к тому, что Вселенная рухнет сама по себе, но, к сожалению, я довольно слаб в науке. Например, существуют теоретические ограничения на энергию, необходимую для хранения бита.

3. «Звучит неплохо, когда это можно будет сделать?»

4. отличное объяснение! большое вам спасибо!

Ответ №2:

Правильно, так как, надеюсь, ясно, что этого делать не следует, я рискну и попытаюсь решить вашу реальную проблему.

Вы упомянули в комментариях, что вам нужен этот массив для тестирования свойств — я сделаю здесь огромный шаг вперед и предположу, что вы хотите проверить, что каждая возможная комбинация удовлетворяет некоторым условиям — и это ошибка здесь, так как количество возможных комбинаций просто… велико…

Вместо этого вы можете проверить, работают ли некоторые комбинации. Вы можете легко сгенерировать короткий рандомизированный список комбинаций, используя:

 Array.new(num) { DATASET.map(amp;:sample) }  

Где num указано количество комбинаций, которые вы хотите протестировать. Обратите внимание, что существует вероятность того, что некоторые записи будут дублироваться, но, учитывая размер вашего набора данных, шансы будут сопоставимы с столкнувшимися uuid и могут быть безопасно проигнорированы.

Создание такого подмножества возможных решений намного проще, быстрее и, самое главное, возможно. Поскольку выходные данные рандомизированы, при каждом запуске они будут тестировать несколько иную комбинацию, поэтому не забудьте настроить рандомизацию в своем наборе тестов, если вы хотите иметь возможность воссоздавать сбои.