/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* This file is part of the class library */ /* SoPlex --- the Sequential object-oriented simPlex. */ /* */ /* Copyright (c) 1996-2024 Zuse Institute Berlin (ZIB) */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ /* See the License for the specific language governing permissions and */ /* limitations under the License. */ /* */ /* You should have received a copy of the Apache-2.0 license */ /* along with SoPlex; see the file LICENSE. If not email to soplex@zib.de. */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include #include #include #include "spxdefines.h" #include "soplex.h" #include "spxsolver.h" #include #include #include #include "timer.h" #include "spxpricer.h" #include "spxdantzigpr.h" #include "spxparmultpr.h" #include "spxdevexpr.h" #include "spxhybridpr.h" #include "spxsteeppr.h" #include "spxweightpr.h" #include "spxratiotester.h" #include "spxharrisrt.h" #include "spxdefaultrt.h" #include "spxfastrt.h" #include "spxsimplifier.h" #include "spxmainsm.h" #include "spxscaler.h" #include "spxequilisc.h" #include "spxgeometsc.h" #include "spxsumst.h" #include "spxweightst.h" #include "spxvectorst.h" #include "slufactor.h" #include "spxout.h" using namespace soplex; ///see "soplex -help", s means Simplifier, g means Scaler, c means Starter, p for Pricer and t for Ratiotester void set_s_g_c_p_t (SoPlex& work, const int simplifying, // 0 for none and 1 for Main, please see "soplex -help" const int scaling, // see above const int starting, const int pricing, const int ratiotest); void set_simplifier (SoPlex& work, const int simplifying); // 0 for none and 1 for Main, please see "soplex -help" void set_scalers (SoPlex& work, const int scaling ); // see above void set_starter (SoPlex& work, const int starting ); // see above void set_pricer (SoPlex& work, const int pricing ); // see above void set_ratio_tester (SoPlex& work, const int ratiotest ); // see above double abs(double a, double b); /** Unit test for copy constructors and assignment operators with random combinations of pricer, * ratiotester, simplifier, scaler, and starter. * * NOTE: Fails from singular bases usually come from using "bad" pricers or ratiotesters etc., * not from incorrect copying. */ int main(int argc, const char* const argv[]) { if(argc < 2) { std::cerr << "You must input a test file name, e.g. quick.test." << std::endl; exit(0); } std::ifstream in; in.open(argv[argc-1]); if(!in) { std::cerr << "No such file "<< argv[argc-1] << " can be found," << std::endl; exit(0); } int times = 0; int succ_times = 0; const int num_rows_output = 6; const int num_type = 2; const int num_timepoint = 3; const int num_copies = 3; int cnt[num_rows_output]; int pass[num_rows_output]; int fail[num_rows_output]; int singularBasis[num_rows_output]; int bigErr[num_rows_output]; std::string type[] = {"assign", "copy"}; std::string timepoint[] = {"before_load", "after_load", "after_solve"}; for(int num = 0; num < num_rows_output; ++num) { cnt[num] = 0; pass[num] = 0; fail[num] = 0; singularBasis[num] = 0; bigErr[num] = 0; } while(!in.eof()) { std::string ffname; std::getline(in, ffname); if(ffname.length() > 1) { if(ffname[0] == '/' && ffname[0] == '/') { std::cout << ffname << "skipped\n"; continue; } else times++; std::cout << "\n\n\nReading file " << ffname << "..." <setVerbose(0); set_s_g_c_p_t(lp_ori, 1, 1, 0, 4, 2); SoPlex lp[num_timepoint][num_type][num_copies] ; lp[0][1][0] = SoPlex(lp_ori); lp[0][1][1] = SoPlex(lp_ori); lp[0][1][2] = SoPlex(lp_ori); set_s_g_c_p_t(lp[0][1][0], 1, 1, 0, 0, 0); lp[0][0][0] = SoPlex(SPxSolver::LEAVE, SPxSolver::ROW); lp[0][0][1] = SoPlex(SPxSolver::ENTER, SPxSolver::COLUMN); lp[0][0][2] = SoPlex(SPxSolver::ENTER, SPxSolver::ROW); lp[0][0][0] = lp_ori; lp[0][0][1] = lp_ori; lp[0][0][2] = lp_ori; set_s_g_c_p_t(lp[0][0][0], 0, 4, 3, 3, 0); set_s_g_c_p_t(lp[0][0][2], 0, 0, 2, 4/*5*/, 2); lp[0][1][1].setType(SPxSolver::ENTER); lp[0][0][0].setRep(SPxSolver::ROW); if(!lp_ori.readFile(fname.c_str(), 0, 0, 0)) { std::cout << "error while reading file '" << fname.c_str() << "' -- terminating." << std::endl; exit(1); } // get the optimal objValue of the lp double optObjValue = 0.0; SoPlex* lp_cp_pr = new SoPlex(lp_ori); try{ lp_cp_pr->optimize(); if(lp_cp_pr->status() == SPxSolver::OPTIMAL) { std::cout << "Lp has been solved to optimality with default settings, objValue is " << lp_cp_pr->objValue() << std::endl; } else { std::cout << "Lp '" << fname.c_str() << "' has not been solved optimally with default settings -- terminating. (Choose a simpler test set!)" << std::endl; exit(1); } optObjValue = lp_cp_pr->objValue(); delete lp_cp_pr; }catch(SPxException& x) { std::cout << "exception caught : " << x.what() << std::endl; } lp[0][1][0].readFile(fname.c_str(), 0, 0, 0); lp[0][1][1].readFile(fname.c_str(), 0, 0, 0); lp[0][1][2].readFile(fname.c_str(), 0, 0, 0); set_s_g_c_p_t(lp[0][1][1], 0, 2, 2, 1, 1); set_s_g_c_p_t(lp[0][1][2], 1, 3, 1, 2, 2); lp[0][0][0].readFile(fname.c_str(), 0, 0, 0); lp[0][0][1].readFile(fname.c_str(), 0, 0, 0); lp[0][0][2].readFile(fname.c_str(), 0, 0, 0); set_s_g_c_p_t(lp[0][0][2], 0, 0, 2, 4/*5*/, 2); set_s_g_c_p_t(lp[0][0][1], 0, 0, 2, 4/*5*/, 2); //set_s_g_c_p_t(lp[0][0][1], 1, 2, 0, 4, 1); lp[0][1][2].setType(SPxSolver::ENTER); lp[0][0][1].setRep(SPxSolver::ROW); lp[0][0][1].setType(SPxSolver::LEAVE); /** test copy constructor and assignment function before soplex reads a lp */ int current_timepoint = 0; for(int n_type = 0; n_type < num_type; ++n_type) { int stat_idx = 2*current_timepoint + n_type; for(int n_time = 0; n_time < num_copies; ++n_time) { try{ (cnt[stat_idx])++; lp[current_timepoint][n_type][n_time].optimize(); if(lp[current_timepoint][n_type][n_time].status() == SPxSolver::OPTIMAL) { double absError = abs(lp[current_timepoint][n_type][n_time].objValue(), optObjValue); if(absError < lp[current_timepoint][n_type][n_time].delta() ) { (pass[stat_idx])++; std::cout << "lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " solved, num of iterations is " << lp[current_timepoint][n_type][n_time].iteration() << std::endl; } else { if( absError / optObjValue < lp[current_timepoint][n_type][n_time].delta() ) { (pass[stat_idx])++; } else { (fail[stat_idx])++; (bigErr[stat_idx])++; std::cout << "lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " solved " << "but does not have the same objValue with original, num of iterations is " << lp[current_timepoint][n_type][n_time].iteration() << ", the difference is " << abs(lp[current_timepoint][n_type][n_time].objValue(), optObjValue) << std::endl; } } } }catch(SPxException& x) { (fail[stat_idx])++; std::cout << "exception caught by" << " lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " :" << x.what() << std::endl; std::string exceptionContent(x.what()); if(exceptionContent.find("XSOLVE21") != std::string::npos || exceptionContent.find("singular") != std::string::npos) { (singularBasis[stat_idx])++; } std::cout << "\n\n\n"; } } } /** test copy constructor and assignment function after soplex reads a lp */ lp[1][1][0] = SoPlex(lp_ori); lp[1][1][1] = SoPlex(lp_ori); lp[1][1][2] = SoPlex(lp_ori); set_s_g_c_p_t(lp[1][1][0], 0, 2, 2, 1, 1); set_s_g_c_p_t(lp[1][1][1], 0, 4, 3, 3, 0); set_s_g_c_p_t(lp[1][1][2], 0, 0, 2, 4/*5*/, 2); lp[1][0][0] = SoPlex(SPxSolver::LEAVE, SPxSolver::ROW); lp[1][0][1] = SoPlex(SPxSolver::ENTER, SPxSolver::COLUMN); lp[1][0][2] = SoPlex(SPxSolver::ENTER, SPxSolver::ROW); set_s_g_c_p_t(lp[1][0][0], 1, 1, 0, 0, 0); lp[1][0][0] = lp_ori; lp[1][0][1] = lp_ori; lp[1][0][2] = lp_ori; set_s_g_c_p_t(lp[1][0][1], 1, 3, 1, 2, 2); set_s_g_c_p_t(lp[1][0][2], 1, 2, 0, 4, 1); lp[1][0][2].setType(SPxSolver::ENTER); // see above lp[1][1][2].setType(SPxSolver::ENTER); lp[1][0][0].setRep(SPxSolver::ROW); lp[1][0][1].setRep(SPxSolver::ROW); current_timepoint = 1; for(int n_type = 0; n_type < num_type; ++n_type) { int stat_idx = 2*current_timepoint + n_type; for(int n_time = 0; n_time < num_copies; ++n_time) { try{ (cnt[stat_idx])++; lp[current_timepoint][n_type][n_time].optimize(); if(lp[current_timepoint][n_type][n_time].status() == SPxSolver::OPTIMAL) { double absError = abs(lp[current_timepoint][n_type][n_time].objValue(), optObjValue); if(absError < lp[current_timepoint][n_type][n_time].delta() ) { (pass[stat_idx])++; std::cout << "lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " solved, num of iterations is " << lp[current_timepoint][n_type][n_time].iteration() << std::endl; } else { if( absError / optObjValue < lp[current_timepoint][n_type][n_time].delta() ) { (pass[stat_idx])++; } else { (fail[stat_idx])++; (bigErr[stat_idx])++; std::cout << "lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " solved " << "but does not have the same objValue with original, num of iterations is " << lp[current_timepoint][n_type][n_time].iteration() << ", the difference is " << abs(lp[current_timepoint][n_type][n_time].objValue(), optObjValue) << std::endl; } } } }catch(SPxException& x) { (fail[stat_idx])++; std::cout << "exception caught by" << " lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " :" << x.what() << std::endl; std::string exceptionContent(x.what()); if(exceptionContent.find("XSOLVE21") != std::string::npos || exceptionContent.find("singular") != std::string::npos) { (singularBasis[stat_idx])++; } std::cout << "\n\n\n"; } } } // solve the original problem try{ lp_ori.optimize(); if(lp_ori.status() == SPxSolver::OPTIMAL) { std::cout << "The original lp has been solved to optimality with default settings, num of iterations is " << lp_ori.iteration() << std::endl; } else { std::cout << "The original lp '" << fname.c_str() << "' has not been solved optimally with default settings -- terminating. (Choose a simpler test set!)" << std::endl; exit(1); } }catch(SPxException& x) { std::cout << "exception caught : " << x.what() << std::endl; std::cout << "\n\n\n"; } /** test copy constructor and assignment function before soplex solved an lp */ lp[2][1][0] = SoPlex(lp_ori); lp[2][1][1] = SoPlex(lp_ori); lp[2][1][2] = SoPlex(lp_ori); set_s_g_c_p_t(lp[2][1][0], 1, 3, 1, 2, 2); set_s_g_c_p_t(lp[2][1][1], 0, 4, 3, 3, 0); set_s_g_c_p_t(lp[2][1][2], 1, 2, 0, 4, 1); lp[2][0][0] = SoPlex(SPxSolver::LEAVE, SPxSolver::ROW); lp[2][0][1] = SoPlex(SPxSolver::ENTER, SPxSolver::COLUMN); lp[2][0][2] = SoPlex(SPxSolver::ENTER, SPxSolver::ROW); set_s_g_c_p_t(lp[2][0][0], 1, 1, 0, 0, 0); lp[2][0][0] = lp_ori; lp[2][0][1] = lp_ori; lp[2][0][2] = lp_ori; set_s_g_c_p_t(lp[2][0][1], 0, 2, 2, 1, 1); set_s_g_c_p_t(lp[2][0][2], 0, 0, 2, 4/*5*/, 2); lp[2][1][0].setType(SPxSolver::ENTER); lp[2][0][2].setRep(SPxSolver::ROW); lp[2][0][1].setRep(SPxSolver::ROW); current_timepoint = 2; for(int n_type = 0; n_type < num_type; ++n_type) { int stat_idx = 2*current_timepoint + n_type; for(int n_time = 0; n_time < num_copies; ++n_time) { try{ (cnt[stat_idx])++; lp[current_timepoint][n_type][n_time].optimize(); if(lp[current_timepoint][n_type][n_time].status() == SPxSolver::OPTIMAL) { double absError = abs(lp[current_timepoint][n_type][n_time].objValue(), optObjValue); if(absError < lp[current_timepoint][n_type][n_time].delta() ) { (pass[stat_idx])++; std::cout << "lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " solved, num of iterations is " << lp[current_timepoint][n_type][n_time].iteration() << std::endl; } else { if( absError / optObjValue < lp[current_timepoint][n_type][n_time].delta() ) { (pass[stat_idx])++; } else { (fail[stat_idx])++; (bigErr[stat_idx])++; std::cout << "lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " solved " << "but does not have the same objValue with original, num of iterations is " << lp[current_timepoint][n_type][n_time].iteration() << ", the difference is " << abs(lp[current_timepoint][n_type][n_time].objValue(), optObjValue) << std::endl; } } } }catch(SPxException& x) { (fail[stat_idx])++; std::cout << "exception caught by" << " lp_" << type[n_type] << "_" << timepoint[current_timepoint] << "_" << n_time << " :" << x.what() << std::endl; std::string exceptionContent(x.what()); if(exceptionContent.find("XSOLVE21") != std::string::npos || exceptionContent.find("singular") != std::string::npos) { (singularBasis[stat_idx])++; } std::cout << "\n\n\n"; } } } } } // test end // output the result std::cout << "\n\n"; std::cout << "---------------------------------------------------------------------------------------\n"; std::cout << "Type Cnt Pass Fail SingularBasis BigErr\n"; std::cout << "---------------------------------------------------------------------------------------\n"; for(int n_type = 0; n_type < num_type; ++n_type) { for(int n_timepoint = 0; n_timepoint < num_timepoint; ++n_timepoint) { int idx = 2*n_timepoint + n_type; std::cout << std::setw(14) << std::left << type[n_type] << std::setw(14) << std::right << timepoint[n_timepoint] << std::setw(11) << std::right << cnt[idx] << std::setw(10) << std::right << pass[idx] << std::setw(9) << std::right << fail[idx] << std::setw(19) << std::right << singularBasis[idx] << std::setw(10) << std::right << bigErr[idx] << std::endl; } } int sum_cnt = 0; int sum_pass = 0; int sum_fail = 0; int sum_singularBasis = 0; int sum_bigErr = 0; for(int num = 0; num < num_rows_output; ++num) { sum_cnt += cnt[num]; sum_pass += pass[num]; sum_fail += fail[num]; sum_singularBasis += singularBasis[num]; sum_bigErr += bigErr[num]; } std::cout << "---------------------------------------------------------------------------------------\n"; std::cout << std::setw(14) << std::left << "Sum" << std::setw(14) << std::right << "" << std::setw(11) << std::right << sum_cnt << std::setw(10) << std::right << sum_pass << std::setw(9) << std::right << sum_fail << std::setw(19) << std::right << sum_singularBasis << std::setw(10) << std::right << sum_bigErr << std::endl; std::cout << "---------------------------------------------------------------------------------------\n"; } void set_simplifier(SoPlex& work, const int simplifying) { switch(simplifying) { case 1 : work.setSimplifier(new SPxMainSM(), true); break; case 0 : /*FALLTHROUGH*/ default : break; } } void set_scalers(SoPlex& work, const int scaling) { switch(scaling) { case 4: work.setPreScaler(new SPxEquiliSC(true), true); work.setPostScaler(new SPxGeometSC(8), true); break; case 3: work.setPreScaler(new SPxEquiliSC(true), true); work.setPostScaler(new SPxGeometSC(1), true); break; case 2 : work.setPreScaler(new SPxEquiliSC(true), true); work.setPostScaler(0, false); break; case 1 : work.setPreScaler(new SPxEquiliSC(false), true); work.setPostScaler(0, false); break; case 0 : /*FALLTHROUGH*/ default : work.setPreScaler(0, false); work.setPostScaler(0, false); break; } } void set_starter(SoPlex& work, const int starting) { switch(starting) { case 3 : work.setStarter(new SPxVectorST, true); break; case 2 : work.setStarter(new SPxSumST, true); break; case 1 : work.setStarter(new SPxWeightST, true); break; case 0 : /*FALLTHROUGH*/ default : work.setStarter(0, false); break; } } void set_pricer(SoPlex& work, const int pricing) { switch(pricing) { case 5 : work.setPricer(new SPxWeightPR, true); break; case 4 : work.setPricer(new SPxSteepPR, true); break; case 3 : work.setPricer(new SPxHybridPR, true); break; case 2 : work.setPricer(new SPxDevexPR, true); break; case 1 : work.setPricer(new SPxParMultPR, true); break; case 0 : /*FALLTHROUGH*/ default : work.setPricer(new SPxDantzigPR, true); break; } } void set_ratio_tester(SoPlex& work, const int ratiotest) { switch(ratiotest) { case 2 : work.setTester(new SPxFastRT, true); break; case 1 : work.setTester(new SPxHarrisRT, true); break; case 0 : /*FALLTHROUGH*/ default: work.setTester(new SPxDefaultRT, true); break; } } void set_s_g_c_p_t (SoPlex& work, const int simplifying, const int scaling, const int starting, const int pricing, const int ratiotest) { set_simplifier (work, simplifying); set_scalers (work, scaling ); set_starter (work, starting ); set_pricer (work, pricing ); set_ratio_tester (work, ratiotest ); } double abs(double a, double b) { if(a >= b) return a-b; else return b-a; } //----------------------------------------------------------------------------- //Emacs Local Variables: //Emacs mode:c++ //Emacs c-basic-offset:3 //Emacs tab-width:8 //Emacs indent-tabs-mode:nil //Emacs End: //-----------------------------------------------------------------------------