# Classification Training Operation
#
# Train a machine learning classifier for image classification.
# Creates a model that can classify pixels based on spectral characteristics.

id: classification_train
name: Train Classifier
description: >
  Train a machine learning classifier on labeled imagery. Creates a model
  that can be used with classification_predict to classify new imagery.
  Supports Random Forest, SVM, Decision Trees, KNN, and Neural Networks.
version: 1.0.0
category: classification
type: raster-vector-to-model
default_implementation: otb

inputs:
  - name: images
    type: array
    items: raster
    description: >
      Training images. All images should have the same bands and be
      radiometrically consistent (same sensor, similar conditions).
    required: true

  - name: training_data
    type: array
    items: vector
    format: geoparquet
    description: >
      Training polygons with class labels. Each polygon represents a
      sample of a land cover class. Must have a field with class labels.
    required: true

# Structural ML op — works on any imagery + labeled-polygon pair. The bands
# present in the training images become the bands the resulting model
# expects; the op itself has no fixed band requirement.
requires: {}

outputs:
  - name: model
    type: file
    format: model
    # No concept slug — output is a model artifact (sklearn-style file), not
    # a concept-bearing raster. The target concept lives downstream in
    # classification_predict's invocation context.
    description: >
      Trained classifier model file. Can be used with classification_predict
      to classify new imagery.

  - name: statistics
    type: file
    format: json
    description: >
      Training statistics including confusion matrix, accuracy metrics,
      and feature importance (for applicable classifiers).

params:
  classifier:
    type: enum
    enum: [rf, svm, dt, knn, ann]
    default: rf
    description: >
      Classifier algorithm:
      - rf: Random Forest (default) - robust, handles noise well
      - svm: Support Vector Machine - good for small training sets
      - dt: Decision Tree - fast, interpretable
      - knn: K-Nearest Neighbors - simple, no training phase
      - ann: Artificial Neural Network - complex patterns

  label_field:
    type: string
    default: class
    description: Field name in training_data containing class labels

  # Random Forest parameters
  rf_trees:
    type: integer
    default: 100
    description: Number of trees in the forest (rf only)
    min: 10
    max: 1000

  rf_max_depth:
    type: integer
    default: 25
    description: Maximum depth of each tree (rf only)
    min: 1
    max: 100

  rf_min_samples:
    type: integer
    default: 5
    description: Minimum samples required at a leaf node (rf only)
    min: 1
    max: 100

  # SVM parameters
  svm_kernel:
    type: enum
    enum: [linear, rbf, poly, sigmoid]
    default: rbf
    description: SVM kernel type (svm only)

  svm_c:
    type: number
    default: 1.0
    description: SVM regularization parameter (svm only)
    min: 0.001
    max: 1000

  # Sampling parameters
  sample_strategy:
    type: enum
    enum: [all, smallest, constant, percent]
    default: smallest
    description: >
      How to balance samples across classes:
      - all: Use all available samples
      - smallest: Match the smallest class
      - constant: Fixed number per class
      - percent: Percentage of available samples

  sample_count:
    type: integer
    default: 1000
    description: Samples per class (for constant/percent strategies)
    min: 10
    max: 100000

execution:
  realtime_max_km2: 50
  cost_per_km2: 0.02
  time_per_km2_sec: 10.0
  memory_profile: high

# backends: audited 2026-08-14 (defect 50). A key means a runtime that DISPATCHES this op —
# folia-engine `dispatch_op` (products/sdk/folia-engine/src/lib.rs), a `registerOp`/OP_TABLE
# entry in packages/compute, `_BUILTIN_OP_MAP` in folia/compute.py, or a backend manifest
# (folia/backends/*/backend.yaml).
backends:
  js:
    function: classification_train
    dispatch: packages/compute/src/ops/classify-rf.ts
  python:
    function: geo.otb.train_classifier
    dispatch: folia/compute.py _BUILTIN_OP_MAP

display_hints:
  table:
    renderer: tanstack-table
    sortBy: accuracy
    sortOrder: desc
  chart:
    renderer: observable-plot
    chartType: bar

cache_policy:
  ttl_days: 90
  invalidate_on: [training_data_update]

examples:
  - name: Land cover classification
    description: Train Random Forest for land cover mapping
    inputs:
      images: ["sentinel2_summer.tif", "sentinel2_winter.tif"]
      training_data: ["landcover_training.gpkg"]
    params:
      classifier: rf
      label_field: landcover_class
      rf_trees: 200
      rf_max_depth: 30
