-
Notifications
You must be signed in to change notification settings - Fork 48
Expand file tree
/
Copy pathbackend-mip.h
More file actions
717 lines (634 loc) · 26.7 KB
/
backend-mip.h
File metadata and controls
717 lines (634 loc) · 26.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
/*
Abstract MIP solver backend wrapper.
Copyright (C) 2022 AMPL Optimization Inc
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that the copyright notice and this permission notice and warranty
disclaimer appear in supporting documentation.
The author and AMPL Optimization Inc disclaim all warranties with
regard to this software, including all implied warranties of
merchantability and fitness. In no event shall the author be liable
for any special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether in an
action of contract, negligence or other tortious action, arising out
of or in connection with the use or performance of this software.
*/
#ifndef MIPBACKEND_H_
#define MIPBACKEND_H_
#include "mp/common.h"
#include "mp/backend-std.h"
namespace mp {
/// Basis status values of a solution (postsolved)
struct SolutionBasis {
/// Check if has both vars and cons' statuses
operator bool() const { return varstt.size() && constt.size(); }
/// Var and con statuses
std::vector<int> varstt, constt;
};
/// IIS (postsolved).
/// Elements correspond to IISStatus
struct IIS {
/// Var and con IIS statuses
std::vector<int> variis, coniis;
};
/// Sensitivity ranges (postsolved)
struct SensRanges {
std::vector<double>
varlblo, varlb, varlbhi, // varlb/ub, conlb/ub/rhs not needed
varublo, varub, varubhi,
varobjlo, varobj, varobjhi, // varobj is compulsory
conrhslo, conrhs, conrhshi, // for rhs-constraints
conlblo, conlb, conlbhi,
conublo, conub, conubhi; // for range constraints
};
/// MIP backend wrapper
///
/// The MIP wrapper provides common functionality relative to MIP solvers;
/// it implements the common suffixes and the logic shared across all MIP
/// solvers
template <class Impl,
class BaseBackend = StdBackend<Impl> > ///< parameter for base class
class MIPBackend : public BaseBackend
{
public:
/// IsMIP().
/// Basic version: does not consider PL or SOS or Q(C)P.
bool IsMIP() const override
{ return BackendWithModelManager::HasUnfixedIntVars(); }
/// IsQP()
virtual bool IsQP() const { return false; }
/// IsQCP()
virtual bool IsQCP() const { return false; }
/// Always add MIP start if supported:
/// Gurobi 9.1.2 solves non-convex Q(C)P as MIP.
/// But model attributes don't work before solve.
/// Distinguish LP / non-LP instead?
virtual bool CanBeMIP() const { return true; }
////////////////////////////////////////////////////////////
/////////////// OPTIONAL STANDARD FEATURES /////////////////
/////////////// Most are disabled by default ///////////////
//// To enable, declare ALLOW_STD_FEATURE( name, true ) ////
/////////// and implement the relevant methods /////////////
////////////////////////////////////////////////////////////
USING_STD_FEATURES;
/**
* Set lazy/user cut attributes.
* Negative suffix values are "user cuts".
* Check lazy_/user_cuts() to see which kinds are allowed.
* Presolve the values if needed.
**/
DEFINE_STD_FEATURE( LAZY_USER_CUTS )
ALLOW_STD_FEATURE( LAZY_USER_CUTS, false )
virtual void MarkLazyOrUserCuts(ArrayRef<int> ) { }
/**
* Get/Set AMPL var/con statii
**/
DEFINE_STD_FEATURE( BASIS )
ALLOW_STD_FEATURE( BASIS, false )
/// The basis statuses of vars and cons.
/// MIPBackend handles them in postsolved form (for the NL model)
/// Impl has to perform value pre- / postsolve if needed
/// Getter (returns postsolved basis)
virtual SolutionBasis GetBasis() { return {}; }
/// Setter (takes unpresolved basis)
virtual void SetBasis(SolutionBasis )
{ MP_UNSUPPORTED("MIPBackend::SetBasis"); }
/**
* General LP warm start, e.g.,
* set primal/dual initial guesses for continuous case.
* The specific Backend should
* presolve the values if needed.
**/
DEFINE_STD_FEATURE( WARMSTART )
ALLOW_STD_FEATURE( WARMSTART, false )
virtual void AddPrimalDualStart(Solution )
{ MP_UNSUPPORTED("MIPBackend::AddPrimalDualStart"); }
/**
* MIP warm start.
* Provides solution hints (dense vector),
* as well as sparsity pattern (dense 0-1 vector),
* allowing partial MIP warm start.
* Presolve the values if needed.
**/
DEFINE_STD_FEATURE( MIPSTART )
ALLOW_STD_FEATURE( MIPSTART, false )
virtual void AddMIPStart(
ArrayRef<double> , ArrayRef<int> )
{ MP_UNSUPPORTED("MIPBackend::AddMIPStart"); }
/**
* Set branch and bound priority
**/
DEFINE_STD_FEATURE( VAR_PRIORITIES )
ALLOW_STD_FEATURE( VAR_PRIORITIES, false )
virtual void VarPriorities(ArrayRef<int>)
{ MP_UNSUPPORTED("MIPBackend::VarPriorities"); }
/**
* Obtain unbounded/inf rays
**/
DEFINE_STD_FEATURE( RAYS )
ALLOW_STD_FEATURE( RAYS, false )
virtual ArrayRef<double> Ray() { return {}; }
virtual ArrayRef<double> DRay() { return {}; }
/**
* Compute the IIS and obtain relevant values (postsolved)
**/
DEFINE_STD_FEATURE( IIS )
ALLOW_STD_FEATURE( IIS, false )
virtual void ComputeIIS() {}
virtual IIS GetIIS() { return {}; }
/**
* Get MIP Gap
**/
DEFINE_STD_FEATURE( RETURN_MIP_GAP )
ALLOW_STD_FEATURE( RETURN_MIP_GAP, false )
/// Should return AMPLInf() if not available
virtual double MIPGap() { return MP_DISPATCH( AMPLInf() ); }
/// Should return AMPLInf() if not available
virtual double MIPGapAbs() { return MP_DISPATCH( AMPLInf() ); }
/**
* Get MIP dual bound
**/
DEFINE_STD_FEATURE( RETURN_BEST_DUAL_BOUND )
ALLOW_STD_FEATURE( RETURN_BEST_DUAL_BOUND, false )
virtual double BestDualBound()
{ MP_UNSUPPORTED("BestDualBound()"); return 0.0; }
/**
* Report sensitivity analysis suffixes
**/
DEFINE_STD_FEATURE( SENSITIVITY_ANALYSIS )
ALLOW_STD_FEATURE( SENSITIVITY_ANALYSIS, false )
virtual SensRanges GetSensRanges() { return {}; }
/**
* FixModel - duals, basis, and sensitivity for MIP
* No API to overload,
* Impl should check need_fixed_MIP()
**/
DEFINE_STD_FEATURE( FIX_MODEL )
ALLOW_STD_FEATURE( FIX_MODEL, false )
////////////////////////////////////////////////////////////////////////////
/////////////////////// MIP specific derived calculations //////////////////
////////////////////////////////////////////////////////////////////////////
//////////////////////// STANDARD MIP SUFFIXES //////////////////////////
//////////////////////// INPUT //////////////////////////
using BaseBackend::ReadSuffix;
using BaseBackend::ReadIntSuffix;
using BaseBackend::ReadDblSuffix;
using BaseBackend::ReportSuffix;
using BaseBackend::ReportIntSuffix;
using BaseBackend::ReportDblSuffix;
void InputExtras() override {
BaseBackend::InputExtras();
InputMIPExtras();
}
virtual void InputMIPExtras() {
if (lazy_user_cuts())
InputLazyUserCuts();
InputStartValues();
if (priorities()) {
if (auto pri_array = ReadSuffix(suf_varpriority))
VarPriorities( pri_array );
}
}
virtual void InputLazyUserCuts() {
auto sufLazyVal = ReadIntSuffix( {"lazy", suf::CON} );
if (sufLazyVal)
MarkLazyOrUserCuts(sufLazyVal);
}
/// Report a suffix on the problem.
/// Mainly used for testing.
virtual void ReportProblemSuffix(const char* suf_name, int val) {
ReportIntSuffix({suf_name, suf::PROBLEM}, {{val}});
}
virtual void InputStartValues() {
InputPrimalDualStartOrBasis(); /// Always
if ( CanBeMIP() ) {
InputMIPStart();
}
}
virtual void InputPrimalDualStartOrBasis() {
bool useBasis = need_basis_in();
SolutionBasis basis;
if (useBasis) {
basis.varstt = ReadSuffix(suf_varstatus);
basis.constt = ReadSuffix(suf_constatus);
useBasis = bool(basis);
}
Solution sol0; // initial guesses
sol0.primal = this->InitialValues();
sol0.spars_primal = this->InitialValuesSparsity();
sol0.dual = this->InitialDualValues();
bool haveInis = sol0.primal.size() && sol0.dual.size();
if (haveInis && (
2<=warmstart() ||
(1==warmstart() && !useBasis))) {
AddPrimalDualStart(sol0);
if ( 2==warmstart() ) // Why should we submit only the warmstart?
useBasis = false;
if (debug_mode()) { // Report received initials
ReportSuffix(suf_testvarini, sol0.primal); // Should we check that
ReportSuffix(suf_testconini, sol0.dual); // Impl uses them?
}
}
if (useBasis) {
SetBasis(basis);
if (debug_mode()) { // Report received statuses
ReportSuffix(suf_testvarstatus, basis.varstt); // Should we check that
ReportSuffix(suf_testconstatus, basis.constt); // Impl uses them?
}
}
}
virtual void InputMIPStart() {
if (warmstart() && this->InitialValues().size() > 0) {
if (IMPL_HAS_STD_FEATURE( MIPSTART )) {
AddMIPStart(
this->InitialValues(),
this->InitialValuesSparsity() );
if (debug_mode()) { // Report received initials
ReportSuffix(suf_testMIPini, // Should we check that
this->InitialValues());
} // Impl uses them?
}
}
}
//////////////////////// STANDARD MIP SUFFIXES //////////////////////////
//////////////////////// OUtPUT //////////////////////////
void ReportStandardSuffixes() override {
BaseBackend::ReportStandardSuffixes();
ReportStandardMIPSuffixes();
}
virtual void ReportStandardMIPSuffixes() {
if (need_basis_out())
ReportBasis();
ReportRays();
CalculateAndReportIIS();
if (IsMIP())
CalculateAndReportMIPGap();
ReportBestDualBound();
if (sensitivity())
ReportSensitivity();
}
virtual void ReportBasis() {
/// Rely on solver reporting both vectors only if valid basis exists
if (auto basis = GetBasis()) {
ReportSuffix(suf_varstatus, basis.varstt);
ReportSuffix(suf_constatus, basis.constt);
}
}
virtual void ReportRays() {
if ( need_ray_primal() &&
( this->IsProblemUnbounded() ||
this->IsProblemIndiffInfOrUnb() )) {
ReportSuffix(suf_unbdd, Ray() );
}
if ( need_ray_dual() &&
( this->IsProblemInfeasible() ||
this->IsProblemIndiffInfOrUnb() )) {
ReportSuffix(suf_dunbdd, DRay() );
}
}
virtual void CalculateAndReportIIS() {
if (( this->IsProblemInfeasible() ||
this->IsProblemIndiffInfOrUnb() ) &&
GetMIPOptions().exportIIS_) {
try {
ComputeIIS();
} catch (const std::exception& exc) {
this->AddWarning("IIS_COMPUTE", // Can add warning before SOL output
std::string("Error computing IIS: ")
+ exc.what());
}
this->SetStatus( this->GetSolveResult() );
if (this->IsProblemInfeasible()) { // can be unbounded
auto iis = GetIIS();
ReportSuffix(sufIISCon, iis.coniis);
ReportSuffix(sufIISVar, iis.variis);
}
}
}
virtual void CalculateAndReportMIPGap() {
std::vector<double> dbl(1);
if (1 & GetMIPOptions().returnMipGap_) {
dbl[0] = MP_DISPATCH( MIPGap() );
ReportSuffix(sufRelMipGapObj, dbl);
ReportSuffix(sufRelMipGapProb, dbl);
}
if (2 & GetMIPOptions().returnMipGap_) {
dbl[0] = MP_DISPATCH( MIPGapAbs() );
ReportSuffix(sufAbsMipGapObj, dbl);
ReportSuffix(sufAbsMipGapProb, dbl);
}
if (!(GetMIPOptions().returnMipGap_ & 4)) {
double absMIPGap = MP_DISPATCH(MIPGapAbs());
if(absMIPGap > 0. && absMIPGap < MP_DISPATCH(Infinity()))
BaseBackend::AddToSolverMessage(
fmt::format("absmipgap={}, relmipgap={}",
absMIPGap, MP_DISPATCH(MIPGap())));
}
}
virtual void ReportBestDualBound() {
if (GetMIPOptions().returnBestDualBound_) {
std::vector<double> dbl(1, MP_DISPATCH( BestDualBound() ));
ReportSuffix(sufBestBoundObj, dbl);
ReportSuffix(sufBestBoundProb, dbl);
}
}
virtual void ReportSensitivity() {
SensRanges sensr = GetSensRanges();
ReportSuffix( {"senslbhi", suf::Kind::VAR}, sensr.varlbhi );
// ReportSuffix( {"senslb", suf::Kind::VAR}, sensr.varlb );
ReportSuffix( {"senslblo", suf::Kind::VAR}, sensr.varlblo );
ReportSuffix( {"sensubhi", suf::Kind::VAR}, sensr.varubhi );
// ReportSuffix( {"sensub", suf::Kind::VAR}, sensr.varub );
ReportSuffix( {"sensublo", suf::Kind::VAR}, sensr.varublo );
ReportSuffix( {"sensobjhi", suf::Kind::VAR}, sensr.varobjhi );
ReportSuffix( {"up", suf::Kind::VAR}, sensr.varobjhi ); // CPLEXASL
ReportSuffix( {"sensobj", suf::Kind::VAR}, sensr.varobj );
ReportSuffix( {"current", suf::Kind::VAR}, sensr.varobj );
ReportSuffix( {"sensobjlo", suf::Kind::VAR}, sensr.varobjlo );
ReportSuffix( {"down", suf::Kind::VAR}, sensr.varobjlo );
ReportSuffix( {"sensrhshi", suf::Kind::CON}, sensr.conrhshi );
ReportSuffix( {"up", suf::Kind::CON}, sensr.conrhshi );
// ReportSuffix( {"sensrhs", suf::Kind::CON}, sensr.conrhs );
ReportSuffix( {"sensrhslo", suf::Kind::CON}, sensr.conrhslo );
ReportSuffix( {"down", suf::Kind::CON}, sensr.conrhslo );
ReportSuffix( {"senslbhi", suf::Kind::CON}, sensr.conlbhi );
// ReportSuffix( {"senslb", suf::Kind::CON}, sensr.conlb );
ReportSuffix( {"senslblo", suf::Kind::CON}, sensr.conlblo );
ReportSuffix( {"sensubhi", suf::Kind::CON}, sensr.conubhi );
// ReportSuffix( {"sensub", suf::Kind::CON}, sensr.conub );
ReportSuffix( {"sensublo", suf::Kind::CON}, sensr.conublo );
}
////////////////////////////////////////////////////////////
/////////////////// MIP Backend options ////////////////////
////////////////////////////////////////////////////////////
private:
struct Options {
int lazy_user_cuts_ = 3;
int basis_=3;
int warmstart_=3;
int importPriorities_=1;
int rays_=3;
int exportIIS_=0;
int returnMipGap_=0;
int returnBestDualBound_=0;
int solnSens_=0;
int fixModel_=0;
};
Options mipStoredOptions_;
protected:
const Options& GetMIPOptions() const { return mipStoredOptions_; }
Options& GetMIPOptions() { return mipStoredOptions_; }
int lazy_user_cuts() const {
return IMPL_HAS_STD_FEATURE(LAZY_USER_CUTS) ?
GetMIPOptions().lazy_user_cuts_ : 0;
}
/// Whether we need to mark .lazy>0 cuts as 'lazy'
bool lazy_cuts() const { return 1 & lazy_user_cuts(); }
/// Whether we need to mark .lazy<0 cuts as 'user'
bool user_cuts() const { return 2 & lazy_user_cuts(); }
int basis() const
{ return IMPL_HAS_STD_FEATURE(BASIS) ? GetMIPOptions().basis_ : 0; }
bool need_basis_in() const { return 1 & basis(); }
bool need_basis_out() const {
return IsMIP() ?
(need_fixed_MIP()) : // assume the solver did it
(2 & basis());
}
int warmstart() const
{ return IMPL_HAS_STD_FEATURE(WARMSTART) ? GetMIPOptions().warmstart_ : 0; }
int priorities() const {
return IMPL_HAS_STD_FEATURE(VAR_PRIORITIES) ?
GetMIPOptions().importPriorities_ : 0;
}
int rays() const
{ return IMPL_HAS_STD_FEATURE(RAYS) ? GetMIPOptions().rays_ : 0; }
bool need_ray_primal() const { return 1 & rays(); }
bool need_ray_dual() const { return 2 & rays(); }
int sensitivity() const {
return IMPL_HAS_STD_FEATURE(SENSITIVITY_ANALYSIS) ?
GetMIPOptions().solnSens_ : 0;
}
/// Whether need duals/basis/sens from MIP
/// Need at least duals when this option is on
int need_fixed_MIP() const {
return IMPL_HAS_STD_FEATURE( FIX_MODEL ) ?
GetMIPOptions().fixModel_ : 0;
}
public:
void InitStandardOptions() override {
BaseBackend::InitStandardOptions();
InitMIPOptions();
}
using BaseBackend::AddStoredOption;
using BaseBackend::debug_mode;
////////////////////////////////////////////////////////////////
protected:
const mp::OptionValueInfo values_01_noyes_0default_[2] = {
{ "0", "No (default)", 0 },
{ "1", "Yes.", 1}
};
const mp::OptionValueInfo values_01_noyes_1default_[2] = {
{ "0", "No", 0 },
{ "1", "Yes (default)", 1}
};
const mp::OptionValueInfo values_lpwarmstart_[4] = {
{ "-1", "Default (equivalent to 2 for PDHG, to 1 otherwise)", -1 },
{ "0", "Ignore any warm start information (generally).", 0 },
{ "1", "Use warm start information to solve the original, unpresolved problem.", 1},
{ "2", "If presolve is enabled, use warm start to solve the presolved problem. "
"Otherwise, setting 2 prioritizes start vectors (primal/dual), while "
"setting 1 prioritizes basis statuses.", 2 }
};
const mp::OptionValueInfo values_autonoyes_[3] = {
{ "-1", "Automatic choice (default)", 0 },
{ "0", "No", 0 },
{ "1", "Yes.", 1}
};
const mp::OptionValueInfo values_autonomodaggr_[4] = {
{ "-1", "Automatic choice (default)", 0 },
{ "0", "No", 0 },
{ "1", "Yes, moderate", 1},
{ "2", "Yes, aggressive.", 2}
};
const mp::OptionValueInfo values_autonoconsaggr_[4] = {
{ "-1", "Automatic choice (default)", -1},
{ "0", "No", 0},
{ "1", "Conservative", 1},
{ "2", "Aggressive.", 2}
};
const mp::OptionValueInfo values_basis_[4] = {
{ "0", "No", 0 },
{ "1", "Use incoming basis (if provided)", 1},
{ "2", "Return final basis", 2},
{ "3", "Both (1 + 2 = default)", 3}
};
const mp::OptionValueInfo values_warmstart_[4] = {
{ "0", "No", 0 },
{ "1", "Yes (for LP: if there is no incoming alg:basis)", 1},
{ "2", "Yes (for LP: omitting the incoming alg:basis, if any)", 2},
{ "3", "Yes (for LP: together with the incoming alg:basis, if any; default).", 3}
};
const mp::OptionValueInfo values_rays_[4] = {
{ "0", "Neither", 0 },
{ "1", "Just .unbdd", 1},
{ "2", "Just .dunbdd", 2},
{ "3", "Both (default)", 3}
};
////////////////////////////////////////////////////////////////
virtual void InitMIPOptions() {
if (IMPL_HAS_STD_FEATURE( LAZY_USER_CUTS ))
AddStoredOption("mip:lazy lazy",
"Whether to recognize suffix .lazy on constraints: "
"sum of\n"
"\n"
"| 1 - Accept .lazy>0 values (true lazy constraints, if supported)\n"
"| 2 - Accept .lazy<0 values (user cuts, if supported)\n"
"\n"
"Default lazy = 3 ==> accept both.",
GetMIPOptions().lazy_user_cuts_);
if (IMPL_HAS_STD_FEATURE( BASIS ))
AddStoredOption("alg:basis basis",
"Whether to use and/or return a basis for LP models "
"(variable/constraint suffixes .(s)status):\n"
"\n.. value-table::\n"
"\n"
"See alg:start for interaction with the LP warmstart.\n"
"\n"
"See also mip:basis and qcp:dual (for some solvers).",
GetMIPOptions().basis_, values_basis_);
if (IMPL_HAS_STD_FEATURE( WARMSTART ))
AddStoredOption("alg:start warmstart",
"Whether to use incoming primal (and dual, for LP) variable values "
"in a warmstart:\n "
"\n.. value-table::",
GetMIPOptions().warmstart_, values_warmstart_);
if (IMPL_HAS_STD_FEATURE( VAR_PRIORITIES ))
AddStoredOption("mip:priorities priorities",
"0/1*: Whether to read the branch and bound priorities from the"
" .priority suffix.",
GetMIPOptions().importPriorities_);
if (IMPL_HAS_STD_FEATURE( RAYS ))
AddStoredOption("alg:rays rays",
"Whether to return suffix .unbdd (unbounded ray) "
"if the objective is unbounded "
"or suffix .dunbdd (Farkas dual) if the constraints "
"are infeasible:\n"
"\n.. value-table::\n",
GetMIPOptions().rays_, values_rays_);
if (IMPL_HAS_STD_FEATURE( IIS ))
AddStoredOption("iis:find iisfind iis alg:iisfind",
"Whether to find and export an IIS. "
"Default = 0 (don't export).",
GetMIPOptions().exportIIS_);
if (IMPL_HAS_STD_FEATURE( RETURN_MIP_GAP ))
AddStoredOption("mip:return_gap return_mipgap",
"Whether to return mipgap suffixes or include mipgap values "
"(|objectve - .bestbound|) in the solve_message: sum of\n"
"\n"
"| 1 - Return .relmipgap suffix (relative to |obj|)\n"
"| 2 - Return .absmipgap suffix (absolute mipgap)\n"
"| 4 - Suppress mipgap values in solve_message.\n"
"\n"
"Default = 0. The suffixes are on the objective and problem. "
"Returned suffix values are +Infinity if no integer-feasible "
"solution has been found, in which case no mipgap values are "
"reported in the solve_message.",
GetMIPOptions().returnMipGap_);
if (IMPL_HAS_STD_FEATURE( RETURN_BEST_DUAL_BOUND ))
AddStoredOption("mip:bestbound bestbound return_bound",
"Whether to return suffix .bestbound for the "
"best known MIP dual bound on the objective value:\n"
"\n.. value-table::\n"
"The suffix is on the objective and problem and is -Infinity "
"for minimization problems and +Infinity for maximization "
"problems if there are no integer variables or if a dual bound "
"is not available.",
GetMIPOptions().returnBestDualBound_, values_01_noyes_0default_);
if (IMPL_HAS_STD_FEATURE( SENSITIVITY_ANALYSIS ))
AddStoredOption("alg:sens sens solnsens sensitivity",
"Whether to return suffixes for solution sensitivities, i.e., "
"ranges of values for which the optimal basis remains optimal "
"(note that the variable and objective values can change):\n"
"\n"
"| 0 - No (default)\n"
"| 1 - Yes: suffixes returned on variables are\n"
"| .sensobjlo = smallest objective coefficients\n"
"| .down = same as .sensobjlo\n"
"| .sensobj = current objective coefficients\n"
"| .current = same as .sensobj\n"
"| .sensobjhi = greatest objective coefficients\n"
"| .up = same as .sensobjhi\n"
"| .senslblo = smallest variable lower bounds\n"
// "| .senslb = current variable lower bounds\n"
"| .senslbhi = greatest variable lower bounds\n"
"| .sensublo = smallest variable upper bounds\n"
// "| .sensub = current variable upper bounds\n"
"| .sensubhi = greatest variable upper bounds;\n\n"
" suffixes for all constraints are\n"
"| .senslblo = smallest constraint lower bounds\n"
// "| .senslb = current constraint lower bounds\n"
"| .senslbhi = greatest constraint lower bounds\n"
"| .sensublo = smallest constraint upper bounds\n"
// "| .sensub = current constraint upper bounds\n"
"| .sensubhi = greatest constraint upper bounds;\n\n"
" suffixes for one-sided constraints only:\n"
"| .sensrhslo = smallest right-hand side values\n"
"| .down = same as .sensrhslo\n"
// "| .sensrhs = current right-hand side values\n"
"| .sensrhshi = greatest right-hand side values.\n"
"| .up = same as .sensrhshi.\n"
"\n"
"The suffixes correspond to the AMPL solver model, "
"command 'solexpand'. For easiest interpretation, "
"disable AMPL presolve, 'option presolve 0;'"
,
GetMIPOptions().solnSens_);
if (IMPL_HAS_STD_FEATURE( FIX_MODEL ))
AddStoredOption("mip:basis fixmodel mip:fix",
"Whether to compute duals / basis / sensitivity for MIP models:\n"
"\n.. value-table::\n",
GetMIPOptions().fixModel_, values_01_noyes_0default_);
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// STANDARD MIP SUFFIXES ///////////////////////////
//////////////////////////////////////////////////////////////////////////////
private:
const SuffixDef<int> suf_varstatus = { "sstatus", suf::VAR | suf::OUTPUT };
const SuffixDef<int> suf_constatus = { "sstatus", suf::CON | suf::OUTPUT };
/// Testing API
/// Output suffix values to check they were read correctly
const SuffixDef<int> suf_testvarstatus = { "test_sstatus", suf::VAR | suf::OUTPUT };
const SuffixDef<int> suf_testconstatus = { "test_sstatus", suf::CON | suf::OUTPUT };
/// Testing API
/// Output primal/dual initials to check they were read correctly
const SuffixDef<double> suf_testvarini = { "test_ini_pri", suf::VAR | suf::OUTPUT };
const SuffixDef<double> suf_testconini = { "test_ini_dua", suf::CON | suf::OUTPUT };
/// Testing API
/// Output MIP initials to check they were read correctly
const SuffixDef<double> suf_testMIPini = { "test_ini_mip", suf::VAR | suf::OUTPUT };
const SuffixDef<int> suf_varpriority = { "priority", suf::VAR | suf::INPUT };
const SuffixDef<double> suf_unbdd = { "unbdd", suf::VAR | suf::OUTPUT };
const SuffixDef<double> suf_dunbdd = { "dunbdd", suf::CON | suf::OUTPUT };
const SuffixTable iis_table =
"\n"
"0\tnon\tnot in the iis\n"
"1\tlow\tlower bound in the iis\n"
"2\tfix\tboth bounds in the iis\n"
"3\tupp\tupper bound in the iis\n"
"4\tmem\tmember\n"
"5\tpmem\tpossible member\n"
"6\tplow\tpossibly lower bound\n"
"7\tpupp\tpossibly upper bound\n"
"8\tbug\n";
const SuffixDef<int> sufIISCon = { "iis", suf::CON | suf::OUTPUT, iis_table };
const SuffixDef<int> sufIISVar = { "iis", suf::VAR | suf::OUTPUT, iis_table };
const SuffixDef<double> sufRelMipGapObj = { "relmipgap", suf::OBJ | suf::OUTPUT };
const SuffixDef<double> sufRelMipGapProb = { "relmipgap", suf::PROBLEM | suf::OUTPUT };
const SuffixDef<double> sufAbsMipGapObj = { "absmipgap", suf::OBJ | suf::OUTPUT };
const SuffixDef<double> sufAbsMipGapProb = { "absmipgap", suf::PROBLEM | suf::OUTPUT };
const SuffixDef<double> sufBestBoundObj = { "bestbound", suf::OBJ | suf::OUTPUT };
const SuffixDef<double> sufBestBoundProb = { "bestbound", suf::PROBLEM | suf::OUTPUT };
};
} // namespace mp
#endif // MIPBACKEND_H_