Кто-нибудь знает автоматические методы оценки алгоритмической сложности?



Пост не совсем про хайлоад, но надеюсь достаточно "хакерский". Кто-нибудь знает автоматические методы оценки алгоритмической сложности? Мне приходит в голову 4 метода: (1) в-общем конечно можно просто мерять процессорное время gettimeofday/RDTCS, меняя условные n. Есть сомнения в том, что за несколько итераций получится определить сложность. Во-первых это не совсем сложность - но это практически даже плюс, нужно именно время/такты процессора. Во-вторых из-за каких-нибудь side effects в многозадачной/виртуальной среде (впрочем, может быть я это зря, и ядро будет считать точно даже для загруженных виртуалок - не пробовал).(2) Можно "влезть" внутрь интерпретатора байт-кода и считать число операций. Сработает только если есть фаза генерации байт-кода.(3) Можно использовать мок-объекты (типа map<Mock,int> map) - накладывает ограничение на текст программы, доступно далеко не во всех языках (я нашел только пример на Си++, нужно оперировать только замоченными базисными структурами данных).(4) Можно написать "парсер" кода и на выходе получить код с "каунтерами" операций. Главная проблема будет в том, чтобы отловить и обработать работу с готовыми структурами данных или с другими либами, не уверен, что это вообще можно сделать.Задача исключительно на размять мозги, практическое применение только если "олимпиадное", типа можно сделать не такими "тупыми" проекты навроде Project Euler (они вроде не считают сложность). Что думаете - как это можно бы сделать? Или есть какие-то готовые решения/статьи?UPDATE: в каментах пишут, что codility это делает, и сносно
644   37  

Comments

  1. Денис Габайдулин
    Денис Габайдулин 5 лет назад
    Ну чисто теоретически, запуская на разных n и получая время или таймаут, можно наверное подобрать аппроксимирующую функцию, скажем, с помощью мнк?
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      именно, вопрос только не будет ли каких-то side effects
    • Денис Габайдулин
      Денис Габайдулин 5 лет назад
      Alexey Rybak да будут наверное. Но чисто интуитивно, мне не кажется, что задача вполне решаема. К тому же, я видел продукт, который такое делал. В какой то системе, которая предоставляла задачки кандидатам (задачка, редактор, тестер) и их анализ, сложность решения автоматически проверялась и сносно попадала. Имя компании не вспомню (
    • Дмитрий Зенович
      Дмитрий Зенович 5 лет назад
      Denis Gabaydulin codility?
    • Денис Габайдулин
      Денис Габайдулин 5 лет назад
      Dmitry Zenovich точно!
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Дмитрий Зенович сносно определял?
    • Дмитрий Зенович
      Дмитрий Зенович 5 лет назад
      Alexey Rybak очень даже сносно
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Дмитрий Зенович на любом языке?
    • Дмитрий Зенович
      Дмитрий Зенович 5 лет назад
      Alexey Rybak, они поддерживают много языков. Хинт в том, что они точно знают, какую задачу решает программа и под каждую задачу подготавливают тестовые наборы данных. На этих наборах замеряется сложность алгоритма по быстродействию и по памяти.
    • Дмитрий Зенович
      Дмитрий Зенович 5 лет назад
      https://app.codility.com/.../17-dynamic.../min_abs_sum/
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Дмитрий Зенович да, это ровно то практическое применение, о котором я думал.
  2. Оксана Павшок
    Оксана Павшок 5 лет назад
    Уже давно есть. Но дорого. https://matlab.ru/partner-products/LDRA
  3. Павел Клеменков
    Павел Клеменков 5 лет назад
    Проблема ещё и в том, что сложность может зависеть не только от длины входа, но и от распределения входа. Типичный пример - сортировка уже упорядоченных данных. Кроме того, это тупо может быть нереализуемо, например алгоритм полиномиалльный и уже на третьем запуске считается около часа. А чтоб построить стат значимую оценку, нужно больше наблюдений.
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Павел Клеменков формально да, но в контексте задачи тестирования программистов нам известен вход и метод, которятся генерятся входные данные, то есть мы можем гарантировать определенное распределение
  4. Giorgi Kutsu
    Giorgi Kutsu 5 лет назад
    Скорее решение данной проблемы попахивает на решение P и NP полных задач. Другими словами, проще-ли или возможно-ли вообще найти оптимальность данного алгоритма за полиномиальное время и память.
    • Денис Габайдулин
      Денис Габайдулин 5 лет назад
      Giorgi Kutsu не вижу связи здесь. Вот у вас есть набор f(x)=y, где, x и y известны, а f надо найти. По моему, чуть ли не в школе вас учили табличному методу нахождения функции.Проблемы практического характеры тут будут, конечно.
    • Giorgi Kutsu
      Giorgi Kutsu 5 лет назад
      Ну смотри, наверное так и решают такие задачки на ощупь, может быть пока что. Вот у тебя есть функция записанная на мат. языке f(x)=y, а от тебя требуют найти g(x) функцию которая показывает оптимальность твоего решения f(x)=y. Пока такие задачки решают как-бы на ощупь, прибегая к приближенным величинам...
  5. Konstantin Gontarenko
    Konstantin Gontarenko 5 лет назад
    Постановка задачи так себе.
    • Павел Клеменков
      Павел Клеменков 5 лет назад
      Хм, так себе довод. Если у меня есть выбор между двумя алгоритмами, один из которых работает не четыре часа, а полчаса, то это вполне себе аргумент в пользу вычислительной сложности
    • Konstantin Gontarenko
      Konstantin Gontarenko 5 лет назад
      Pavel Klemenkov Аргумент про 4 часа годный. Только если посмотреть внутрь обоих алгоритмов, вполне может оказаться так, что тот, который 4 часа, асимптотически быстрее того, который полчаса. Я довольно часто такое вижу на практике, с production алгоритмами и профайлером.
    • Денис Габайдулин
      Денис Габайдулин 5 лет назад
      Любая оптимизация должна начинаться с анализа алгоритмов, а потом все остальное. Потому что переход от скажем квадратичного алгоритма к линейному, а еще лучше к логарифмическому или даже константному даст гораздо больше в плане уменьшения latency, чем любые микрооптимизации, на реальных примерах. Странно, считать этот факт устаревшим.
    • Павел Клеменков
      Павел Клеменков 5 лет назад
      Konstantin Gontarenko согласен, что асимптотика скрывает константы, которые на практике зачастую решают, но фундаментально асимптотика важна
    • Konstantin Gontarenko
      Konstantin Gontarenko 5 лет назад
      Denis Gabaydulin «Любая оптимизация должна начинаться с анализа алгоритмов, а потом все остальное» А мне кажется, что любая оптимизация должна начинаться с profiling. Во-первых это сильно быстрее, чем алгоритмы анализировать. Во-вторых и в главных, начиная с алгоритмов вы скорее всего потратите кучу времени, оптимизируя код, который вообще или почти не влияет на performance.
    • Денис Габайдулин
      Денис Габайдулин 5 лет назад
      Konstantin Gontarenko профайлинг понятно, но это инструмент. Я про анализ и выводы. Где-то они влезло, а где-то нет (другой процессор). Опять же распределение этого n. В реальном мире часто можно увидеть нормальное распределние с тяжелыми хвостами, но довольно редко можно встретить равномерное.Да, иногда делают несколько алгоритмов в зависиомсти от n (например joins в базах данных, разные алгоритмы сжатия), но это абсолютно не значит, что надо с этого начинать. Этим стоит заниматься когда возможности по замене алгоритма исчерпаны.Я сам на практике встречал случаи когда бинарный поиск обгонял хештаблицы. Но это очень специфичные кейсы с constant max n, например.
    • Konstantin Gontarenko
      Konstantin Gontarenko 5 лет назад
      Denis Gabaydulin Надо знать железо, шоб оптимизировать. Например шоб найти проц, где меньше 32kb L1 data cache, нужен Pentium 4. На всех современных как минимум 32, даже на ужасно медленных Atoms, за очень редкими исключениями (некоторые AMD 15h).Но даже если не влезло, L2 не сильно медленнее, т.е. всё равно O(n^2) скорее всего будет сильно быстрее, чем O(n) но со случайным доступом в память.
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Про профайлеры дельная мысль, кстати. Касательно бесполезности поспорил бы, но не хочется флейм раздувать. JIT не мешает тому, чтобы был байт-код. Но опять же не хочется флеймить.
    • Денис Габайдулин
      Денис Габайдулин 5 лет назад
      Konstantin Gontarenko ок, попробую написать последний комментарий на эту тему. Железо конечно надо знать, и ос и runtime. Но вот смотрите, вы делаете оптимизацию, которая базируется на очень хрупких условиях. Процессор, компилятор, какое-то распределение кол-ва входных данных, кол-во процессов в системе и т.д. Как только любое из этих условий ломается, ваш performance деградирует на порядок, в случае квадратичного алгоритма. Есди вы сначала сделали нормальный алгоритм, а потом уже начали заниматься всем этим, то ваша система будет не настолько хрупка.
    • Konstantin Gontarenko
      Konstantin Gontarenko 5 лет назад
      Alexey Rybak Я не знаю какая у вас задача вообще, пост очень абстрактно сформулирован.
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Konstantin Gontarenko давайте сузим задачу в практическую область - автоматически определить сложность решения какой-то конкретной задачи (project euler, codility - последний вроде это умеет). У профайлеров разве нет анализаторов кода, которые могут связывать логически профилируемую программу и исходный код? Просто мерять время и без профайлера можно.
    • Konstantin Gontarenko
      Konstantin Gontarenko 5 лет назад
      Alexey Rybak “У профайлеров разве нет анализаторов кода, которые могут связывать логически профилируемую программу и исходный код?” Оно немного не так работает. Sampling profilers с высокой частотой (много килогерц иногда мегагерц) генерируют прерывания, каждое из которых записывает, какая именно инструкция исполнялась.
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Konstantin Gontarenko да, спасибо за ликбез, получается, что на выходе у меня вообще нет данных о числе операций, только время, и определить алгоритмическую сложность я смогу только если буду запускать это дело при разных n и дальше та же аппроксимация и поиск подходящей функции. Непонятно, чем это точнее просто измерения процессорного времени до и после.
    • Денис Габайдулин
      Денис Габайдулин 5 лет назад
      Ну тут еще вопрос, что считать элементарной операцией? Можно же закопаться. Вот вызов функции, printf, это же не элементарная операция? Ну, нет, ну там же массив char. А дальше, ну там чтение из памяти, ну оно наверное тоже не побайтное, а какими-то большими кусками, поэтому для малого количества байт, это будет одна операция, а для большого не одна. А еще есть кеши. И вот про конвейер тоже упомянули. Ну и короче говоря модель получается очень сложной, поэтому вот эта абстракция big o и работает до сих, но она менее точная и понятно что для микромира работает хуже, чем для макро. Ну и кажется что более менее реальных может быть два подхода. Один, это эксперимент и поиск функции, которая макс. близко описывает то что получили, либо анализ конкретного языка. Скажем jvm байткод можно наверное проанализировать (заранее подумать в каких конструкциях "зашита" complexity, потом найти их в байткоде, связать с input и аккуратно почитать на разных n).
    • Konstantin Gontarenko
      Konstantin Gontarenko 5 лет назад
      Denis Gabaydulin Чтение из памяти кусками по 128 бит обычно, это если dual-channel DDR (шина данных модуля памяти параллельная и 64 бита в ширину).
    • Eugene Klimov
      Eugene Klimov 5 лет назад
      Alexey Rybak погугли на тему flamegraph и поиска bottleneck по нему, человек очень годную мысль озвучил"для обучения" да, надо считать алгоритмическую сложность, для продакшена нужен sampling profiling и выискаваем плато, смотрим в код, смотрим что слишком часто дергается, переписываем так чтобы дергалось меньше, снова снимаем самплинг под нагрузкой, сравниваем flamegraphs
    • Alexey Rybak
      Alexey Rybak 5 лет назад
      Eugene, я именно автоматический поиск алгоритмической сложности имел в виду, а не профайлинг. Посмотри выше тред про codility. Дали задачу, получили решение, прогнали тесты - получили верное ли решение, и получили алгоритмическую сложность.
  6. Mikhail Konyukhov
    Mikhail Konyukhov 5 лет назад
    Чисто по определению алгоритмической сложности это величина математическая источником которой является анализ алгоритма. Её нельзя найти эксперементально) эксперементально это будет size scale factor)Если говорить об автоматическом анализе алгоритмов то на уровне sql есть explain он позволяет начать анализ. Если речь о других языках то профайлер в помощь)
  7. Андрей Григорьев
    Андрей Григорьев 5 лет назад
    Для go есть gocyclo - cyclomatic complexity checker, но это не совсем то. Для Python тоже есть, https://github.com/PyCQA/mccabe.