436 _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); |
436 _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); |
437 rows.clear(); |
437 rows.clear(); |
438 cols.clear(); |
438 cols.clear(); |
439 } |
439 } |
440 |
440 |
441 // LpCplex members |
441 // CplexLp members |
442 |
442 |
443 LpCplex::LpCplex() |
443 CplexLp::CplexLp() |
444 : LpBase(), CplexBase(), LpSolver() {} |
444 : LpBase(), CplexBase(), LpSolver() {} |
445 |
445 |
446 LpCplex::LpCplex(const CplexEnv& env) |
446 CplexLp::CplexLp(const CplexEnv& env) |
447 : LpBase(), CplexBase(env), LpSolver() {} |
447 : LpBase(), CplexBase(env), LpSolver() {} |
448 |
448 |
449 LpCplex::LpCplex(const LpCplex& other) |
449 CplexLp::CplexLp(const CplexLp& other) |
450 : LpBase(), CplexBase(other), LpSolver() {} |
450 : LpBase(), CplexBase(other), LpSolver() {} |
451 |
451 |
452 LpCplex::~LpCplex() {} |
452 CplexLp::~CplexLp() {} |
453 |
453 |
454 LpCplex* LpCplex::_newSolver() const { return new LpCplex; } |
454 CplexLp* CplexLp::_newSolver() const { return new CplexLp; } |
455 LpCplex* LpCplex::_cloneSolver() const {return new LpCplex(*this); } |
455 CplexLp* CplexLp::_cloneSolver() const {return new CplexLp(*this); } |
456 |
456 |
457 const char* LpCplex::_solverName() const { return "LpCplex"; } |
457 const char* CplexLp::_solverName() const { return "CplexLp"; } |
458 |
458 |
459 void LpCplex::_clear_temporals() { |
459 void CplexLp::_clear_temporals() { |
460 _col_status.clear(); |
460 _col_status.clear(); |
461 _row_status.clear(); |
461 _row_status.clear(); |
462 _primal_ray.clear(); |
462 _primal_ray.clear(); |
463 _dual_ray.clear(); |
463 _dual_ray.clear(); |
464 } |
464 } |
470 // user-specified CPLEX limit, or proving the model infeasible or |
470 // user-specified CPLEX limit, or proving the model infeasible or |
471 // unbounded, are not considered errors. Note that a zero return |
471 // unbounded, are not considered errors. Note that a zero return |
472 // value does not necessarily mean that a solution exists. Use query |
472 // value does not necessarily mean that a solution exists. Use query |
473 // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain |
473 // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain |
474 // further information about the status of the optimization. |
474 // further information about the status of the optimization. |
475 LpCplex::SolveExitStatus LpCplex::convertStatus(int status) { |
475 CplexLp::SolveExitStatus CplexLp::convertStatus(int status) { |
476 #if CPX_VERSION >= 800 |
476 #if CPX_VERSION >= 800 |
477 if (status == 0) { |
477 if (status == 0) { |
478 switch (CPXgetstat(cplexEnv(), _prob)) { |
478 switch (CPXgetstat(cplexEnv(), _prob)) { |
479 case CPX_STAT_OPTIMAL: |
479 case CPX_STAT_OPTIMAL: |
480 case CPX_STAT_INFEASIBLE: |
480 case CPX_STAT_INFEASIBLE: |
503 return UNSOLVED; |
503 return UNSOLVED; |
504 } |
504 } |
505 #endif |
505 #endif |
506 } |
506 } |
507 |
507 |
508 LpCplex::SolveExitStatus LpCplex::_solve() { |
508 CplexLp::SolveExitStatus CplexLp::_solve() { |
509 _clear_temporals(); |
509 _clear_temporals(); |
510 return convertStatus(CPXlpopt(cplexEnv(), _prob)); |
510 return convertStatus(CPXlpopt(cplexEnv(), _prob)); |
511 } |
511 } |
512 |
512 |
513 LpCplex::SolveExitStatus LpCplex::solvePrimal() { |
513 CplexLp::SolveExitStatus CplexLp::solvePrimal() { |
514 _clear_temporals(); |
514 _clear_temporals(); |
515 return convertStatus(CPXprimopt(cplexEnv(), _prob)); |
515 return convertStatus(CPXprimopt(cplexEnv(), _prob)); |
516 } |
516 } |
517 |
517 |
518 LpCplex::SolveExitStatus LpCplex::solveDual() { |
518 CplexLp::SolveExitStatus CplexLp::solveDual() { |
519 _clear_temporals(); |
519 _clear_temporals(); |
520 return convertStatus(CPXdualopt(cplexEnv(), _prob)); |
520 return convertStatus(CPXdualopt(cplexEnv(), _prob)); |
521 } |
521 } |
522 |
522 |
523 LpCplex::SolveExitStatus LpCplex::solveBarrier() { |
523 CplexLp::SolveExitStatus CplexLp::solveBarrier() { |
524 _clear_temporals(); |
524 _clear_temporals(); |
525 return convertStatus(CPXbaropt(cplexEnv(), _prob)); |
525 return convertStatus(CPXbaropt(cplexEnv(), _prob)); |
526 } |
526 } |
527 |
527 |
528 LpCplex::Value LpCplex::_getPrimal(int i) const { |
528 CplexLp::Value CplexLp::_getPrimal(int i) const { |
529 Value x; |
529 Value x; |
530 CPXgetx(cplexEnv(), _prob, &x, i, i); |
530 CPXgetx(cplexEnv(), _prob, &x, i, i); |
531 return x; |
531 return x; |
532 } |
532 } |
533 |
533 |
534 LpCplex::Value LpCplex::_getDual(int i) const { |
534 CplexLp::Value CplexLp::_getDual(int i) const { |
535 Value y; |
535 Value y; |
536 CPXgetpi(cplexEnv(), _prob, &y, i, i); |
536 CPXgetpi(cplexEnv(), _prob, &y, i, i); |
537 return y; |
537 return y; |
538 } |
538 } |
539 |
539 |
540 LpCplex::Value LpCplex::_getPrimalValue() const { |
540 CplexLp::Value CplexLp::_getPrimalValue() const { |
541 Value objval; |
541 Value objval; |
542 CPXgetobjval(cplexEnv(), _prob, &objval); |
542 CPXgetobjval(cplexEnv(), _prob, &objval); |
543 return objval; |
543 return objval; |
544 } |
544 } |
545 |
545 |
546 LpCplex::VarStatus LpCplex::_getColStatus(int i) const { |
546 CplexLp::VarStatus CplexLp::_getColStatus(int i) const { |
547 if (_col_status.empty()) { |
547 if (_col_status.empty()) { |
548 _col_status.resize(CPXgetnumcols(cplexEnv(), _prob)); |
548 _col_status.resize(CPXgetnumcols(cplexEnv(), _prob)); |
549 CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0); |
549 CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0); |
550 } |
550 } |
551 switch (_col_status[i]) { |
551 switch (_col_status[i]) { |
557 return LOWER; |
557 return LOWER; |
558 case CPX_AT_UPPER: |
558 case CPX_AT_UPPER: |
559 return UPPER; |
559 return UPPER; |
560 default: |
560 default: |
561 LEMON_ASSERT(false, "Wrong column status"); |
561 LEMON_ASSERT(false, "Wrong column status"); |
562 return LpCplex::VarStatus(); |
562 return CplexLp::VarStatus(); |
563 } |
563 } |
564 } |
564 } |
565 |
565 |
566 LpCplex::VarStatus LpCplex::_getRowStatus(int i) const { |
566 CplexLp::VarStatus CplexLp::_getRowStatus(int i) const { |
567 if (_row_status.empty()) { |
567 if (_row_status.empty()) { |
568 _row_status.resize(CPXgetnumrows(cplexEnv(), _prob)); |
568 _row_status.resize(CPXgetnumrows(cplexEnv(), _prob)); |
569 CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front()); |
569 CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front()); |
570 } |
570 } |
571 switch (_row_status[i]) { |
571 switch (_row_status[i]) { |
579 } |
579 } |
580 case CPX_AT_UPPER: |
580 case CPX_AT_UPPER: |
581 return UPPER; |
581 return UPPER; |
582 default: |
582 default: |
583 LEMON_ASSERT(false, "Wrong row status"); |
583 LEMON_ASSERT(false, "Wrong row status"); |
584 return LpCplex::VarStatus(); |
584 return CplexLp::VarStatus(); |
585 } |
585 } |
586 } |
586 } |
587 |
587 |
588 LpCplex::Value LpCplex::_getPrimalRay(int i) const { |
588 CplexLp::Value CplexLp::_getPrimalRay(int i) const { |
589 if (_primal_ray.empty()) { |
589 if (_primal_ray.empty()) { |
590 _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob)); |
590 _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob)); |
591 CPXgetray(cplexEnv(), _prob, &_primal_ray.front()); |
591 CPXgetray(cplexEnv(), _prob, &_primal_ray.front()); |
592 } |
592 } |
593 return _primal_ray[i]; |
593 return _primal_ray[i]; |
594 } |
594 } |
595 |
595 |
596 LpCplex::Value LpCplex::_getDualRay(int i) const { |
596 CplexLp::Value CplexLp::_getDualRay(int i) const { |
597 if (_dual_ray.empty()) { |
597 if (_dual_ray.empty()) { |
598 |
598 |
599 } |
599 } |
600 return _dual_ray[i]; |
600 return _dual_ray[i]; |
601 } |
601 } |
684 } |
684 } |
685 #else |
685 #else |
686 void statusSwitch(CPXENVptr,int&){} |
686 void statusSwitch(CPXENVptr,int&){} |
687 #endif |
687 #endif |
688 |
688 |
689 LpCplex::ProblemType LpCplex::_getPrimalType() const { |
689 CplexLp::ProblemType CplexLp::_getPrimalType() const { |
690 // Unboundedness not treated well: the following is from cplex 9.0 doc |
690 // Unboundedness not treated well: the following is from cplex 9.0 doc |
691 // About Unboundedness |
691 // About Unboundedness |
692 |
692 |
693 // The treatment of models that are unbounded involves a few |
693 // The treatment of models that are unbounded involves a few |
694 // subtleties. Specifically, a declaration of unboundedness means that |
694 // subtleties. Specifically, a declaration of unboundedness means that |
766 // CPX_STAT_OPTIMAL_FACE_UNBOUNDED |
766 // CPX_STAT_OPTIMAL_FACE_UNBOUNDED |
767 // CPX_STAT_OPTIMAL_INFEAS |
767 // CPX_STAT_OPTIMAL_INFEAS |
768 // CPX_STAT_OPTIMAL_RELAXED |
768 // CPX_STAT_OPTIMAL_RELAXED |
769 // CPX_STAT_UNBOUNDED |
769 // CPX_STAT_UNBOUNDED |
770 |
770 |
771 LpCplex::ProblemType LpCplex::_getDualType() const { |
771 CplexLp::ProblemType CplexLp::_getDualType() const { |
772 int stat = CPXgetstat(cplexEnv(), _prob); |
772 int stat = CPXgetstat(cplexEnv(), _prob); |
773 #if CPX_VERSION >= 800 |
773 #if CPX_VERSION >= 800 |
774 switch (stat) { |
774 switch (stat) { |
775 case CPX_STAT_OPTIMAL: |
775 case CPX_STAT_OPTIMAL: |
776 return OPTIMAL; |
776 return OPTIMAL; |
793 //FIXME error |
793 //FIXME error |
794 } |
794 } |
795 #endif |
795 #endif |
796 } |
796 } |
797 |
797 |
798 // MipCplex members |
798 // CplexMip members |
799 |
799 |
800 MipCplex::MipCplex() |
800 CplexMip::CplexMip() |
801 : LpBase(), CplexBase(), MipSolver() { |
801 : LpBase(), CplexBase(), MipSolver() { |
802 |
802 |
803 #if CPX_VERSION < 800 |
803 #if CPX_VERSION < 800 |
804 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); |
804 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); |
805 #else |
805 #else |
806 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); |
806 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); |
807 #endif |
807 #endif |
808 } |
808 } |
809 |
809 |
810 MipCplex::MipCplex(const CplexEnv& env) |
810 CplexMip::CplexMip(const CplexEnv& env) |
811 : LpBase(), CplexBase(env), MipSolver() { |
811 : LpBase(), CplexBase(env), MipSolver() { |
812 |
812 |
813 #if CPX_VERSION < 800 |
813 #if CPX_VERSION < 800 |
814 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); |
814 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); |
815 #else |
815 #else |
816 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); |
816 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); |
817 #endif |
817 #endif |
818 |
818 |
819 } |
819 } |
820 |
820 |
821 MipCplex::MipCplex(const MipCplex& other) |
821 CplexMip::CplexMip(const CplexMip& other) |
822 : LpBase(), CplexBase(other), MipSolver() {} |
822 : LpBase(), CplexBase(other), MipSolver() {} |
823 |
823 |
824 MipCplex::~MipCplex() {} |
824 CplexMip::~CplexMip() {} |
825 |
825 |
826 MipCplex* MipCplex::_newSolver() const { return new MipCplex; } |
826 CplexMip* CplexMip::_newSolver() const { return new CplexMip; } |
827 MipCplex* MipCplex::_cloneSolver() const {return new MipCplex(*this); } |
827 CplexMip* CplexMip::_cloneSolver() const {return new CplexMip(*this); } |
828 |
828 |
829 const char* MipCplex::_solverName() const { return "MipCplex"; } |
829 const char* CplexMip::_solverName() const { return "CplexMip"; } |
830 |
830 |
831 void MipCplex::_setColType(int i, MipCplex::ColTypes col_type) { |
831 void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) { |
832 |
832 |
833 // Note If a variable is to be changed to binary, a call to CPXchgbds |
833 // Note If a variable is to be changed to binary, a call to CPXchgbds |
834 // should also be made to change the bounds to 0 and 1. |
834 // should also be made to change the bounds to 0 and 1. |
835 |
835 |
836 switch (col_type){ |
836 switch (col_type){ |
860 return ColTypes(); |
860 return ColTypes(); |
861 } |
861 } |
862 |
862 |
863 } |
863 } |
864 |
864 |
865 MipCplex::SolveExitStatus MipCplex::_solve() { |
865 CplexMip::SolveExitStatus CplexMip::_solve() { |
866 int status; |
866 int status; |
867 status = CPXmipopt (cplexEnv(), _prob); |
867 status = CPXmipopt (cplexEnv(), _prob); |
868 if (status==0) |
868 if (status==0) |
869 return SOLVED; |
869 return SOLVED; |
870 else |
870 else |
871 return UNSOLVED; |
871 return UNSOLVED; |
872 |
872 |
873 } |
873 } |
874 |
874 |
875 |
875 |
876 MipCplex::ProblemType MipCplex::_getType() const { |
876 CplexMip::ProblemType CplexMip::_getType() const { |
877 |
877 |
878 int stat = CPXgetstat(cplexEnv(), _prob); |
878 int stat = CPXgetstat(cplexEnv(), _prob); |
879 |
879 |
880 //Fortunately, MIP statuses did not change for cplex 8.0 |
880 //Fortunately, MIP statuses did not change for cplex 8.0 |
881 switch (stat) { |
881 switch (stat) { |
907 // a feasible solution exists. Users can call the routine CPXsolninfo |
907 // a feasible solution exists. Users can call the routine CPXsolninfo |
908 // to determine whether ILOG CPLEX has also concluded that the model |
908 // to determine whether ILOG CPLEX has also concluded that the model |
909 // has a feasible solution. |
909 // has a feasible solution. |
910 } |
910 } |
911 |
911 |
912 MipCplex::Value MipCplex::_getSol(int i) const { |
912 CplexMip::Value CplexMip::_getSol(int i) const { |
913 Value x; |
913 Value x; |
914 CPXgetmipx(cplexEnv(), _prob, &x, i, i); |
914 CPXgetmipx(cplexEnv(), _prob, &x, i, i); |
915 return x; |
915 return x; |
916 } |
916 } |
917 |
917 |
918 MipCplex::Value MipCplex::_getSolValue() const { |
918 CplexMip::Value CplexMip::_getSolValue() const { |
919 Value objval; |
919 Value objval; |
920 CPXgetmipobjval(cplexEnv(), _prob, &objval); |
920 CPXgetmipobjval(cplexEnv(), _prob, &objval); |
921 return objval; |
921 return objval; |
922 } |
922 } |
923 |
923 |