20 #include "SolverConfig.h"
23 #define UB_W 1000000.0
28 mA.clear(); mOp.clear(); mB.clear(); mConDesc.clear();
32 assert(r !=
nullptr &&
"Invalid pointer to robot!");
33 mRobots = {r}; mLine =
nullptr; mMapping = m;
34 initializeDataStructures();
38 mRobots = l.robots(); mLine = &l; mMapping = m;
39 initializeDataStructures();
43 uint64_t numberOfMovedConstraints = mA.numberOfRows();
45 for (uint32_t r = 0; r < numberOfMovedConstraints; ++r)
48 m.
ops.insert(m.
ops.end(), make_move_iterator(mOp.begin()), make_move_iterator(mOp.end()));
49 m.
b.insert(m.
b.end(), make_move_iterator(mB.begin()), make_move_iterator(mB.end()));
50 m.
conDesc.insert(m.
conDesc.end(), make_move_iterator(mConDesc.begin()), make_move_iterator(mConDesc.end()));
54 return numberOfMovedConstraints;
60 for (
Location* l : sa->locations()) {
61 assert(sa->parent() !=
nullptr &&
"Each static activity had to have assigned a robot!");
63 double b = 2*UB_W;
Operator op = LESS_EQUAL;
64 double inputPower = sa->inputPower(l->lid(), pm->pid());
66 {getValue(d, sa->aid(), caller()), inputPower}, {getValue(z, {sa->aid(), pm->pid()}, caller()), UB_W},
67 {getValue(x, {sa->aid(), l->point()}, caller()), UB_W}, {getValue(W, sa->aid(), caller()), -1.0}
70 addConstraint(row, op, b,
"(1$"+to_string(mConstraintsCounter++)+
")");
79 for (
Movement* mv : da->movements()) {
80 assert(mMapping !=
nullptr &&
"Mapping should be set!");
81 const tuple<vector<double>, vector<double>>& ef = getValue(mMapping->mvToEnergyFunc, mv, caller());
82 const vector<double>& t = get<0>(ef), & e = get<1>(ef);
83 for (
size_t s = 0; s+1 < min(t.size(), e.size()); ++s) {
84 double k = (e[s+1]-e[s])/(t[s+1]-t[s]), q = e[s]-k*t[s];
85 double b = UB_W-q;
Operator op = LESS_EQUAL;
87 {getValue(d, da->aid(), caller()), k},
88 {getValue(y, {da->aid(), mv->mid()}, caller()), UB_W}, {getValue(W, da->aid(), caller()), -1.0}
91 addConstraint(row, op, b,
"(2$"+to_string(mConstraintsCounter++)+
")");
98 addEnergyFunctions1(d, W, x, z);
99 addEnergyFunctions2(d, W, y);
105 double b = 1.0;
Operator op = EQUAL;
108 row.emplace_back(getValue(x, {sa->aid(), l->point()}, caller()), 1.0);
110 addConstraint(row, op, b,
"(3$"+to_string(mConstraintsCounter++)+
")");
117 double b = 1.0;
Operator op = EQUAL;
119 assert(sa->parent() !=
nullptr &&
"Each static activity had to have assigned a robot!");
121 row.emplace_back(getValue(z, {sa->aid(), pm->pid()}, caller()), 1.0);
123 addConstraint(row, op, b,
"(4$"+to_string(mConstraintsCounter++)+
")");
128 addUniquePointSelection(x);
129 addUniquePowerModeSelection(z);
138 for (
Location* l : sa->locations()) {
139 double b = 0.0;
Operator op = EQUAL;
141 for (
Movement* mv : l->enteringMovements())
142 row1.emplace_back(getValue(y, {mv->parent()->aid(), mv->mid()}, caller()), 1.0);
143 for (
Movement* mv : l->leavingMovements())
144 row2.emplace_back(getValue(y, {mv->parent()->aid(), mv->mid()}, caller()), 1.0);
146 addConstraint(row1, op, b,
"(5$"+to_string(mConstraintsCounter++)+
")");
147 addConstraint(row2, op, b,
"(6$"+to_string(mConstraintsCounter++)+
")");
154 for (
Robot* r : mRobots) {
155 for (
Activity* i : r->activities()) {
156 if (i->mandatory()) {
157 for (
Activity* j : i->successors()) {
159 double b = (i->lastInCycle() ==
false) ? 0.0 : -mCycleTime;
161 {getValue(s, j->aid(), caller()), 1.0}, {getValue(s, i->aid(), caller()), -1.0}, {getValue(d, i->aid(), caller()), -1.0}
164 addConstraint(row, op, b,
"(7$"+to_string(mConstraintsCounter++)+
")");
174 if (da->optional()) {
176 double b = 0.0;
Operator op = EQUAL;
177 row.emplace_back(getValue(w, {da->aid(), da->successor()->aid()}, caller()), -1.0);
178 for (
Movement* mv : da->movements())
179 row.emplace_back(getValue(y, {da->aid(), mv->mid()}, caller()), 1.0);
181 addConstraint(row, op, b,
"(8$"+to_string(mConstraintsCounter++)+
")");
193 for (
Activity *j : i->successors()) {
194 Operator op1 = GREATER_EQUAL, op2 = LESS_EQUAL;
195 double b1 = (i->lastInCycle() ==
false) ? -mCycleTime : -2.0*mCycleTime;
196 double b2 = (i->lastInCycle() ==
false) ? mCycleTime : 0.0;
198 {getValue(s, j->aid(), caller()), 1.0}, {getValue(s, i->aid(), caller()), -1.0}, {getValue(d, i->aid(), caller()), -1.0}
199 }, row1 = row, row2 = row;
200 row1.emplace_back(getValue(w, {i->aid(), j->aid()}, caller()), -mCycleTime);
201 row2.emplace_back(getValue(w, {i->aid(), j->aid()}, caller()), mCycleTime);
203 addConstraint(row1, op1, b1,
"(9$"+to_string(mConstraintsCounter++)+
")");
204 addConstraint(row2, op2, b2,
"(10$"+to_string(mConstraintsCounter++)+
")");
211 addFixedPrecedences(s, d);
212 addPrecedenceSelectionConstraints(y, w);
213 addSelectablePrecedences(s, d, w);
219 assert(sa->parent() !=
nullptr &&
"Each static activity had to have assigned a robot!");
221 double b = 0.0;
Operator op = LESS_EQUAL;
223 {getValue(z, {sa->aid(), pm->pid()}, caller()), pm->minimalDelay()}, {getValue(d, sa->aid(), caller()), -1.0}
226 addConstraint(row, op, b,
"(11$"+to_string(mConstraintsCounter++)+
")");
234 for (
Movement* mv : da->movements()) {
235 double b = 0.0;
Operator op = LESS_EQUAL;
237 {getValue(y, {da->aid(), mv->mid()}, caller()), mv->minDuration()}, {getValue(d, da->aid(), caller()), -1.0}
240 addConstraint(row, op, b,
"(12$"+to_string(mConstraintsCounter++)+
")");
248 for (
Movement* mv : da->movements()) {
250 double b = mCycleTime+mv->maxDuration();
252 {getValue(d, da->aid(), caller()), 1.0}, {getValue(y, {da->aid(), mv->mid()}, caller()), mCycleTime}
255 addConstraint(row, op, b,
"(13$"+to_string(mConstraintsCounter++)+
")");
261 addMinimalDurationConstraints1(d, z);
262 addMinimalDurationConstraints2(d, y);
263 addMaximalDurationConstraints2(d, y);
268 assert(mRobots.size() > 1 && mLine !=
nullptr &&
"More than one robot expected!");
270 for (
const TimeLag& l : op->timeLags()) {
271 map1to1::const_iterator it1 = s.find(l.to()->aid()), it2 = s.find(l.from()->aid());
272 if (it1 != s.cend() && it2 != s.cend()) {
274 double b = l.length()-mCycleTime*l.height();
275 assert(l.from() !=
nullptr && l.to() !=
nullptr &&
"Unexpected null pointers!");
277 {it1->second, 1.0}, {it2->second, -1.0}
280 addConstraint(row, op, b,
"(14$"+to_string(mConstraintsCounter++)+
")");
283 throw SolverException(caller(),
"Robotic cell data structures are corrupted! Cannot find the time lag.");
291 assert(mRobots.size() > 1 && mLine !=
nullptr &&
"More than one robot expected!");
293 map<uint32_t, uint32_t> pointToId;
294 map<uint32_t, vector<uint32_t> > pointToPoints;
295 for (
const pair<Location*, Location*>& p : op->spatialCompatibility()) {
296 Location *l1 = p.first, *l2 = p.second;
298 pointToId[l1->point()] = sa1->aid(); pointToId[l2->point()] = sa2->aid();
299 pointToPoints[l1->point()].push_back(l2->point()); pointToPoints[l2->point()].push_back(l1->point());
302 for (map<uint32_t, vector<uint32_t> >::const_iterator it = pointToPoints.cbegin(); it != pointToPoints.cend(); ++it) {
303 double b = 0.0;
Operator op = LESS_EQUAL;
305 row.emplace_back(getValue(x, {getValue(pointToId, it->first, caller()), it->first}, caller()), 1.0);
306 for (
const uint32_t& pt : it->second)
307 row.emplace_back(getValue(x, {getValue(pointToId, pt, caller()), pt}, caller()), -1.0);
309 addConstraint(row, op, b,
"(15$"+to_string(mConstraintsCounter++)+
")");
319 assert(mRobots.size() > 1 && mLine !=
nullptr &&
"More than one robot expected!");
320 for (
const pair<ActivityMode*, ActivityMode*>& col : mLine->collisions()) {
321 int32_t numberOfRobots = mRobots.size();
322 for (int32_t r = -numberOfRobots; r <= numberOfRobots; ++r) {
325 double constVal = 2.0*numberOfRobots*mCycleTime;
326 double b1 = -3.0*constVal-r*mCycleTime, b2 = -2.0*constVal+r*mCycleTime;
328 uint32_t a[2], m[2], i = 0;
333 a[i] = da->aid(); m[i] = mv->mid();
334 row.emplace_back(getValue(y, {a[i], m[i]}, caller()), -constVal);
338 if (loc !=
nullptr) {
340 a[i] = sa->aid(); m[i] = loc->lid();
341 row.emplace_back(getValue(x, {a[i], loc->point()}, caller()), -constVal);
348 const vector<uint32_t>& v = getValue(c, {
pack(a[0], m[0]),
pack(a[1], m[1])}, caller());
349 row1.insert(row1.end(), {{getValue(s, a[1], caller()), 1.0}, {getValue(s, a[0], caller()), -1.0}, {getValue(d, a[0], caller()), -1.0}, {v[r+numberOfRobots], -constVal}});
350 row2.insert(row2.end(), {{getValue(s, a[0], caller()), 1.0}, {getValue(s, a[1], caller()), -1.0}, {getValue(d, a[1], caller()), -1.0}, {v[r+numberOfRobots], constVal}});
352 addConstraint(row1, op, b1,
"(16$"+to_string(mConstraintsCounter++)+
")");
353 addConstraint(row2, op, b2,
"(17$"+to_string(mConstraintsCounter++)+
")");
360 addSpatialCompatibilityConstraints(x);
361 addCollisions(s, d, x, y, c);
366 assert(loc->parent() !=
nullptr &&
"Each location must be a part of a static activity!");
369 double b = 0;
Operator op = LESS_EQUAL;
371 {getValue(d, sa->aid(), caller()), loc->
inputPower(pwrm)}, {getValue(W, sa->aid(), caller()), -1.0}
374 addConstraint(row, op, b,
"(1@"+to_string(mConstraintsCounter++)+
")");
379 assert(mMapping !=
nullptr && mv->parent() !=
nullptr &&
"It should be initialized!");
381 uint32_t aid = mv->parent()->aid();
382 const auto& efit = mMapping->mvToEnergyFunc.find(mv);
384 if (efit != mMapping->mvToEnergyFunc.cend()) {
386 const tuple<vector<double>, vector<double>>& ef = efit->second;
388 const vector<double>& t = get<0>(ef), & e = get<1>(ef);
389 for (
size_t s = 0; s+1 < min(t.size(), e.size()); ++s) {
390 double k = (e[s+1]-e[s])/(t[s+1]-t[s]), q = e[s]-k*t[s];
391 double b = -q;
Operator op = LESS_EQUAL;
393 const auto& dit = d.find(aid), &Wit = W.find(aid);
394 if (dit != d.cend() && Wit != W.cend()) {
396 addConstraint(row, op, b,
"(2@"+to_string(mConstraintsCounter++)+
")");
398 throw SolverException(caller(),
"Invalid mapping of variables d or W!");
403 throw SolverException(caller(),
"Cannot find the energy function for movement "+to_string(mv->mid())+
"!");
410 assert(mv->parent() !=
nullptr &&
"Movement should be a part of a dynamic activity!");
413 vector<pair<Activity*, Activity*>> prec = {{from, da}, {da, to}};
414 for (
const pair<Activity*, Activity*>& p : prec) {
416 double b = (p.first->lastInCycle() ==
false) ? 0.0 : -mCycleTime;
418 const auto &sit1 = s.find(p.second->aid()), &sit2 = s.find(p.first->aid()), &dit = d.find(p.first->aid());
419 if (sit1 != s.cend() && sit2 != s.cend() && dit != d.cend()) {
420 uint32_t idx1 = sit1->second, idx2 = sit2->second, idx3 = dit->second;
422 {idx1, 1.0}, {idx2, -1.0}, {idx3, -1.0}
425 addConstraint(row, op, b,
"(7@"+to_string(mConstraintsCounter++)+
")");
436 double b = multipleOfCycleTime*mCycleTime;
438 {getValue(s, j, caller()), 1.0}, {getValue(s, i, caller()), -1.0}, {getValue(d, i, caller()), -1.0}
441 addConstraint(row, op, b,
"(16|17@"+to_string(mConstraintsCounter++)+
")");
445 reset(); mStaticActivities.clear(); mDynamicActivities.clear();
446 assert(!mRobots.empty() &&
"At least one robot must be added by the reset method!");
447 assert(mRobots[0]->parent() !=
nullptr &&
"Even one robot must be encapsulated by the RoboticLine class!");
448 mCycleTime = (mRobots[0]->parent())->productionCycleTime();
449 for (
Robot* r : mRobots) {
450 for (
Activity* a : r->activities()) {
453 mStaticActivities.push_back(sa);
457 mDynamicActivities.push_back(da);
463 this->mA.addRow(row); this->mOp.push_back(op); this->mB.push_back(b);
464 this->mConDesc.push_back(conDesc);
void addEnergyFunctions1(const map1to1 &d, const map1to1 &W, const map2to1 &x, const map2to1 &z)
Add the constraints propagating the consumption of static activities to the criterion.
The instance of the class corresponds to a robot movement between two coordinates.
std::vector< double > b
Constants in the constraints, i.e. the right-hand side vector of .
void addPrecedenceSelectionConstraints(const map2to1 &y, const map2to1 &w)
According to the selected movements it decides which optional dynamic activities are performed...
The base class incorporating common properties of robot operations and movements. ...
void addEnergyFunction(const map1to1 &d, const map1to1 &W, Location *loc, RobotPowerMode *pwrm)
Adds energy function for a static activity, its location, and its applied power saving mode...
double inputPower(RobotPowerMode *m) const
Instance of this class includes all the data structures and methods related to a robot.
void addCollisionResolution(const map1to1 &s, const map1to1 &d, uint32_t i, uint32_t j, int32_t multipleOfCycleTime)
It adds a constraint to resolve a collision, i.e. it adds a precedence for a given multiple of the r...
Collection of movements between two static activities.
void addMinimalDurationConstraints1(const map1to1 &d, const map2to1 &z)
Constraints restricting the minimal duration of static activities with respect to their assigned powe...
SparseMatrix< double > A
Constraint matrix of the problem.
void addUniqueModeSelection(const map2to1 &x, map2to1 &z)
It calls addUniquePointSelection and addUniquePowerModeSelection methods.
void addEnergyFunctions2(const map1to1 &d, const map1to1 &W, const map2to1 &y)
Add the constraints propagating the consumption of dynamic activities to the criterion.
Integer Linear Programming problem is stored in this data structure.
A general exception of the program.
void addSpatialCompatibilityConstraints(const map2to1 &x)
It defines the spatial compatibility between robots, in other words a workpice is taken from the same...
void addTimeLags(const map1to1 &s, bool allRequired=true)
Time lags enforcing correct time synchronizations between robots are added.
std::map< std::pair< uint64_t, uint64_t >, std::vector< uint32_t > > map4toN
Mapping of variables indexed by four numbers.
Various auxiliary functions used across the program.
void addUniquePowerModeSelection(const map2to1 &z)
Just one power saving mode (including the dummy one - motors) is applied for each static activity...
Declares a class for the generation of constraints.
void addEnergyFunctions(const map1to1 &d, const map1to1 &W, const map2to1 &x, const map2to1 &z, const map2to1 &y)
It adds the energy functions of both the static and dynamic activities.
void reset()
All the generated constraints are removed.
void addSelectedPrecedences(const map1to1 &s, const map1to1 &d, const std::vector< Movement * > &mvs)
Each has-to-be movement imposes a fixed precedence that is added to the formulation in the form of a ...
uint64_t pack(const uint32_t &v1, const uint32_t &v2)
It packs two uint32_t numbers to uint64_t data type.
Collection of locations in which a robot operation (or waiting) can be performed. ...
void addFlowConstraints(const map2to1 &x, const map2to1 &y)
Add flow preservation constraints ensuring that robot leaves the same location as it enters...
Memory efficient storage of the constraint matrix.
std::vector< Operator > ops
Operators of the constraints, see Operator enum.
void addFixedPrecedences(const map1to1 &s, const map1to1 &d)
Adds fixed precedences, i.e. enforces the have-to-be order of some activities.
It represents the power saving mode of the robot.
void addSelectablePrecedences(const map1to1 &s, const map1to1 &d, const map2to1 &w)
It adds selectable precedences which model alternative orders of activities.
It declares the namespace for program settings.
void addCollisions(const map1to1 &s, const map1to1 &d, const map2to1 &x, const map2to1 &y, const map4toN &c)
Adds constraints that enforce a collision-free solution.
Instance of TimeLag class defines a time relation between two different robots.
std::map< uint32_t, uint32_t > map1to1
Identification of the activity is mapped to the index of the variable.
void addAllPrecedences(const map1to1 &s, const map1to1 &d, const map2to1 &y, const map2to1 &w)
It calls all the methods related to the order of activities.
void initializeDataStructures()
It initializes the member variables and removes all the constraints.
void addGlobalConstraints(const map1to1 &s, const map1to1 &d, const map2to1 &x, const map2to1 &y, const map4toN &c)
Adds all the global constraints, i.e. time lags, spatial compatibility, and collision resolution...
void addMaximalDurationConstraints2(const map1to1 &d, const map2to1 &y)
Constraints restricting the maximal duration of dynamic activities with respect to their selected mov...
The inter-robot operation corresponding to the workpiece/weldment handling.
void addDurationConstraints(const map1to1 &d, const map2to1 &z, const map2to1 &y)
It constructs all the constraints that limit the duration of activities.
Either a movement or location.
void addMinimalDurationConstraints2(const map1to1 &d, const map2to1 &y)
Constraints restricting the minimal duration of dynamic activities with respect to their selected mov...
void addUniquePointSelection(const map2to1 &x)
Just one location, i.e. coordinate, is selected for each static activity.
Location of the robot used either during work (welding) or waiting.
std::vector< std::string > conDesc
Optional description of the constraints.
The robotic cell corresponds to an instance of this class.
The structure contains the maps for fast searching in the robotic cell.
void addConstraint(SparseMatrix< double >::Row &row, Operator op, const double &b, std::string conDesc="")
Add constraint "row'*vars op b" into the formulation.
void addRow(Row &row)
Adds precreated row to the matrix. Passed argument is destroyed.
std::map< std::pair< uint32_t, uint32_t >, uint32_t > map2to1
Mapping of variables indexed by two numbers.
uint64_t moveConstraintsToModel(ILPModel &m)
It efficiently moves all the generated constraints to the given model.
Operator
Constants for operators '<=', '=', and '>=', respectively.