Limbo 3.5.4
Loading...
Searching...
No Matches
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>
13
15namespace limbo
16{
18namespace solvers
19{
20
21// forward declaration
22template <typename T>
24template <typename T>
26template <typename T, typename V>
27class ProblemScaler;
28template <typename T, typename V>
29class L2NormScaler;
30template <typename T, typename V>
32template <typename T, typename V>
34
65template <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;
74 typedef typename model_type::variable_type variable_type;
75 typedef typename model_type::constraint_type constraint_type;
76 typedef typename model_type::expression_type expression_type;
77 typedef typename model_type::term_type term_type;
78 typedef typename model_type::property_type property_type;
84
88 {
89 // T must be a floating point number
90 limboStaticAssert(!std::numeric_limits<T>::is_integer);
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;
97 m_constrMatrix.reset();
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;
114 m_bestObj = std::numeric_limits<coefficient_value_type>::max();
115 m_useInitialSol = false;
116 }
117
120 {
121 copy(rhs);
122 }
123
126 {
127 if (this != &rhs)
128 copy(rhs);
129 return *this;
130 }
131
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 }
221
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
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
331template <typename T, typename V>
333{
334 return m_maxIters;
335}
336template <typename T, typename V>
338{
339 m_maxIters = maxIters;
340}
341template <typename T, typename V>
346template <typename T, typename V>
351template <typename T, typename V>
353{
354 return m_lagObjFlag;
355}
356template <typename T, typename V>
361template <typename T, typename V>
363{
364 unsigned int result = 0;
365 if (evaluateFlag)
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}
371template <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 }
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]];
396 m_vVariableGroupBeginIndex = new unsigned int [m_numGroups+1];
399 }
400
402 if (rhs.m_vLagMultiplier)
403 {
404 m_vLagMultiplier = new coefficient_value_type [m_constrMatrix.numRows];
406 m_vNewLagMultiplier = new coefficient_value_type [m_constrMatrix.numRows];
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 }
412 m_lagObj = rhs.m_lagObj;
414 m_iter = rhs.m_iter;
417
419 m_bestObj = rhs.m_bestObj;
420}
421template <typename T, typename V>
423{
424 // recycle variable groups
426 {
427 delete [] m_vGroupedVariable;
429 m_vGroupedVariable = 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
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}
454template <typename T, typename V>
455SolverProperty MultiKnapsackLagRelax<T, V>::solve(typename MultiKnapsackLagRelax<T, V>::updater_type* updater, typename MultiKnapsackLagRelax<T, V>::scaler_type* scaler, typename MultiKnapsackLagRelax<T, V>::searcher_type* searcher)
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}
508template <typename T, typename V>
509SolverProperty MultiKnapsackLagRelax<T, V>::solveSubproblems(typename MultiKnapsackLagRelax<T, V>::updater_type* updater, unsigned int beginIter, unsigned int endIter)
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();
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);
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}
535template <typename T, typename V>
536void MultiKnapsackLagRelax<T, V>::scale(typename MultiKnapsackLagRelax<T, V>::scaler_type* scaler)
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}
550template <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}
559template <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)
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];
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();
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}
672template <typename T, typename V>
673void MultiKnapsackLagRelax<T, V>::updateLagMultipliers(typename MultiKnapsackLagRelax<T, V>::updater_type* updater)
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
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 {
699 }
700}
701template <typename T, typename V>
703{
704 // for each item
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)
725
726}
727template <typename T, typename V>
729{
730 // s = b-Ax
731 bMinusAx(m_constrMatrix, &m_model->variableSolutions()[0], m_vConstrRhs, m_vSlackness);
732}
733template <typename T, typename V>
734typename 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}
742template <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}
784template <typename T, typename V>
785SolverProperty MultiKnapsackLagRelax<T, V>::postProcess(typename MultiKnapsackLagRelax<T, V>::updater_type* updater, typename MultiKnapsackLagRelax<T, V>::searcher_type* searcher, SolverProperty status)
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}
800
801template <typename T, typename V>
802template <typename TT, typename VV>
803void 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}
810template <typename T, typename V>
811bool 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 }
820 out.close();
821 return true;
822}
823template <typename T, typename V>
824std::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}
842template <typename T, typename V>
843bool 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}
855template <typename T, typename V>
856std::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}
865template <typename T, typename V>
866bool 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 }
875 out.close();
876 return true;
877}
878template <typename T, typename V>
879std::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}
888template <typename T, typename V>
889std::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}
903template <typename T, typename V>
904template <typename TT>
905void 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
932template <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
961template <typename T>
963{
964 public:
969
975 , m_alpha(alpha)
976 , m_beta(beta)
977 , m_iter(std::numeric_limits<unsigned int>::max())
978 , m_scalingFactor(1)
979 {
980 }
981
984 {
985 copy(rhs);
986 }
987
990 {
991 if (this != &rhs)
992 {
993 this->base_type::operator=(rhs);
994 copy(rhs);
995 }
996 return *this;
997 }
998
1000 {
1001 }
1002
1008 value_type operator()(unsigned int iter, value_type multiplier, value_type slackness)
1009 {
1010 // compute scaling factor
1012 value_type result = std::max((value_type)0, multiplier-m_scalingFactor*slackness);
1013 return result;
1014 }
1015
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
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;
1045 }
1046
1048 void computeScalingFactor(unsigned int iter)
1049 {
1050 // avoid frequent computation of scaling factor
1051 if (m_iter != iter)
1052 {
1053 m_iter = iter;
1055 }
1056 }
1057
1060 unsigned int m_iter;
1062};
1063
1067template <typename T, typename V>
1069{
1070 public:
1081
1085 virtual ~ProblemScaler() {}
1086
1091 virtual value_type operator()(expression_type const& /*expr*/) const
1092 {
1093 return 1;
1094 }
1095
1098 virtual value_type operator()(constraint_type const& constr) const
1099 {
1100 return this->operator()(constr.expression());
1101 }
1102};
1103
1107template <typename T, typename V>
1109{
1110 public:
1123
1129
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 }
1140
1144 {
1145 return this->operator()(constr.expression());
1146 }
1147
1148 protected:
1150};
1151
1155template <typename T, typename V>
1156class L2NormScaler : public ProblemScaler<T, V>
1157{
1158 public:
1171
1176
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 }
1187
1191 {
1192 return this->operator()(constr.expression());
1193 }
1194};
1195
1199template <typename T, typename V>
1201{
1202 public:
1208 typedef typename solver_type::updater_type updater_type;
1222 typedef typename solver_type::matrix_type matrix_type;
1223
1227 : m_solver(solver)
1228 , m_model(solver->m_model)
1229 , m_vObjCoef(solver->m_vObjCoef)
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)
1245 , m_bestObj(solver->m_bestObj)
1246 {
1247 }
1248
1250
1255 virtual SolverProperty operator()(updater_type* /*updater*/) {return INFEASIBLE;}
1256
1257 protected:
1260 {
1261 m_solver->computeSlackness();
1262 }
1263
1267 SolverProperty solveSubproblems(updater_type* updater, unsigned int beginIter, unsigned int endIter)
1268 {
1269 return m_solver->solveSubproblems(updater, beginIter, endIter);
1270 }
1271
1274
1278
1280 unsigned int* const& m_vVariableGroupBeginIndex;
1281 unsigned int const& m_numGroups;
1282 std::vector<unsigned int> const& m_vConstraintPartition;
1285 std::vector<coefficient_value_type> const& m_vScalingFactor;
1288 unsigned int& m_iter;
1289 unsigned int& m_maxIters;
1291
1292 std::vector<variable_value_type>& m_vBestVariableSol;
1294};
1295
1300template <typename T, typename V>
1302{
1303 public:
1311 typedef typename solver_type::updater_type updater_type;
1325 typedef typename solver_type::matrix_type matrix_type;
1326
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
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
1436 this->m_vVariable2Group.assign(this->m_model->numVariables(), std::numeric_limits<unsigned int>::max());
1437 for (unsigned int i = 0; i < this->m_numGroups; ++i)
1438 {
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 }
1447
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;
1481};
1482
1486template <typename T, typename V>
1488{
1489 public:
1497 typedef typename solver_type::updater_type updater_type;
1509 typedef typename solver_type::matrix_type matrix_type;
1510
1529
1532 {
1536 bool operator()(VariableMoveCost const& c1, VariableMoveCost const& c2) const
1537 {
1538 return c1.moveCost < c2.moveCost;
1539 }
1540 };
1541
1542
1545 {
1547
1554 bool operator()(unsigned int i, unsigned int j) const
1555 {
1556 return vSlackness[i] < vSlackness[j];
1557 }
1558 };
1559
1565
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 }
1665
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
1724template <typename T, typename V>
1776
1777} // namespace solvers
1778} // namespace limbo
1779
1780#endif
#define limboAssert(condition)
custom assertion without message
Definition AssertMsg.h:36
#define limboStaticAssert(condition)
compile time assertion
Definition AssertMsg.h:59
numerical functions for linear algebra
Basic utilities such as variables and linear expressions in solvers.
Base heuristic to search for feasible solutions.
FeasibleSearcher(solver_type *solver)
constructor
SolverProperty solveSubproblems(updater_type *updater, unsigned int beginIter, unsigned int endIter)
kernel lagrangian iterations
virtual SolverProperty operator()(updater_type *)
API to search for feasible solutions.
void computeSlackness()
compute slackness in an iteration
MultiKnapsackLagRelax< coefficient_value_type, variable_value_type > solver_type
LinearModel< coefficient_value_type, variable_value_type > model_type
Scaling scheme with default L2 norm scaling.
base_type::model_type model_type
model type
base_type::term_type term_type
term type
base_type::value_type value_type
value type
value_type operator()(constraint_type const &constr) const
API to compute scaling factor for constraints using L2 norm.
value_type operator()(expression_type const &expr) const
API to compute scaling factor for expression using L2 norm.
ProblemScaler< T, V > base_type
base type
base_type::expression_type expression_type
expression type
base_type::constraint_type constraint_type
constraint type
A base helper function object to update lagrangian multipliers using subgradient descent....
virtual value_type operator()(unsigned int iter, value_type multiplier, value_type slackness)=0
API to update lagrangian multiplier.
virtual void operator()(unsigned int iter, unsigned int n, value_type const *vSlackness, value_type const *vLagMultiplier, value_type *vNewLagMultiplier)=0
API to update lagrangian multiplier using subgradient descent.
coefficient_value_type rightHandSide() const
Definition Solvers.h:1034
expression_type const & expression() const
Definition Solvers.h:1028
std::vector< term_type > const & terms() const
Definition Solvers.h:655
model to describe an optimization problem
Definition Solvers.h:1161
V variable_value_type
V variable.
Definition Solvers.h:1166
VariableProperty< variable_value_type > property_type
variable property type
Definition Solvers.h:1178
Variable< coefficient_value_type > variable_type
variable type
Definition Solvers.h:1170
T coefficient_value_type
T coefficient.
Definition Solvers.h:1164
LinearConstraint< coefficient_value_type > constraint_type
constraint type
Definition Solvers.h:1176
LinearExpression< coefficient_value_type > expression_type
expression type
Definition Solvers.h:1174
LinearTerm< coefficient_value_type > term_type
term type
Definition Solvers.h:1172
coefficient_value_type coefficient() const
Definition Solvers.h:388
value_type m_scalingFactor
constant scaling factor
base_type::expression_type expression_type
expression type
base_type::model_type model_type
model type
ProblemScaler< T, V > base_type
base type
base_type::constraint_type constraint_type
constraint type
base_type::value_type value_type
value type
value_type operator()(constraint_type const &constr) const
API to compute scaling factor for constraints using L2 norm.
value_type operator()(expression_type const &expr) const
API to compute scaling factor for expression using L2 norm.
base_type::term_type term_type
term type
MinCoefficientScaler(value_type factor=1)
constructor
Solve multiple knapsack problem with lagrangian relaxation.
coefficient_value_type * m_vNewLagMultiplier
array of new lagrangian multipliers, temporary storage
unsigned int numNegativeSlackConstraints(bool evaluateFlag)
get number of constraints with negative slackness in current iteration
void scale(scaler_type *scaler)
scale problem for better numerical instability
std::vector< variable_value_type > m_vBestVariableSol
best feasible solution found so far
coefficient_value_type evaluateLagObjective() const
evaluate objective of the lagrangian subproblem
bool printVariableGroup(std::string const &filename) const
print variable groups to file
std::ostream & printConstraint(std::ostream &os, std::string const &name) const
print constraint
bool m_useInitialSol
whether use initial solutions or not
std::vector< unsigned int > m_vConstraintPartition
indices of constraints, the first partition is capacity constraints
SolverProperty solveSubproblems(updater_type *updater, unsigned int beginIter, unsigned int endIter)
kernel lagrangian iterations
coefficient_value_type * m_vObjCoef
coefficients variables in objective
MultiKnapsackLagRelax(model_type *model)
constructor
void updateLagMultipliers(updater_type *updater)
update lagrangian multipliers
void solveLag()
solve lagrangian subproblem
void computeSlackness()
compute slackness in an iteration
coefficient_value_type * m_vLagMultiplier
array of lagrangian multipliers
coefficient_value_type * m_vConstrRhs
constraint right hand side
void printArray(unsigned int n, TT const *array, bool nonzeroFlag) const
print array
void copy(MultiKnapsackLagRelax const &rhs)
copy object
void setLagObjFlag(bool f)
set evaluating objective of lagrangian subproblem in each iteration
SolverProperty solve(updater_type *updater, scaler_type *scaler, searcher_type *searcher)
kernel function to solve the problem
coefficient_value_type m_lagObj
current objective of the lagrangian subproblem
variable_type * m_vGroupedVariable
array of grouped variables according to item
unsigned int * m_vVariableGroupBeginIndex
begin index of grouped variable
coefficient_value_type m_bestObj
best objective found so far
unsigned int m_maxIters
maximum number of iterations
model_type * m_model
model for the problem
LinearModel< T, V > model_type
linear model type for the problem
coefficient_value_type * m_vSlackness
array of slackness values in each iteration,
void bMinusAx(matrix_type const &A, VV const *x, TT const *b, TT *y) const
function to compute
void setMaxIterations(unsigned int maxIter)
set maximum iterations
matrix_type m_constrMatrix
constraint matrix
bool m_lagObjFlag
whether evaluate objective of the lagrangian subproblem in each iteration
void setUseInitialSolutions(bool f)
set whether use initial solutions
MultiKnapsackLagRelax & operator=(MultiKnapsackLagRelax const &rhs)
assignment
SolverProperty converge()
check convergence of current solution
bool printLagMultiplier(std::string const &filename) const
print lagrangian multipliers to file
SolverProperty operator()(updater_type *updater=NULL, scaler_type *scaler=NULL, searcher_type *searcher=NULL)
API to run the algorithm.
coefficient_value_type m_objConstant
constant value in objective from lagrangian relaxation
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...
bool printObjCoef(std::string const &filename) const
print coefficients of variables in objective to file
void prepare()
prepare weights of variables in objective and classify constraints by marking capacity constraints an...
void unscale()
recover problem from scaling
MultiKnapsackLagRelax(MultiKnapsackLagRelax const &rhs)
copy constructor
std::vector< coefficient_value_type > m_vScalingFactor
scaling factor for constraints and objective, last entry is for objective
Base class for scaling scheme with default no scaling.
LinearModel< coefficient_value_type, variable_value_type > model_type
virtual value_type operator()(constraint_type const &constr) const
API to compute scaling factor for constraints using L2 norm.
virtual value_type operator()(expression_type const &) const
API to compute scaling factor for expression using L2 norm.
Heuristic to search for feasible solutions by adjusting coefficients so that some items will not be a...
coefficient_value_type m_convergeRatio
ratio for convergence criteria, how much percent the number of negative slacks reduced
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
void mapVariable2Group()
construct mapping from variables to groups
FeasibleSearcher< T, V > base_type
base type
model_type::variable_value_type variable_value_type
variable value type
virtual SolverProperty operator()(updater_type *updater)
API to search for feasible solutions.
model_type::constraint_type constraint_type
constraint type
solver_type::matrix_type matrix_type
matrix type
model_type::coefficient_value_type coefficient_value_type
coefficient value type
model_type::variable_type variable_type
variable type
solver_type::updater_type updater_type
updater type for lagrangian multipliers
base_type::solver_type solver_type
solver type
model_type::expression_type expression_type
expression type
std::vector< unsigned int > m_vVariable2Group
map variables to groups
SearchByAdjustCoefficient(solver_type *solver, coefficient_value_type convergeRatio=0.1)
constructor
Heuristic to search for feasible solutions by smoothing dense bins.
base_type::model_type model_type
model type
virtual SolverProperty operator()(updater_type *)
API to search for feasible solutions.
SearchByAdjustCoefficient< T, V > base_type
base type
solver_type::updater_type updater_type
updater type for lagrangian multipliers
SearchByBinSmoothing(solver_type *solver)
constructor
model_type::term_type term_type
term type
void mapVariable2Constraint()
construct mapping from variables to constraints
model_type::variable_type variable_type
variable type
model_type::constraint_type constraint_type
constraint type
std::vector< coefficient_value_type > m_vObjCoefOrig
original coefficient of variable in objective
model_type::coefficient_value_type coefficient_value_type
coefficient value type
model_type::expression_type expression_type
expression type
solver_type::matrix_type matrix_type
matrix type
void computeMoveCost(constraint_type const &constr, std::vector< VariableMoveCost > &vVariableMoveCost) const
compute move cost for an item to move out from current bin
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 ...
base_type::solver_type solver_type
solver type
base_type::solver_type solver_type
solver type
SearchByBinSmoothing< coefficient_value_type, variable_value_type > m_searcherSmoothing
search by smoothing dense bins
model_type::expression_type expression_type
expression type
model_type::variable_value_type variable_value_type
variable value type
FeasibleSearcher< T, V > base_type
base type
SearchByAdjustCoefficient< coefficient_value_type, variable_value_type > m_searcherCoeff
search by adjusting coefficient
SearchByCombinedStrategy(solver_type *solver, coefficient_value_type convergeRatio=0.1)
constructor
solver_type::updater_type updater_type
updater type for lagrangian multipliers
model_type::constraint_type constraint_type
constraint type
virtual SolverProperty operator()(updater_type *updater)
API to search for feasible solutions.
model_type::coefficient_value_type coefficient_value_type
coefficient value type
model_type::variable_type variable_type
variable type
Update lagrangian multiplier with subgradient descent.
value_type operator()(unsigned int iter, value_type multiplier, value_type slackness)
API to update lagrangian multiplier using subgradient descent.
base_type::value_type value_type
value type
void copy(SubGradientDescent const &rhs)
copy object
SubGradientDescent(value_type alpha=1, value_type beta=1)
constructor
SubGradientDescent & operator=(SubGradientDescent const &rhs)
assignment
void computeScalingFactor(unsigned int iter)
compute scaling factor
unsigned int m_iter
current iteration
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.
LagMultiplierUpdater< T > base_type
base type
SubGradientDescent(SubGradientDescent const &rhs)
copy constructor
unsigned int id() const
Definition Solvers.h:117
namespace for Limbo.Solvers
void vcopy(unsigned int n, T const *x, T *y)
copy vector
Definition Numerical.h:269
SolverProperty
Some enums used in solver.
Definition Solvers.h:30
@ OPTIMAL
optimally solved
Definition Solvers.h:36
@ SUBOPTIMAL
the model is suboptimal
Definition Solvers.h:38
@ INFEASIBLE
the model is infeasible
Definition Solvers.h:37
void axpy(unsigned int n, T a, V const *x, T *y)
Definition Numerical.h:179
void AxPlusy(T a, MatrixType const &A, V const *x, T *y)
Definition Numerical.h:198
T dot(unsigned int n, T const *x, T const *y)
compute dot product
Definition Numerical.h:252
void ATxPlusy(T a, MatrixType const &A, V const *x, T *y)
Definition Numerical.h:226
namespace for Limbo
std::iterator_traits< Iterator >::value_type max(Iterator first, Iterator last)
get max of an array
Definition Math.h:61
int limboPrint(MessageType m, const char *format,...)
formatted print with prefix
Definition PrintMsg.h:49
int limboSPrint(MessageType m, char *buf, const char *format,...)
formatted print with prefix to buffer
Definition PrintMsg.h:101
Compressed sparse row (CSR) matrix.
Definition Solvers.h:1716
index_type numRows
number of rows, not in the CSR format
Definition Solvers.h:1725
Predicate whether a constraint is a capacity constraint.
std::vector< constraint_type > const & vConstraint
constraints
CapacityConstraintPred(std::vector< constraint_type > const &v)
constructor
Predicate to sort variables according to their coefficient from small to large.
bool operator()(variable_type const &v1, variable_type const &v2) const
CompareVariableByCoefficient(coefficient_value_type const *v)
constructor
coefficient_value_type const * vObjCoef
coefficients in objective for comparison
bool operator()(VariableMoveCost const &c1, VariableMoveCost const &c2) const
VariableMoveCost(variable_type var, coefficient_value_type mc, coefficient_value_type cap)
constructor
CompareConstraintSlack(coefficient_value_type const *v)
constructor
coefficient_value_type const * vSlackness
array of slackness
bool operator()(VariableMoveCost const &c1, VariableMoveCost const &c2) const
variable_type variable
variable of the item for the original bin
VariableMoveCost(variable_type var, variable_type targetVar, coefficient_value_type mc)
constructor
variable_type targetVariable
variable of the item for the target bin