ProblemType Trait

The ProblemType trait defines the interface for a calibration problem. It specifies the types for configuration, input, state, output, and export, along with validation and lifecycle hooks. The trait is intentionally minimal — behavior is implemented in external step functions, not trait methods.

Definition

#![allow(unused)]
fn main() {
pub trait ProblemType: Sized + 'static {
    type Config: Clone + Default + Serialize + DeserializeOwned + Debug;
    type Input: Clone + Serialize + DeserializeOwned + Debug;
    type State: Clone + Default + Serialize + DeserializeOwned + Debug;
    type Output: Clone + Serialize + DeserializeOwned + Debug;
    type Export: Clone + Serialize + DeserializeOwned + Debug;

    fn name() -> &'static str;
    fn schema_version() -> u32 { 1 }

    fn validate_input(input: &Self::Input) -> Result<()> { Ok(()) }
    fn validate_config(config: &Self::Config) -> Result<()> { Ok(()) }
    fn validate_input_config(
        input: &Self::Input, config: &Self::Config
    ) -> Result<()> { Ok(()) }

    fn on_input_change() -> InvalidationPolicy {
        InvalidationPolicy::CLEAR_COMPUTED
    }
    fn on_config_change() -> InvalidationPolicy {
        InvalidationPolicy::KEEP_ALL
    }

    fn export(
        output: &Self::Output, config: &Self::Config
    ) -> Result<Self::Export>;
}
}

Associated Types

TypePurposeRequirements
ConfigAlgorithm parametersDefault (sensible defaults)
InputObservation dataValidated on set
StateIntermediate resultsDefault (empty initial state)
OutputFinal calibration resultSet by last step
ExportUser-facing resultCreated from Output + Config

The Serialize + DeserializeOwned bounds enable JSON checkpointing. Clone enables snapshot operations.

Required Method: name()

Returns a stable string identifier for the problem type:

#![allow(unused)]
fn main() {
fn name() -> &'static str { "planar_intrinsics_v2" }
}

This is stored in session metadata and used for deserialization. Changing the name breaks compatibility with existing checkpoints.

Required Method: export()

Converts the internal output to a user-facing export format:

#![allow(unused)]
fn main() {
fn export(output: &Self::Output, config: &Self::Config) -> Result<Self::Export>;
}

The export may transform, filter, or enrich the output. For example, PlanarIntrinsicsProblem::export() computes reprojection error metrics from the raw optimization output.

Validation Hooks

Three optional validation hooks run at specific points:

HookWhen it runs
validate_input(input)On session.set_input(input)
validate_config(config)On session.set_config(config) or update_config()
validate_input_config(input, config)When both input and config are present

Example: PlanarIntrinsicsProblem validates that input has ≥ 3 views with ≥ 4 points each.

Invalidation Policies

Control what happens when input or config changes:

#![allow(unused)]
fn main() {
pub struct InvalidationPolicy {
    pub clear_state: bool,
    pub clear_output: bool,
    pub clear_exports: bool,
}

impl InvalidationPolicy {
    pub const KEEP_ALL: Self = ...;       // Nothing cleared
    pub const CLEAR_COMPUTED: Self = ...; // State + output cleared
    pub const CLEAR_ALL: Self = ...;      // Everything cleared
}
}

Defaults:

  • Input change → CLEAR_COMPUTED (re-running steps is needed)
  • Config change → KEEP_ALL (output is still valid, but may not reflect new config)

Existing Problem Types

TypeNameSteps
PlanarIntrinsicsProblem"planar_intrinsics_v2"init → optimize
SingleCamHandeyeProblem"single_cam_handeye"intrinsics_init → intrinsics_optimize → handeye_init → handeye_optimize
RigExtrinsicsProblem"rig_extrinsics"intrinsics_init_all → intrinsics_optimize_all → rig_init → rig_optimize
RigHandeyeProblem"rig_handeye"6 steps (intrinsics + rig + handeye)
LaserlineDeviceProblem"laserline_device"init → optimize

Design Philosophy

The trait is minimal by design:

  • No step methods: Steps are free functions, not trait methods. This allows flexible composition and avoids trait object limitations.
  • No algorithm logic: The trait defines data types and validation, not computation.
  • Serialization-first: All types are serializable, enabling checkpointing from day one.