1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
//! COCO problem instance.
use coco_sys::coco_problem_t;
use std::{ffi::CStr, marker::PhantomData, ops::RangeInclusive};
use crate::{
suite::{self, Suite},
Observer,
};
/// A specific problem instance.
///
/// Instances can be optained using [Suite::next_problem]
/// and [Suite::problem_by_function_dimension_instance].
pub struct Problem<'suite> {
pub(crate) inner: *mut coco_problem_t,
_phantom: PhantomData<&'suite Suite>,
}
unsafe impl Send for Problem<'_> {}
impl<'suite> Problem<'suite> {
pub(crate) fn new(inner: *mut coco_problem_t, _suite: &'suite Suite) -> Self {
Problem {
inner,
_phantom: PhantomData,
}
}
}
impl Problem<'_> {
/// Returns the ID of the problem.
///
/// For the `toy` suite this is
/// - `{function-name}_d{dimension}`
///
/// For `bbob` it is
/// - bbob_f{function-index}_i{instance}_d{dimension}
pub fn id(&self) -> &str {
unsafe {
CStr::from_ptr(coco_sys::coco_problem_get_id(self.inner))
.to_str()
.unwrap()
}
}
/// Returns the name of the problem.
pub fn name(&self) -> &str {
unsafe {
CStr::from_ptr(coco_sys::coco_problem_get_name(self.inner))
.to_str()
.unwrap()
}
}
/// Returns the type of the problem.
pub fn typ(&self) -> &str {
unsafe {
CStr::from_ptr(coco_sys::coco_problem_get_type(self.inner))
.to_str()
.unwrap()
}
}
/// Adds an observer to the given problem.
pub fn add_observer(&mut self, observer: &Observer) {
// The Python bindings also mutate the problem instead of returning a new one.
self.inner = unsafe { coco_sys::coco_problem_add_observer(self.inner, observer.inner) };
assert!(!self.inner.is_null())
}
/// Removes an observer to the given problem.
pub fn remove_observer(&mut self, observer: &Observer) {
// The Python bindings also mutate the problem instead of returning a new one.
self.inner = unsafe { coco_sys::coco_problem_remove_observer(self.inner, observer.inner) };
assert!(!self.inner.is_null())
}
/// Returns the problem index of the problem in its current suite.
pub fn suite_index(&self) -> suite::ProblemIdx {
let idx = unsafe { coco_sys::coco_problem_get_suite_dep_index(self.inner) };
suite::ProblemIdx(idx)
}
/// Evaluates the problem at `x` and returns the result in `y`.
///
/// The length of `x` must match [Problem::dimension] and the
/// length of `y` must match [Problem::number_of_objectives].
pub fn evaluate_function(&mut self, x: &[f64], y: &mut [f64]) {
assert_eq!(self.dimension(), x.len());
assert_eq!(self.number_of_objectives(), y.len());
unsafe {
coco_sys::coco_evaluate_function(self.inner, x.as_ptr(), y.as_mut_ptr());
}
}
/// Evaluates the problem constraints in point x and save the result in y.
///
/// The length of `x` must match [Problem::dimension] and the
/// length of `y` must match [Problem::number_of_constraints].
pub fn evaluate_constraint(&mut self, x: &[f64], y: &mut [f64]) {
assert_eq!(self.dimension(), x.len());
assert_eq!(self.number_of_constraints(), y.len());
unsafe {
coco_sys::coco_evaluate_constraint(self.inner, x.as_ptr(), y.as_mut_ptr());
}
}
/// Returns true if a previous evaluation hit the target value.
pub fn final_target_hit(&self) -> bool {
unsafe { coco_sys::coco_problem_final_target_hit(self.inner) == 1 }
}
/// Returns the optimal function value + delta of the problem
pub fn final_target_value(&self) -> f64 {
unsafe { coco_sys::coco_problem_get_final_target_fvalue1(self.inner) }
}
/// Returns the optimal function value of the problem
///
/// To check whether the target has been reached use [[Problem::final_target_value]]
/// or [[Problem::final_target_hit]] instead.
pub fn best_value(&self) -> f64 {
unsafe { coco_sys::coco_problem_get_best_value(self.inner) }
}
/// Returns the best observed value for the first objective.
pub fn best_observed_value(&self) -> f64 {
unsafe { coco_sys::coco_problem_get_best_observed_fvalue1(self.inner) }
}
/// Returns the dimension of the problem.
pub fn dimension(&self) -> usize {
unsafe {
coco_sys::coco_problem_get_dimension(self.inner)
.try_into()
.unwrap()
}
}
/// Returns the number of objectives of the problem.
pub fn number_of_objectives(&self) -> usize {
unsafe {
coco_sys::coco_problem_get_number_of_objectives(self.inner)
.try_into()
.unwrap()
}
}
/// Returns the number of constraints of the problem.
pub fn number_of_constraints(&self) -> usize {
unsafe {
coco_sys::coco_problem_get_number_of_constraints(self.inner)
.try_into()
.unwrap()
}
}
/// Returns the numver of integer variables of the problem.
///
/// The first `n` variables will be integers then.
/// Returns `0` if all variables are continuous.
pub fn number_of_integer_variables(&self) -> usize {
unsafe {
coco_sys::coco_problem_get_number_of_integer_variables(self.inner)
.try_into()
.unwrap()
}
}
/// Returns the upper and lover bounds of the problem.
pub fn ranges_of_interest(&self) -> Vec<RangeInclusive<f64>> {
let dimension = self.dimension() as isize;
unsafe {
let smallest = coco_sys::coco_problem_get_smallest_values_of_interest(self.inner);
let largest = coco_sys::coco_problem_get_largest_values_of_interest(self.inner);
(0..dimension)
.map(|i| (*smallest.offset(i))..=(*largest.offset(i)))
.collect()
}
}
/// Returns how often this instance has been evaluated.
pub fn evaluations(&self) -> u64 {
unsafe {
#[allow(clippy::useless_conversion)]
coco_sys::coco_problem_get_evaluations(self.inner)
.try_into()
.unwrap()
}
}
/// Returns how often this instances constrants have been evaluated.
pub fn evaluations_constraints(&self) -> u64 {
unsafe {
#[allow(clippy::useless_conversion)]
coco_sys::coco_problem_get_evaluations_constraints(self.inner)
.try_into()
.unwrap()
}
}
/// Writes a feasible initial solution into `x`.
///
/// If the problem does not provide a specific solution,
/// it will be the center of the problem's region of interest.
pub fn initial_solution(&self, x: &mut [f64]) {
assert_eq!(self.dimension(), x.len());
unsafe {
coco_sys::coco_problem_get_initial_solution(self.inner, x.as_mut_ptr());
}
}
}
impl Drop for Problem<'_> {
fn drop(&mut self) {
unsafe {
coco_sys::coco_problem_free(self.inner);
}
}
}