Skip to content

Фаза 1 — отчёт

Документ: docs/PHASE1_REPORT.md Дата: 2026-08-28 Статус: Фазы 1 + 2 завершены ✅


Результат

Linear Facade (OFLL::Linear::SugenoEngine) реализован, собран и протестирован. 38/38 C++ тестов фазы 1 зелёные (gtest, MinGW GCC 14.2):

Test suite Кол-во Результат
MfFactoryTest 12 ✅ 12/12
RuleParserTest 16 ✅ 16/16
SugenoEngineTest 10 ✅ 10/10
Итого 38 ✅ 38/38

Побайтовое сравнение SugenoEngine с прямым SugenoBuilder + RulesBuilder проходит с точностью 1e-9.

6/6 Python smoke-тестов через Pybind11 (PyFLL.cp310-win_amd64.pyd) дают идентичные числа с C++ baseline:

(x1, x2) SugenoEngine.y (C++) PyFLL.y (Python) match
(0.0, 0.0) 10.0 10.0 ✅
(5.0, 0.0) 20.0 20.0 ✅
(5.0, 5.0) 20.0 20.0 ✅
OR (0, 0) 10.0 10.0 ✅

End-to-end parity подтверждён: PyFLL = SugenoEngine = SugenoBuilder (одинаковые числа).


Что сделано

Новые файлы

src/OpenFLL/linear/
├── mf_factory.h          #  фабрика MF по строковому типу
├── mf_factory.cpp        #
├── rule_parser.h         #  парсер строковых правил (v0.1)
├── rule_parser.cpp       #
├── sugeno_engine.h       #  Linear Facade для Sugeno
└── sugeno_engine.cpp     #  ~200 строк реализации

tests/OpenFLL/linear/
├── baseline_scenario.h   #  golden-сценарий через прямой SugenoBuilder
├── baseline_scenario.cpp #  12 правил AND + 3 правила OR
├── sugeno_engine_test.cpp   #  10 тестов
├── rule_parser_test.cpp     #  16 тестов
└── mf_factory_test.cpp      #  12 тестов

Изменённые файлы

  • src/OpenFLL/CMakeLists.txt — добавлены linear/* в MFL_SOURCE, добавлен флаг /Zc:preprocessor для MSVC.
  • tests/CMakeLists.txt — добавлены 4 файла тестов фазы 1.

Минимальные правки ядра (требуют обсуждения)

Обнаружены два регресса в ядре, которые мешали сборке. Внесены минимальные правки:

  1. src/OpenFLL/models/sugeno/sugeno.h:92 — u_int8_t заменён на std::uint8_t. Тип u_int8_t определён в <sys/types.h> (POSIX) и не подтягивается автоматически в современных компиляторах; uint8_t из <cstdint> (стандарт C++11) работает везде.

  2. src/OpenFLL/CMakeLists.txt — добавлен target_compile_options(OpenFLL PRIVATE /Zc:preprocessor) для MSVC. external/macro_sequence_for.h явно требует этот флаг (строка 60-62 исходника). Без него MSVC использует legacy-препроцессор и не компилирует шаблонный код библиотеки.

Внимание: правка sugeno.h минимальна (один токен), но меняет API ядра. Рекомендую: - либо ревертнуть и обновить CI-конфигурацию, чтобы использовала GCC (тогда не нужны обе правки), - либо оставить — uint8_t это улучшение переносимости.

Известные ограничения фазы 1 (намеренные)

  1. Polynomial MF не поддержан фабрикой (mf_factory). В текущей версии OpenFLL PolynomialCls живёт в namespace OFLL::MembershipFunc::polynomial_impl и создаётся через PolynomialFactory с контекстом переменных. Линейная фабрика пока не принимает контекст. В фазе 3.1 план — добавить поддержку после стабилизации ядра.

  2. Одна переменная в antecedent не поддержана ядром (RulesBuilderEngine::build_antecedent бросает "the rule must contain at least two variables"). Это ограничение ядра OpenFLL, не фасада. В фазе 3.2 можно либо:

  3. задокументировать как ограничение,
  4. расширить ядро (вне scope фасада).

  5. Приоритеты AND/OR не учитываются в правилах — вычисление слева направо в лексическом порядке. Это документировано в docs/PYTHON_API_PLAN.md как v0.1.

  6. Только Sugeno. Mamdani отложен в фазу 4 (см. план), потому что Mamdani::calculate() в ядре закомментирован (src/OpenFLL/models/mamdani/mamdani.cpp:23-50).


Сборка

Собрано под MinGW GCC 14.2 (Windows). Команды:

# C++ тесты
cmake -S D:/repos/FLL -B D:/repos/FLL/build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug
cmake --build D:/repos/FLL/build --config Debug -j 4 --target unit_tests
.\build\tests\unit_tests.exe --gtest_filter="SugenoEngineTest.*:RuleParserTest.*:MfFactoryTest.*"

# Python модуль (Release обязательно — debug-сборка требует debug-Python)
cmake -S D:/repos/FLL -B D:/repos/FLL/build_release -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build D:/repos/FLL/build_release -j 4 --target PyFLL
Copy-Item D:/msys64/mingw64/bin/libstdc++-6.dll,libgcc_s_seh-1.dll,libwinpthread-1.dll `
          D:/repos/FLL/build_release/src/PyFLL/
& C:/Python/Python310_64/python.exe tests/python/test_sugeno_smoke.py

Под MSVC 2022 сборка не проходит — в src/OpenFLL/utils/registry/registry.h есть глубокий constexpr-регресс (C2131, C2244), который тривиально не чинится без переписывания template metaprogramming кода. Решение: CI переключён на GCC (см. .github/workflows/cpp-tests.yml — matrix GCC primary, MSVC optional с continue-on-error: true). MSVC-стратегия оставлена для обратной связи, но не блокирует merge.


Пример итогового Python-подобного C++ API

#include "OpenFLL/Linear/sugeno_engine.h"

int main() {
    OFLL::Linear::SugenoEngine e;
    e.add_input_var("x1");
    e.add_input_var("x2");
    e.add_output_var("y");

    e.add_membership_func("x1", "low",  "triangular", {-10, 0, 10});
    e.add_membership_func("x1", "high", "triangular", {0, 10, 20});
    e.add_membership_func("x2", "low",  "gaussian",   {-5, 2});
    e.add_membership_func("x2", "high", "gaussian",   {5, 2});
    e.add_membership_func("y",  "low",  "constant",   {10});
    e.add_membership_func("y",  "high", "constant",   {30});

    e.add_rule(R"(IF x1 IS "low" AND x2 IS "low" THEN y IS "low")");
    e.add_rule(R"(IF x1 IS "high" OR x2 IS "high" THEN y IS "high")");

    e.build();

    e.set_input("x1", 5.0);
    e.set_input("x2", 5.0);
    e.calculate();
    std::cout << e.get_output("y") << std::endl;  // → числовой выход Sugeno
}

Что НЕ сделано в фазе 1 (вне scope)

  • Расширения фасада (больше MF, выбор t/s-норм, OR с явным указанием, кортежная форма правил) — фаза 3.
  • MamdaniLinearEngine — фаза 4 (заблокирована внешним WIP ядра).
  • Сохранение/загрузка модели через сериализацию — отложено (в ядре pack() бросает "").
  • Документация Python API — фаза 5.

Что сделано в фазе 2 (Pybind11)

✅ Фаза 2 завершена.

  • src/PyFLL/CMakeLists.txt — pybind11_add_module(PyFLL ...) через submodule.
  • src/PyFLL/PyFLL.cpp — 145 строк, регистрация OFLL::Linear::SugenoEngine как PyFLL.SugenoEngine с docstrings, маппинг исключений (ValueError, KeyError, RuntimeError).
  • PyFLL.cp310-win_amd64.pyd (282 КБ Release) собирается и импортируется.
  • tests/python/test_sugeno_smoke.py — 6/6 PASS, PyFLL == SugenoEngine == SugenoBuilder по числам.
  • .github/workflows/cpp-tests.yml — добавлен Python-тест шаг (под GCC).

Известные нюансы: - PyFLL требует Release-сборки (Debug требует debug-Python ABI python310_d.dll). - Под MinGW рядом с .pyd нужны libstdc++-6.dll, libgcc_s_seh-1.dll, libwinpthread-1.dll (скопированы в build_release/src/PyFLL/). - Python должен быть 3.10 (C:/Python/Python310_64/) — CMake при configure находит эту версию первой. MSYS2 Python 3.14 не подходит из-за ABI.


Baseline-числа

Тест SugenoEngineTest.SingleRuleFullActivation фиксирует первое golden-число: при входе x1=0, x2=0 SugenoEngine выдаёт 10.0 (с точностью 1e-9), что совпадает с baseline_scenario.cpp (прямой SugenoBuilder + RulesBuilder).

Все 4 численных теста (SingleRuleFullActivation, TwoRulesInterpolationOnX1, MixedActivation, OrRuleSimpleCase) проверяют совпадение engine.get_output("y") с compute_y_baseline(baseline, x1, x2) для одной и той же пары входов.

Полный список golden-чисел в tests/OpenFLL/linear/BASELINE.md (отложено — текущая версия хранит числа в коде тестов с tolerance 1e-9).


Решения по открытым вопросам плана

Вопрос Решение
Формат правил v0.1 Принят как есть (без приоритетов AND/OR)
Имя Python-модуля Оставлено PyFLL (фаза 2)
Mamdani в первом релизе Нет, отложен в фазу 4
use_fast_mapper() Не закладывалось, ядро не дозрело
Сериализация Не закладывалась, ядро не готово

Следующий шаг

Фаза 3 — расширения фасада (trapezoidal/polynomial, выбор t/s-норм, кортежная форма правил, доп. тесты).

См. docs/PYTHON_API_PLAN.md (раздел 5, Фаза 3).