Line data Source code
1 : /*
2 : * File: DistanceToBox.cpp
3 : * Author: Pantelis Sopasakis
4 : *
5 : * Created on October 27, 2015, 6:05 PM
6 : *
7 : * ForBES is free software: you can redistribute it and/or modify
8 : * it under the terms of the GNU Lesser General Public License as published by
9 : * the Free Software Foundation, either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * ForBES is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU Lesser General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public License
18 : * along with ForBES. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "DistanceToBox.h"
22 : #include <cmath>
23 :
24 : void checkBounds(const Matrix* lb, const Matrix* ub);
25 :
26 4 : void checkBounds(const Matrix* lb, const Matrix* ub) {
27 : //LCOV_EXCL_START
28 : if (lb == NULL || ub == NULL) {
29 : throw std::invalid_argument("LB and UB cannot be NULL");
30 : }
31 : if (lb->isEmpty()) {
32 : throw std::invalid_argument("Lower bound is not allowed to be empty");
33 : }
34 : if (ub->isEmpty()) {
35 : throw std::invalid_argument("Upper bound is not allowed to be empty");
36 : }
37 : if (!lb->isColumnVector() || !ub->isColumnVector()) {
38 : throw std::invalid_argument("UB and LB must be column vectors");
39 : }
40 : if (ub->getNcols() != lb->getNcols() || ub->getNrows() != lb->getNrows()) {
41 : throw std::invalid_argument("UB and LB and must be vectors of the same size");
42 : }
43 : if (lb->getType() != Matrix::MATRIX_DENSE || ub->getType() != Matrix::MATRIX_DENSE) {
44 : throw std::invalid_argument("UB and LB must be dense vectors - other types are not supported");
45 : }
46 : //LCOV_EXCL_STOP
47 4 : }
48 :
49 : /*
50 : * Constructors
51 : */
52 :
53 3 : DistanceToBox::DistanceToBox(Matrix* lb, Matrix* ub, Matrix* weights) :
54 3 : Function(), m_weights(weights), m_lb(lb), m_ub(ub) {
55 : //LCOV_EXCL_START
56 : if (!weights->isColumnVector() || weights->isEmpty() || weights->getNrows() != lb->getNrows()) {
57 : throw std::invalid_argument("Invalid size of weights");
58 : }
59 : //LCOV_EXCL_STOP
60 3 : checkBounds(lb, ub);
61 3 : m_is_weights_equal = false;
62 3 : m_is_bounds_uniform = false;
63 3 : m_weight = 0.0;
64 3 : m_uniform_lb = 0.0;
65 3 : m_uniform_ub = 0.0;
66 3 : }
67 :
68 1 : DistanceToBox::DistanceToBox(Matrix* lb, Matrix* ub, double weight) :
69 1 : Function(), m_weight(weight), m_lb(lb), m_ub(ub) {
70 1 : m_weights = NULL;
71 1 : checkBounds(lb, ub);
72 1 : m_is_weights_equal = true;
73 1 : m_is_bounds_uniform = false;
74 1 : m_uniform_lb = 0.0;
75 1 : m_uniform_ub = 0.0;
76 1 : }
77 :
78 1 : DistanceToBox::DistanceToBox(double uniform_lb, double uniform_ub, double weight) :
79 1 : Function(), m_weight(weight), m_uniform_lb(uniform_lb), m_uniform_ub(uniform_ub) {
80 1 : m_is_weights_equal = true;
81 1 : m_is_bounds_uniform = true;
82 1 : m_lb = NULL;
83 1 : m_ub = NULL;
84 1 : m_weights = NULL;
85 1 : }
86 :
87 6 : DistanceToBox::~DistanceToBox() {
88 : // nothing to delete
89 6 : }
90 :
91 104 : int DistanceToBox::compute_dx(const Matrix& x, const size_t n, Matrix& dx) const {
92 1112 : for (size_t i = 0; i < n; i++) {
93 1008 : if (x[i] < (m_is_bounds_uniform ? m_uniform_lb : m_lb->get(i))) {
94 4 : dx[i] = x[i] - (m_is_bounds_uniform ? m_uniform_lb : m_lb->get(i));
95 1004 : } else if (x[i] > (m_is_bounds_uniform ? m_uniform_ub : m_ub->get(i))) {
96 4 : dx[i] = x[i] - (m_is_bounds_uniform ? m_uniform_ub : m_ub->get(i));
97 : }
98 : }
99 104 : return ForBESUtils::STATUS_OK;
100 : }
101 :
102 3 : int DistanceToBox::compute_grad(Matrix& dx, const size_t n, Matrix& grad) const {
103 3 : if (!m_is_weights_equal) {
104 6 : for (size_t i = 0; i < n; i++) {
105 4 : grad.set(i, 0, m_weights->get(i, 0) * dx.get(i, 0));
106 : }
107 : } else {
108 1 : grad = m_weight * dx;
109 : }
110 3 : return ForBESUtils::STATUS_OK;
111 : }
112 :
113 104 : int DistanceToBox::compute_fun(const Matrix& dx, const size_t n, double& f) const {
114 104 : f = 0.0;
115 1112 : for (size_t i = 0; i < n; i++) {
116 1008 : f += (m_is_weights_equal ? m_weight : m_weights->get(i, 0)) * std::pow(dx.get(i, 0), 2);
117 : }
118 104 : f /= 2.0;
119 104 : return ForBESUtils::STATUS_OK;
120 : }
121 :
122 3 : int DistanceToBox::call(Matrix& x, double& f, Matrix& grad) {
123 3 : const size_t n = x.getNrows(); // input dimension
124 3 : Matrix dx(n, 1); // dx : n-by-1 (all zeros)
125 3 : compute_dx(x, n, dx); // compute d(x)
126 3 : compute_grad(dx, n, grad); // compute the gradient
127 3 : compute_fun(dx, n, f); // compute f(x)
128 3 : return ForBESUtils::STATUS_OK; // OK
129 : }
130 :
131 101 : int DistanceToBox::call(Matrix& x, double& f) {
132 101 : const size_t n = x.getNrows(); // input dimension
133 101 : Matrix dx(n, 1); // dx : n-by-1 (all zeros)
134 101 : compute_dx(x, n, dx); // compute d(x)
135 101 : compute_fun(dx, n, f); // compute f(x)
136 101 : return ForBESUtils::STATUS_OK; // OK
137 : }
138 :
139 4 : FunctionOntologicalClass DistanceToBox::category() {
140 4 : FunctionOntologicalClass distToBox("DistanceToBox");
141 4 : distToBox.set_defines_f(true);
142 4 : distToBox.set_defines_grad(true);
143 4 : distToBox.add_superclass(FunctionOntologyRegistry::distance());
144 4 : return distToBox;
145 3 : }
146 :
|