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.