Skip to main content

trellis_runner/
result.rs

1//! This module defines the canonical output types produced by an execution.
2//!
3//! It separates:
4//! - the *user-defined result* of a computation
5//! - the final solver state
6//! - termination metadata (success vs early stop)
7
8use crate::{
9    state::{Snapshotable, StateView, UserState},
10    Termination,
11};
12use num_traits::float::FloatCore;
13
14/// Summary information describing a completed engine run.
15#[derive(Clone, Debug)]
16pub struct RunSummary<F> {
17    /// Final iteration count.
18    pub iterations: usize,
19
20    /// Total execution time.
21    pub elapsed: std::time::Duration,
22
23    /// Best metric value observed during the run.
24    pub best_measure: Option<F>,
25}
26
27impl<F> RunSummary<F> {
28    pub(crate) fn new<S>(state: StateView<'_, S>) -> RunSummary<F>
29    where
30        S: UserState<Float = F>,
31        F: FloatCore,
32    {
33        Self {
34            iterations: state.iteration(),
35            elapsed: state.duration(),
36            best_measure: Some(state.best_measure()),
37        }
38    }
39}
40
41/// Result of a completed calculation.
42///
43/// Returned by the engine run method
44#[derive(Debug)]
45pub struct EngineOutput<R, S>
46where
47    S: UserState,
48{
49    /// User-defined result produced by the procedure.
50    pub result: R,
51
52    /// Execution summary.
53    pub summary: RunSummary<S::Float>,
54
55    /// Reason execution terminated.
56    pub termination: Termination,
57}
58
59/// Result of a completed calculation including a restart snapshot.
60///
61/// Returned by the engine run_with_snapshot method
62#[derive(Debug)]
63pub struct EngineOutputWithSnapshot<R, S>
64where
65    S: UserState + Snapshotable,
66{
67    /// User-defined result produced by the procedure.
68    pub result: R,
69
70    /// Snapshot captured from the final state.
71    pub snapshot: S::Snapshot,
72
73    /// Execution summary.
74    pub summary: RunSummary<S::Float>,
75
76    /// Reason execution terminated.
77    pub termination: Termination,
78}
79
80impl<R, S> EngineOutput<R, S>
81where
82    S: UserState,
83{
84    pub(crate) fn new(result: R, state: StateView<'_, S>, termination: Termination) -> Self {
85        let summary = RunSummary::new(state);
86        Self {
87            result,
88            summary,
89            termination,
90        }
91    }
92
93    pub fn with_snapshot(self, snapshot: S::Snapshot) -> EngineOutputWithSnapshot<R, S>
94    where
95        S: UserState + Snapshotable,
96    {
97        EngineOutputWithSnapshot {
98            result: self.result,
99            summary: self.summary,
100            termination: self.termination,
101            snapshot,
102        }
103    }
104}
105
106#[derive(thiserror::Error, Debug)]
107/// Error returned when engine execution fails during procedure execution.
108///
109/// This error wraps:
110/// - the underlying procedure error (`E`)
111/// - optionally a partial output (`O`) representing the last known state
112///
113/// This is useful for partial recovery scenarios where:
114/// - execution failed mid-run
115/// - but the solver state is still meaningful
116pub struct TrellisError<O, E> {
117    #[source]
118    pub error: E,
119
120    /// Optional partial result produced before failure.
121    pub result: Option<O>,
122}
123
124impl<O, E: ::std::fmt::Debug> ::std::fmt::Display for TrellisError<O, E> {
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        writeln!(f, "Trellis error: {:?}", self.error)
127    }
128}