PaGMO  1.1.5
problem/base.cpp
1 /*****************************************************************************
2  * Copyright (C) 2004-2015 The PaGMO development team, *
3  * Advanced Concepts Team (ACT), European Space Agency (ESA) *
4  * *
5  * https://github.com/esa/pagmo *
6  * *
7  * act@esa.int *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the *
21  * Free Software Foundation, Inc., *
22  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23  *****************************************************************************/
24 
25 // 30/01/10 Created by Francesco Biscani.
26 
27 #include <algorithm>
28 #include <boost/math/special_functions/fpclassify.hpp>
29 #include <boost/numeric/conversion/bounds.hpp>
30 #include <boost/numeric/conversion/cast.hpp>
31 #include <boost/random/uniform_real.hpp>
32 #include <boost/ref.hpp>
33 #include <cmath>
34 #include <climits>
35 #include <cstddef>
36 #include <iostream>
37 #include <iterator>
38 #include <numeric>
39 #include <sstream>
40 #include <string>
41 #include <typeinfo>
42 #include <vector>
43 
44 #include "../exceptions.h"
45 #include "../population.h"
46 #include "../types.h"
47 #include "base.h"
48 
49 namespace pagmo
50 {
51 namespace problem {
52 
54 
65 base::base(int n, int ni, int nf, int nc, int nic, const double &c_tol): //TODO should we use size_type directly?
66  m_i_dimension(boost::numeric_cast<size_type>(ni)),m_f_dimension(boost::numeric_cast<f_size_type>(nf)),
67  m_c_dimension(boost::numeric_cast<c_size_type>(nc)),m_ic_dimension(boost::numeric_cast<c_size_type>(nic)),
68  m_c_tol(nc,c_tol),
69  m_decision_vector_cache_f(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
70  m_fitness_vector_cache(boost::numeric_cast<fitness_vector_cache_type::size_type>(cache_capacity)),
71  m_decision_vector_cache_c(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
72  m_constraint_vector_cache(boost::numeric_cast<constraint_vector_cache_type::size_type>(cache_capacity)),
73  m_best_x(0),
74  m_best_f(0),
75  m_best_c(0),
76  m_fevals(0),
77  m_cevals(0)
78 {
79  if (c_tol < 0) {
80  pagmo_throw(value_error,"constraints tolerance must be non-negative");
81  }
82  if (n <= 0 || !nf || ni > n || nic > nc) {
83  pagmo_throw(value_error,"invalid dimension(s)");
84  }
85  const size_type size = boost::numeric_cast<size_type>(n);
86  m_lb.resize(size);
87  m_ub.resize(size);
88  std::fill(m_lb.begin(),m_lb.end(),0);
89  std::fill(m_ub.begin(),m_ub.end(),1);
90  // Resize properly temporary fitness and constraint storage.
91  m_tmp_f1.resize(m_f_dimension);
92  m_tmp_f2.resize(m_f_dimension);
93  m_tmp_c1.resize(m_c_dimension);
94  m_tmp_c2.resize(m_c_dimension);
95  // Normalise bounds.
96  normalise_bounds();
97 }
98 
100 
111 base::base(int n, int ni, int nf, int nc, int nic, const std::vector<double> &c_tol): //TODO should we use size_type directly?
112  m_i_dimension(boost::numeric_cast<size_type>(ni)),m_f_dimension(boost::numeric_cast<f_size_type>(nf)),
113  m_c_dimension(boost::numeric_cast<c_size_type>(nc)),m_ic_dimension(boost::numeric_cast<c_size_type>(nic)),
114  m_c_tol(c_tol),
115  m_decision_vector_cache_f(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
116  m_fitness_vector_cache(boost::numeric_cast<fitness_vector_cache_type::size_type>(cache_capacity)),
117  m_decision_vector_cache_c(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
118  m_constraint_vector_cache(boost::numeric_cast<constraint_vector_cache_type::size_type>(cache_capacity)),
119  m_best_x(0),
120  m_best_f(0),
121  m_best_c(0),
122  m_fevals(0),
123  m_cevals(0)
124 {
125  if (c_tol.size() != static_cast<constraint_vector::size_type>(nc) ) {
126  pagmo_throw(value_error,"invalid constraints vector dimension");
127  }
128  for(unsigned int i=0; i<(m_c_dimension - m_ic_dimension);i++) {
129  if (c_tol[i] < 0) {
130  pagmo_throw(value_error,"constraints tolerance must be non-negative for equality constraints");
131  }
132  }
133  if (n <= 0 || !nf || ni > n || nic > nc) {
134  pagmo_throw(value_error,"invalid dimension(s)");
135  }
136  const size_type size = boost::numeric_cast<size_type>(n);
137  m_lb.resize(size);
138  m_ub.resize(size);
139  std::fill(m_lb.begin(),m_lb.end(),0);
140  std::fill(m_ub.begin(),m_ub.end(),1);
141  // Resize properly temporary fitness and constraint storage.
142  m_tmp_f1.resize(m_f_dimension);
143  m_tmp_f2.resize(m_f_dimension);
144  m_tmp_c1.resize(m_c_dimension);
145  m_tmp_c2.resize(m_c_dimension);
146  // Normalise bounds.
147  normalise_bounds();
148 }
149 
151 
164 base::base(const double &l_value, const double &u_value, int n, int ni, int nf, int nc, int nic, const double &c_tol):
165  m_i_dimension(boost::numeric_cast<size_type>(ni)),m_f_dimension(boost::numeric_cast<f_size_type>(nf)),
166  m_c_dimension(boost::numeric_cast<c_size_type>(nc)),m_ic_dimension(boost::numeric_cast<c_size_type>(nic)),
167  m_c_tol(nc,c_tol),
168  m_decision_vector_cache_f(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
169  m_fitness_vector_cache(boost::numeric_cast<fitness_vector_cache_type::size_type>(cache_capacity)),
170  m_decision_vector_cache_c(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
171  m_constraint_vector_cache(boost::numeric_cast<constraint_vector_cache_type::size_type>(cache_capacity)),
172  m_best_x(0),
173  m_best_f(0),
174  m_best_c(0),
175  m_fevals(0),
176  m_cevals(0)
177 {
178  if (c_tol < 0) {
179  pagmo_throw(value_error,"constraints tolerance must be non-negative");
180  }
181  if (n <= 0 || !nf || ni > n || nic > nc) {
182  pagmo_throw(value_error,"invalid dimension(s)");
183  }
184  if (l_value > u_value) {
185  pagmo_throw(value_error,"value for lower bounds cannot be greater than value for upper bounds");
186  }
187  const size_type size = boost::numeric_cast<size_type>(n);
188  m_lb.resize(size);
189  m_ub.resize(size);
190  std::fill(m_lb.begin(),m_lb.end(),l_value);
191  std::fill(m_ub.begin(),m_ub.end(),u_value);
192  // Resize properly temporary fitness and constraint storage.
193  m_tmp_f1.resize(m_f_dimension);
194  m_tmp_f2.resize(m_f_dimension);
195  m_tmp_c1.resize(m_c_dimension);
196  m_tmp_c2.resize(m_c_dimension);
197  // Normalise bounds.
198  normalise_bounds();
199 }
200 
202 
215 base::base(const decision_vector &lb, const decision_vector &ub, int ni, int nf, int nc, int nic, const double &c_tol):
216  m_i_dimension(boost::numeric_cast<size_type>(ni)),m_f_dimension(boost::numeric_cast<f_size_type>(nf)),
217  m_c_dimension(boost::numeric_cast<c_size_type>(nc)),m_ic_dimension(boost::numeric_cast<c_size_type>(nic)),
218  m_c_tol(nc,c_tol),
219  m_decision_vector_cache_f(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
220  m_fitness_vector_cache(boost::numeric_cast<fitness_vector_cache_type::size_type>(cache_capacity)),
221  m_decision_vector_cache_c(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity)),
222  m_constraint_vector_cache(boost::numeric_cast<constraint_vector_cache_type::size_type>(cache_capacity)),
223  m_best_x(0),
224  m_best_f(0),
225  m_best_c(0),
226  m_fevals(0),
227  m_cevals(0)
228 {
229  if (c_tol < 0) {
230  pagmo_throw(value_error,"constraints tolerance must be non-negative");
231  }
232  if (!nf || m_i_dimension > lb.size() || nic > nc) {
233  pagmo_throw(value_error,"invalid dimension(s)");
234  }
235  construct_from_iterators(lb.begin(),lb.end(),ub.begin(),ub.end());
236  // Resize properly temporary fitness and constraint storage.
237  m_tmp_f1.resize(m_f_dimension);
238  m_tmp_f2.resize(m_f_dimension);
239  m_tmp_c1.resize(m_c_dimension);
240  m_tmp_c2.resize(m_c_dimension);
241  // Normalise bounds.
242  normalise_bounds();
243 }
244 
246 
250 
252 
257 std::string base::get_name() const
258 {
259  return typeid(*this).name();
260 }
261 
263 
267 {
268  return m_lb;
269 }
270 
272 
276 {
277  return m_ub;
278 }
279 
281 
289 {
290  if (lb.size() != ub.size() || lb.size() != m_lb.size()) {
291  pagmo_throw(value_error,"invalid or inconsistent bounds dimensions in set_bounds()");
292  }
293  verify_bounds(lb.begin(),lb.end(),ub.begin(),ub.end());
294  m_lb = lb;
295  m_ub = ub;
296  // Normalise bounds.
297  normalise_bounds();
298 }
299 
301 
307 void base::set_bounds(const double &l_value, const double &u_value)
308 {
309  if (l_value > u_value) {
310  pagmo_throw(value_error,"lower bound cannot be greater than upper bound in set_bounds()");
311  }
312  std::fill(m_lb.begin(),m_lb.end(),l_value);
313  std::fill(m_ub.begin(),m_ub.end(),u_value);
314  normalise_bounds();
315 }
316 
318 
325 void base::set_bounds(int n, const double &l_value, const double &u_value)
326 {
327  if (l_value > u_value) {
328  pagmo_throw(value_error,"lower bound cannot be greater than upper bound in set_bounds()");
329  }
330  m_lb[n] = l_value;
331  m_ub[n] = u_value;
332  // Normalise bounds.
333  normalise_bounds();
334 }
335 
337 
343 {
344  if (lb.size() != m_lb.size()) {
345  pagmo_throw(value_error,"invalid bounds dimension in set_lb()");
346  }
347  verify_bounds(lb.begin(),lb.end(),m_ub.begin(),m_ub.end());
348  m_lb = lb;
349  // Normalise bounds.
350  normalise_bounds();
351 }
352 
354 
360 void base::set_lb(int n, const double &value)
361 {
362  const size_type i = boost::numeric_cast<size_type>(n);
363  if (i >= m_lb.size() || m_ub[i] < value) {
364  pagmo_throw(value_error,"invalid index and/or value for lower bound");
365  }
366  m_lb[i] = value;
367  // Normalise bounds.
368  normalise_bounds();
369 }
370 
372 
377 void base::set_lb(const double &value)
378 {
379  for (size_type i = 0; i < m_lb.size(); ++i) {
380  if (m_ub[i] < value) {
381  pagmo_throw(value_error,"invalid value for lower bound");
382  }
383  }
384  std::fill(m_lb.begin(),m_lb.end(),value);
385  // Normalise bounds.
386  normalise_bounds();
387 }
388 
390 
396 {
397  if (ub.size() != m_lb.size()) {
398  pagmo_throw(value_error,"invalid bounds dimension in set_ub()");
399  }
400  verify_bounds(m_lb.begin(),m_lb.end(),ub.begin(),ub.end());
401  m_ub = ub;
402  // Normalise bounds.
403  normalise_bounds();
404 }
405 
407 
413 void base::set_ub(int n, const double &value)
414 {
415  const size_type i = boost::numeric_cast<size_type>(n);
416  if (i >= m_lb.size() || m_lb[i] > value) {
417  pagmo_throw(value_error,"invalid index and/or value for upper bound");
418  }
419  m_ub[i] = value;
420  // Normalise bounds.
421  normalise_bounds();
422 }
423 
425 
430 void base::set_ub(const double &value)
431 {
432  for (size_type i = 0; i < m_lb.size(); ++i) {
433  if (m_lb[i] > value) {
434  pagmo_throw(value_error,"invalid value for upper bound");
435  }
436  }
437  std::fill(m_ub.begin(),m_ub.end(),value);
438  // Normalise bounds.
439  normalise_bounds();
440 }
441 
443 
446 unsigned int base::get_fevals() const
447 {
448  return m_fevals;
449 }
450 
452 
455 unsigned int base::get_cevals() const
456 {
457  return m_cevals;
458 }
459 
460 
462 
466 {
467  return m_lb.size();
468 }
469 
471 
475 {
476  return m_i_dimension;
477 }
478 
480 
484 {
485  return m_f_dimension;
486 }
487 
489 
493 {
494  return m_c_dimension;
495 }
496 
498 
502 {
503  return m_ic_dimension;
504 }
505 
507 
510 const std::vector<double>& base::get_c_tol() const
511 {
512  return m_c_tol;
513 }
514 
516 
521 double base::get_diameter() const
522 {
523  double retval = 0;
524  for (size_type i = 0; i < get_dimension(); ++i) {
525  retval += (m_ub[i] - m_lb[i]) * (m_ub[i] - m_lb[i]);
526  }
527  return std::sqrt(retval);
528 }
529 
531 
545 {
546  if (x.size()!=get_dimension()) {
547  pagmo_throw(value_error,"invalid chromosome length");
548  }
549  fitness_vector f(m_f_dimension);
550  objfun(f,x);
551  return f;
552 }
553 
555 
565 {
566  // Some checks on the input values.
567  if (f.size() != m_f_dimension) {
568  pagmo_throw(value_error,"wrong fitness vector size when calling objective function");
569  }
570  if (x.size() != get_dimension()) {
571  pagmo_throw(value_error,"wrong decision vector size when calling objective function");
572  }
573  // Look into the cache.
574  typedef decision_vector_cache_type::iterator x_iterator;
575  typedef fitness_vector_cache_type::iterator f_iterator;
576  const x_iterator x_it = std::find(m_decision_vector_cache_f.begin(),m_decision_vector_cache_f.end(),x);
577  if (x_it == m_decision_vector_cache_f.end()) {
578  // Fitness is not into memory. Calculate it.
579  objfun_impl(f,x);
580  // Increase function evaluation counter.
581  m_fevals++;
582  // Make sure that the implementation of objfun_impl() in the derived class did not fuck up the dimension of the fitness vector.
583  if (f.size() != m_f_dimension) {
584  pagmo_throw(value_error,"fitness dimension was changed inside objfun_impl()");
585  }
586  // Store the decision vector and the newly-calculated fitness in the front of the buffers.
587  m_decision_vector_cache_f.push_front(x);
588  m_fitness_vector_cache.push_front(f);
589  } else {
590  // Compute the corresponding iterator in the fitness vector cache.
591  f_iterator f_it = m_fitness_vector_cache.begin();
592  std::advance(f_it,std::distance(m_decision_vector_cache_f.begin(),x_it));
593  pagmo_assert(f_it != m_fitness_vector_cache.end());
594  // Assign to the fitness vector the value in the cache.
595  f = *f_it;
596  // Move the content of the current positions to the front of the buffers, and shift everything else down
597  // by one position.
598  x_iterator tmp_x_it = m_decision_vector_cache_f.begin();
599  f_iterator tmp_f_it = m_fitness_vector_cache.begin();
600  while (x_it != tmp_x_it) {
601  x_it->swap(*tmp_x_it);
602  f_it->swap(*tmp_f_it);
603  ++tmp_x_it;
604  ++tmp_f_it;
605  }
606  pagmo_assert(tmp_f_it == f_it);
607  }
608 }
609 
611 
619 bool base::compare_fitness(const fitness_vector &v_f1, const fitness_vector &v_f2) const
620 {
621  if (v_f1.size() != m_f_dimension || v_f2.size() != m_f_dimension) {
622  pagmo_throw(value_error,"invalid sizes for fitness vector(s) during comparison");
623  }
624  return compare_fitness_impl(v_f1,v_f2);
625 }
626 
628 
639 bool base::compare_fitness_impl(const fitness_vector &v_f1, const fitness_vector &v_f2) const
640 {
641  pagmo_assert(v_f1.size() == v_f2.size()); // NOTE: v_f1.size CAN be different from m_f_dimension (i.e. when its a base_meta calling it)
642  f_size_type count1 = 0; f_size_type count2 = 0;
643  for (f_size_type i = 0; i < v_f1.size(); ++i) {
644  if (v_f1[i] < v_f2[i]) {
645  ++count1;
646  }
647  if (v_f1[i] == v_f2[i]) {
648  ++count2;
649  }
650  }
651  return ( ( (count1+count2) == v_f1.size()) && (count1>0) );
652 }
653 
655 
665 std::string base::human_readable() const
666 {
667  std::ostringstream s;
668  s << "Problem name: " << get_name() << '\n';
669  const size_type size = get_dimension();
670  s << "\tGlobal dimension:\t\t\t" << size << '\n';
671  s << "\tInteger dimension:\t\t\t" << m_i_dimension << '\n';
672  s << "\tFitness dimension:\t\t\t" << m_f_dimension << '\n';
673  s << "\tConstraints dimension:\t\t\t" << m_c_dimension << '\n';
674  s << "\tInequality constraints dimension:\t" << m_ic_dimension << '\n';
675  s << "\tLower bounds: ";
676  s << m_lb << '\n';
677  s << "\tUpper bounds: ";
678  s << m_ub << '\n';
679  s << "\tConstraints tolerance: ";
680  s << m_c_tol << '\n';
681  s << human_readable_extra();
682  return s.str();
683 }
684 
686 
691 std::string base::human_readable_extra() const
692 {
693  return std::string();
694 }
695 
697 
708 bool base::operator==(const base &p) const
709 {
710  if (!is_compatible(p)) {
711  return false;
712  }
713  return equality_operator_extra(p);
714 }
715 
717 
734 bool base::is_compatible(const base &p) const
735 {
736 // marcusm: changed this for experiments with migration between single- and multiobjective islands.
737 /* if (typeid(*this) != typeid(p) || get_dimension() != p.get_dimension() || m_i_dimension != p.m_i_dimension || m_f_dimension != p.m_f_dimension ||
738  m_c_dimension != p.m_c_dimension || m_ic_dimension != p.m_ic_dimension)*/
739  if (typeid(*this) != typeid(p) || get_dimension() != p.get_dimension() || m_i_dimension != p.m_i_dimension ||
740  m_c_dimension != p.m_c_dimension || m_ic_dimension != p.m_ic_dimension)
741  {
742  return false;
743  }
744  return true;
745 }
746 
748 
759 bool base::compare_x(const decision_vector &x1, const decision_vector &x2) const
760 {
761  // Make sure the size of the tmp fitness vectors are suitable.
762  pagmo_assert(m_tmp_f1.size() == m_f_dimension && m_tmp_f2.size() == m_f_dimension);
763  // Store fitnesses into temporary space.
764  objfun(m_tmp_f1,x1);
765  objfun(m_tmp_f2,x2);
766  // Make sure the size of the tmp constraint vectors are suitable.
767  pagmo_assert(m_tmp_c1.size() == m_c_dimension && m_tmp_c2.size() == m_c_dimension);
768  // Store constraint vector into temporary space.
769  compute_constraints(m_tmp_c1,x1);
770  compute_constraints(m_tmp_c2,x2);
771  // Call the comparison implementation.
772  return compare_fc(m_tmp_f1,m_tmp_c1,m_tmp_f2,m_tmp_c2);
773 }
774 
776 
787 bool base::compare_fc(const fitness_vector &f1, const constraint_vector &c1, const fitness_vector &f2, const constraint_vector &c2) const
788 {
789  if (f1.size() != m_f_dimension || f2.size() != m_f_dimension) {
790  pagmo_throw(value_error,"wrong size(s) for fitness vector(s)");
791  }
792  if (c1.size() != m_c_dimension || c2.size() != m_c_dimension) {
793  pagmo_throw(value_error,"wrong size(s) for constraint vector(s)");
794  }
795  if (m_c_dimension) {
796  return compare_fc_impl(f1,c1,f2,c2);
797  } else {
798  return compare_fitness_impl(f1,f2);
799  }
800 }
801 
803 
821 bool base::compare_fc_impl(const fitness_vector &f1, const constraint_vector &c1, const fitness_vector &f2, const constraint_vector &c2) const
822 {
823  const bool test1 = feasibility_c(c1), test2 = feasibility_c(c2);
824  if (test1 && !test2) {
825  return true;
826  }
827  if (!test1 && test2) {
828  return false;
829  }
830  // At this point, either they are both feasible or they are not.
831  if (test1) {
832  pagmo_assert(test2);
833  // If they are feasible, compare fitnesses and return.
834  return compare_fitness_impl(f1,f2);
835  } else {
836  pagmo_assert(!test2);
837  // If they are not feasible, compare constraints and return.
838  return compare_constraints_impl(c1,c2);
839  }
840 }
841 
846 
848 
860 {
861  (void)x;
862  std::fill(c.begin(),c.end(),0);
863 }
864 
866 
875 {
876  if (x.size() != get_dimension() || c.size() != get_c_dimension()) {
877  pagmo_throw(value_error,"invalid constraint and/or decision vector(s) size(s) during constraint testing");
878  }
879  // Do not do anything if constraints size is 0.
880  if (!m_c_dimension) {
881  return;
882  }
883  // Look into the cache.
884  typedef decision_vector_cache_type::iterator x_iterator;
885  typedef constraint_vector_cache_type::iterator c_iterator;
886  const x_iterator x_it = std::find(m_decision_vector_cache_c.begin(),m_decision_vector_cache_c.end(),x);
887  if (x_it == m_decision_vector_cache_c.end()) {
888  // Constraint vector is not into memory. Calculate it.
890  m_cevals++;
891  // Make sure c was not fucked up in the implementation of constraints calculation.
892  if (c.size() != get_c_dimension()) {
893  pagmo_throw(value_error,"constraints dimension was changed inside compute_constraints_impl()");
894  }
895  // Store the decision vector and the newly-calculated constraint vector in the front of the buffers.
896  m_decision_vector_cache_c.push_front(x);
897  m_constraint_vector_cache.push_front(c);
898  } else {
899  // Compute the corresponding iterator in the constraint vector cache.
900  c_iterator c_it = m_constraint_vector_cache.begin();
901  std::advance(c_it,std::distance(m_decision_vector_cache_c.begin(),x_it));
902  pagmo_assert(c_it != m_constraint_vector_cache.end());
903  // Assign to the fitness vector the value in the cache.
904  c = *c_it;
905  // Move the content of the current positions to the front of the buffers, and shift everything else down
906  // by one position.
907  x_iterator tmp_x_it = m_decision_vector_cache_c.begin();
908  c_iterator tmp_c_it = m_constraint_vector_cache.begin();
909  while (x_it != tmp_x_it) {
910  x_it->swap(*tmp_x_it);
911  c_it->swap(*tmp_c_it);
912  ++tmp_x_it;
913  ++tmp_c_it;
914  }
915  pagmo_assert(tmp_c_it == c_it);
916  }
917 }
918 
920 
933 {
935  compute_constraints(c,x);
936  return c;
937 }
938 
940 
948 {
949  // Compute the constraints and store internally.
950  compute_constraints(m_tmp_c1,x);
951  return feasibility_c(m_tmp_c1);
952 }
953 
955 
964 {
965  pagmo_assert(i < m_c_dimension);
966  if (i < m_c_dimension - m_ic_dimension) {
967  // Equality constraint testing.
968  return (std::abs(c[i]) <= m_c_tol[i]);
969  } else {
970  return c[i] <= m_c_tol[i];
971  }
972 }
973 
975 
983 {
984  if (c.size() != m_c_dimension) {
985  pagmo_throw(value_error,"invalid size for constraint vector");
986  }
987  pagmo_assert(m_c_dimension >= m_ic_dimension);
988  for (c_size_type i = 0; i < m_c_dimension; ++i) {
989  if (!test_constraint(c,i)) {
990  return false;
991  }
992  }
993  return true;
994 }
995 
997 
1006 {
1007  if (c1.size() != m_c_dimension || c2.size() != m_c_dimension) {
1008  pagmo_throw(value_error,"invalid size(s) for constraint vector(s)");
1009  }
1010  return compare_constraints_impl(c1,c2);
1011 }
1012 
1014 
1028 {
1029  pagmo_assert(c1.size() == c2.size() && c1.size() == m_c_dimension);
1030  // Counters of satisfied constraints.
1031  c_size_type count1 = 0, count2 = 0;
1032  // L2 norm of constraints mismatches.
1033  double norm1 = 0, norm2 = 0;
1034  // Equality constraints.
1035  for (c_size_type i = 0; i < m_c_dimension - m_ic_dimension; ++i) {
1036  if (test_constraint(c1,i)) {
1037  ++count1;
1038  }
1039  if (test_constraint(c2,i)) {
1040  ++count2;
1041  }
1042  norm1 += std::abs(c1[i]) * std::abs(c1[i]);
1043  norm2 += std::abs(c2[i]) * std::abs(c2[i]);
1044  }
1045  // Inequality constraints.
1046  for (c_size_type i = m_c_dimension - m_ic_dimension; i < m_c_dimension; ++i) {
1047  if (test_constraint(c1,i)) {
1048  ++count1;
1049  } else {
1050  norm1 += c1[i] * c1[i];
1051  }
1052  if (test_constraint(c2,i)) {
1053  ++count2;
1054  } else {
1055  norm2 += c2[i] * c2[i];
1056  }
1057  }
1058  if (count1 > count2) {
1059  return true;
1060  } else if (count1 < count2) {
1061  return false;
1062  } else {
1063  return (norm1 < norm2);
1064  }
1065 }
1066 
1068 
1070 
1078 {
1079  (void)p;
1080  return true;
1081 }
1082 
1084 
1091 bool base::operator!=(const base &p) const
1092 {
1093  return !(*this == p);
1094 }
1095 
1097 
1109 bool base::verify_x(const decision_vector &x) const
1110 {
1111  if (x.size() != get_dimension()) {
1112  return false;
1113  }
1114  for (size_type i = 0; i < get_dimension(); ++i) {
1115  if (x[i] < m_lb[i] || x[i] > m_ub[i]) {
1116  return false;
1117  }
1118  // Check that, if this is an integer component, it is really an integer.
1119  if (i >= (get_dimension() - m_i_dimension) && double_to_int::convert(x[i]) != x[i]) {
1120  return false;
1121  }
1122  }
1123  return true;
1124 }
1125 
1126 // This function will round to the nearest integer the upper/lower bounds of the integer part of the problem.
1127 // This should be called each time bounds are set.
1128 void base::normalise_bounds()
1129 {
1130  pagmo_assert(m_lb.size() >= m_i_dimension);
1131  // Flag to be set if we had to fix the bounds.
1132  bool bounds_fixed = false;
1133  for (size_type i = 0; i < m_lb.size() - m_i_dimension; ++i) {
1134  // Handle NaNs: if either lower/upper bound(s) are NaN, replace with 0 and 1 respectively.
1135  if (boost::math::isnan(m_lb[i]) || boost::math::isnan(m_ub[i])) {
1136  m_lb[i] = 0;
1137  m_ub[i] = 1;
1138  bounds_fixed = true;
1139  }
1140  // +-Infs are replaced by the highest/lowest values representable by double.
1141  if (boost::math::isinf(m_lb[i])) {
1142  m_lb[i] = (m_lb[i] > 0) ? boost::numeric::bounds<double>::highest() : boost::numeric::bounds<double>::lowest();
1143  bounds_fixed = true;
1144  }
1145  if (boost::math::isinf(m_ub[i])) {
1146  m_ub[i] = (m_ub[i] > 0) ? boost::numeric::bounds<double>::highest() : boost::numeric::bounds<double>::lowest();
1147  bounds_fixed = true;
1148  }
1149  }
1150  for (size_type i = m_lb.size() - m_i_dimension; i < m_lb.size(); ++i) {
1151  // First let's make sure that integer bounds are in the allowed range.
1152  if (m_lb[i] < INT_MIN) {
1153  m_lb[i] = INT_MIN;
1154  bounds_fixed = true;
1155  }
1156  if (m_lb[i] > INT_MAX) {
1157  m_lb[i] = INT_MAX;
1158  bounds_fixed = true;
1159  }
1160  if (m_ub[i] < INT_MIN) {
1161  m_ub[i] = INT_MIN;
1162  bounds_fixed = true;
1163  }
1164  if (m_ub[i] > INT_MAX) {
1165  m_ub[i] = INT_MAX;
1166  bounds_fixed = true;
1167  }
1168  // Then convert them to the nearest integer if necessary.
1169  if (m_lb[i] != double_to_int::convert(m_lb[i])) {
1170  m_lb[i] = double_to_int::convert(m_lb[i]);
1171  bounds_fixed = true;
1172  }
1173  if (m_ub[i] != double_to_int::convert(m_ub[i])) {
1174  m_ub[i] = double_to_int::convert(m_ub[i]);
1175  bounds_fixed = true;
1176  }
1177  }
1178  if (bounds_fixed) {
1179  pagmo_throw(value_error,"problem bounds were invalid and had to be fixed");
1180  }
1181 }
1182 
1184 
1192 std::ostream &operator<<(std::ostream &s, const base &p)
1193 {
1194  s << p.human_readable();
1195  return s;
1196 }
1197 
1199 
1217 void base::set_sparsity(int &lenG, std::vector<int> &iGfun, std::vector<int> &jGvar) const
1218 {
1219  (void)lenG;
1220  (void)iGfun;
1221  (void)jGvar;
1222  pagmo_throw(not_implemented_error,"sparsity is not implemented for this problem");
1223 }
1224 
1226 
1237 void base::estimate_sparsity(const decision_vector &x0, int& lenG, std::vector<int>& iGfun, std::vector<int>& jGvar) const {
1238  // We check that the user is providing a decision vector that is of the required length
1239  if (!verify_x(x0)) {
1240  pagmo_throw(value_error,"cannot estimate pattern from this decision vector: not compatible with problem");
1241  }
1242  size_type Dc = m_lb.size() - m_i_dimension;
1243  fitness_vector f0(m_f_dimension),f_new(m_f_dimension);
1244  objfun(f0,x0);
1245  constraint_vector c0(m_c_dimension),c_new(m_c_dimension);
1246  compute_constraints(c0,x0);
1247  decision_vector x_new = x0;
1248  iGfun.resize(0);jGvar.resize(0); lenG=0;
1249 
1250  for (size_type j=0;j<Dc;++j)
1251  {
1252  //we perturb the component of x0 only if ub>lb, if ub=lb the variable is assumed
1253  //to be 'just' a parameter ... in some problem implementations this is rather
1254  //useful, but it also requires that the algorithm treat those variables accordingly (i.e.
1255  //it does not allow them to be outside the box bounds)
1256  if (m_ub[j] == m_lb[j]) continue;
1257  x_new[j] = x0[j] + std::max(std::fabs(x0[j]), 1.0) * 1e-8;
1258  objfun(f_new,x_new);
1259  compute_constraints(c_new,x_new);
1260  for (size_type i=0;i<m_f_dimension;++i)
1261  {
1262  if (f_new[i]!=f0[i]) {iGfun.push_back(i); jGvar.push_back(j); lenG++;}
1263  }
1264  for (size_type i=0;i<m_c_dimension;++i)
1265  {
1266  if (c_new[i]!=c0[i]) {iGfun.push_back(i+m_f_dimension); jGvar.push_back(j); lenG++;}
1267  }
1268  x_new[j] = x0[j];
1269  }
1270 
1271 }
1272 
1274 
1283 void base::estimate_sparsity(int& lenG, std::vector<int>& iGfun, std::vector<int>& jGvar) const {
1284 
1285  size_type Dc = m_lb.size() - m_i_dimension;
1286  fitness_vector f0(m_f_dimension),f_new(m_f_dimension);
1287  decision_vector x0(Dc);
1288  // Double precision random number generator.
1289  rng_double drng(rng_generator::get<rng_double>());
1290 
1291  for (decision_vector::size_type i = 0; i<Dc;++i) {
1292  x0[i] = boost::uniform_real<double>(m_lb[i],m_ub[i])(drng);
1293  }
1294 
1295  objfun(f0,x0);
1296  constraint_vector c0(m_c_dimension),c_new(m_c_dimension);
1297  compute_constraints(c0,x0);
1298  decision_vector x_new = x0;
1299  iGfun.resize(0);jGvar.resize(0); lenG=0;
1300 
1301  for (decision_vector::size_type j=0;j<Dc;++j)
1302  {
1303  //we perturb the component of x0 only if ub>lb, if ub=lb the variable is assumed
1304  //to be 'just' a parameter ... in some problem implementations this is rather
1305  //useful, but it also requires that the algorithm treat those variables accordingly (i.e.
1306  //it does not allow them to go outside the box bounds)
1307  if (m_ub[j] == m_lb[j]) continue;
1308  x_new[j] = boost::uniform_real<double>(m_lb[j],m_ub[j])(drng);
1309  objfun(f_new,x_new);
1310  compute_constraints(c_new,x_new);
1311  for (fitness_vector::size_type i=0;i<m_f_dimension;++i)
1312  {
1313  if (f_new[i]!=f0[i]) {iGfun.push_back(i); jGvar.push_back(j); lenG++;}
1314  }
1315  for (constraint_vector::size_type i=0;i<m_c_dimension;++i)
1316  {
1317  if (c_new[i]!=c0[i]) {iGfun.push_back(i+m_f_dimension); jGvar.push_back(j); lenG++;}
1318  }
1319  x_new[j] = x0[j];
1320  }
1321 }
1322 
1324 
1329 void base::set_best_x(const std::vector<decision_vector>& best_x)
1330 {
1331  if(best_x.size() != 0){
1332  size_type n_opts = best_x.size();
1333  m_best_x.resize(n_opts);
1334  m_best_f.resize(n_opts);
1335  m_best_c.resize(n_opts);
1336  for (size_type i=0; i<n_opts; i++){
1337  if(best_x.at(i).size() != get_dimension())
1338  pagmo_throw(value_error,"invalid size(s) for best known decision vector(s)");
1339  else{
1340  //save in the class data member the value of the decision variable of solution i
1341  m_best_x.at(i) = best_x.at(i);
1342  //save in the class data member the corresponding value of objective(s)
1343  m_best_f.at(i) = objfun(best_x.at(i));
1344  //save in the class data member the corresponding value of constraint(s)
1345  if(m_c_dimension>0)
1346  m_best_c.at(i) = compute_constraints(best_x.at(i));
1347  }
1348  }
1349  }
1350 }
1351 
1353 
1357 const std::vector<constraint_vector>& base::get_best_c(void) const
1358 {
1359  return m_best_c;
1360 }
1361 
1363 
1367 const std::vector<decision_vector>& base::get_best_x(void) const
1368 {
1369  return m_best_x;
1370 }
1371 
1373 
1377 const std::vector<fitness_vector>& base::get_best_f(void) const
1378 {
1379  return m_best_f;
1380 }
1381 
1383 
1390 {
1391  (void)pop;
1392 }
1393 
1395 
1402 {
1403  (void)pop;
1404 }
1405 
1407 
1414 {
1415  m_decision_vector_cache_f = decision_vector_cache_type(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity));
1416  m_fitness_vector_cache = fitness_vector_cache_type(boost::numeric_cast<fitness_vector_cache_type::size_type>(cache_capacity));
1417  m_decision_vector_cache_c = decision_vector_cache_type(boost::numeric_cast<decision_vector_cache_type::size_type>(cache_capacity));
1418  m_constraint_vector_cache = constraint_vector_cache_type(boost::numeric_cast<constraint_vector_cache_type::size_type>(cache_capacity));
1419 }
1420 
1421 }} //namespaces
Root PaGMO namespace.
bool feasibility_x(const decision_vector &) const
Test feasibility of decision vector.
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
virtual std::string human_readable_extra() const
Extra information in human readable format.
bool operator==(const base &) const
Equality operator.
void set_best_x(const std::vector< decision_vector > &)
Sets the best known decision vectors.
unsigned int get_fevals() const
Return number of function evaluations.
virtual void set_sparsity(int &lenG, std::vector< int > &iGfun, std::vector< int > &jGvar) const
Sets the sparsity pattern of the gradient.
bool feasibility_c(const constraint_vector &) const
Test feasibility of constraint vector.
fitness_vector::size_type f_size_type
Fitness' size type: the same as pagmo::fitness_vector's size type.
Definition: problem/base.h:162
c_size_type get_ic_dimension() const
Return inequality constraints dimension.
unsigned int get_cevals() const
Return number of constraints function evaluations.
bool compare_constraints(const constraint_vector &, const constraint_vector &) const
Compare constraint vectors.
Base problem class.
Definition: problem/base.h:148
double get_diameter() const
Get the diameter of the problem.
Population class.
Definition: population.h:70
std::ostream & operator<<(std::ostream &s, const base &p)
Overload stream operator for problem::base.
virtual bool compare_fitness_impl(const fitness_vector &, const fitness_vector &) const
Implementation of fitness vectors comparison.
bool compare_x(const decision_vector &, const decision_vector &) const
Compare decision vectors.
size_type get_dimension() const
Return global dimension.
void set_lb(const decision_vector &)
Set lower bounds from pagmo::decision_vector.
virtual bool equality_operator_extra(const base &) const
Extra requirements for equality.
const std::vector< constraint_vector > & get_best_c(void) const
Get the best known constraint vector.
bool operator!=(const base &) const
Inequality operator.
bool compare_fitness(const fitness_vector &, const fitness_vector &) const
Compare fitness vectors.
base(int, int=0, int=1, int=0, int=0, const double &=0)
Constructor from global dimension, integer dimension, fitness dimension, global constraints dimension...
virtual void pre_evolution(population &) const
Pre-evolution hook.
std::string human_readable() const
Return human readable representation of the problem.
fitness_vector objfun(const decision_vector &) const
Return fitness of pagmo::decision_vector.
bool test_constraint(const constraint_vector &, const c_size_type &) const
Test i-th constraint of c (using tolerance information).
bool verify_x(const decision_vector &) const
Verify compatibility of decision vector x with problem.
virtual void post_evolution(population &) const
Post-evolution hook.
const std::vector< decision_vector > & get_best_x(void) const
Get the best known decision vector.
virtual bool compare_constraints_impl(const constraint_vector &, const constraint_vector &) const
Implementation of constraint vector comparison.
size_type get_i_dimension() const
Return integer dimension.
void set_ub(const decision_vector &)
Set upper bounds from pagmo::decision_vector.
bool is_compatible(const base &) const
Compatibility operator.
const std::vector< double > & get_c_tol() const
Return constraints tolerance.
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
constraint_vector compute_constraints(const decision_vector &) const
Compute constraints and return constraint vector.
void estimate_sparsity(const decision_vector &, int &lenG, std::vector< int > &iGfun, std::vector< int > &jGvar) const
Heuristics to estimate the sparsity pattern of the problem.
virtual bool compare_fc_impl(const fitness_vector &, const constraint_vector &, const fitness_vector &, const constraint_vector &) const
Implementation of simultaneous fitness-constraint comparison.
c_size_type get_c_dimension() const
Return global constraints dimension.
std::vector< double > constraint_vector
Constraint vector type.
Definition: types.h:44
const decision_vector & get_ub() const
Upper bounds getter.
virtual void objfun_impl(fitness_vector &f, const decision_vector &x) const =0
Objective function implementation.
f_size_type get_f_dimension() const
Return fitness dimension.
constraint_vector::size_type c_size_type
Constraints' size type: the same as pagmo::constraint_vector's size type.
Definition: problem/base.h:164
virtual std::string get_name() const
Get problem's name.
bool compare_fc(const fitness_vector &, const constraint_vector &, const fitness_vector &, const constraint_vector &) const
Simultaneous fitness-constraint comparison.
const decision_vector & get_lb() const
Lower bounds getter.
void reset_caches() const
Reset internal caches.
void set_bounds(const decision_vector &, const decision_vector &)
Bounds setter from pagmo::decision_vector.
const std::vector< fitness_vector > & get_best_f(void) const
Get the best known fitness vector.
virtual void compute_constraints_impl(constraint_vector &, const decision_vector &) const
Implementation of constraint computation.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
Definition: problem/base.h:160
static const std::size_t cache_capacity
Capacity of the internal caches.
Definition: problem/base.h:158
This rng returns a double in the [0,1[ range.
Definition: rng.h:89
virtual ~base()
Trivial destructor.