Skip to content

PR1: PDL contracts & safety hardening#245

Closed
Hedy-dev wants to merge 9 commits into
pdl-time-seriesfrom
feature/pdl-contract-hardening
Closed

PR1: PDL contracts & safety hardening#245
Hedy-dev wants to merge 9 commits into
pdl-time-seriesfrom
feature/pdl-contract-hardening

Conversation

@Hedy-dev

Copy link
Copy Markdown
Collaborator

Отчёт по выполнению PR 1

Статус: Issue 1 — выполнен. Issue 2 — выполнен.

Затронутые файлы:

* fedot_ind/core/models/pdl/pairwise_core.py — контракты, diagnostics, имена
* fedot_ind/core/models/pdl/pairwise_model.py — score_difference
* tests/unit/core/models/test_pdl.py  — контракты, estimator/classifier/regressor
* tests/unit/core/models/test_pairwise_learning_core.py — core-level контракты

* fedot_ind/core/models/pdl/legacy_pairwise_transform.py — модуль transform перенесённый в legacy
* tests/unit/core/models/test_pdl_transform.py — пересобранные тесты для legacy transform

1. Явные constants/metadata для classification target semantics

Статус: выполнено

Файл: pairwise_core.py, строки 14–16

Добавлено:

CLASSIFICATION_SAME_LABEL = 0
CLASSIFICATION_DIFFERENT_LABEL = 1
REGRESSION_DELTA_SIGN = "left_minus_anchor"

Где используется:

Константа Файл Функция / место
CLASSIFICATION_SAME_LABEL pairwise_core.py _predict_same_probability — выбор столбца P(same) из predict_proba; `
CLASSIFICATION_SAME_LABEL, CLASSIFICATION_DIFFERENT_LABEL pairwise_core.py _pair_target_semantics(task="classification") → поля same_label, different_label
REGRESSION_DELTA_SIGN pairwise_core.py _pair_target_semantics(task="regression") → поле delta_sign

2. Политика имён: same и different не смешиваются

Статус: выполнено в active path и legacy helper

Classification — training target

Было Стало Файл
pair_target = (left != anchor) dissimilarity_target = (left != anchor) pairwise_core.py, build_classification_pairs (~143)
dissimilarity_target + docstring контракта 0=same, 1=different pairwise_model.py, pair_output_difference (~65–78)

Семантика (зафиксированный контракт):

same_label           = 0   → одинаковый класс
different_label      = 1   → разные классы
dissimilarity_target = int(left_class != anchor_class)   # 0 если same, 1 если different

В PairwiseBatch.target по-прежнему поле называется target (публичная структура не менялась), но в него кладётся dissimilarity_target.

Classification — inference / scoring

Было Стало Файл
similarity = predict_similarity_by_chunks(...) same_probability = predict_similarity_by_chunks(...) pairwise_model.py, score_difference (~174)
target_difference dissimilarity_target pairwise_model.py, score_difference (~175–176)
predicted_difference = 1.0 - similarity predicted_dissimilarity = 1.0 - same_probability pairwise_model.py, score_difference (~177)

В predict_similarity_by_chunks локальная переменная same_probability (~211) — это P(class == same_label), не «разность» и не dissimilarity.

Не переименовано (косметика, поведение то же):

  • aggregate_similarity_to_class_proba(similarity, ...) — аргумент по-прежнему similarity, по смыслу это матрица P(same).
  • _predict_encoded_proba: локально similarity = predict_similarity_by_chunks(...) (~185).

Regression — training target

Было Стало Файл
pair_target = left - anchor delta_left_minus_anchor = left - anchor pairwise_core.py, build_regression_pairs (~166)
return anchor - left delta_left_minus_anchor = left - anchor pairwise_model.py, pair_output (~60–63)

3. Regression sign convention left - anchor

Статус: выполнено, active path и legacy выровнены

Формула:

delta_left_minus_anchor = target_left - target_anchor
feature difference      = left_features - anchor_features   # concat_diff, diff_only
inference               = anchor_target + predicted_delta

Где зафиксировано:

Место Файл
build_regression_pairs pairwise_core.py ~166
predict_regression_by_chunks (anchor_target + deltas) pairwise_core.py ~233–234
_build_pair_features_numpy (left - anchors) pairwise_core.py ~282
Legacy pair_output pairwise_model.py ~60–63

Удалено из тестов: старый test_pair_output с ожиданием anchor - left (y2 - y1); заменён на test_regression_pair_target_is_left_minus_anchor.


4. pair_target_semantics в diagnostics

Статус: выполнено

Добавлено:

Элемент Файл Строки
_pair_target_semantics(task) pairwise_core.py ~303–321
параметр task в _pair_diagnostics pairwise_core.py ~346–366
task="classification" в build_classification_pairs pairwise_core.py ~150
task="regression" в build_regression_pairs pairwise_core.py ~173
ключ "pair_target_semantics" в return diagnostics pairwise_core.py ~365

Цепочка до внешнего API:

build_*_pairs → batch.diagnostics["pair_target_semantics"]
    → PairwiseDifferenceClassifier/Regressor.fit → self.diagnostics_
    → get_diagnostics()

Для classification:

{
  "task": "classification",
  "same_label": 0,
  "different_label": 1,
  "target_type": "dissimilarity",
  "target_formula": "int(left_class != anchor_class)",
  "inference_output": "same_probability"
}

** Для regression:**

{
  "task": "regression",
  "delta_sign": "left_minus_anchor",
  "target_formula": "target_left - target_anchor",
  "inference_reconstruction": "anchor_target + predicted_delta"
}

pair_diagnostics кладётся в PairwiseBatch.diagnostics на этапе построения пар,
источник pairwise_core.py.
В pairwise_model.py: в fit к batch‑диагностике добавляются runtime‑поля модели (diagnostics
).

Опционально доработать: нет типизированного контракта диагностики, оставлены TODO для PairwiseBatch.diagnostics, _pair_diagnostics, и в обоих fit. Сейчас это dict.

Тесты:

  • test_pair_target_semantics_is_reported_in_diagnostics — core (test_pairwise_learning_core.py)
  • test_pair_target_semantics_is_reported_in_diagnostics_classifier / _regressor — estimator (test_pdl.py, TestPDLDiagnostics)

5. Модуль pairwise_transform.py выведены в legacy

  • legacy_pairwise_transform.py
    • Исправлен module docstring: статус deprecated
    • Добавлены DeprecationWarning при создании PDCDataTransformer и SampleWeights
    • transform теперь явно бросает NotImplementedError вместо падения на неинициализированном preprocessing_
    • fit помечает объект как fitted через _legacy_fit_complete_
    • Исправлен fit при отсутствии preprocessing_y_ (getattr)
    • Добавлены import warnings и import sklearn.metrics (раньше SampleWeights ссылался на неимпортированный модуль)
  • test_pdl_transform.py
    • Импорты переведены на legacy_pairwise_transform
    • Обновлён patch-путь для minimize.
    • Удалены мок-тесты сломанного transform; добавлен test_transform_raises_not_implemented
    • Все создания legacy-классов обёрнуты в pytest.warns(DeprecationWarning, ...)

6. Тесты на deterministic toy arrays

Статус: выполнено

tests/unit/core/models/test_pdl.py

Тест Класс Что проверяет
test_regression_pair_target_is_left_minus_anchor TestPairwiseDifferenceEstimator legacy pair_output: [0, -2, 2, 0]
test_classification_pair_target_semantics_same_is_zero_current_contract TestPairwiseDifferenceEstimator legacy pair_output_difference: [0, 0, 1]
test_pair_output_difference TestPairwiseDifferenceEstimator расширенный кейс 3×2 пар (оставлен)
test_predict_same_probability_uses_same_label_column TestPDLContracts столбец class 0 из predict_proba
test_predict_same_probability_falls_back_to_hard_predictions TestPDLContracts predict без predict_proba
test_pair_target_semantics_is_reported_in_diagnostics_classifier TestPDLDiagnostics semantics после Classifier.fit
test_pair_target_semantics_is_reported_in_diagnostics_regressor TestPDLDiagnostics semantics после Regressor.fit

Заглушки _PairProbaStub, _HardLabelStub вместо MagicMock.

tests/unit/core/models/test_pairwise_learning_core.py

Тест Что проверяет
test_classification_pair_target_semantics_same_is_zero_current_contract build_classification_pairs[0, 0, 1]
test_pair_target_semantics_is_reported_in_diagnostics batch.diagnostics clf + reg
test_predict_same_probability_uses_same_label_column _predict_same_probability на уровне core
test_regression_pair_target_uses_left_minus_anchor_sign_convention delta + feature blocks

Опционально следовало бы когда-нибудь сделать:
classification_data/regression_data используют np.random.rand без фиксированного сидирования numpy (сид есть только в train_test_split)
для воспроизводимости где-нибудь в фикстурах зафиксировать.

8. Импорты

«Добавить недостающие imports».
import warnings присутствует (legacy_pairwise_transform.py:12) это был исходный баг из Issue 2 (использование warnings.catch_warnings() без импорта).

@v1docq v1docq closed this Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants