Limbo
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MultiKnapsackLagRelax.h
Go to the documentation of this file.
1 
7 #ifndef LIMBO_SOLVERS_MULTIKNAPSACKLAGRELAX_H
8 #define LIMBO_SOLVERS_MULTIKNAPSACKLAGRELAX_H
9 
10 #include <cmath>
11 #include <limbo/solvers/Solvers.h>
13 
15 namespace limbo
16 {
18 namespace solvers
19 {
20 
21 // forward declaration
22 template <typename T>
24 template <typename T>
26 template <typename T, typename V>
28 template <typename T, typename V>
29 class L2NormScaler;
30 template <typename T, typename V>
32 template <typename T, typename V>
34 
65 template <typename T, typename V>
67 {
68  public:
72  typedef typename model_type::coefficient_value_type coefficient_value_type;
73  typedef typename model_type::variable_value_type variable_value_type;
77  typedef typename model_type::term_type term_type;
84 
87  MultiKnapsackLagRelax(model_type* model)
88  {
89  // T must be a floating point number
91  // V must be a floating point number
92  //limboStaticAssert(!std::numeric_limits<V>::is_integer);
93 
94  m_model = model;
95 
96  m_vObjCoef = NULL;
98  m_vConstrRhs = NULL;
99 
100  m_vGroupedVariable = NULL;
102  m_numGroups = 0;
103 
104  m_vLagMultiplier = NULL;
105  m_vNewLagMultiplier = NULL;
106  m_vSlackness = NULL;
107 
108  m_objConstant = 0;
109  m_lagObj = 0;
110  m_lagObjFlag = false;
111 
112  m_iter = 0;
113  m_maxIters = 1000;
115  m_useInitialSol = false;
116  }
120  {
121  copy(rhs);
122  }
126  {
127  if (this != &rhs)
128  copy(rhs);
129  return *this;
130  }
133  {
134  // recycle model
135  destroy();
136  }
137 
142  SolverProperty operator()(updater_type* updater = NULL, scaler_type* scaler = NULL, searcher_type* searcher = NULL)
143  {
144  return solve(updater, scaler, searcher);
145  }
146 
148  unsigned int maxIterations() const;
151  void setMaxIterations(unsigned int maxIter);
153  bool useInitialSolutions() const;
156  void setUseInitialSolutions(bool f);
158  bool lagObjFlag() const;
160  void setLagObjFlag(bool f);
161 
164  unsigned int numNegativeSlackConstraints(bool evaluateFlag);
165 
171  bool printVariableGroup(std::string const& filename) const;
175  std::ostream& printVariableGroup(std::ostream& os = std::cout) const;
179  bool printObjCoef(std::string const& filename) const;
183  std::ostream& printObjCoef(std::ostream& os = std::cout) const;
187  bool printLagMultiplier(std::string const& filename) const;
191  std::ostream& printLagMultiplier(std::ostream& os = std::cout) const;
196  std::ostream& printConstraint(std::ostream& os, std::string const& name) const;
202  template <typename TT>
203  void printArray(unsigned int n, TT const* array, bool nonzeroFlag) const;
205 
208  {
209  std::vector<constraint_type> const& vConstraint;
210 
213  CapacityConstraintPred(std::vector<constraint_type> const& v) : vConstraint(v) {}
214 
217  bool operator()(constraint_type const& constr) const
218  {
219  return constr.sense() != '=';
220  }
223  bool operator()(unsigned int id) const
224  {
225  return this->operator()(vConstraint[id]);
226  }
227  };
228 
231  {
232  coefficient_value_type const* vObjCoef;
233 
236  CompareVariableByCoefficient(coefficient_value_type const* v)
237  : vObjCoef(v)
238  {
239  }
240 
244  bool operator()(variable_type const& v1, variable_type const& v2) const
245  {
246  return vObjCoef[v1.id()] < vObjCoef[v2.id()];
247  }
248  };
249 
250  protected:
252  void copy(MultiKnapsackLagRelax const& rhs);
254  void destroy();
259  SolverProperty solve(updater_type* updater, scaler_type* scaler, searcher_type* searcher);
264  SolverProperty solveSubproblems(updater_type* updater, unsigned int beginIter, unsigned int endIter);
267  void scale(scaler_type* scaler);
269  void unscale();
272  void prepare();
275  void updateLagMultipliers(updater_type* updater);
277  void solveLag();
279  void computeSlackness();
281  coefficient_value_type evaluateLagObjective() const;
290  SolverProperty postProcess(updater_type* updater, searcher_type* searcher, SolverProperty status);
298  template <typename TT, typename VV>
299  void bMinusAx(matrix_type const& A, VV const* x, TT const* b, TT* y) const;
300 
301  model_type* m_model;
302 
303  coefficient_value_type* m_vObjCoef;
304  matrix_type m_constrMatrix;
305  coefficient_value_type* m_vConstrRhs;
306 
307  variable_type* m_vGroupedVariable;
309  unsigned int m_numGroups;
310  std::vector<unsigned int> m_vConstraintPartition;
311  coefficient_value_type* m_vLagMultiplier;
312  coefficient_value_type* m_vNewLagMultiplier;
313  coefficient_value_type* m_vSlackness;
314  std::vector<coefficient_value_type> m_vScalingFactor;
315 
316  coefficient_value_type m_objConstant;
317  coefficient_value_type m_lagObj;
319 
320  unsigned int m_iter;
321  unsigned int m_maxIters;
323 
324  std::vector<variable_value_type> m_vBestVariableSol;
325  coefficient_value_type m_bestObj;
326 
327  private:
328  friend class FeasibleSearcher<coefficient_value_type, variable_value_type>;
329 };
330 
331 template <typename T, typename V>
333 {
334  return m_maxIters;
335 }
336 template <typename T, typename V>
338 {
339  m_maxIters = maxIters;
340 }
341 template <typename T, typename V>
343 {
344  return m_useInitialSol;
345 }
346 template <typename T, typename V>
348 {
349  m_useInitialSol = f;
350 }
351 template <typename T, typename V>
353 {
354  return m_lagObjFlag;
355 }
356 template <typename T, typename V>
358 {
359  m_lagObjFlag = f;
360 }
361 template <typename T, typename V>
363 {
364  unsigned int result = 0;
365  if (evaluateFlag)
366  computeSlackness();
367  for (typename matrix_type::index_type i = 0; i < m_constrMatrix.numRows; ++i)
368  result += (m_vSlackness[i] < 0)? 1 : 0;
369  return result;
370 }
371 template <typename T, typename V>
373 {
374  m_model = rhs.m_model;
375 
376  // recycle model
377  destroy();
378  // copy problem model
379  if (rhs.m_vObjCoef)
380  {
381  m_vObjCoef = new coefficient_value_type [m_model->numVariables()];
382  std::copy(rhs.m_vObjCoef, rhs.m_vObjCoef+m_model->numVariables(), m_vObjCoef);
383  }
384  m_constrMatrix = rhs.m_constrMatrix;
385  if (rhs.m_vConstrRhs)
386  {
387  m_vConstrRhs = new coefficient_value_type [m_constrMatrix.numRows];
388  std::copy(rhs.m_vConstrRhs, rhs.m_vConstrRhs+m_constrMatrix.numRows, m_vConstrRhs);
389  }
390 
391  // copy variable groups
392  if (rhs.m_vGroupedVariable)
393  {
394  m_vGroupedVariable = new variable_type [rhs.m_vVariableGroupBeginIndex[rhs.m_numGroups]];
395  m_numGroups = rhs.m_numGroups;
396  m_vVariableGroupBeginIndex = new unsigned int [m_numGroups+1];
397  std::copy(rhs.m_vGroupedVariable, rhs.m_vGroupedVariable+rhs.m_vVariableGroupBeginIndex[rhs.m_numGroups], m_vGroupedVariable);
398  std::copy(rhs.m_vVariableGroupBeginIndex, rhs.m_vVariableGroupBeginIndex+rhs.m_numGroups+1, m_vVariableGroupBeginIndex);
399  }
400 
401  m_vConstraintPartition = rhs.m_vConstraintPartition;
402  if (rhs.m_vLagMultiplier)
403  {
404  m_vLagMultiplier = new coefficient_value_type [m_constrMatrix.numRows];
405  std::copy(rhs.m_vLagMultiplier, rhs.m_vLagMultiplier+m_constrMatrix.numRows, m_vLagMultiplier);
406  m_vNewLagMultiplier = new coefficient_value_type [m_constrMatrix.numRows];
407  std::copy(rhs.m_vNewLagMultiplier, rhs.m_vNewLagMultiplier+m_constrMatrix.numRows, m_vNewLagMultiplier);
408  m_vSlackness = new coefficient_value_type [m_constrMatrix.numRows];
409  std::copy(rhs.m_vSlackness, rhs.m_vSlackness+m_constrMatrix.numRows, m_vSlackness);
410  }
411  m_objConstant = rhs.m_objConstant;
412  m_lagObj = rhs.m_lagObj;
413  m_lagObjFlag = rhs.m_lagObjFlag;
414  m_iter = rhs.m_iter;
415  m_maxIters = rhs.m_maxIters;
416  m_useInitialSol = rhs.m_useInitialSol;
417 
418  m_vBestVariableSol = rhs.m_vBestVariableSol;
419  m_bestObj = rhs.m_bestObj;
420 }
421 template <typename T, typename V>
423 {
424  // recycle variable groups
425  if (m_vGroupedVariable)
426  {
427  delete [] m_vGroupedVariable;
428  delete [] m_vVariableGroupBeginIndex;
429  m_vGroupedVariable = NULL;
430  m_vVariableGroupBeginIndex = NULL;
431  }
432  if (m_vObjCoef)
433  {
434  delete [] m_vObjCoef;
435  m_vObjCoef = NULL;
436  }
437  m_constrMatrix.reset();
438  if (m_vConstrRhs)
439  {
440  delete [] m_vConstrRhs;
441  m_vConstrRhs = NULL;
442  }
443  // recycle lagrangian data
444  if (m_vLagMultiplier)
445  {
446  delete [] m_vLagMultiplier;
447  delete [] m_vNewLagMultiplier;
448  delete [] m_vSlackness;
449  m_vLagMultiplier = NULL;
450  m_vNewLagMultiplier = NULL;
451  m_vSlackness = NULL;
452  }
453 }
454 template <typename T, typename V>
456 {
457  bool defaultUpdater = false;
458  bool defaultScaler = false;
459  bool defaultSearcher = false;
460  // use default updater if NULL
461  if (updater == NULL)
462  {
464  defaultUpdater = true;
465  }
466  // use default scaler if NULL
467  if (scaler == NULL)
468  {
470  defaultScaler = true;
471  }
472  // use default searcher if NULL
473  if (searcher == NULL)
474  {
476  defaultSearcher = true;
477  }
478 
479  // recycle old model
480  destroy();
481 
482  // scale problem
483  scale(scaler);
484  // prepare data structure
485  prepare();
486 
487  // solve lagrangian subproblem
488  SolverProperty status = solveSubproblems(updater, 0, m_maxIters);
489 
490  // try to find a feasible solution by post refinement
491  status = postProcess(updater, searcher, status);
492 
493  // recover problem from scaling
494  unscale();
495 
496  // recycle default updater
497  if (defaultUpdater)
498  delete updater;
499  // recycle default scaler
500  if (defaultScaler)
501  delete scaler;
502  // recycle default searcher
503  if (defaultSearcher)
504  delete searcher;
505 
506  return status;
507 }
508 template <typename T, typename V>
510 {
511  // solve lagrangian subproblem
512  SolverProperty status = INFEASIBLE;
513  for (m_iter = beginIter; m_iter < endIter; ++m_iter)
514  {
515  if (!useInitialSolutions() || m_iter != 0)
516  solveLag();
517  computeSlackness();
518 #ifdef DEBUG_MULTIKNAPSACKLAGRELAX
519  limboPrint(kDEBUG, "iteration %u with %u negative slacks, %g lagrangian objective, %g objective\n", m_iter, numNegativeSlackConstraints(false), evaluateLagObjective(), m_model->evaluateObjective());
520  char buf[64];
521  limboSPrint(kNONE, buf, "lag%u", m_iter);
522  std::ofstream out (buf);
523  printObjCoef(out);
524  printLagMultiplier(out);
525  out.close();
526 #endif
527  if ((status = converge()) == OPTIMAL || m_iter+1 == endIter)
528  break;
529 
530  updateLagMultipliers(updater);
531  }
532 
533  return status;
534 }
535 template <typename T, typename V>
537 {
538  // compute scaling factors and perform scale
539  m_vScalingFactor.resize(m_model->constraints().size()+1);
540  // constraints
541  for (unsigned int i = 0, ie = m_model->constraints().size(); i < ie; ++i)
542  {
543  m_vScalingFactor[i] = scaler->operator()(m_model->constraints()[i]);
544  m_model->scaleConstraint(i, 1.0/m_vScalingFactor[i]);
545  }
546  // objective
547  m_vScalingFactor.back() = scaler->operator()(m_model->objective());
548  m_model->scaleObjective(1.0/m_vScalingFactor.back());
549 }
550 template <typename T, typename V>
552 {
553  // constraints
554  for (unsigned int i = 0, ie = m_model->constraints().size(); i < ie; ++i)
555  m_model->scaleConstraint(i, m_vScalingFactor[i]);
556  // objective
557  m_model->scaleObjective(m_vScalingFactor.back());
558 }
559 template <typename T, typename V>
561 {
562  // initialize weights of variables in objective
563  m_vObjCoef = new coefficient_value_type [m_model->numVariables()];
564  std::fill(m_vObjCoef, m_vObjCoef+m_model->numVariables(), 0);
565  for (typename std::vector<term_type>::const_iterator it = m_model->objective().terms().begin(), ite = m_model->objective().terms().end(); it != ite; ++it)
566  m_vObjCoef[it->variable().id()] += it->coefficient();
567 
568  // for fixed variables, set correct solutions
569  unsigned int i = 0;
570  for (unsigned int ie = m_model->numVariables(); i < ie; ++i)
571  {
572  variable_type var (i);
573  variable_value_type lowerBound = m_model->variableLowerBound(var);
574  variable_value_type upperBound = m_model->variableUpperBound(var);
575  if (lowerBound == upperBound)
576  m_model->setVariableSolution(var, lowerBound);
577  }
578 
579  // partition all capacity constraints to the beginning of the array
580  m_vConstraintPartition.resize(m_model->constraints().size());
581  i = 0;
582  for (unsigned int ie = m_model->constraints().size(); i < ie; ++i)
583  m_vConstraintPartition[i] = i;
584  std::vector<unsigned int>::iterator bound = std::partition(m_vConstraintPartition.begin(), m_vConstraintPartition.end(), CapacityConstraintPred(m_model->constraints()));
585  unsigned int numCapacityConstraints = std::distance(m_vConstraintPartition.begin(), bound);
586  m_vLagMultiplier = new coefficient_value_type [numCapacityConstraints];
587  std::fill(m_vLagMultiplier, m_vLagMultiplier+numCapacityConstraints, 0);
588  m_vNewLagMultiplier = new coefficient_value_type [numCapacityConstraints];
589  std::fill(m_vNewLagMultiplier, m_vNewLagMultiplier+numCapacityConstraints, 0);
590  m_vSlackness = new coefficient_value_type [numCapacityConstraints];
591  std::fill(m_vSlackness, m_vSlackness+numCapacityConstraints, 0);
592 
593  // change the sense of '>' to '<'
594  for (std::vector<unsigned int>::iterator it = m_vConstraintPartition.begin(); it != bound; ++it)
595  m_model->constraints().at(*it).normalize('<');
596 
597  // initialize constraint matrix
598  m_constrMatrix.numRows = numCapacityConstraints;
599  m_constrMatrix.numColumns = m_model->numVariables();
600  m_constrMatrix.numElements = 0;
601  m_constrMatrix.vRowBeginIndex = new typename matrix_type::index_type [m_constrMatrix.numRows+1];
602  m_constrMatrix.vRowBeginIndex[0] = matrix_type::s_startingIndex;
603 
604  // initialize vRowBeginIndex
605  i = 1;
606  for (std::vector<unsigned int>::iterator it = m_vConstraintPartition.begin(); it != bound; ++it, ++i)
607  {
608 #ifdef DEBUG_MULTIKNAPSACKLAGRELAX
609  limboAssert(i <= m_constrMatrix.numRows);
610 #endif
611  constraint_type const& constr = m_model->constraints()[*it];
612  m_constrMatrix.vRowBeginIndex[i] = m_constrMatrix.vRowBeginIndex[i-1]+constr.expression().terms().size();
613  }
614  // last element of vRowBeginIndex denotes the total number of elements
615  m_constrMatrix.numElements = m_constrMatrix.vRowBeginIndex[m_constrMatrix.numRows]-matrix_type::s_startingIndex;
616 
617  // initialize vElement and vColumn
618  m_constrMatrix.vElement = new coefficient_value_type [m_constrMatrix.numElements];
619  m_constrMatrix.vColumn = new typename matrix_type::index_type [m_constrMatrix.numElements];
620  i = 0;
621  for (std::vector<unsigned int>::iterator it = m_vConstraintPartition.begin(); it != bound; ++it)
622  {
623  constraint_type const& constr = m_model->constraints()[*it];
624  for (typename std::vector<typename constraint_type::term_type>::const_iterator itt = constr.expression().terms().begin(), itte = constr.expression().terms().end(); itt != itte; ++itt, ++i)
625  {
626 #ifdef DEBUG_MULTIKNAPSACKLAGRELAX
627  limboAssert(i < m_constrMatrix.numElements);
628 #endif
629  m_constrMatrix.vElement[i] = itt->coefficient();
630  m_constrMatrix.vColumn[i] = itt->variable().id()+matrix_type::s_startingIndex;
631  }
632  }
633  // initialize right hand side of constraints
634  m_vConstrRhs = new coefficient_value_type [m_constrMatrix.numRows];
635  i = 0;
636  for (std::vector<unsigned int>::iterator it = m_vConstraintPartition.begin(); it != bound; ++it, ++i)
637  {
638  constraint_type const& constr = m_model->constraints()[*it];
639  m_vConstrRhs[i] = constr.rightHandSide();
640  }
641 
642  // group variables according items
643  // the variables for one item will be grouped
644  // I assume the rest constraints are all single item constraints
645  m_numGroups = std::distance(bound, m_vConstraintPartition.end());
646  unsigned int numGroupElements = 0; // it may be smaller than number of variables due to the existence of fixed variables
647  for (std::vector<unsigned int>::iterator it = bound, ite = m_vConstraintPartition.end(); it != ite; ++it, ++i)
648  {
649  constraint_type const& constr = m_model->constraints()[*it];
650  numGroupElements += constr.expression().terms().size();
651  }
652  m_vGroupedVariable = new variable_type [numGroupElements];
653  m_vVariableGroupBeginIndex = new unsigned int [m_numGroups+1]; // append a dummy begin index as the ending index for last group
654  // append a dummy begin index as the ending index for last group
655  m_vVariableGroupBeginIndex[m_numGroups] = numGroupElements;
656  i = 0; // use as group index
657  unsigned int j = 0; // use as group variable index
658  for (std::vector<unsigned int>::iterator it = bound, ite = m_vConstraintPartition.end(); it != ite; ++it, ++i)
659  {
660  constraint_type const& constr = m_model->constraints()[*it];
661 #ifdef DEBUG_MULTIKNAPSACKLAGRELAX
662  limboAssert(constr.sense() == '=');
663 #endif
664  expression_type const& expr = constr.expression();
665  m_vVariableGroupBeginIndex[i] = j;
666  for (typename std::vector<term_type>::const_iterator itt = expr.terms().begin(), itte = expr.terms().end(); itt != itte; ++itt, ++j)
667  {
668  m_vGroupedVariable[j] = itt->variable();
669  }
670  }
671 }
672 template <typename T, typename V>
674 {
675 #if 1
676  // update lagrangian multiplier
677  // \lambda^{k+1} = \lambda^{k} + t_k (Ax-b)
678  // vector scaling, the slackness we computed is b-Ax
679  updater->operator()(m_iter, m_constrMatrix.numRows, m_vSlackness, m_vLagMultiplier, m_vNewLagMultiplier);
680 
681  // update objective coefficients
682  // c^{k+1, T} = c^{0, T} + \lambda^{k+1, T} (Ax-b) = c^{0, T} + \lambda^{k+1, T} A - \lambda^{k+1, T} b
683  // c^{k+1} = c^{0} + A^T \lambda^{k+1} - b^T \lambda^{k+1} = c^{k} + A^T \Delta \lambda^{k+1} - b^T \lambda^{k+1}
684  axpy(m_constrMatrix.numRows, (coefficient_value_type)-1, m_vLagMultiplier, m_vNewLagMultiplier); // m_vNewLagMultiplier becomes delta multipliers
685  ATxPlusy((coefficient_value_type)1, m_constrMatrix, m_vNewLagMultiplier, m_vObjCoef);
686  axpy(m_constrMatrix.numRows, (coefficient_value_type)1, m_vNewLagMultiplier, m_vLagMultiplier); // update delta multipliers of m_vNewLagMultiplier to m_vLagMultiplier
687 #else
688  updater->operator()(m_iter, m_constrMatrix.numRows, m_vSlackness, m_vLagMultiplier, m_vLagMultiplier);
689 
690  std::fill(m_vObjCoef, m_vObjCoef+m_model->numVariables(), 0);
691  for (typename std::vector<term_type>::const_iterator it = m_model->objective().terms().begin(), ite = m_model->objective().terms().end(); it != ite; ++it)
692  m_vObjCoef[it->variable().id()] += it->coefficient();
693  ATxPlusy((coefficient_value_type)1, m_constrMatrix, m_vLagMultiplier, m_vObjCoef);
694 #endif
695 
696  if (m_lagObjFlag)
697  {
698  m_objConstant = -dot(m_constrMatrix.numRows, m_vConstrRhs, m_vLagMultiplier);
699  }
700 }
701 template <typename T, typename V>
703 {
704  // for each item
705  CompareVariableByCoefficient helper (m_vObjCoef);
706  variable_value_type* vVariableSol = &m_model->variableSolutions()[0];
707  unsigned int i = 0;
708  variable_type const* variableGroupBegin = m_vGroupedVariable;
709  variable_type const* variableGroupEnd = m_vGroupedVariable;
710  variable_type const* variable;
711 
712  // reset variables in this group
713  std::fill(vVariableSol, vVariableSol+m_model->numVariables(), 0);
714  for (i = 0; i < m_numGroups; ++i)
715  {
716  variableGroupBegin = variableGroupEnd;
717  variableGroupEnd = m_vGroupedVariable+m_vVariableGroupBeginIndex[i+1];
718  // find the bin with minimum cost for each item
719  variable = std::min_element(variableGroupBegin, variableGroupEnd, helper);
720  vVariableSol[variable->id()] = 1;
721  }
722  // evaluate current objective
723  if (m_lagObjFlag)
724  m_lagObj = evaluateLagObjective();
725 
726 }
727 template <typename T, typename V>
729 {
730  // s = b-Ax
731  bMinusAx(m_constrMatrix, &m_model->variableSolutions()[0], m_vConstrRhs, m_vSlackness);
732 }
733 template <typename T, typename V>
734 typename MultiKnapsackLagRelax<T, V>::coefficient_value_type MultiKnapsackLagRelax<T, V>::evaluateLagObjective() const
735 {
736  // evaluate current objective
737  coefficient_value_type objValue = m_objConstant;
738  for (unsigned int i = 0, ie = m_model->numVariables(); i < ie; ++i)
739  objValue += m_vObjCoef[i]*m_model->variableSolution(variable_type(i));
740  return objValue;
741 }
742 template <typename T, typename V>
744 {
745  bool feasibleFlag = true;
746  bool convergeFlag = true;
747  for (typename matrix_type::index_type i = 0; i < m_constrMatrix.numRows; ++i)
748  {
749  coefficient_value_type multiplier = m_vLagMultiplier[i];
750  coefficient_value_type slackness = m_vSlackness[i];
751  // must satisfy KKT condition
752  // lambda >= 0
753  // g(x) <= 0
754  // lambda * g(x) = 0
755  //
756  // g(x) = Ax-b = -slackness
757  if (slackness < 0)
758  {
759  convergeFlag = feasibleFlag = false;
760  break;
761  }
762  else if (multiplier*slackness != 0)
763  {
764  convergeFlag = false;
765  }
766  }
767  SolverProperty status = INFEASIBLE;
768  // store feasible solutions with better objective
769  if (feasibleFlag)
770  {
771  coefficient_value_type obj = m_model->evaluateObjective();
772  if (obj < m_bestObj)
773  {
774  m_vBestVariableSol = m_model->variableSolutions();
775  m_bestObj = obj;
776  }
777  status = SUBOPTIMAL;
778  }
779  if (convergeFlag)
780  status = OPTIMAL;
781 
782  return status;
783 }
784 template <typename T, typename V>
786 {
787  if (status == OPTIMAL) // already OPTIMAL
788  return status;
789  else if (m_bestObj != std::numeric_limits<coefficient_value_type>::max()) // there is a best feasible solution in store
790  {
791  m_model->variableSolutions() = m_vBestVariableSol;
792  return SUBOPTIMAL;
793  }
794  else // no best solutions in store
795  {
796  // try to search feasible solution with heuristic
797  return searcher->operator()(updater);
798  }
799 }
801 template <typename T, typename V>
802 template <typename TT, typename VV>
803 void MultiKnapsackLagRelax<T, V>::bMinusAx(typename MultiKnapsackLagRelax<T, V>::matrix_type const& A, VV const* x, TT const* b, TT* y) const
804 {
805  // s = b-Ax
806  vcopy(A.numRows, b, y);
807  AxPlusy((coefficient_value_type)-1, A, x, y);
808 }
810 template <typename T, typename V>
811 bool MultiKnapsackLagRelax<T, V>::printVariableGroup(std::string const& filename) const
812 {
813  std::ofstream out (filename.c_str());
814  if (!out.good())
815  {
816  limbo::limboPrint(kWARN, "failed to open %s for write", filename.c_str());
817  return false;
818  }
819  printVariableGroup(out);
820  out.close();
821  return true;
822 }
823 template <typename T, typename V>
824 std::ostream& MultiKnapsackLagRelax<T, V>::printVariableGroup(std::ostream& os) const
825 {
826  os << __func__ << " iteration " << m_iter << "\n";
827  for (unsigned int i = 0; i < m_numGroups; ++i)
828  {
829  os << "[" << i << "]";
830  for (unsigned int j = m_vVariableGroupBeginIndex[i]; j < m_vVariableGroupBeginIndex[i+1]; ++j)
831  {
832  variable_type* variable = m_vGroupedVariable[j];
833  if (m_model->variableSolution(*variable) == 1)
834  os << " *" << m_model->variableName(*variable) << "*";
835  else
836  os << " " << m_model->variableName(*variable);
837  }
838  os << "\n";
839  }
840  return os;
841 }
842 template <typename T, typename V>
843 bool MultiKnapsackLagRelax<T, V>::printObjCoef(std::string const& filename) const
844 {
845  std::ofstream out (filename.c_str());
846  if (!out.good())
847  {
848  limbo::limboPrint(kWARN, "failed to open %s for write", filename.c_str());
849  return false;
850  }
851  printObjCoef(out);
852  out.close();
853  return true;
854 }
855 template <typename T, typename V>
856 std::ostream& MultiKnapsackLagRelax<T, V>::printObjCoef(std::ostream& os) const
857 {
858  os << __func__ << " iteration " << m_iter << "\n";
859  os << "lagrangian objective = " << m_lagObj << "\n";
860  os << "objective = " << m_model->evaluateObjective() << "\n";
861  for (unsigned int i = 0, ie = m_model->numVariables(); i < ie; ++i)
862  os << m_model->variableName(variable_type(i)) << " = " << m_vObjCoef[i] << "\n";
863  return os;
864 }
865 template <typename T, typename V>
866 bool MultiKnapsackLagRelax<T, V>::printLagMultiplier(std::string const& filename) const
867 {
868  std::ofstream out (filename.c_str());
869  if (!out.good())
870  {
871  limbo::limboPrint(kWARN, "failed to open %s for write", filename.c_str());
872  return false;
873  }
874  printLagMultiplier(out);
875  out.close();
876  return true;
877 }
878 template <typename T, typename V>
879 std::ostream& MultiKnapsackLagRelax<T, V>::printLagMultiplier(std::ostream& os) const
880 {
881  os << __func__ << " iteration " << m_iter << "\n";
882  for (int i = 0; i < m_constrMatrix.numRows; ++i)
883  os << "[" << m_model->constraintName(m_model->constraints().at(m_vConstraintPartition[i])) << "] = " << m_vLagMultiplier[i]
884  << " slack = " << m_vSlackness[i]
885  << "\n";
886  return os;
887 }
888 template <typename T, typename V>
889 std::ostream& MultiKnapsackLagRelax<T, V>::printConstraint(std::ostream& os, std::string const& name) const
890 {
891  for (int i = 0; i < this->m_constrMatrix.numRows; ++i)
892  {
893  constraint_type const& constr = this->m_model->constraints()[i];
894  if (m_model->constraintName(constr) == name)
895  {
896  os << "constraint " << name << ": rhs = " << constr.rightHandSide() << "\n";
897  for (typename std::vector<term_type>::const_iterator it = constr.expression().terms().begin(), ite = constr.expression().terms().end(); it != ite; ++it)
898  os << m_model->variableName(it->variable()) << ": " << m_model->variableSolution(it->variable()) << "*" << it->coefficient() << "\n";
899  }
900  }
901  return os;
902 }
903 template <typename T, typename V>
904 template <typename TT>
905 void MultiKnapsackLagRelax<T, V>::printArray(unsigned int n, TT const* array, bool nonzeroFlag) const
906 {
907  limboPrint(kNONE, "array of length %u = {", n);
908  for (unsigned int i = 0; i < n; ++i)
909  {
910  if (nonzeroFlag)
911  {
912  if (array[i] != 0)
913  {
914  if (i != 0)
915  limboPrint(kNONE, ", ");
916  limboPrint(kNONE, "%u:%g", i, (double)array[i]);
917  }
918  }
919  else
920  {
921  if (i != 0)
922  limboPrint(kNONE, ", ");
923  limboPrint(kNONE, "%g", (double)array[i]);
924  }
925  }
926  limboPrint(kNONE, "}\n");
927 }
928 
932 template <typename T>
934 {
935  public:
937  typedef T value_type;
938 
943 
949  virtual value_type operator()(unsigned int iter, value_type multiplier, value_type slackness) = 0;
956  virtual void operator()(unsigned int iter, unsigned int n, value_type const* vSlackness, value_type const* vLagMultiplier, value_type* vNewLagMultiplier) = 0;
957 };
958 
961 template <typename T>
962 class SubGradientDescent : public LagMultiplierUpdater<T>
963 {
964  public:
969 
973  SubGradientDescent(value_type alpha = 1, value_type beta = 1)
974  : SubGradientDescent::base_type()
975  , m_alpha(alpha)
976  , m_beta(beta)
977  , m_iter(std::numeric_limits<unsigned int>::max())
978  , m_scalingFactor(1)
979  {
980  }
984  {
985  copy(rhs);
986  }
990  {
991  if (this != &rhs)
992  {
993  this->base_type::operator=(rhs);
994  copy(rhs);
995  }
996  return *this;
997  }
1000  {
1001  }
1002 
1008  value_type operator()(unsigned int iter, value_type multiplier, value_type slackness)
1009  {
1010  // compute scaling factor
1011  computeScalingFactor(iter);
1012  value_type result = std::max((value_type)0, multiplier-m_scalingFactor*slackness);
1013  return result;
1014  }
1021  void operator()(unsigned int iter, unsigned int n, value_type const* vSlackness, value_type const* vLagMultiplier, value_type* vNewLagMultiplier)
1022  {
1023  // compute scaling factor
1024  computeScalingFactor(iter);
1025  value_type const* slackness = vSlackness;
1026  value_type const* multiplier = vLagMultiplier;
1027  value_type* newMultiplier = vNewLagMultiplier;
1028  for (unsigned int i = 0; i < n; ++i)
1029  {
1030  *newMultiplier = std::max((value_type)0, *multiplier-m_scalingFactor*(*slackness));
1031  ++multiplier;
1032  ++slackness;
1033  ++newMultiplier;
1034  }
1035  }
1036  protected:
1039  void copy(SubGradientDescent const& rhs)
1040  {
1041  m_alpha = rhs.m_alpha;
1042  m_beta = rhs.m_beta;
1043  m_iter = rhs.m_iter;
1044  m_scalingFactor = rhs.m_scalingFactor;
1045  }
1048  void computeScalingFactor(unsigned int iter)
1049  {
1050  // avoid frequent computation of scaling factor
1051  if (m_iter != iter)
1052  {
1053  m_iter = iter;
1054  m_scalingFactor = pow((value_type)m_iter+1, -m_alpha)*m_beta;
1055  }
1056  }
1057 
1058  value_type m_alpha;
1059  value_type m_beta;
1060  unsigned int m_iter;
1061  value_type m_scalingFactor;
1062 };
1063 
1067 template <typename T, typename V>
1068 class ProblemScaler
1069 {
1070  public:
1081 
1085  virtual ~ProblemScaler() {}
1086 
1091  virtual value_type operator()(expression_type const& /*expr*/) const
1092  {
1093  return 1;
1094  }
1098  virtual value_type operator()(constraint_type const& constr) const
1099  {
1100  return this->operator()(constr.expression());
1101  }
1102 };
1103 
1107 template <typename T, typename V>
1109 {
1110  public:
1122  typedef typename base_type::term_type term_type;
1123 
1126  MinCoefficientScaler(value_type factor = 1) : base_type(), m_scalingFactor(factor) {}
1129 
1133  value_type operator()(expression_type const& expr) const
1134  {
1135  value_type result = std::numeric_limits<value_type>::max();
1136  for (typename std::vector<term_type>::const_iterator it = expr.terms().begin(), ite = expr.terms().end(); it != ite; ++it)
1137  result = std::min(result, it->coefficient());
1138  return result*m_scalingFactor;
1139  }
1143  value_type operator()(constraint_type const& constr) const
1144  {
1145  return this->operator()(constr.expression());
1146  }
1147 
1148  protected:
1149  value_type m_scalingFactor;
1150 };
1151 
1155 template <typename T, typename V>
1156 class L2NormScaler : public ProblemScaler<T, V>
1157 {
1158  public:
1170  typedef typename base_type::term_type term_type;
1171 
1173  L2NormScaler() : base_type() {}
1176 
1180  value_type operator()(expression_type const& expr) const
1181  {
1182  value_type result = 0;
1183  for (typename std::vector<term_type>::const_iterator it = expr.terms().begin(), ite = expr.terms().end(); it != ite; ++it)
1184  result += it->coefficient()*it->coefficient();
1185  return sqrt(result/expr.terms().size());
1186  }
1190  value_type operator()(constraint_type const& constr) const
1191  {
1192  return this->operator()(constr.expression());
1193  }
1194 };
1195 
1199 template <typename T, typename V>
1200 class FeasibleSearcher
1201 {
1202  public:
1223 
1226  FeasibleSearcher(solver_type* solver)
1227  : m_solver(solver)
1228  , m_model(solver->m_model)
1229  , m_vObjCoef(solver->m_vObjCoef)
1230  , m_constrMatrix(solver->m_constrMatrix)
1231  , m_vConstrRhs(solver->m_vConstrRhs)
1234  , m_numGroups(solver->m_numGroups)
1237  , m_vSlackness(solver->m_vSlackness)
1239  , m_objConstant(solver->m_objConstant)
1240  , m_lagObj(solver->m_lagObj)
1241  , m_iter(solver->m_iter)
1242  , m_maxIters(solver->m_maxIters)
1243  , m_useInitialSol(solver->m_useInitialSol)
1245  , m_bestObj(solver->m_bestObj)
1246  {
1247  }
1249  virtual ~FeasibleSearcher() {}
1250 
1255  virtual SolverProperty operator()(updater_type* /*updater*/) {return INFEASIBLE;}
1256 
1257  protected:
1260  {
1262  }
1267  SolverProperty solveSubproblems(updater_type* updater, unsigned int beginIter, unsigned int endIter)
1268  {
1269  return m_solver->solveSubproblems(updater, beginIter, endIter);
1270  }
1271 
1272  solver_type* m_solver;
1273  model_type* const& m_model;
1274 
1275  coefficient_value_type*& m_vObjCoef;
1276  matrix_type const& m_constrMatrix;
1277  coefficient_value_type* const& m_vConstrRhs;
1278 
1279  variable_type* const& m_vGroupedVariable;
1280  unsigned int* const& m_vVariableGroupBeginIndex;
1281  unsigned int const& m_numGroups;
1282  std::vector<unsigned int> const& m_vConstraintPartition;
1283  coefficient_value_type*& m_vLagMultiplier;
1284  coefficient_value_type*& m_vSlackness;
1285  std::vector<coefficient_value_type> const& m_vScalingFactor;
1286  coefficient_value_type& m_objConstant;
1287  coefficient_value_type& m_lagObj;
1288  unsigned int& m_iter;
1289  unsigned int& m_maxIters;
1291 
1292  std::vector<variable_value_type>& m_vBestVariableSol;
1293  coefficient_value_type& m_bestObj;
1294 };
1295 
1300 template <typename T, typename V>
1301 class SearchByAdjustCoefficient : public FeasibleSearcher<T, V>
1302 {
1303  public:
1326 
1329  {
1330  variable_type variable;
1331  coefficient_value_type moveCost;
1332  coefficient_value_type capacity;
1333 
1338  VariableMoveCost(variable_type var, coefficient_value_type mc, coefficient_value_type cap)
1339  : variable(var)
1340  , moveCost(mc)
1341  , capacity(cap)
1342  {
1343  }
1344  };
1345 
1348  {
1352  bool operator()(VariableMoveCost const& c1, VariableMoveCost const& c2) const
1353  {
1354  return c1.moveCost/(1+c1.capacity) < c2.moveCost/(1+c2.capacity);
1355  }
1356  };
1357 
1361  SearchByAdjustCoefficient(solver_type* solver, coefficient_value_type convergeRatio = 0.1) : base_type(solver), m_convergeRatio(convergeRatio) {}
1364 
1368  virtual SolverProperty operator()(updater_type* updater)
1369  {
1370  SolverProperty status = INFEASIBLE;
1371  // map variable to group
1372  this->mapVariable2Group();
1373  // record number of bins with negative slack
1374  unsigned int numNegativeSlacksPrev = std::numeric_limits<unsigned int>::max();
1375  unsigned int numNegativeSlacks = std::numeric_limits<unsigned int>::max();
1376  // mark whether a variable has been processed
1377  std::vector<bool> vVariableProcess (this->m_model->numVariables(), false);
1378  // record move cost of items
1379  std::vector<VariableMoveCost> vVariableMoveCost;
1380  // large cost
1381  coefficient_value_type largeCost = 0;
1382  for (coefficient_value_type const* it = this->m_vObjCoef, * ite = this->m_vObjCoef+this->m_model->numVariables(); it != ite; ++it)
1383  largeCost += (*it > 0)? *it : 0;
1384  do
1385  {
1386  vVariableProcess.assign(this->m_model->numVariables(), false);
1387  // update number of bins with negative slack for previous iteration
1388  numNegativeSlacksPrev = numNegativeSlacks;
1389  numNegativeSlacks = 0;
1390  // go through all bins with negative slack
1391  for (typename matrix_type::index_type i = 0; i < this->m_constrMatrix.numRows; ++i)
1392  {
1393  coefficient_value_type slackness = this->m_vSlackness[i];
1394  if (slackness < 0)
1395  {
1396  constraint_type const& constr = this->m_model->constraints()[i];
1397  // compute move cost for items in this bin
1398  computeMoveCost(constr, vVariableProcess, vVariableMoveCost);
1399  // try to forbid some items to be assigned to this bin
1400  // sort items by its cost of moving to other bins
1401  std::sort(vVariableMoveCost.begin(), vVariableMoveCost.end(), CompareVariableMoveCost());
1402 
1403  // the total capacity of items moving out
1404  for (typename std::vector<VariableMoveCost>::const_iterator it = vVariableMoveCost.begin(), ite = vVariableMoveCost.end(); it != ite; ++it)
1405  {
1406  if (slackness < 0)
1407  {
1408  // increase the cost of assigning the item to this bin
1409  //this->m_vObjCoef[it->variable.id()] += (it->moveCost+1)*100;
1410  this->m_vObjCoef[it->variable.id()] = largeCost;
1411  // update total capacity of items moving out
1412  slackness += it->capacity;
1413  // mark as processed
1414  vVariableProcess[it->variable.id()] = true;
1415  }
1416  else break;
1417  }
1418  // compute number of bins with negative slack
1419  ++numNegativeSlacks;
1420  }
1421  }
1422  if (numNegativeSlacks == 0)
1423  break;
1424  // run more iterations with the updated coefficients
1425  status = this->solveSubproblems(updater, this->m_iter+1, this->m_iter+this->m_maxIters/2);
1426  } while (numNegativeSlacks && numNegativeSlacks*(1+m_convergeRatio) < numNegativeSlacksPrev);
1427 
1428  return status;
1429  }
1430  protected:
1433  {
1434  // be careful that some variables may not belong to any group
1435  // I do not handle this since it should not be a problem if the variables are accessed from constraints
1437  for (unsigned int i = 0; i < this->m_numGroups; ++i)
1438  {
1439  variable_type const* it = this->m_vGroupedVariable+this->m_vVariableGroupBeginIndex[i];
1440  variable_type const* ite = this->m_vGroupedVariable+this->m_vVariableGroupBeginIndex[i+1];
1441  for (; it != ite; ++it)
1442  {
1443  this->m_vVariable2Group[it->id()] = i;
1444  }
1445  }
1446  }
1451  void computeMoveCost(constraint_type const& constr, std::vector<bool> const& vVariableProcess, std::vector<VariableMoveCost>& vVariableMoveCost) const
1452  {
1453  // extract items that are currently assigned to this bin
1454  vVariableMoveCost.clear();
1455  unsigned int j = 0;
1456  for (typename std::vector<term_type>::const_iterator it = constr.expression().terms().begin(), ite = constr.expression().terms().end(); it != ite; ++it, ++j)
1457  {
1458  // selected but not processed yet
1459  if (this->m_model->variableSolution(it->variable()) && !vVariableProcess[it->variable().id()])
1460  {
1461  // compute move cost of moving item to other bins
1462  coefficient_value_type moveCost = std::numeric_limits<coefficient_value_type>::max();
1463  unsigned int group = this->m_vVariable2Group[it->variable().id()];
1464  variable_type const* itv = this->m_vGroupedVariable+this->m_vVariableGroupBeginIndex[group];
1465  variable_type const* itve = this->m_vGroupedVariable+this->m_vVariableGroupBeginIndex[group+1];
1466  for (; itv != itve; ++itv)
1467  {
1468  if (it->variable() != *itv) // different variables
1469  {
1470  moveCost = std::min(moveCost, this->m_vObjCoef[itv->id()]-this->m_vObjCoef[it->variable().id()]);
1471  }
1472  }
1473  // use the ratio of move cost to capacity
1474  vVariableMoveCost.push_back(VariableMoveCost(it->variable(), moveCost, it->coefficient()));
1475  }
1476  }
1477  }
1478 
1479  std::vector<unsigned int> m_vVariable2Group;
1480  coefficient_value_type m_convergeRatio;
1481 };
1482 
1486 template <typename T, typename V>
1488 {
1489  public:
1510 
1513  {
1514  variable_type variable;
1515  variable_type targetVariable;
1516  coefficient_value_type moveCost;
1517 
1522  VariableMoveCost(variable_type var, variable_type targetVar, coefficient_value_type mc)
1523  : variable(var)
1524  , targetVariable(targetVar)
1525  , moveCost(mc)
1526  {
1527  }
1528  };
1529 
1532  {
1536  bool operator()(VariableMoveCost const& c1, VariableMoveCost const& c2) const
1537  {
1538  return c1.moveCost < c2.moveCost;
1539  }
1540  };
1541 
1542 
1545  {
1546  coefficient_value_type const* vSlackness;
1547 
1550  CompareConstraintSlack(coefficient_value_type const* v) : vSlackness(v) {}
1554  bool operator()(unsigned int i, unsigned int j) const
1555  {
1556  return vSlackness[i] < vSlackness[j];
1557  }
1558  };
1559 
1562  SearchByBinSmoothing(solver_type* solver) : base_type(solver) {}
1565 
1570  virtual SolverProperty operator()(updater_type* /*updater*/)
1571  {
1572  SolverProperty status = INFEASIBLE;
1573  // map variable to group
1574  this->mapVariable2Group();
1575  // map variable to constraint
1576  this->mapVariable2Constraint();
1577  // record move cost of items
1578  std::vector<VariableMoveCost> vVariableMoveCost;
1579  // collect bins with negative slack
1580  std::vector<unsigned int> vNegativeSlackConstr;
1581 
1582  // go through all bins with negative slack
1583  for (typename matrix_type::index_type i = 0; i < this->m_constrMatrix.numRows; ++i)
1584  {
1585  coefficient_value_type slackness = this->m_vSlackness[i];
1586  if (slackness < 0)
1587  vNegativeSlackConstr.push_back(i);
1588  }
1589 
1590  // sort bins from small slackness to large
1591  std::sort(vNegativeSlackConstr.begin(), vNegativeSlackConstr.end(), CompareConstraintSlack(this->m_vSlackness));
1592 
1593  // go through all bins with negative slack
1594  for (std::vector<unsigned int>::const_iterator it = vNegativeSlackConstr.begin(), ite = vNegativeSlackConstr.end(); it != ite; ++it)
1595  {
1596  constraint_type const& constr = this->m_model->constraints()[*it];
1597 
1598  while (this->m_vSlackness[*it] < 0)
1599  {
1600  // compute move cost for items in this bin
1601  vVariableMoveCost.clear();
1602  computeMoveCost(constr, vVariableMoveCost);
1603  // sort items by its cost of moving to other bins
1604  typename std::vector<VariableMoveCost>::const_iterator itm = std::min_element(vVariableMoveCost.begin(), vVariableMoveCost.end(), CompareVariableMoveCost());
1605 
1606  // move out at most one item once
1607  // so that we can always get the accurate capacity of all bins
1608  if (itm->moveCost != std::numeric_limits<coefficient_value_type>::max())
1609  {
1610  // update total capacity of all bins when the item moves out
1611  variable_type const& var = itm->variable;
1612  this->m_model->setVariableSolution(var, 0);
1613  for (std::vector<std::pair<unsigned int, unsigned int> >::const_iterator itc = this->m_mVariable2Constr[var.id()].begin(), itce = this->m_mVariable2Constr[var.id()].end(); itc != itce; ++itc)
1614  {
1615  constraint_type const& curConstr = this->m_model->constraints()[itc->first];
1616  term_type const& curTerm = curConstr.expression().terms()[itc->second];
1617  coefficient_value_type& curSlackness = this->m_vSlackness[itc->first];
1618 
1619  curSlackness += curTerm.coefficient();
1620  }
1621  // update capacity of all bins when the item moves into other bins
1622  variable_type const& targetVar = itm->targetVariable;
1623  this->m_model->setVariableSolution(targetVar, 1);
1624  for (std::vector<std::pair<unsigned int, unsigned int> >::const_iterator itc = this->m_mVariable2Constr[targetVar.id()].begin(), itce = this->m_mVariable2Constr[targetVar.id()].end(); itc != itce; ++itc)
1625  {
1626  constraint_type const& curConstr = this->m_model->constraints()[itc->first];
1627  term_type const& curTerm = curConstr.expression().terms()[itc->second];
1628  coefficient_value_type& curSlackness = this->m_vSlackness[itc->first];
1629 
1630  curSlackness -= curTerm.coefficient();
1631  }
1632  }
1633  else break;
1634  }
1635  }
1636  // go through all bins with negative slack and compute status
1637  status = SUBOPTIMAL;
1638  for (std::vector<unsigned int>::const_iterator it = vNegativeSlackConstr.begin(), ite = vNegativeSlackConstr.end(); it != ite; ++it)
1639  {
1640  if (this->m_vSlackness[*it] < 0)
1641  {
1642  status = INFEASIBLE;
1643  break;
1644  }
1645  }
1646  return status;
1647  }
1648  protected:
1651  {
1652  this->m_mVariable2Constr.resize(this->m_model->numVariables());
1653  for (typename matrix_type::index_type i = 0; i < this->m_constrMatrix.numRows; ++i)
1654  {
1655  constraint_type const& constr = this->m_model->constraints()[i];
1656  unsigned int j = 0;
1657  for (typename std::vector<term_type>::const_iterator it = constr.expression().terms().begin(), ite = constr.expression().terms().end(); it != ite; ++it, ++j)
1658  this->m_mVariable2Constr[it->variable().id()].push_back(std::make_pair(i, j));
1659  }
1660 
1661  m_vObjCoefOrig.resize(this->m_model->numVariables(), 0);
1662  for (typename std::vector<term_type>::const_iterator it = this->m_model->objective().terms().begin(), ite = this->m_model->objective().terms().end(); it != ite; ++it)
1663  m_vObjCoefOrig[it->variable().id()] = it->coefficient();
1664  }
1668  void computeMoveCost(constraint_type const& constr, std::vector<VariableMoveCost>& vVariableMoveCost) const
1669  {
1670  // extract items that are currently assigned to this bin
1671  vVariableMoveCost.clear();
1672  unsigned int j = 0;
1673  for (typename std::vector<term_type>::const_iterator it = constr.expression().terms().begin(), ite = constr.expression().terms().end(); it != ite; ++it, ++j)
1674  {
1675  variable_type const& var = it->variable();
1676  // selected items
1677  if (this->m_model->variableSolution(var))
1678  {
1679  // compute move cost of moving item to other bins
1680  coefficient_value_type moveCost = std::numeric_limits<coefficient_value_type>::max();
1681  variable_type targetVar;
1682  unsigned int group = this->m_vVariable2Group[it->variable().id()];
1683  variable_type const* itv = this->m_vGroupedVariable+this->m_vVariableGroupBeginIndex[group];
1684  variable_type const* itve = this->m_vGroupedVariable+this->m_vVariableGroupBeginIndex[group+1];
1685  for (; itv != itve; ++itv)
1686  {
1687  if (var != *itv) // different variables
1688  {
1689  // find the minimum slackness of target bins
1690  bool enoughCapacityFlag = true;
1691  for (std::vector<std::pair<unsigned int, unsigned int> >::const_iterator itc = this->m_mVariable2Constr[itv->id()].begin(), itce = this->m_mVariable2Constr[itv->id()].end(); itc != itce; ++itc)
1692  {
1693  coefficient_value_type slackness = this->m_vSlackness[itc->first];
1694  coefficient_value_type coeff = this->m_model->constraints()[itc->first].expression().terms()[itc->second].coefficient();
1695  if (slackness < coeff)
1696  {
1697  enoughCapacityFlag = false;
1698  break;
1699  }
1700  }
1701  if (!enoughCapacityFlag)
1702  continue;
1703  coefficient_value_type targetCost = this->m_vObjCoefOrig[itv->id()];
1704  if (moveCost > targetCost)
1705  {
1706  moveCost = targetCost;
1707  targetVar = *itv;
1708  }
1709  }
1710  }
1711  // use the ratio of move cost to capacity
1712  vVariableMoveCost.push_back(VariableMoveCost(var, targetVar, moveCost));
1713  }
1714  }
1715  }
1716 
1717  std::vector<std::vector<std::pair<unsigned int, unsigned int> > > m_mVariable2Constr;
1718  std::vector<coefficient_value_type> m_vObjCoefOrig;
1719 };
1720 
1724 template <typename T, typename V>
1726 {
1727  public:
1748 
1752  SearchByCombinedStrategy(solver_type* solver, coefficient_value_type convergeRatio = 0.1)
1753  : base_type(solver)
1754  , m_searcherCoeff(solver, convergeRatio)
1755  , m_searcherSmoothing(solver)
1756  {
1757  }
1760 
1764  virtual SolverProperty operator()(updater_type* updater)
1765  {
1766  SolverProperty status = m_searcherCoeff(updater);
1767  if (status == INFEASIBLE)
1768  status = m_searcherSmoothing(updater);
1769  return status;
1770  }
1771 
1772  protected:
1775 };
1776 
1777 } // namespace solvers
1778 } // namespace limbo
1779 
1780 #endif
model_type::term_type term_type
term type
std::vector< unsigned int > m_vVariable2Group
map variables to groups
SearchByAdjustCoefficient< T, V > base_type
base type
Scaling scheme with minimum coefficient in an expression.
unsigned int id() const
Definition: Solvers.h:117
coefficient_value_type const * vSlackness
array of slackness
solver_type::matrix_type matrix_type
matrix type
variable_value_type variableSolution(variable_type const &var) const
Definition: Solvers.h:1376
solver_type::updater_type updater_type
updater type for lagrangian multipliers
variable_type targetVariable
variable of the item for the target bin
Base heuristic to search for feasible solutions.
MultiKnapsackLagRelax(MultiKnapsackLagRelax const &rhs)
copy constructor
Describe properties of a variable.
Definition: Solvers.h:72
std::vector< unsigned int > m_vConstraintPartition
indices of constraints, the first partition is capacity constraints
bool m_lagObjFlag
whether evaluate objective of the lagrangian subproblem in each iteration
base_type::model_type model_type
model type
SolverProperty
Some enums used in solver.
Definition: Solvers.h:29
FeasibleSearcher(solver_type *solver)
constructor
SolverProperty solveSubproblems(updater_type *updater, unsigned int beginIter, unsigned int endIter)
kernel lagrangian iterations
value_type operator()(expression_type const &expr) const
API to compute scaling factor for expression using L2 norm.
unsigned int m_maxIters
maximum number of iterations
model_type::coefficient_value_type coefficient_value_type
coefficient value type
int limboSPrint(MessageType m, char *buf, const char *format,...)
formatted print with prefix to buffer
Definition: PrintMsg.h:101
ProblemScaler< T, V > base_type
base type
base_type::term_type term_type
term type
SearchByCombinedStrategy(solver_type *solver, coefficient_value_type convergeRatio=0.1)
constructor
coefficient_value_type coefficient() const
Definition: Solvers.h:388
LinearModel< T, V > model_type
linear model type for the problem
coefficient_value_type *& m_vLagMultiplier
array of lagrangian multipliers
std::vector< coefficient_value_type > m_vObjCoefOrig
original coefficient of variable in objective
model_type::variable_value_type variable_value_type
variable value type
model_type::constraint_type constraint_type
constraint type
void reset()
Destroy matrix and recycle memory.
Definition: Solvers.h:1774
coefficient_value_type *const & m_vConstrRhs
constraint right hand side
unsigned int *const & m_vVariableGroupBeginIndex
begin index of grouped variable
model_type::term_type term_type
term type
Basic utilities such as variables and linear expressions in solvers.
void computeSlackness()
compute slackness in an iteration
virtual value_type operator()(expression_type const &) const
API to compute scaling factor for expression using L2 norm.
LinearModel< T, V > model_type
model type
base_type::term_type term_type
term type
bool is_integer(string const &s)
check whether string represents an integer
Definition: String.h:28
Predicate to sort variables according to their coefficient from small to large.
model_type *const & m_model
model for the problem
void ATxPlusy(T a, MatrixType const &A, V const *x, T *y)
Definition: Numerical.h:226
bool m_useInitialSol
whether use initial solutions or not
bool & m_useInitialSol
whether use initial solutions or not
void mapVariable2Constraint()
construct mapping from variables to constraints
model_type::variable_type variable_type
variable type
SubGradientDescent(value_type alpha=1, value_type beta=1)
constructor
coefficient_value_type m_bestObj
best objective found so far
Predicate whether a constraint is a capacity constraint.
SubGradientDescent(SubGradientDescent const &rhs)
copy constructor
V variable_value_type
V variable.
Definition: Solvers.h:1166
unsigned int numNegativeSlackConstraints(bool evaluateFlag)
get number of constraints with negative slackness in current iteration
SolverProperty solveSubproblems(updater_type *updater, unsigned int beginIter, unsigned int endIter)
kernel lagrangian iterations
coefficient_value_type m_objConstant
constant value in objective from lagrangian relaxation
model_type::variable_type variable_type
variable type
void setLagObjFlag(bool f)
set evaluating objective of lagrangian subproblem in each iteration
std::vector< coefficient_value_type > const & m_vScalingFactor
scaling factor for constraints and objective, last entry is for objective
model_type::constraint_type constraint_type
constraint type
FeasibleSearcher< T, V > base_type
base type
T coefficient_value_type
T coefficient.
Definition: Solvers.h:1164
model_type::coefficient_value_type coefficient_value_type
coefficient value type
MultiKnapsackLagRelax & operator=(MultiKnapsackLagRelax const &rhs)
assignment
void copy(MultiKnapsackLagRelax const &rhs)
copy object
solver_type::matrix_type matrix_type
matrix type
MinCoefficientScaler(value_type factor=1)
constructor
void computeMoveCost(constraint_type const &constr, std::vector< bool > const &vVariableProcess, std::vector< VariableMoveCost > &vVariableMoveCost) const
compute move cost for an item to move out from current bin
SolverProperty operator()(updater_type *updater=NULL, scaler_type *scaler=NULL, searcher_type *searcher=NULL)
API to run the algorithm.
expression_type const & objective() const
Definition: Solvers.h:1292
model_type::constraint_type constraint_type
constraint type
value_type operator()(constraint_type const &constr) const
API to compute scaling factor for constraints using L2 norm.
base_type::model_type model_type
model type
coefficient_value_type *& m_vSlackness
array of slackness values in each iteration,
coefficient_value_type m_lagObj
current objective of the lagrangian subproblem
std::vector< variable_value_type > m_vBestVariableSol
best feasible solution found so far
Describe linear constraint.
Definition: Solvers.h:78
bool operator()(VariableMoveCost const &c1, VariableMoveCost const &c2) const
virtual SolverProperty operator()(updater_type *updater)
API to search for feasible solutions.
void bMinusAx(matrix_type const &A, VV const *x, TT const *b, TT *y) const
function to compute
virtual value_type operator()(constraint_type const &constr) const
API to compute scaling factor for constraints using L2 norm.
SubGradientDescent & operator=(SubGradientDescent const &rhs)
assignment
void printArray(unsigned int n, TT const *array, bool nonzeroFlag) const
print array
bool printLagMultiplier(std::string const &filename) const
print lagrangian multipliers to file
std::vector< constraint_type > const & constraints() const
Definition: Solvers.h:1210
bool operator()(variable_type const &v1, variable_type const &v2) const
numerical functions for linear algebra
model_type::variable_type variable_type
variable type
LinearModel< T, V > model_type
model type
unsigned int numVariables() const
Definition: Solvers.h:1316
base_type::solver_type solver_type
solver type
coefficient_value_type & m_objConstant
constant value in objective from lagrangian relaxation
base_type::model_type model_type
model type
void setMaxIterations(unsigned int maxIter)
set maximum iterations
base_type::expression_type expression_type
expression type
coefficient_value_type * m_vSlackness
array of slackness values in each iteration,
MultiKnapsackLagRelax< T, V > solver_type
solver type
MultiKnapsackLagRelax(model_type *model)
constructor
void axpy(unsigned int n, T a, V const *x, T *y)
Definition: Numerical.h:179
Heuristic to search for feasible solutions by smoothing dense bins.
void mapVariable2Group()
construct mapping from variables to groups
CapacityConstraintPred(std::vector< constraint_type > const &v)
constructor
base_type::value_type value_type
value type
unsigned int & m_maxIters
maximum number of iterations
SearchByBinSmoothing< coefficient_value_type, variable_value_type > m_searcherSmoothing
search by smoothing dense bins
model_type::expression_type expression_type
expression type
CompareConstraintSlack(coefficient_value_type const *v)
constructor
model_type::term_type term_type
term type
the model is infeasible
Definition: Solvers.h:37
std::ostream & printConstraint(std::ostream &os, std::string const &name) const
print constraint
std::vector< unsigned int > const & m_vConstraintPartition
indices of constraints, the first partition is capacity constraints
bool printObjCoef(std::string const &filename) const
print coefficients of variables in objective to file
Solve multiple knapsack problem with lagrangian relaxation.
coefficient_value_type & m_bestObj
best objective found so far
coefficient_value_type *& m_vObjCoef
coefficients variables in objective
model_type::expression_type expression_type
expression type
base_type::solver_type solver_type
solver type
Base class for scaling scheme with default no scaling.
expression_type const & expression() const
Definition: Solvers.h:1028
coefficient_value_type evaluateLagObjective() const
evaluate objective of the lagrangian subproblem
#define limboStaticAssert(condition)
compile time assertion
Definition: AssertMsg.h:87
variable_type * m_vGroupedVariable
array of grouped variables according to item
model_type * m_model
model for the problem
SolverProperty solve(updater_type *updater, scaler_type *scaler, searcher_type *searcher)
kernel function to solve the problem
virtual SolverProperty operator()(updater_type *)
API to search for feasible solutions.
the model is suboptimal
Definition: Solvers.h:38
model_type::expression_type expression_type
expression type
SearchByAdjustCoefficient< coefficient_value_type, variable_value_type > m_searcherCoeff
search by adjusting coefficient
value_type operator()(expression_type const &expr) const
API to compute scaling factor for expression using L2 norm.
base_type::model_type model_type
model type
FeasibleSearcher< T, V > base_type
base type
coefficient_value_type * m_vObjCoef
coefficients variables in objective
model_type::coefficient_value_type value_type
value type
void unscale()
recover problem from scaling
std::vector< coefficient_value_type > m_vScalingFactor
scaling factor for constraints and objective, last entry is for objective
value_type m_scalingFactor
constant scaling factor
solver_type::updater_type updater_type
updater type for lagrangian multipliers
coefficient_value_type & m_lagObj
current objective of the lagrangian subproblem
model_type::constraint_type constraint_type
constraint type
namespace for Limbo
Definition: GraphUtility.h:22
model_type::variable_type variable_type
variable type
matrix_type m_constrMatrix
constraint matrix
SearchByAdjustCoefficient(solver_type *solver, coefficient_value_type convergeRatio=0.1)
constructor
Heuristic to search for feasible solutions by combined strategies.
Update lagrangian multiplier with subgradient descent.
std::iterator_traits< Iterator >::value_type max(Iterator first, Iterator last)
get max of an array
Definition: Math.h:61
model_type::coefficient_value_type coefficient_value_type
coefficient value type
std::vector< variable_value_type > & m_vBestVariableSol
best feasible solution found so far
VariableMoveCost(variable_type var, variable_type targetVar, coefficient_value_type mc)
constructor
model_type::coefficient_value_type coefficient_value_type
coefficient value type
unsigned int m_iter
current iteration
coefficient_value_type rightHandSide() const
Definition: Solvers.h:1034
virtual SolverProperty operator()(updater_type *)
API to search for feasible solutions.
matrix_type const & m_constrMatrix
constraint matrix
base_type::constraint_type constraint_type
constraint type
model_type::variable_value_type variable_value_type
variable value type
coefficient_value_type * m_vConstrRhs
constraint right hand side
LagMultiplierUpdater< T > base_type
base type
void vcopy(unsigned int n, T const *x, T *y)
copy vector
Definition: Numerical.h:269
CompareVariableByCoefficient(coefficient_value_type const *v)
constructor
unsigned int * m_vVariableGroupBeginIndex
begin index of grouped variable
void scale(scaler_type *scaler)
scale problem for better numerical instability
model_type::term_type term_type
term type
model_type::expression_type expression_type
expression type
variable_type variable
variable of the item for the original bin
Scaling scheme with default L2 norm scaling.
void computeMoveCost(constraint_type const &constr, std::vector< VariableMoveCost > &vVariableMoveCost) const
compute move cost for an item to move out from current bin
solver_type * m_solver
problem solver
#define limboAssert(condition)
custom assertion without message
Definition: AssertMsg.h:64
int limboPrint(MessageType m, const char *format,...)
formatted print with prefix
Definition: PrintMsg.h:49
void computeSlackness()
compute slackness in an iteration
std::vector< term_type > const & terms() const
Definition: Solvers.h:655
SolverProperty postProcess(updater_type *updater, searcher_type *searcher, SolverProperty status)
post process solution if failed to converge to OPTIMAL after maximum iteration. It choose the best fe...
optimally solved
Definition: Solvers.h:36
void operator()(unsigned int iter, unsigned int n, value_type const *vSlackness, value_type const *vLagMultiplier, value_type *vNewLagMultiplier)
API to update lagrangian multiplier using subgradient descent.
void AxPlusy(T a, MatrixType const &A, V const *x, T *y)
Definition: Numerical.h:198
coefficient_value_type const * vObjCoef
coefficients in objective for comparison
model_type::constraint_type constraint_type
constraint type
solver_type::updater_type updater_type
updater type for lagrangian multipliers
void setUseInitialSolutions(bool f)
set whether use initial solutions
void updateLagMultipliers(updater_type *updater)
update lagrangian multipliers
unsigned int m_numGroups
number of groups
model_type::variable_value_type variable_value_type
variable value type
base_type::value_type value_type
value type
void computeScalingFactor(unsigned int iter)
compute scaling factor
model_type::expression_type expression_type
expression type
value_type operator()(constraint_type const &constr) const
API to compute scaling factor for constraints using L2 norm.
base_type::solver_type solver_type
solver type
coefficient_value_type m_convergeRatio
ratio for convergence criteria, how much percent the number of negative slacks reduced ...
void setVariableSolution(variable_type const &var, variable_value_type v)
Definition: Solvers.h:1379
ProblemScaler< T, V > base_type
base type
SolverProperty converge()
check convergence of current solution
unsigned int const & m_numGroups
number of groups
model to describe an optimization problem
Definition: Solvers.h:80
base_type::value_type value_type
value type
unsigned int & m_iter
current iteration
void copy(SubGradientDescent const &rhs)
copy object
index_type numRows
number of rows, not in the CSR format
Definition: Solvers.h:1725
virtual value_type operator()(unsigned int iter, value_type multiplier, value_type slackness)=0
API to update lagrangian multiplier.
void solveLag()
solve lagrangian subproblem
variable_type *const & m_vGroupedVariable
array of grouped variables according to item
std::iterator_traits< Iterator >::value_type min(Iterator first, Iterator last)
get min of an array
Definition: Math.h:77
base_type::expression_type expression_type
expression type
value_type m_scalingFactor
scaling factor
SearchByBinSmoothing(solver_type *solver)
constructor
void prepare()
prepare weights of variables in objective and classify constraints by marking capacity constraints an...
coefficient_value_type * m_vLagMultiplier
array of lagrangian multipliers
virtual SolverProperty operator()(updater_type *updater)
API to search for feasible solutions.
solver_type::matrix_type matrix_type
matrix type
solver_type::updater_type updater_type
updater type for lagrangian multipliers
A base helper function object to update lagrangian multipliers using subgradient descent. All other schemes can be derived from this class.
unsigned int m_iter
current iteration
VariableMoveCost(variable_type var, coefficient_value_type mc, coefficient_value_type cap)
constructor
std::vector< constraint_type > const & vConstraint
constraints
value_type operator()(unsigned int iter, value_type multiplier, value_type slackness)
API to update lagrangian multiplier using subgradient descent.
base_type::model_type model_type
model type
std::vector< std::vector< std::pair< unsigned int, unsigned int > > > m_mVariable2Constr
map variables to constraints by pair of (constraint index, term index), a variable may have multiple ...
Heuristic to search for feasible solutions by adjusting coefficients so that some items will not be a...
coefficient_value_type * m_vNewLagMultiplier
array of new lagrangian multipliers, temporary storage
T dot(unsigned int n, T const *x, T const *y)
compute dot product
Definition: Numerical.h:252
bool operator()(VariableMoveCost const &c1, VariableMoveCost const &c2) const
base_type::constraint_type constraint_type
constraint type