4242//! println!("Solve time: {:.3}ms", stats.solve_time.as_secs_f64() * 1000.0);
4343//! println!("Peak memory usage: {}MB", stats.peak_memory_mb);
4444//! println!("Problem size: {} variables, {} constraints",
45- //! stats.variable_count , stats.constraint_count);
45+ //! stats.variables , stats.constraint_count);
4646//!
4747//! // Use convenience analysis methods
4848//! println!("Search efficiency: {:.1} propagations/node", stats.efficiency());
8383//! println!(" Peak memory: {}MB", stats.peak_memory_mb);
8484//!
8585//! println!("Problem characteristics:");
86- //! println!(" Variables: {}", stats.variable_count );
86+ //! println!(" Variables: {}", stats.variables );
8787//! println!(" Constraints: {}", stats.constraint_count);
8888//!
8989//! // Use all convenience analysis methods
@@ -141,28 +141,67 @@ impl std::error::Error for ValueAccessError {}
141141/// Statistics collected during the solving process.
142142#[ derive( Clone , Debug , Default , PartialEq ) ]
143143pub struct SolveStats {
144+ // ===== Search Metrics =====
144145 /// Number of propagation steps performed during solving
145146 pub propagation_count : usize ,
146147 /// Number of search nodes (branching points) explored during solving
147148 pub node_count : usize ,
148- /// Total time spent solving
149+
150+ // ===== Timing =====
151+ /// Total time spent solving (in seconds)
149152 pub solve_time : Duration ,
150- /// Number of variables in the problem
151- pub variable_count : usize ,
153+ /// Initialisation time (in seconds)
154+ pub init_time : Duration ,
155+
156+ // ===== Memory =====
157+ /// Peak memory usage during solving (in MB)
158+ ///
159+ /// This is the TOTAL peak memory used, including:
160+ /// - CSP solver memory (search stack, variables, propagators)
161+ /// - LP solver memory (if LP was used)
162+ ///
163+ /// For breakdown of LP-specific memory, see lp_stats.peak_memory_mb
164+ pub peak_memory_mb : usize ,
165+
166+ // ===== Variable Counts =====
167+ /// Total number of variables
168+ pub variables : usize ,
169+ /// Number of integer variables created
170+ pub int_variables : usize ,
171+ /// Number of bool variables created
172+ pub bool_variables : usize ,
173+ /// Number of float variables created
174+ pub float_variables : usize ,
175+ /// Number of set variables created
176+ pub set_variables : usize ,
177+
178+ // ===== Constraint Metrics =====
152179 /// Number of constraints in the problem
153180 pub constraint_count : usize ,
154- /// Peak memory usage estimate during solving (in MB)
155- pub peak_memory_mb : usize ,
181+ /// Number of propagators created
182+ pub propagators : usize ,
183+
184+ // ===== Objective =====
185+ /// Current objective value
186+ pub objective : f64 ,
187+ /// Dual bound on the objective value
188+ pub objective_bound : f64 ,
189+
190+ // ===== LP Solver Integration =====
156191 /// Whether the LP solver was used during solving
157192 pub lp_solver_used : bool ,
158193 /// Number of linear constraints extracted for LP solver
159194 pub lp_constraint_count : usize ,
195+ /// Number of variables used in LP solver (subset of total variables that appear in linear constraints)
196+ pub lp_variable_count : usize ,
160197 /// Statistics from LP solver (if used)
161198 pub lp_stats : Option < crate :: lpsolver:: types:: LpStats > ,
162199}
163200
164201impl SolveStats {
165- /// Create new statistics with all fields
202+ /// Create new statistics with core fields (for backward compatibility)
203+ ///
204+ /// Other fields are set to default values.
166205 pub fn new (
167206 propagation_count : usize ,
168207 node_count : usize ,
@@ -175,11 +214,68 @@ impl SolveStats {
175214 propagation_count,
176215 node_count,
177216 solve_time,
178- variable_count,
217+ variables : variable_count,
179218 constraint_count,
180219 peak_memory_mb,
220+ init_time : Duration :: ZERO ,
221+
222+ int_variables : 0 ,
223+ bool_variables : 0 ,
224+ float_variables : 0 ,
225+ set_variables : 0 ,
226+
227+ propagators : 0 ,
228+ objective : 0.0 ,
229+ objective_bound : 0.0 ,
230+
231+ lp_solver_used : false ,
232+ lp_constraint_count : 0 ,
233+ lp_variable_count : 0 ,
234+ lp_stats : None ,
235+ }
236+ }
237+
238+ /// Create new statistics with all fields
239+ pub fn with_all_fields (
240+ propagation_count : usize ,
241+ node_count : usize ,
242+ solve_time : Duration ,
243+ init_time : Duration ,
244+ variables : usize ,
245+ int_variables : usize ,
246+ bool_variables : usize ,
247+ float_variables : usize ,
248+ set_variables : usize ,
249+ constraint_count : usize ,
250+ propagators : usize ,
251+ peak_memory_mb : usize ,
252+ objective : f64 ,
253+ objective_bound : f64 ,
254+ ) -> Self {
255+ Self {
256+ propagation_count,
257+ node_count,
258+
259+ solve_time,
260+ init_time,
261+
262+ peak_memory_mb,
263+
264+ variables,
265+ int_variables,
266+ bool_variables,
267+ float_variables,
268+ set_variables,
269+
270+ constraint_count,
271+ propagators,
272+
273+ objective,
274+ objective_bound,
275+
181276 lp_solver_used : false ,
182277 lp_constraint_count : 0 ,
278+ lp_variable_count : 0 ,
183279 lp_stats : None ,
184280 }
185281 }
@@ -214,20 +310,71 @@ impl SolveStats {
214310 /// Display a summary of the solving statistics
215311 pub fn display_summary ( & self ) {
216312 println ! ( "=== Solving Statistics ===" ) ;
217- println ! ( "Time: {:.3}ms" , self . solve_time. as_secs_f64( ) * 1000.0 ) ;
218- println ! ( "Memory: {}MB peak usage" , self . peak_memory_mb) ;
219- println ! ( "Problem: {} variables, {} constraints" , self . variable_count, self . constraint_count) ;
220- println ! ( "Search: {} propagations, {} nodes" ,
221- self . propagation_count, self . node_count) ;
222313
223- if self . node_count > 0 {
224- println ! ( "Efficiency: {:.1} propagations/node" , self . efficiency( ) ) ;
225- } else {
226- println ! ( "Efficiency: Pure propagation (no search required)" ) ;
314+ // Timing
315+ println ! ( "Timing:" ) ;
316+ println ! ( " Solve time: {:.3}ms" , self . solve_time. as_secs_f64( ) * 1000.0 ) ;
317+ println ! ( " Init time: {:.3}ms" , self . init_time. as_secs_f64( ) * 1000.0 ) ;
318+
319+ // Memory
320+ println ! ( "Memory:" ) ;
321+ println ! ( " Total peak usage: {}MB" , self . peak_memory_mb) ;
322+
323+ // LP Solver information (if used)
324+ if self . lp_solver_used {
325+ if let Some ( ref lp_stats) = self . lp_stats {
326+ println ! ( " (includes LP solver: {:.2}MB)" , lp_stats. peak_memory_mb) ;
327+ }
227328 }
228329
229- if self . propagation_count > 0 {
230- println ! ( "Performance: {:.2}μs/propagation" ,
330+ // Problem characteristics
331+ println ! ( "Problem:" ) ;
332+ println ! ( " Total variables: {}" , self . variables) ;
333+ if self . int_variables > 0 {
334+ println ! ( " - Integer: {}" , self . int_variables) ;
335+ }
336+ if self . bool_variables > 0 {
337+ println ! ( " - Bool: {}" , self . bool_variables) ;
338+ }
339+ if self . float_variables > 0 {
340+ println ! ( " - Float: {}" , self . float_variables) ;
341+ }
342+ if self . set_variables > 0 {
343+ println ! ( " - Set: {}" , self . set_variables) ;
344+ }
345+ println ! ( " Constraints: {}" , self . constraint_count) ;
346+ println ! ( " Propagators: {}" , self . propagators) ;
347+
348+ // LP Solver information (if used)
349+ if self . lp_solver_used {
350+ println ! ( "LP Solver:" ) ;
351+ println ! ( " Linear constraints: {}" , self . lp_constraint_count) ;
352+ println ! ( " Linear variables: {}" , self . lp_variable_count) ;
353+ }
354+
355+ // Search metrics
356+ println ! ( "Search:" ) ;
357+ println ! ( " Nodes: {}" , self . node_count) ;
358+ println ! ( " Propagations: {}" , self . propagation_count) ;
359+
360+ // Objective (if applicable)
361+ if self . objective != 0.0 || self . objective_bound != 0.0 {
362+ println ! ( "Objective:" ) ;
363+ println ! ( " Current value: {}" , self . objective) ;
364+ println ! ( " Bound: {}" , self . objective_bound) ;
365+ }
366+
367+ // Efficiency analysis
368+ if self . node_count > 0 {
369+ println ! ( "Efficiency:" ) ;
370+ println ! ( " {:.1} propagations/node" , self . efficiency( ) ) ;
371+ println ! ( " {:.2}μs/propagation" ,
372+ self . time_per_propagation( ) . as_nanos( ) as f64 / 1000.0 ) ;
373+ println ! ( " {:.2}μs/node" ,
374+ self . time_per_node( ) . as_nanos( ) as f64 / 1000.0 ) ;
375+ } else if self . propagation_count > 0 {
376+ println ! ( "Efficiency: Pure propagation (no search required)" ) ;
377+ println ! ( " {:.2}μs/propagation" ,
231378 self . time_per_propagation( ) . as_nanos( ) as f64 / 1000.0 ) ;
232379 }
233380 println ! ( "==========================" ) ;
0 commit comments