25 #include "SolverConfig.h"
32 if (mSolution.status == OPTIMAL || mSolution.status == FEASIBLE) {
45 throw_with_nested(
SolverException(caller(),
"Mapping or data structures are flawed!"));
50 return mErrorMsg.empty();
54 double consumedEnergy = 0.0;
55 for (
const auto& p : mSolution.startTimeAndDuration) {
56 Activity* a = getValue(mMapping.aidToActivity, p.first, caller());
57 double duration = p.second.second;
61 const auto j = getValue(mSolution.pointAndPowerMode, sa->aid(), caller());
62 uint32_t lid = getValue(mMapping.pointToLocation, j.first, caller())->lid();
73 if (consumedEnergy < 0.0 || abs(consumedEnergy-mSolution.totalEnergy)/(consumedEnergy+F64_EPS) >
CRITERION_RTOL) {
74 mErrorMsg.emplace_back(
"Invalid calculation of the criterion!");
75 mErrorMsg.emplace_back(
"Calculated - "+to_string(consumedEnergy)+
" J; given - "+to_string(mSolution.totalEnergy)+
" J.");
76 mErrorMsg.emplace_back(
"Discretization of energy functions could be imprecise (more than "+to_string(
CRITERION_RTOL*100.0)+
" % error)!");
77 mErrorMsg.emplace_back(
"You can try to increase the number of segments for each energy function.");
83 for (
Robot* r : mLine.robots()) {
84 double cycleTime = 0.0;
85 for (
Activity *a : r->activities()) {
86 const auto& sit = mSolution.startTimeAndDuration.find(a->aid());
87 if (sit != mSolution.startTimeAndDuration.cend())
88 cycleTime += sit->second.second;
91 if (abs(cycleTime-mLine.productionCycleTime()) >
TIME_TOL) {
92 mErrorMsg.emplace_back(
"Cycle time for robot '"+r->name()+
"' does not correspond to the production cycle time!");
93 mErrorMsg.emplace_back(
"(robot cycle time "+to_string(cycleTime)+
")/(production cycle time "+to_string(mLine.productionCycleTime())+
")");
99 for (
const auto& p : mSolution.pointAndPowerMode) {
100 uint32_t aid = p.first, pwrm = p.second.second;
101 double duration = getValue(mSolution.startTimeAndDuration, aid, caller()).second;
103 Activity *a = getValue(mMapping.aidToActivity, aid, caller());
104 assert(a->parent() !=
nullptr &&
"Each activity should belong to some robot!");
106 double minDuration = a->minAbsDuration();
107 vector<RobotPowerMode*> m = a->parent()->powerModes();
108 auto sit = find_if(m.cbegin(), m.cend(), [&pwrm](
RobotPowerMode* k) {
return k->pid() == pwrm; });
109 if (sit != m.cend()) {
110 minDuration = max(minDuration, (*sit)->minimalDelay());
111 if (duration-minDuration < -TIME_TOL || duration-a->maxAbsDuration() >
TIME_TOL)
112 mErrorMsg.emplace_back(
"Static activity "+to_string(aid)+
" (power saving mode "+to_string(pwrm)+
") has invalid duration!");
114 mErrorMsg.emplace_back(
"Cannot find the robot power mode "+to_string(pwrm)+
" for static activity "+to_string(aid));
120 for (
const auto& p : mSolution.startTimeAndDuration) {
123 double duration = p.second.second;
125 if (duration-mv->minDuration() < -
TIME_TOL || duration-mv->maxDuration() >
TIME_TOL)
126 mErrorMsg.emplace_back(
"Activity "+to_string(da->aid())+
"'s movement "+to_string(mv->mid())+
" has set invalid duration!");
132 for (
Robot* r : mLine.robots()) {
133 set<uint32_t> activityId;
134 for (
const auto& p : mSolution.startTimeAndDuration)
135 activityId.insert(p.first);
137 vector<Activity*> filteredRobotActivities, robotActivities = r->activities();
138 copy_if(robotActivities.cbegin(), robotActivities.cend(), back_inserter(filteredRobotActivities),
139 [&activityId](
Activity* a) {
return activityId.count(a->aid()) > 0 ?
true :
false; });
142 map<uint32_t, Activity*> successors;
144 for (
Activity *a : filteredRobotActivities) {
147 Activity *suc = da->successor(), *pred = da->predecessor();
148 setValue(successors, pred->aid(), a, caller());
149 setValue(successors, a->aid(), suc, caller());
152 if (a->lastInCycle())
156 if (successors.size() != filteredRobotActivities.size() || filteredRobotActivities.empty()) {
157 mErrorMsg.emplace_back(
"Uncomplete graph of the solution!");
162 mErrorMsg.emplace_back(
"The process flow of the robot '"+r->name()+
"' is broken!");
163 mErrorMsg.emplace_back(
"The graph of the solution is either acyclic or disconnected.");
167 bool cycleFinished =
false;
168 Activity *curAct = getValue(successors, endId, caller());
169 while (!cycleFinished) {
170 const auto p = getValue(mSolution.startTimeAndDuration, curAct->aid(), caller());
171 double startCur = p.first, duration = p.second;
172 Activity *next = getValue(successors, curAct->aid(), caller());
173 double startNext = getValue(mSolution.startTimeAndDuration, next->aid(), caller()).first;
175 if (startNext-startCur < -
TIME_TOL || abs(startNext-startCur-duration) >
TIME_TOL) {
176 mErrorMsg.emplace_back(
"The process flow of the robot '"+r->name()+
"' is broken!");
177 mErrorMsg.emplace_back(
"Check start times and activity durations!");
181 if (next->aid() == endId)
182 cycleFinished =
true;
190 double productionCycleTime = mLine.productionCycleTime();
192 for (
const TimeLag& tl : o->timeLags()) {
193 Activity *from = tl.from(), *to = tl.to();
194 const auto& sit1 = mSolution.startTimeAndDuration.find(from->aid());
195 const auto& sit2 = mSolution.startTimeAndDuration.find(to->aid());
196 if (sit1 != mSolution.startTimeAndDuration.cend() && sit2 != mSolution.startTimeAndDuration.cend()) {
197 double s1 = sit1->second.first, s2 = sit2->second.first;
198 if (s2-s1+
TIME_TOL < tl.length()-productionCycleTime*tl.height()) {
199 mErrorMsg.emplace_back(
"Time lag '"+to_string(from->aid())+
" -> "+to_string(to->aid())+
"' is broken!");
200 mErrorMsg.emplace_back(
"Check the formulation of the problem.");
206 for (
const auto& t : mMapping.sptCompVec) {
207 Activity *a1 = get<2>(t), *a2 = get<3>(t);
209 const array<uint32_t, 2>& m = extractModes(a1, a2);
210 const vector<pair<Location*, Location*>>& modes = get<4>(t);
211 const auto sit = find_if(modes.cbegin(), modes.cend(), [=](pair<Location*, Location*> p) {
return m[0] == p.first->lid() && m[1] == p.second->lid(); });
212 if (sit == modes.cend()) {
213 mErrorMsg.emplace_back(
"Incompatible modes for activities "+to_string(a1->aid())+
" and "+to_string(a2->aid())+
"!");
214 mErrorMsg.emplace_back(
"Check the used algorithm!");
217 string msg =
"Cannot find the modes for static activities "+to_string(a1->aid())+
" and "+to_string(a2->aid())+
"!";
218 throw_with_nested(
SolverException(caller(), msg+
"\nCorrupted data structures!"));
224 for (
const pair<ActivityMode*, ActivityMode*>& col : mLine.collisions()) {
227 uint32_t m1 = am1->id(), m2 = am2->id();
228 Activity *a1 = am1->baseParent(), *a2 = am2->baseParent();
230 array<uint32_t, 2> selectedModes = extractModes(a1, a2);
231 if (selectedModes[0] == m1 && selectedModes[1] == m2) {
232 double cycleTime = mLine.productionCycleTime();
233 const auto& p1 = getValue(mSolution.startTimeAndDuration, a1->aid(), caller());
234 const auto& p2 = getValue(mSolution.startTimeAndDuration, a2->aid(), caller());
236 double d1 = p1.second, d2 = p2.second;
237 double s1 = fmod(p1.first, cycleTime), s2 = fmod(p2.first, cycleTime);
244 mErrorMsg.emplace_back(
"Collision for activity "+to_string(a1->aid())+
" (mode "+to_string(m1)
245 +
") and "+to_string(a2->aid())+
" (mode "+to_string(m2)+
") not resolved!");
246 mErrorMsg.emplace_back(
"Please check the collision resolution in the selected algorithm.");
258 array<uint32_t, 2> mode = {{ 0xffffffff, 0xffffffff }};
262 uint32_t point = getValue(mSolution.pointAndPowerMode, sa->aid(), caller()).first;
263 mode[i] = getValue(mMapping.pointToLocation, point, caller())->lid();
The instance of the class corresponds to a robot movement between two coordinates.
The base class incorporating common properties of robot operations and movements. ...
Instance of this class includes all the data structures and methods related to a robot.
void checkDynamicActivities()
Checks durations of dynamic activities.
void checkCriterion()
Checks the calculation of the criterion.
Collection of movements between two static activities.
void checkStaticActivities()
Checks durations of static activities.
An instance of this class is devoted to the solution checking.
A general exception of the program.
constexpr double CRITERION_RTOL
A maximal relative tolerance of the criterion error imposed by the piece-wise linearization of energy...
bool checkAll()
It calls the private member methods to verify the solution.
constexpr double TIME_TOL
A minimal time difference that is considered significant for a solution.
void checkGlobalConstraints()
Verifies that time lags and spatial compatibility are not violated.
Collection of locations in which a robot operation (or waiting) can be performed. ...
std::array< uint32_t, 2 > extractModes(Activity *a1, Activity *a2) const
Auxiliary method that extracts selected modes (location/movement identifications) for activities a1 a...
void checkCollisionZones()
Verifies that a collision does not occur in the solution.
double energyConsumption(double duration, const uint32_t &lid, const uint32_t &pid) const
It represents the power saving mode of the robot.
void checkScheduleContinuity()
Checks whether each robot path is closed and hamiltonian (each static activity is visited just once)...
Instance of TimeLag class defines a time relation between two different robots.
Movement * getSelectedMovement(const Solution &s, const PrecalculatedMapping &m, DynamicActivity *da)
It extracts the selected movement of the given dynamic activity from the solution.
double energyConsumption(const double &duration) const
void checkProductionCycleTime()
Checks whether the robot, i.e. production, cycle time is met.
The inter-robot operation corresponding to the workpiece/weldment handling.
Either a movement or location.
The file declares a class responsible for checking of solutions.
The file defines allowed inaccuracies in a solution and constants for floats.