coco_rs/
observer.rs

1//! COCO observer.
2
3use coco_sys::coco_observer_t;
4use std::ffi::{CStr, CString};
5
6/// Observers provided by COCO.
7///
8/// The observer name should match the [`suite::Name`](crate::suite::Name).
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Name {
11    /// Observer for the BBOB suite.
12    Bbob,
13    /// Observer for the BBOB Bi-Objective suite.
14    BbobBiobj,
15    /// Observer for the toy suite.
16    Toy,
17    /// Dont use any observer.
18    None,
19}
20
21impl Name {
22    fn as_str(&self) -> &'static str {
23        match self {
24            Name::Bbob => "bbob",
25            Name::BbobBiobj => "bbob-biobj",
26            Name::Toy => "toy",
27            Name::None => "no-observer",
28        }
29    }
30}
31
32/// An observer to log results in COCO's data format.
33///
34/// Can be provided to [`Suite::next_problem`](crate::Suite::next_problem) and it will
35/// automatically be attached to the returned problem.
36pub struct Observer {
37    pub(crate) inner: *mut coco_observer_t,
38}
39
40impl Observer {
41    /// Creates a new observer.
42    ///
43    /// # observer_options
44    /// A string of pairs "key: value" used to pass the options to the observer. Some
45    /// observer options are general, while others are specific to some observers. Here we list only the general
46    /// options, see observer_bbob, observer_biobj and observer_toy for options of the specific observers.
47    /// - "result_folder: NAME" determines the folder within the "exdata" folder into which the results will be
48    /// output. If the folder with the given name already exists, first NAME_001 will be tried, then NAME_002 and
49    /// so on. The default value is "default".
50    /// - "algorithm_name: NAME", where NAME is a short name of the algorithm that will be used in plots (no
51    /// spaces are allowed). The default value is "ALG".
52    /// - "algorithm_info: STRING" stores the description of the algorithm. If it contains spaces, it must be
53    /// surrounded by double quotes. The default value is "" (no description).
54    /// - "number_target_triggers: VALUE" defines the number of targets between each 10^i and 10^(i+1)
55    /// (equally spaced in the logarithmic scale) that trigger logging. The default value is 100.
56    /// - "target_precision: VALUE" defines the precision used for targets (there are no targets for
57    /// abs(values) < target_precision). The default value is 1e-8.
58    /// - "number_evaluation_triggers: VALUE" defines the number of evaluations to be logged between each 10^i
59    /// and 10^(i+1). The default value is 20.
60    /// - "base_evaluation_triggers: VALUES" defines the base evaluations used to produce an additional
61    /// evaluation-based logging. The numbers of evaluations that trigger logging are every
62    /// base_evaluation * dimension * (10^i). For example, if base_evaluation_triggers = "1,2,5", the logger will
63    /// be triggered by evaluations dim*1, dim*2, dim*5, 10*dim*1, 10*dim*2, 10*dim*5, 100*dim*1, 100*dim*2,
64    /// 100*dim*5, ... The default value is "1,2,5".
65    /// - "precision_x: VALUE" defines the precision used when outputting variables and corresponds to the number
66    /// of digits to be printed after the decimal point. The default value is 8.
67    /// - "precision_f: VALUE" defines the precision used when outputting f values and corresponds to the number of
68    /// digits to be printed after the decimal point. The default value is 15.
69    /// - "precision_g: VALUE" defines the precision used when outputting constraints and corresponds to the number
70    /// of digits to be printed after the decimal point. The default value is 3.
71    /// - "log_discrete_as_int: VALUE" determines whether the values of integer variables (in mixed-integer problems)
72    /// are logged as integers (1) or not (0 - in this case they are logged as doubles). The default value is 0.
73    pub fn new(name: Name, options: &str) -> Option<Observer> {
74        let name = CString::new(name.as_str()).unwrap();
75        let options = CString::new(options).unwrap();
76
77        let inner = unsafe { coco_sys::coco_observer(name.as_ptr(), options.as_ptr()) };
78
79        if inner.is_null() {
80            None
81        } else {
82            Some(Observer { inner })
83        }
84    }
85
86    /// Prints where the result is written to.
87    pub fn result_folder(&self) -> &str {
88        unsafe {
89            CStr::from_ptr(coco_sys::coco_observer_get_result_folder(self.inner))
90                .to_str()
91                .unwrap()
92        }
93    }
94}
95
96impl Drop for Observer {
97    fn drop(&mut self) {
98        unsafe {
99            coco_sys::coco_observer_free(self.inner);
100        }
101    }
102}