Доброго дня всем! Протестировал выше упомянутые модели одной задачей. Делал это за завтраком перед работой, писал сюда по дороге в автобусе.
. Оценки от меня не будет, только от Qwen 3.7 plus, для лентяев вроде меня, ну и исходники для самостоятельной оценки.
Задача:
Напиши на Python движок для парсинга и вычисления математических выражений, переданных в виде текстовой строки.
Требования и архитектурные ограничения:
Строго без
eval(): Движок должен самостоятельно токенизировать строку и строить Абстрактное Синтаксическое Дерево (AST) с помощью алгоритма рекурсивного спуска (Recursive Descent) или сортировочной станции (Shunting-yard).Поддержка операций: Базовые арифметические (
+,-,*,/,^для степени), скобки для приоритета, а также встроенные функции (sin,cos).Переменные (Контекст): Возможность передавать словарь переменных для вычисления. Например:
evaluate("x^2 + 2*y", {x: 3, y: 4}).Символьное дифференцирование (Главная сложность): Реализуй метод
differentiate(variable), который принимает построенное AST, дифференцирует его по заданной переменной (применяя правила производной суммы, произведения, сложной функции) и возвращает новое AST.Упрощение дерева: После дифференцирования полученное дерево часто получается избыточным. Реализуй базовую оптимизацию AST (например, ветки
x 0должны сворачиваться в0,y + 0вy,1 xвx,5 + 3в8).Обработка ошибок: Информативные исключения при синтаксических ошибках (например, "Неожиданный токен на позиции 5" или "Несбалансированные скобки") и защите от деления на ноль.
Ожидаемый результат: Код должен быть production-ready. Ожидается строгая типизация, грамотное использование ООП (например, паттерн Visitor или полиморфизм узлов дерева) или чистого функционального подхода, а также небольшой блок unit-тестов, проверяющих вычисление, дифференцирование и обработку ошибок.
Оценка от Qwen 3.7 plus.
Я проанализировал предоставленные реализации математического движка. Это отличная подборка, демонстрирующая разные архитектурные подходы и уровни проработки от различных языковых моделей.
Ниже представлен подробный разбор и оценка каждой модели (Opus, Sonnet, GLM, Fable) по критериям: архитектура, полнота математического аппарата, качество кода и тестирование.
1. Fable (Fable5) ? Лидер (Production-Ready)
Архитектура: Классический и строгий паттерн Посетитель (Visitor). Узлы AST (Node) хранят только данные (они frozen, то есть неизменяемы), а вся логика (вычисление, дифференцирование, упрощение, печать) вынесена в отдельные классы-посетители.
-
Плюсы:
Полнота математики: Реализовано общее степенное правило (логарифмическое дифференцирование для
).
Умный принтер: Отдельный класс
_Printerс системой приоритетов. Он расставляет скобки минимально необходимо, а не вокруг каждого узла.Расширяемость: Наличие
register_functionпозволяет добавлять новые функции (с их численной реализацией и правилами дифференцирования) на лету.Тесты: Вынесены в отдельный файл. Включают метод конечных разностей для проверки символьных производных и тесты на структурный round-trip (парсинг -> печать -> парсинг).
Минусы: Код более многословен из-за разделения на Visitor’ы, но для сложного движка это скорее плюс (соответствует принципу Open/Closed).
Вердикт: 10/10. Энтерпрайз-уровень. Код готов к использованию в реальных проектах (например, в CAS-системах или образовательных платформах).
2. Opus (opus4.8) ? Отличная ООП-реализация
Архитектура: Полиморфизм в узлах AST. Каждый узел (Number, BinaryOp и т.д.) сам знает, как себя вычислить, продифференцировать и напечатать.
-
Плюсы:
Инкапсуляция: Очень чистый ООП-подход. Не нужно плодить сущности-посетители, если логика узлов не будет часто меняться.
Полнота математики: Также реализовано общее степенное правило (
).
Упрощение: Использует итеративный подход (fixpoint), что позволяет сворачивать каскадные тождества (например,
(x 0 + y) 1->y).Тесты: Отличное покрытие, включая проверки на мутабельность и числовую сходимость.
-
Минусы:
Монолитность: Тесты и исходный код находятся в одном файле. Для продакшена их лучше разделять.
Нарушение SRP (Single Responsibility Principle): Узлы AST отвечают и за хранение данных, и за рендеринг, и за вычисления. Если понадобится добавить новую операцию (например, интеграцию), придется править каждый класс узла.
Вердикт: 8.5/10. Очень сильный, элегантный код. Отличный выбор для прототипа или проекта, где набор операций фиксирован и не будет расширяться.
3. GLM (glm_math_engine) ? Академический подход
Архитектура: Строгий Паттерн Посетитель (Visitor), но с рядом критических упущений.
-
Плюсы:
Чистое разделение данных и поведения (как у Fable).
Хорошая обработка ошибок лексера и парсера с указанием позиции.
-
Минусы:
Нет модуля печати (Printer): В коде вообще нет метода
strили класса для преобразования AST обратно в строку. Вы не сможете красиво вывести результат дифференцирования.Обрезанное дифференцирование: Не поддерживает дифференцирование переменной в степени (
x^yилиx^x). Выбрасывает ошибку.Упрощение за один проход: Не использует итеративное упрощение до неподвижной точки. Каскадные тождества (например,
0 * x + y) могут не свернуться до конца.
Вердикт: 6/10. Хорошая заготовка, демонстрирующая понимание паттерна Visitor, но функционально неполноценна из-за отсутствия принтера и урезанной математики.
4. Sonnet (sonet5) ? Сырой прототип
Архитектура: Полиморфизм в узлах (как у Opus), но с использованием dataclass(frozen=True).
-
Плюсы:
Токенизатор на Regex: Очень элегантное и компактное решение для разбора строки на токены. Это быстрее и короче, чем посимвольный разбор.
Отличные сообщения об ошибках с точными позициями.
-
Минусы:
Ужасный Принтер: Метод
_renderвBinaryOpвсегда оборачивает операнды в скобки, если их приоритет ниже или равен текущему. В результате выражениеx + y zнапечатается как(x + (y z)), а производная превратится в нечитаемую “капусту” из скобок.Обрезанное дифференцирование: Явно отказывается дифференцировать
, выбрасывая
DifferentiationError.Смешивание типов: Использование
Union[int, float]и возвратintтам, где ожидаетсяfloat, может привести к багам в строгих математических вычислениях.
Вердикт: 5/10. Токенизатор хорош, но отсутствие нормального принтера и неполная поддержка математического аппарата (отказ от общего степенного правила) делают движок непригодным для символьных вычислений.
Сводная таблица сравнения
Критерий |
Fable (Fable5) |
Opus (opus4.8) |
GLM |
Sonnet (sonet5) |
|---|---|---|---|---|
Архитектура |
Visitor (Идеально) |
Полиморфизм (Хорошо) |
Visitor (Хорошо) |
Полиморфизм (Средне) |
Дифф. |
✅ Есть (логарифм) |
✅ Есть (логарифм) |
❌ Нет (только |
❌ Нет (только |
Печать (AST -> str) |
✅ Умная (мин. скобок) |
✅ Хорошая |
❌ Отсутствует |
❌ Плохая (лишние скобки) |
Упрощение |
✅ Итеративное (fixpoint) |
✅ Итеративное (fixpoint) |
⚠️ За 1 проход |
⚠️ За 1 проход |
Расширяемость |
✅ |
❌ Захардкожено |
❌ Захардкожено |
❌ Захардкожено |
Токенизатор |
Посимвольный |
Посимвольный |
Посимвольный |
✅ Regex |
Тесты |
✅ Отдельный файл, мат. стат. |
✅ Встроенные, хорошие |
✅ Встроенные, базовые |
✅ Встроенные, базовые |
Итоговое резюме
Fable5 — безоговорочный победитель. Код написан как для серьезной библиотеки: расширяемый, неизменяемый (immutability), с умным форматированием и строгими тестами через численные методы.
Opus — второе место. Очень достойная ООП-реализация, но архитектурно она менее гибкая для добавления новых операций по сравнению с Visitor-подходом Fable.
GLM — крепкий середняк. Понимает паттерны проектирования, но не доводит задачу до конца (забыл написать Printer).
Sonnet — аутсайдер. Несмотря на красивый Regex-токенизатор, модель не справилась с задачей вывода строк и ограничила математический аппарат.
Github: https://github.com/Paradoxdov/fable-opus-sonnet-glm-test
Оценкавычисление, дифференцирование и обработку ошибок.
tester37
Забыл написать printer может и некритично. Дёшево обнаружили, напомнили, дописали. Делать все сразу по одному промпту это несерьезно