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
//! Validation methods for bounded arrays and vectors.
use crate::ValidationError;
use nalgebra::{DMatrix, DVector};
pub trait MatrixValidate {
/// Validates the bounds for each criteria follows the form $[min, max]$.
///
/// This function checks that the bounds matrix has exactly two columns and that, for each row,
/// the first column (minimum value) is less than the second column (maximum value).
///
/// # Returns
///
/// * `Result<(), ValidationError>` - Returns `Ok(())` if the bounds matrix is valid.
///
/// # Errors
///
/// * [`ValidationError::InvalidShape`] - If the bounds matrix does not have exactly two
/// columns.
/// * [`ValidationError::InvalidValue`] - If any row in the bounds matrix has a minimum value
/// that is not less than the maximum value.
fn is_bounds_valid(&self) -> Result<(), ValidationError>;
/// Validates that the reference ideal matrix is within the specified bounds.
///
/// This function checks that each element of the reference ideal matrix is within the
/// corresponding bounds specified in the bounds matrix. The bounds matrix should have two
/// columns, where the first column represents the minimum values and the second column
/// represents the maximum values.
///
/// # Arguments
///
/// * `bounds` - A `DMatrix<f64>` representing the bounds for each criterion.
///
/// # Returns
///
/// * `Result<(), ValidationError>` - Returns `Ok(())` if the reference ideal matrix is within
/// the bounds.
///
/// # Errors
///
/// * [`ValidationError::InvalidShape`] - If the bounds matrix does not have exactly two
/// columns.
/// * [`ValidationError::DimensionMismatch`] - If any element of the reference ideal matrix is
/// outside the specified bounds.
fn is_reference_ideal_bounds_valid(&self, bounds: &DMatrix<f64>)
-> Result<(), ValidationError>;
/// Ensures that the decision matrix is within the specified bounds.
///
/// This function checks that each element of the decision matrix is within the corresponding
/// bounds specified in the bounds matrix. The bounds matrix should have two columns, where the
/// first column represents the minimum values and the second column represents the maximum
/// values.
///
/// # Arguments
///
/// * `bounds` - A `DMatrix<f64>` representing the bounds for each criterion.
///
/// # Returns
///
/// * `Result<(), ValidationError>` - Returns `Ok(())` if the decision matrix is within the
/// bounds.
///
/// # Errors
///
/// * [`ValidationError::InvalidShape`] - If the bounds matrix does not have exactly two
/// columns.
fn is_within_bounds(&self, bounds: &DMatrix<f64>) -> Result<(), ValidationError>;
}
pub trait VectorValidate {
/// Validates that the expected solution point values lie within the specified bounds for each
/// criterion.
///
/// This function checks that each element of the expected solution point vector is within the
/// corresponding bounds specified in the bounds matrix. The bounds matrix should have two
/// columns, where the first column represents the minimum values and the second column
/// represents the maximum values.
///
/// # Arguments
///
/// * `bounds` - A `DMatrix<f64>` representing the bounds for each criterion. The shape should
/// be $(n, 2)$ where $n$ is the number of criteria. Each row defines the minimum and maximum
/// values for a criterion and must be in the form $[min, max]$.
///
/// # Returns
///
/// * `Result<(), ValidationError>` - Returns `Ok(())` if the expected solution point values are
/// within the bounds.
///
/// # Errors
///
/// * [`ValidationError::DimensionMismatch`] - If the length of the expected solution point
/// vector does not match the number of rows in the bounds matrix.
/// * [`ValidationError::InvalidValue`] - If any element of the expected solution point vector
/// is outside the specified bounds.
fn is_expected_solution_point_in_bounds(
&self,
bounds: &DMatrix<f64>,
) -> Result<(), ValidationError>;
}
impl MatrixValidate for DMatrix<f64> {
fn is_bounds_valid(&self) -> Result<(), ValidationError> {
if self.ncols() != 2 {
return Err(ValidationError::InvalidShape);
}
for row in self.row_iter() {
let min = row[0];
let max = row[1];
if min >= max {
return Err(ValidationError::InvalidValue);
}
}
Ok(())
}
fn is_reference_ideal_bounds_valid(
&self,
bounds: &DMatrix<f64>,
) -> Result<(), ValidationError> {
if self.ncols() != 2 {
return Err(ValidationError::InvalidShape);
}
if self.shape() != bounds.shape() {
return Err(ValidationError::DimensionMismatch);
}
for (i, row) in self.row_iter().enumerate() {
let min = bounds[(i, 0)];
let max = bounds[(i, 1)];
if (row[0] < min || row[1] > max) || row[0] > row[1] {
return Err(ValidationError::InvalidValue);
}
}
Ok(())
}
fn is_within_bounds(&self, bounds: &DMatrix<f64>) -> Result<(), ValidationError> {
if self.ncols() != bounds.nrows() {
return Err(ValidationError::InvalidShape);
}
bounds.is_bounds_valid()?;
for (i, col) in self.column_iter().enumerate() {
let min = bounds[(i, 0)];
let max = bounds[(i, 1)];
if col.min() < min || col.max() > max {
return Err(ValidationError::InvalidValue);
}
}
Ok(())
}
}
impl VectorValidate for DVector<f64> {
fn is_expected_solution_point_in_bounds(
&self,
bounds: &DMatrix<f64>,
) -> Result<(), ValidationError> {
bounds.is_bounds_valid()?;
if self.len() != bounds.nrows() {
return Err(ValidationError::DimensionMismatch);
}
for (i, row) in bounds.row_iter().enumerate() {
let min = row[0];
let max = row[1];
if self[i] < min || self[i] > max {
return Err(ValidationError::InvalidValue);
}
}
Ok(())
}
}