1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                       */
3 /*    This file is part of the HiGHS linear optimization suite           */
4 /*                                                                       */
5 /*    Written and engineered 2008-2021 at the University of Edinburgh    */
6 /*                                                                       */
7 /*    Available as open-source under the MIT License                     */
8 /*                                                                       */
9 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10 /**@file lp_data/HighsOptions.h
11  * @brief
12  * @author Julian Hall, Ivet Galabova, Qi Huangfu and Michael Feldmeier
13  */
14 #ifndef LP_DATA_HIGHS_OPTIONS_H_
15 #define LP_DATA_HIGHS_OPTIONS_H_
16 
17 #include <cstring>  // For strlen
18 #include <vector>
19 
20 #include "io/HighsIO.h"
21 #include "lp_data/HConst.h"
22 #include "lp_data/HighsStatus.h"
23 #include "simplex/HFactor.h"
24 #include "simplex/SimplexConst.h"
25 
26 using std::string;
27 
28 enum class OptionStatus { OK = 0, NO_FILE, UNKNOWN_OPTION, ILLEGAL_VALUE };
29 
30 class OptionRecord {
31  public:
32   HighsOptionType type;
33   std::string name;
34   std::string description;
35   bool advanced;
36 
OptionRecord(HighsOptionType Xtype,std::string Xname,std::string Xdescription,bool Xadvanced)37   OptionRecord(HighsOptionType Xtype, std::string Xname,
38                std::string Xdescription, bool Xadvanced) {
39     this->type = Xtype;
40     this->name = Xname;
41     this->description = Xdescription;
42     this->advanced = Xadvanced;
43   }
44 
~OptionRecord()45   virtual ~OptionRecord() {}
46 };
47 
48 class OptionRecordBool : public OptionRecord {
49  public:
50   bool* value;
51   bool default_value;
OptionRecordBool(std::string Xname,std::string Xdescription,bool Xadvanced,bool * Xvalue_pointer,bool Xdefault_value)52   OptionRecordBool(std::string Xname, std::string Xdescription, bool Xadvanced,
53                    bool* Xvalue_pointer, bool Xdefault_value)
54       : OptionRecord(HighsOptionType::BOOL, Xname, Xdescription, Xadvanced) {
55     advanced = Xadvanced;
56     value = Xvalue_pointer;
57     default_value = Xdefault_value;
58     *value = default_value;
59   }
60 
assignvalue(bool Xvalue)61   void assignvalue(bool Xvalue) { *value = Xvalue; }
62 
~OptionRecordBool()63   virtual ~OptionRecordBool() {}
64 };
65 
66 class OptionRecordInt : public OptionRecord {
67  public:
68   int* value;
69   int lower_bound;
70   int default_value;
71   int upper_bound;
OptionRecordInt(std::string Xname,std::string Xdescription,bool Xadvanced,int * Xvalue_pointer,int Xlower_bound,int Xdefault_value,int Xupper_bound)72   OptionRecordInt(std::string Xname, std::string Xdescription, bool Xadvanced,
73                   int* Xvalue_pointer, int Xlower_bound, int Xdefault_value,
74                   int Xupper_bound)
75       : OptionRecord(HighsOptionType::INT, Xname, Xdescription, Xadvanced) {
76     value = Xvalue_pointer;
77     lower_bound = Xlower_bound;
78     default_value = Xdefault_value;
79     upper_bound = Xupper_bound;
80     *value = default_value;
81   }
82 
assignvalue(int Xvalue)83   void assignvalue(int Xvalue) { *value = Xvalue; }
84 
~OptionRecordInt()85   virtual ~OptionRecordInt() {}
86 };
87 
88 class OptionRecordDouble : public OptionRecord {
89  public:
90   double* value;
91   double lower_bound;
92   double upper_bound;
93   double default_value;
OptionRecordDouble(std::string Xname,std::string Xdescription,bool Xadvanced,double * Xvalue_pointer,double Xlower_bound,double Xdefault_value,double Xupper_bound)94   OptionRecordDouble(std::string Xname, std::string Xdescription,
95                      bool Xadvanced, double* Xvalue_pointer,
96                      double Xlower_bound, double Xdefault_value,
97                      double Xupper_bound)
98       : OptionRecord(HighsOptionType::DOUBLE, Xname, Xdescription, Xadvanced) {
99     value = Xvalue_pointer;
100     lower_bound = Xlower_bound;
101     default_value = Xdefault_value;
102     upper_bound = Xupper_bound;
103     *value = default_value;
104   }
105 
assignvalue(double Xvalue)106   void assignvalue(double Xvalue) { *value = Xvalue; }
107 
~OptionRecordDouble()108   virtual ~OptionRecordDouble() {}
109 };
110 
111 class OptionRecordString : public OptionRecord {
112  public:
113   std::string* value;
114   std::string default_value;
OptionRecordString(std::string Xname,std::string Xdescription,bool Xadvanced,std::string * Xvalue_pointer,std::string Xdefault_value)115   OptionRecordString(std::string Xname, std::string Xdescription,
116                      bool Xadvanced, std::string* Xvalue_pointer,
117                      std::string Xdefault_value)
118       : OptionRecord(HighsOptionType::STRING, Xname, Xdescription, Xadvanced) {
119     value = Xvalue_pointer;
120     default_value = Xdefault_value;
121     *value = default_value;
122   }
123 
assignvalue(std::string Xvalue)124   void assignvalue(std::string Xvalue) { *value = Xvalue; }
125 
~OptionRecordString()126   virtual ~OptionRecordString() {}
127 };
128 
129 inline const char* bool2string(bool b);
130 
131 bool commandLineOffChooseOnOk(FILE* logfile, const string& value);
132 bool commandLineSolverOk(FILE* logfile, const string& value);
133 
134 bool boolFromString(const std::string value, bool& bool_value);
135 
136 OptionStatus getOptionIndex(FILE* logfile, const std::string& name,
137                             const std::vector<OptionRecord*>& option_records,
138                             int& index);
139 
140 OptionStatus checkOptions(FILE* logfile,
141                           const std::vector<OptionRecord*>& option_records);
142 OptionStatus checkOption(FILE* logfile, const OptionRecordInt& option);
143 OptionStatus checkOption(FILE* logfile, const OptionRecordDouble& option);
144 
145 OptionStatus checkOptionValue(FILE* logfile,
146                               std::vector<OptionRecord*>& option_records,
147                               const int value);
148 OptionStatus checkOptionValue(FILE* logfile,
149                               std::vector<OptionRecord*>& option_records,
150                               const double value);
151 OptionStatus checkOptionValue(FILE* logfile,
152                               std::vector<OptionRecord*>& option_records,
153                               const std::string value);
154 
155 OptionStatus setOptionValue(FILE* logfile, const std::string& name,
156                             std::vector<OptionRecord*>& option_records,
157                             const bool value);
158 OptionStatus setOptionValue(FILE* logfile, const std::string& name,
159                             std::vector<OptionRecord*>& option_records,
160                             const int value);
161 OptionStatus setOptionValue(FILE* logfile, const std::string& name,
162                             std::vector<OptionRecord*>& option_records,
163                             const double value);
164 OptionStatus setOptionValue(FILE* logfile, const std::string& name,
165                             std::vector<OptionRecord*>& option_records,
166                             const std::string value);
167 OptionStatus setOptionValue(FILE* logfile, const std::string& name,
168                             std::vector<OptionRecord*>& option_records,
169                             const char* value);
170 
171 OptionStatus setOptionValue(OptionRecordBool& option, const bool value);
172 OptionStatus setOptionValue(FILE* logfile, OptionRecordInt& option,
173                             const int value);
174 OptionStatus setOptionValue(FILE* logfile, OptionRecordDouble& option,
175                             const double value);
176 OptionStatus setOptionValue(FILE* logfile, OptionRecordString& option,
177                             std::string const value);
178 
179 OptionStatus passOptions(FILE* logfile, const HighsOptions& from_options,
180                          HighsOptions& to_options);
181 
182 OptionStatus getOptionValue(FILE* logfile, const std::string& name,
183                             const std::vector<OptionRecord*>& option_records,
184                             bool& value);
185 OptionStatus getOptionValue(FILE* logfile, const std::string& name,
186                             const std::vector<OptionRecord*>& option_records,
187                             int& value);
188 OptionStatus getOptionValue(FILE* logfile, const std::string& name,
189                             const std::vector<OptionRecord*>& option_records,
190                             double& value);
191 OptionStatus getOptionValue(FILE* logfile, const std::string& name,
192                             const std::vector<OptionRecord*>& option_records,
193                             std::string& value);
194 
195 OptionStatus getOptionType(FILE* logfile, const std::string& name,
196                            const std::vector<OptionRecord*>& option_records,
197                            HighsOptionType& type);
198 
199 void resetOptions(std::vector<OptionRecord*>& option_records);
200 
201 HighsStatus writeOptionsToFile(FILE* file,
202                                const std::vector<OptionRecord*>& option_records,
203                                const bool report_only_non_default_values = true,
204                                const bool html = false);
205 void reportOptions(FILE* file, const std::vector<OptionRecord*>& option_records,
206                    const bool report_only_non_default_values = true,
207                    const bool html = false);
208 void reportOption(FILE* file, const OptionRecordBool& option,
209                   const bool report_only_non_default_values, const bool html);
210 void reportOption(FILE* file, const OptionRecordInt& option,
211                   const bool report_only_non_default_values, const bool html);
212 void reportOption(FILE* file, const OptionRecordDouble& option,
213                   const bool report_only_non_default_values, const bool html);
214 void reportOption(FILE* file, const OptionRecordString& option,
215                   const bool report_only_non_default_values, const bool html);
216 
217 const string simplex_string = "simplex";
218 const string ipm_string = "ipm";
219 const string mip_string = "mip";
220 
221 const int KEEP_N_ROWS_DELETE_ROWS = -1;
222 const int KEEP_N_ROWS_DELETE_ENTRIES = 0;
223 const int KEEP_N_ROWS_KEEP_ROWS = 1;
224 
225 // Strings for command line options
226 const string model_file_string = "model_file";
227 const string presolve_string = "presolve";
228 const string solver_string = "solver";
229 const string parallel_string = "parallel";
230 const string time_limit_string = "time_limit";
231 const string options_file_string = "options_file";
232 
233 // enum objSense { OBJSENSE_MINIMIZE = 1, OBJSENSE_MAXIMIZE = -1 };
234 
235 struct HighsOptionsStruct {
236   // Options read from the command line
237   std::string model_file;
238   std::string presolve;
239   std::string solver;
240   std::string parallel;
241   double time_limit;
242   std::string options_file;
243 
244   // Options read from the file
245   double infinite_cost;
246   double infinite_bound;
247   double small_matrix_value;
248   double large_matrix_value;
249   double primal_feasibility_tolerance;
250   double dual_feasibility_tolerance;
251   double ipm_optimality_tolerance;
252   double dual_objective_value_upper_bound;
253   int highs_debug_level;
254   int simplex_strategy;
255   int simplex_scale_strategy;
256   int simplex_crash_strategy;
257   int simplex_dual_edge_weight_strategy;
258   int simplex_primal_edge_weight_strategy;
259   int simplex_iteration_limit;
260   int simplex_update_limit;
261   int ipm_iteration_limit;
262   int highs_min_threads;
263   int highs_max_threads;
264   int message_level;
265   std::string solution_file;
266   bool write_solution_to_file;
267   bool write_solution_pretty;
268 
269   // Advanced options
270   bool run_crossover;
271   bool mps_parser_type_free;
272   int keep_n_rows;
273   int allowed_simplex_matrix_scale_factor;
274   int allowed_simplex_cost_scale_factor;
275   int simplex_dualise_strategy;
276   int simplex_permute_strategy;
277   int dual_simplex_cleanup_strategy;
278   int simplex_price_strategy;
279   int dual_chuzc_sort_strategy;
280   bool simplex_initial_condition_check;
281   double simplex_initial_condition_tolerance;
282   double dual_steepest_edge_weight_log_error_threshold;
283   double dual_simplex_cost_perturbation_multiplier;
284   double factor_pivot_threshold;
285   double factor_pivot_tolerance;
286   double start_crossover_tolerance;
287   bool less_infeasible_DSE_check;
288   bool less_infeasible_DSE_choose_row;
289   bool use_original_HFactor_logic;
290 
291   // Options for MIP solver
292   int mip_max_nodes;
293   int mip_max_leaves;
294   int mip_report_level;
295   double mip_feasibility_tolerance;
296   double mip_epsilon;
297   double mip_heuristic_effort;
298 #ifdef HIGHS_DEBUGSOL
299   std::string mip_debug_solution_file;
300 #endif
301   // Options for HighsPrintMessage and HighsLogMessage
302   FILE* logfile = stdout;
303   FILE* output = stdout;
304 
305   void (*printmsgcb)(int level, const char* msg, void* msgcb_data) = NULL;
306   void (*logmsgcb)(HighsMessageType type, const char* msg,
307                    void* msgcb_data) = NULL;
308   void* msgcb_data = NULL;
309 
~HighsOptionsStructHighsOptionsStruct310   virtual ~HighsOptionsStruct() {}
311 };
312 
313 // For now, but later change so HiGHS properties are string based so that new
314 // options (for debug and testing too) can be added easily. The options below
315 // are just what has been used to parse options from argv.
316 // todo: when creating the new options don't forget underscores for class
317 // variables but no underscores for struct
318 class HighsOptions : public HighsOptionsStruct {
319  public:
HighsOptions()320   HighsOptions() { initRecords(); }
321 
HighsOptions(const HighsOptions & options)322   HighsOptions(const HighsOptions& options) {
323     initRecords();
324     HighsOptionsStruct::operator=(options);
325   }
326 
HighsOptions(HighsOptions && options)327   HighsOptions(HighsOptions&& options) {
328     records = std::move(options.records);
329     HighsOptionsStruct::operator=(std::move(options));
330   }
331 
332   const HighsOptions& operator=(const HighsOptions& other) {
333     if (&other != this) {
334       if ((int)records.size() == 0) initRecords();
335       HighsOptionsStruct::operator=(other);
336     }
337     return *this;
338   }
339 
340   const HighsOptions& operator=(HighsOptions&& other) {
341     if (&other != this) {
342       if ((int)records.size() == 0) initRecords();
343       HighsOptionsStruct::operator=(other);
344     }
345     return *this;
346   }
347 
~HighsOptions()348   virtual ~HighsOptions() {
349     if (records.size() > 0) deleteRecords();
350   }
351 
352  private:
initRecords()353   void initRecords() {
354     OptionRecordBool* record_bool;
355     OptionRecordInt* record_int;
356     OptionRecordDouble* record_double;
357     OptionRecordString* record_string;
358     bool advanced;
359     advanced = false;
360     // Options read from the command line
361     record_string =
362         new OptionRecordString(model_file_string, "Model file", advanced,
363                                &model_file, FILENAME_DEFAULT);
364     records.push_back(record_string);
365     record_string = new OptionRecordString(
366         presolve_string, "Presolve option: \"off\", \"choose\" or \"on\"",
367         advanced, &presolve, choose_string);
368     records.push_back(record_string);
369     record_string = new OptionRecordString(
370         solver_string, "Solver option: \"simplex\", \"choose\" or \"ipm\"",
371         advanced, &solver, choose_string);
372     records.push_back(record_string);
373     record_string = new OptionRecordString(
374         parallel_string, "Parallel option: \"off\", \"choose\" or \"on\"",
375         advanced, &parallel, choose_string);
376     records.push_back(record_string);
377     record_double = new OptionRecordDouble(time_limit_string, "Time limit",
378                                            advanced, &time_limit, 0,
379                                            HIGHS_CONST_INF, HIGHS_CONST_INF);
380     records.push_back(record_double);
381     record_string =
382         new OptionRecordString(options_file_string, "Options file", advanced,
383                                &options_file, FILENAME_DEFAULT);
384     records.push_back(record_string);
385     // Options read from the file
386     record_double = new OptionRecordDouble(
387         "infinite_cost",
388         "Limit on cost coefficient: values larger than "
389         "this will be treated as infinite",
390         advanced, &infinite_cost, 1e15, 1e20, HIGHS_CONST_INF);
391     records.push_back(record_double);
392 
393     record_double = new OptionRecordDouble(
394         "infinite_bound",
395         "Limit on |constraint bound|: values larger "
396         "than this will be treated as infinite",
397         advanced, &infinite_bound, 1e15, 1e20, HIGHS_CONST_INF);
398     records.push_back(record_double);
399 
400     record_double = new OptionRecordDouble(
401         "small_matrix_value",
402         "Lower limit on |matrix entries|: values smaller than this will be "
403         "treated as zero",
404         advanced, &small_matrix_value, 1e-12, 1e-9, HIGHS_CONST_INF);
405     records.push_back(record_double);
406 
407     record_double = new OptionRecordDouble(
408         "large_matrix_value",
409         "Upper limit on |matrix entries|: values larger "
410         "than this will be treated as infinite",
411         advanced, &large_matrix_value, 1e0, 1e15, HIGHS_CONST_INF);
412     records.push_back(record_double);
413 
414     record_double = new OptionRecordDouble(
415         "primal_feasibility_tolerance", "Primal feasibility tolerance",
416         advanced, &primal_feasibility_tolerance, 1e-10, 1e-7, HIGHS_CONST_INF);
417     records.push_back(record_double);
418 
419     record_double = new OptionRecordDouble(
420         "dual_feasibility_tolerance", "Dual feasibility tolerance", advanced,
421         &dual_feasibility_tolerance, 1e-10, 1e-7, HIGHS_CONST_INF);
422     records.push_back(record_double);
423 
424     record_double = new OptionRecordDouble(
425         "ipm_optimality_tolerance", "IPM optimality tolerance", advanced,
426         &ipm_optimality_tolerance, 1e-12, 1e-8, HIGHS_CONST_INF);
427     records.push_back(record_double);
428 
429     record_double = new OptionRecordDouble(
430         "dual_objective_value_upper_bound",
431         "Upper bound on objective value for dual simplex: algorithm terminates "
432         "if reached",
433         advanced, &dual_objective_value_upper_bound, -HIGHS_CONST_INF,
434         HIGHS_CONST_INF, HIGHS_CONST_INF);
435     records.push_back(record_double);
436 
437     record_int =
438         new OptionRecordInt("highs_debug_level", "Debugging level in HiGHS",
439                             advanced, &highs_debug_level, HIGHS_DEBUG_LEVEL_MIN,
440                             HIGHS_DEBUG_LEVEL_MIN, HIGHS_DEBUG_LEVEL_MAX);
441     records.push_back(record_int);
442 
443     record_int =
444         new OptionRecordInt("simplex_strategy", "Strategy for simplex solver",
445                             advanced, &simplex_strategy, SIMPLEX_STRATEGY_MIN,
446                             SIMPLEX_STRATEGY_DUAL, SIMPLEX_STRATEGY_MAX);
447     records.push_back(record_int);
448 
449     record_int = new OptionRecordInt(
450         "simplex_scale_strategy",
451         "Strategy for scaling before simplex solver: off / on (0/1)", advanced,
452         &simplex_scale_strategy, SIMPLEX_SCALE_STRATEGY_MIN,
453         SIMPLEX_SCALE_STRATEGY_HIGHS_FORCED, SIMPLEX_SCALE_STRATEGY_MAX);
454     records.push_back(record_int);
455 
456     record_int = new OptionRecordInt(
457         "simplex_crash_strategy",
458         "Strategy for simplex crash: off / LTSSF / Bixby (0/1/2)", advanced,
459         &simplex_crash_strategy, SIMPLEX_CRASH_STRATEGY_MIN,
460         SIMPLEX_CRASH_STRATEGY_OFF, SIMPLEX_CRASH_STRATEGY_MAX);
461     records.push_back(record_int);
462 
463     record_int =
464         new OptionRecordInt("simplex_dual_edge_weight_strategy",
465                             "Strategy for simplex dual edge weights: Choose / "
466                             "Dantzig / Devex / Steepest "
467                             "Edge (-1/0/1/2)",
468                             advanced, &simplex_dual_edge_weight_strategy,
469                             SIMPLEX_DUAL_EDGE_WEIGHT_STRATEGY_MIN,
470                             SIMPLEX_DUAL_EDGE_WEIGHT_STRATEGY_CHOOSE,
471                             SIMPLEX_DUAL_EDGE_WEIGHT_STRATEGY_MAX);
472     records.push_back(record_int);
473 
474     record_int =
475         new OptionRecordInt("simplex_primal_edge_weight_strategy",
476                             "Strategy for simplex primal edge weights: Choose "
477                             "/ Dantzig / Devex (-1/0/1)",
478                             advanced, &simplex_primal_edge_weight_strategy,
479                             SIMPLEX_PRIMAL_EDGE_WEIGHT_STRATEGY_MIN,
480                             SIMPLEX_PRIMAL_EDGE_WEIGHT_STRATEGY_CHOOSE,
481                             SIMPLEX_PRIMAL_EDGE_WEIGHT_STRATEGY_MAX);
482     records.push_back(record_int);
483 
484     record_int = new OptionRecordInt("simplex_iteration_limit",
485                                      "Iteration limit for simplex solver",
486                                      advanced, &simplex_iteration_limit, 0,
487                                      HIGHS_CONST_I_INF, HIGHS_CONST_I_INF);
488     records.push_back(record_int);
489 
490     record_int = new OptionRecordInt(
491         "simplex_update_limit",
492         "Limit on the number of simplex UPDATE operations", advanced,
493         &simplex_update_limit, 0, 5000, HIGHS_CONST_I_INF);
494     records.push_back(record_int);
495 
496     record_int = new OptionRecordInt(
497         "ipm_iteration_limit", "Iteration limit for IPM solver", advanced,
498         &ipm_iteration_limit, 0, HIGHS_CONST_I_INF, HIGHS_CONST_I_INF);
499     records.push_back(record_int);
500 
501     record_int = new OptionRecordInt(
502         "highs_min_threads", "Minimum number of threads in parallel execution",
503         advanced, &highs_min_threads, 1, 1, HIGHS_THREAD_LIMIT);
504     records.push_back(record_int);
505 
506     record_int = new OptionRecordInt(
507         "highs_max_threads", "Maximum number of threads in parallel execution",
508         advanced, &highs_max_threads, 1, HIGHS_THREAD_LIMIT,
509         HIGHS_THREAD_LIMIT);
510     records.push_back(record_int);
511 
512     record_int = new OptionRecordInt("message_level",
513                                      "HiGHS message level: bit-mask 1 => "
514                                      "VERBOSE; 2 => DETAILED 4 => MINIMAL",
515                                      advanced, &message_level, ML_MIN,
516                                      ML_MINIMAL, ML_MAX);
517     records.push_back(record_int);
518 
519     record_string =
520         new OptionRecordString("solution_file", "Solution file", advanced,
521                                &solution_file, FILENAME_DEFAULT);
522     records.push_back(record_string);
523 
524     record_bool =
525         new OptionRecordBool("write_solution_to_file",
526                              "Write the primal and dual solution to a file",
527                              advanced, &write_solution_to_file, false);
528     records.push_back(record_bool);
529 
530     record_bool = new OptionRecordBool("write_solution_pretty",
531                                        "Write the primal and dual solution in "
532                                        "a pretty (human-readable) format",
533                                        advanced, &write_solution_pretty, false);
534     records.push_back(record_bool);
535 
536     record_int = new OptionRecordInt(
537         "mip_max_nodes", "MIP solver max number of nodes", advanced,
538         &mip_max_nodes, 0, HIGHS_CONST_I_INF, HIGHS_CONST_I_INF);
539     records.push_back(record_int);
540 #ifdef HIGHS_DEBUGSOL
541     record_string = new OptionRecordString(
542         "mip_debug_solution_file",
543         "Solution file for debug solution of the MIP solver", advanced,
544         &mip_debug_solution_file, FILENAME_DEFAULT);
545     records.push_back(record_string);
546 #endif
547 
548     record_int = new OptionRecordInt(
549         "mip_max_leaves", "MIP solver max number of leave nodes", advanced,
550         &mip_max_leaves, 0, HIGHS_CONST_I_INF, HIGHS_CONST_I_INF);
551     records.push_back(record_int);
552 
553     record_int =
554         new OptionRecordInt("mip_report_level", "MIP solver reporting level",
555                             advanced, &mip_report_level, 0, 1, 2);
556     records.push_back(record_int);
557 
558     record_double = new OptionRecordDouble(
559         "mip_feasibility_tolerance", "MIP feasibility tolerance", advanced,
560         &mip_feasibility_tolerance, 1e-10, 1e-6, HIGHS_CONST_INF);
561 
562     record_double =
563         new OptionRecordDouble("mip_epsilon", "MIP epsilon tolerance", advanced,
564                                &mip_epsilon, 1e-15, 1e-9, HIGHS_CONST_INF);
565 
566     record_double = new OptionRecordDouble(
567         "mip_heuristic_effort", "effort spent for MIP heuristics", advanced,
568         &mip_heuristic_effort, 0.0, 0.05, 1.0);
569 
570     records.push_back(record_double);
571 
572     // Advanced options
573     advanced = true;
574 
575     record_bool = new OptionRecordBool("run_crossover",
576                                        "Run the crossover routine for IPX",
577                                        advanced, &run_crossover, true);
578     records.push_back(record_bool);
579 
580     record_bool = new OptionRecordBool("mps_parser_type_free",
581                                        "Use the free format MPS file reader",
582                                        advanced, &mps_parser_type_free, true);
583     records.push_back(record_bool);
584     record_int =
585         new OptionRecordInt("keep_n_rows",
586                             "For multiple N-rows in MPS files: delete rows / "
587                             "delete entries / keep rows (-1/0/1)",
588                             advanced, &keep_n_rows, KEEP_N_ROWS_DELETE_ROWS,
589                             KEEP_N_ROWS_DELETE_ROWS, KEEP_N_ROWS_KEEP_ROWS);
590     records.push_back(record_int);
591     record_int = new OptionRecordInt(
592         "allowed_simplex_matrix_scale_factor",
593         "Largest power-of-two factor permitted when scaling the constraint "
594         "matrix for the simplex solver",
595         advanced, &allowed_simplex_matrix_scale_factor, 0, 10, 20);
596     records.push_back(record_int);
597 
598     record_int = new OptionRecordInt(
599         "allowed_simplex_cost_scale_factor",
600         "Largest power-of-two factor permitted when scaling the costs for the "
601         "simplex solver",
602         advanced, &allowed_simplex_cost_scale_factor, 0, 0, 20);
603     records.push_back(record_int);
604 
605     record_int = new OptionRecordInt(
606         "simplex_dualise_strategy", "Strategy for dualising before simplex",
607         advanced, &simplex_dualise_strategy, OPTION_OFF, OPTION_OFF, OPTION_ON);
608     records.push_back(record_int);
609 
610     record_int = new OptionRecordInt(
611         "simplex_permute_strategy", "Strategy for permuting before simplex",
612         advanced, &simplex_permute_strategy, OPTION_OFF, OPTION_OFF, OPTION_ON);
613     records.push_back(record_int);
614 
615     record_int =
616         new OptionRecordInt("dual_simplex_cleanup_strategy",
617                             "Strategy for cleanup in dual simplex solver: none "
618                             "/ HPrimal / HQPrimal (0/1/2)",
619                             advanced, &dual_simplex_cleanup_strategy,
620                             DUAL_SIMPLEX_CLEANUP_STRATEGY_MIN,
621                             DUAL_SIMPLEX_CLEANUP_STRATEGY_HPRIMAL,
622                             DUAL_SIMPLEX_CLEANUP_STRATEGY_MAX);
623     records.push_back(record_int);
624 
625     record_int = new OptionRecordInt(
626         "simplex_price_strategy", "Strategy for PRICE in simplex", advanced,
627         &simplex_price_strategy, SIMPLEX_PRICE_STRATEGY_MIN,
628         SIMPLEX_PRICE_STRATEGY_ROW_SWITCH_COL_SWITCH,
629         SIMPLEX_PRICE_STRATEGY_MAX);
630     records.push_back(record_int);
631 
632     record_int = new OptionRecordInt(
633         "dual_chuzc_sort_strategy", "Strategy for CHUZC sort in dual simplex",
634         advanced, &dual_chuzc_sort_strategy, SIMPLEX_DUAL_CHUZC_STRATEGY_MIN,
635         SIMPLEX_DUAL_CHUZC_STRATEGY_CHOOSE, SIMPLEX_DUAL_CHUZC_STRATEGY_MAX);
636     records.push_back(record_int);
637 
638     record_bool =
639         new OptionRecordBool("simplex_initial_condition_check",
640                              "Perform initial basis condition check in simplex",
641                              advanced, &simplex_initial_condition_check, true);
642     records.push_back(record_bool);
643 
644     record_double = new OptionRecordDouble(
645         "simplex_initial_condition_tolerance",
646         "Tolerance on initial basis condition in simplex", advanced,
647         &simplex_initial_condition_tolerance, 1.0, 1e14, HIGHS_CONST_INF);
648     records.push_back(record_double);
649 
650     record_double = new OptionRecordDouble(
651         "dual_steepest_edge_weight_log_error_threshold",
652         "Threshold on dual steepest edge weight errors for Devex switch",
653         advanced, &dual_steepest_edge_weight_log_error_threshold, 1.0, 1e1,
654         HIGHS_CONST_INF);
655     records.push_back(record_double);
656 
657     record_double = new OptionRecordDouble(
658         "dual_simplex_cost_perturbation_multiplier",
659         "Dual simplex cost perturbation multiplier: 0 => no perturbation",
660         advanced, &dual_simplex_cost_perturbation_multiplier, 0.0, 1.0,
661         HIGHS_CONST_INF);
662     records.push_back(record_double);
663 
664     record_double = new OptionRecordDouble(
665         "factor_pivot_threshold", "Matrix factorization pivot threshold",
666         advanced, &factor_pivot_threshold, min_pivot_threshold,
667         default_pivot_threshold, max_pivot_threshold);
668     records.push_back(record_double);
669 
670     record_double = new OptionRecordDouble(
671         "factor_pivot_tolerance", "Matrix factorization pivot tolerance",
672         advanced, &factor_pivot_tolerance, min_pivot_tolerance,
673         default_pivot_tolerance, max_pivot_tolerance);
674     records.push_back(record_double);
675 
676     record_double = new OptionRecordDouble(
677         "start_crossover_tolerance",
678         "Tolerance to be satisfied before IPM crossover will start", advanced,
679         &start_crossover_tolerance, 1e-12, 1e-8, HIGHS_CONST_INF);
680     records.push_back(record_double);
681 
682     record_bool = new OptionRecordBool(
683         "use_original_HFactor_logic",
684         "Use original HFactor logic for sparse vs hyper-sparse TRANs", advanced,
685         &use_original_HFactor_logic, true);
686     records.push_back(record_bool);
687 
688     record_bool = new OptionRecordBool(
689         "less_infeasible_DSE_check", "Check whether LP is candidate for LiDSE",
690         advanced, &less_infeasible_DSE_check, true);
691     records.push_back(record_bool);
692 
693     record_bool =
694         new OptionRecordBool("less_infeasible_DSE_choose_row",
695                              "Use LiDSE if LP has right properties", advanced,
696                              &less_infeasible_DSE_choose_row, true);
697     records.push_back(record_bool);
698   }
699 
deleteRecords()700   void deleteRecords() {
701     for (unsigned int i = 0; i < records.size(); i++) delete records[i];
702   }
703 
704  public:
705   std::vector<OptionRecord*> records;
706 };
707 
708 #endif
709