Программно найти нотацию Ландау (Big O или тета-нотацию) алгоритма?

11

Я привык искать нотации Ландау (Big O, Theta ...) моих алгоритмов вручную, чтобы убедиться, что они оптимизированы настолько, насколько это возможно, но когда функции становятся действительно большими и сложными, они начинают слишком много времени, чтобы сделать это вручную. это также склонно к человеческим ошибкам.

Я потратил некоторое время на Codility (упражнения по кодированию / алгоритму) и заметил, что они дадут вам нотацию Ландау для вашего представленного решения (как в использовании времени, так и памяти).

Мне было интересно, как они это делают ... Как бы вы это сделали?

Есть ли другой способ, кроме Lexical Analysis или парсинга кода?

Этот вопрос касается в основном PHP и / или JavaScript, но я открыт для любого языка и теории.

Жюльен Л
источник
4
Проверьте этот ответ от SO. Это звучит как то, что вы ищете.
Деку
2
Если вы сможете создать программу, которая решает эту проблему для каждого алгоритма, вы станете известны как «человек, опровергший Тьюринга».
user281377
1
Доказательства того, что определение времени работы в общем случае невозможно, см. Здесь и здесь - ответы там на самом деле даже больше, чем вы просите.
Алекс десять Бринк

Ответы:

13

Мне было интересно, как они это делают ... Как бы вы это сделали?

Я полагаю, что они на самом деле оценивают показатели Big O ..., запуская программу для разных размеров задач, измеряя время и использование пространства и подбирая кривые к результатам.

Проблема с этим подходом состоит в том, что он может ошибиться, если функции стоимости изменяют форму, когда N становится большим; например 1000 N + N^1.5.

Есть ли другой способ, кроме Lexical Analysis или парсинга кода?

Лексический анализ и разбор не достаточны. Вы также должны сделать некоторые рассуждения о поведении алгоритма. И сделать это автоматически для ранее неизвестного алгоритма сложно.

Стивен С
источник
6
«сделать это автоматически для ранее неизвестного алгоритма сложно» - точнее: это эквивалентно решению проблемы остановки.
Йорг Миттаг
Эмм ... не совсем. Решение проблемы остановки будет эквивалентно возможности сделать это для всех ранее неизвестных алгоритмов.
Стивен С
2
Да, прости. Выполнение этого для одного алгоритма эквивалентно (или скорее подразумевает) доказательство завершения.
Йорг Миттаг
1
Практичность этого состоит в том, что 1) невозможно доказать или опровергнуть завершение для некоторых алгоритмов, но 2) большинство алгоритмов не имеют этого теоретического препятствия, но 3) уровень техники в доказательстве теорем не достаточно продвинут, чтобы быть в состоянии сделать это в любом случае ... за исключением относительно простых случаев. Отсюда мое утверждение, что я думаю, что они делают это по-другому. Но, очевидно, мы не можем быть уверены, как они на самом деле делают это, не глядя на их код.
Стивен С
3

Они не могут без анализа кода.

Приведенные ниже примеры с искусственной «инфляцией / дефляцией» сложности доказывают, что простого измерения времени выполнения программы недостаточно для надежной оценки Big-O

void lets_trick_runtime(int n) {
   if (n == 10 || n == 25 || n == 118) {
      // unfair speed-up
      do_precalculated_solution_in_constant_time(n);
      return;
   }
   if (n == 11 || n == 26 || n == 119) {
      // unfair slow-down
      do_some_fake_processing_in_n_cube_time(n);
      return;
   }
   // fair solution
   do_general_solution_in_quadratic_time(n);
}

Оценка времени выполнения для вышеупомянутого была бы возможна для того, чтобы дать ложные оценки - постоянное время для значений, nгде есть предварительно рассчитанное решение, и кубическое время для значений, где unfair slow-downначинается - вместо "справедливого" квадратичного времени.

комар
источник
Однако, если они действительно проверяют «несправедливые» случаи, они все равно могут предположить, что наихудший случай действительно оценивает сложность Big-O.
Ям Маркович
1

Я думаю, что это невозможно.

Если вы запустите несколько тестов с фиксированным числом входных данных разного размера, вы можете легко вычислить полином, который будет приблизительно соответствовать времени выполнения, которое вы измерили очень хорошо. Таким образом, вы получите многочлен для каждой возможной программы, что будет означать P = NP(да!;)).

Если вы попытаетесь сделать это с помощью символических манипуляций, вы в конечном итоге в halting problem. Поскольку вы не можете решить, остановится ли ваша программа когда-либо, вы не можете решить, какую сложность во время выполнения она будет иметь.

Однако могут быть особые случаи, когда возможен более поздний метод. Но эти случаи могут быть настолько малы, что сомнительно, если усилия когда-либо будут оплачены.

SpaceTrucker
источник
1
+1, хотя я думаю, что проблему остановки можно считать редкостью.
Ям Маркович
0

Как бы я это сделал? То, как я решаю почти любую проблему, я не хочу садиться и решать . Я симулирую.

Для многих задач может быть достаточно запустить ваш алгоритм много раз, используя различные размеры, а затем подогнать кривую регрессии к этим результатам. Это быстро определит некоторые конкретные «фиксированные» накладные расходы вашего алгоритма (пересечение кривой) и то, как он масштабируется по мере увеличения размера вашей проблемы.

Потребуется некоторая обработка, чтобы отразить особенно сложные решения, но особенно если вы просто ищете приблизительную оценку, вы сможете получить ее таким образом, посмотреть, как ваша оценка отличается от ваших фактических результатов, и решить, является ли она приемлемое приближение.

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

фомиты
источник
0

Моя интуиция заключается в том, что общее решение этой проблемы невозможно; утверждение априорных фактов о времени выполнения алгоритмов без их запуска (вы ссылаетесь на лексический анализ). Тем не менее, возможен некоторый эвристический алгоритм для (возможно, большого) класса алгоритмов (поскольку мы делаем это все время), но общий алгоритм для этого будет эквивалентен решению проблемы Энтшайдунга, которая, как известно, не является возможно (ср. Черч, Тьюринг и др.). Я ~ 99,9% уверен в этом сейчас, когда я думаю об этом ...

veryfoolish
источник