GHOST
constraint.hpp
Go to the documentation of this file.
1 /*
2  * GHOST (General meta-Heuristic Optimization Solving Tool) is a C++ framework
3  * designed to help developers to model and implement optimization problem
4  * solving. It contains a meta-heuristic solver aiming to solve any kind of
5  * combinatorial and optimization real-time problems represented by a CSP/COP/EF-CSP/EF-COP.
6  *
7  * First developed to solve game-related optimization problems, GHOST can be used for
8  * any kind of applications where solving combinatorial and optimization problems. In
9  * particular, it had been designed to be able to solve not-too-complex problem instances
10  * within some milliseconds, making it very suitable for highly reactive or embedded systems.
11  * Please visit https://github.com/richoux/GHOST for further information.
12  *
13  * Copyright (C) 2014-2023 Florian Richoux
14  *
15  * This file is part of GHOST.
16  * GHOST is free software: you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License as published
18  * by the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20 
21  * GHOST is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  * GNU General Public License for more details.
25 
26  * You should have received a copy of the GNU General Public License
27  * along with GHOST. If not, see http://www.gnu.org/licenses/.
28  */
29 
30 
31 #pragma once
32 
33 #include <vector>
34 #include <map>
35 #include <utility>
36 #include <iostream>
37 #include <typeinfo>
38 #include <functional>
39 #include <cmath> // for isnan
40 #include <exception>
41 #include <string>
42 
43 #include "variable.hpp"
44 
45 namespace ghost
46 {
47  namespace algorithms
48  {
49  class AdaptiveSearchErrorProjection;
50  class CulpritSearchErrorProjection;
51  }
52 
62  class Constraint
63  {
64  friend class SearchUnit;
65  template<typename ModelBuilderType> friend class Solver;
66  friend class ModelBuilder;
67  friend class algorithms::AdaptiveSearchErrorProjection;
68  friend class algorithms::CulpritSearchErrorProjection;
69 
70  std::vector<Variable*> _variables;
71  std::vector<int> _variables_index; // To know where are the constraint's variables in the global variable vector
72  std::map<int,int> _variables_position; // To know where are global variables in the constraint's variables vector
73 
74  double _current_error; // Current error of the constraint.
75 
76  int _id; // Unique ID integer
77  mutable bool _is_optional_delta_error_defined; // Boolean telling if optional_delta_error() is overrided or not.
78 
79  struct nanException : std::exception
80  {
81  std::vector<Variable*> ptr_variables;
82  std::vector<Variable> variables;
83  std::string message;
84 
85  nanException( const std::vector<Variable*>& ptr_variables ) : ptr_variables(ptr_variables)
86  {
87  message = "Constraint required_error returned a NaN value on variables (";
88  for( int i = 0; i < static_cast<int>( ptr_variables.size() ) - 1; ++i )
89  message += std::to_string( ptr_variables[i]->get_value() ) + ", ";
90  message += std::to_string( ptr_variables[ static_cast<int>( ptr_variables.size() ) - 1 ]->get_value() ) + ")\n";
91  }
92 
93  nanException( const std::vector<Variable>& variables ) : variables(variables)
94  {
95  message = "Constraint optional_delta_error returned a NaN value on variables (";
96  for( int i = 0; i < static_cast<int>( variables.size() ) - 1; ++i )
97  message += std::to_string( variables[i].get_value() ) + ", ";
98  message += std::to_string( variables[ static_cast<int>( variables.size() ) - 1 ].get_value() ) + ")\n";
99  }
100 
101  const char* what() const noexcept { return message.c_str(); }
102  };
103 
104  struct negativeException : std::exception
105  {
106  std::vector<Variable*> ptr_variables;
107  std::vector<Variable> variables;
108  std::string message;
109 
110  negativeException( const std::vector<Variable*>& ptr_variables ) : ptr_variables(ptr_variables)
111  {
112  message = "Constraint required_error returned a negative value on variables (";
113  for( int i = 0; i < static_cast<int>( ptr_variables.size() ) - 1; ++i )
114  message += std::to_string( ptr_variables[i]->get_value() ) + ", ";
115  message += std::to_string( ptr_variables[ static_cast<int>( ptr_variables.size() ) - 1 ]->get_value() ) + ")\n";
116  }
117 
118  const char* what() const noexcept { return message.c_str(); }
119  };
120 
121  struct deltaErrorNotDefinedException : std::exception
122  {
123  std::string message;
124 
125  deltaErrorNotDefinedException()
126  {
127  message = "Constraint::optional_delta_error() has not been user-defined.\n";
128  }
129  const char* what() const noexcept { return message.c_str(); }
130  };
131 
132  struct variableOutOfTheScope : std::exception
133  {
134  std::string message;
135 
136  variableOutOfTheScope( int var_id, int ctr_id )
137  {
138  message = "Variable* ID " + std::to_string( var_id ) + " is not in the scope of Constraint ID " + std::to_string( ctr_id ) + ".\n";
139  }
140  const char* what() const noexcept { return message.c_str(); }
141  };
142 
143  inline bool is_optional_delta_error_defined() { return _is_optional_delta_error_defined; }
144 
145  // Call required_error() after getting sure the error does give a nan, rise an exception otherwise.
146  double error() const;
147 
148  // Compute the delta error of the current assignment, giving a vector of variables index and their candidate values.
149  // Calling optional_delta_error after making the conversion of variables index.
150  // Getting sure the delta error does give a nan, rise an exception otherwise.
151  double delta_error( const std::vector<int>& variables_index, const std::vector<int>& candidate_values ) const;
152 
153  // To simulate the error delta between the current configuration and the candidate configuration.
154  // This calls delta_error() if the user overrided it, otherwise it makes the simulation 'by hand' and calls error()
155  double simulate_delta( const std::vector<int>& variables_index, const std::vector<int>& candidate_values );
156 
157  // Return ids of variable objects in _variables.
158  inline std::vector<int> get_variable_ids() const { return _variables_index; }
159 
160  inline void update( int index, int new_value ) { conditional_update_data_structures( _variables, _variables_position[ index ], new_value ); }
161 
162  protected:
202  virtual double required_error( const std::vector<Variable*>& variables ) const = 0;
203 
241  virtual double optional_delta_error( const std::vector<Variable*>& variables, const std::vector<int>& indexes, const std::vector<int>& candidate_values ) const;
242 
258  virtual void conditional_update_data_structures( const std::vector<Variable*>& variables, int index, int new_value );
259 
265  inline double get_current_error() const { return _current_error; }
266 
268  inline int get_id() const { return _id; }
269 
270  public:
276  Constraint( const std::vector<int>& variables_index );
277 
283  Constraint( const std::vector<Variable>& variables );
284 
286  Constraint( const Constraint& other ) = default;
288  Constraint( Constraint&& other ) = default;
289 
291  Constraint& operator=( const Constraint& other ) = delete;
293  Constraint& operator=( Constraint&& other ) = delete;
294 
296  virtual ~Constraint() = default;
297 
303  bool has_variable( int var_id ) const;
304 
306  friend std::ostream& operator<<( std::ostream& os, const Constraint& c )
307  {
308  return os << "Constraint type: " << typeid(c).name()
309  << "\nId: " << c._id
310  << "\n########";
311  }
312  };
313 
314  /**********************/
316  /**********************/
317  // PureOptimization is used when no constraints have been given to the solver (ie, for pure optimization runs).
319  {
320  double required_error( const std::vector<Variable*>& variables ) const
321  {
322  return 0.;
323  }
324 
325  double optional_delta_error( const std::vector<Variable*>& variables, const std::vector<int>& indexes, const std::vector<int>& candidate_values ) const
326  {
327  return 0.;
328  }
329 
330  public:
331  PureOptimization( const std::vector<Variable>& variables )
332  : Constraint( variables )
333  { }
334  };
335 
336 }
Definition: constraint.hpp:63
Constraint & operator=(const Constraint &other)=delete
Copy assignment operator disabled.
Constraint(const Constraint &other)=default
Default copy contructor.
int get_id() const
Inline method to get the unique id of the Constraint object.
Definition: constraint.hpp:268
friend class SearchUnit
Definition: constraint.hpp:64
Constraint & operator=(Constraint &&other)=delete
Move assignment operator disabled.
bool has_variable(int var_id) const
friend std::ostream & operator<<(std::ostream &os, const Constraint &c)
To have a nicer stream of Constraint.
Definition: constraint.hpp:306
Constraint(const std::vector< int > &variables_index)
virtual void conditional_update_data_structures(const std::vector< Variable * > &variables, int index, int new_value)
virtual double optional_delta_error(const std::vector< Variable * > &variables, const std::vector< int > &indexes, const std::vector< int > &candidate_values) const
double get_current_error() const
Definition: constraint.hpp:265
virtual double required_error(const std::vector< Variable * > &variables) const =0
Constraint(const std::vector< Variable > &variables)
virtual ~Constraint()=default
Default virtual destructor.
Constraint(Constraint &&other)=default
Default move contructor.
Definition: model_builder.hpp:63
Definition: constraint.hpp:319
PureOptimization(const std::vector< Variable > &variables)
Definition: constraint.hpp:331
Definition: solver.hpp:110
Definition: auxiliary_data.hpp:38