delpi  0.0.1
DElta-complete LP solver
Loading...
Searching...
No Matches
main.cpp
1
8#include <iostream>
9#include <vector>
10
11#include "delpi/delpi.h"
12#include "delpi/util/error.h"
13
14#define CSV_HEADER \
15 "file,solver,result,delta,actual_delta,precision,iterations,refinements,obj_lb,obj_ub,time_unit,parser_time,solver_" \
16 "time,total_time"
17#define CSV_FORMAT "{},{},{},{},{},{},{},{},{},{},s,{},{},{}"
18#define CSV_PARTIAL_FORMAT "{},{},partial-{},{},{},{},{},{},{},{},s,{},{},{}"
19
20delpi::Timer global_timer{};
21
22void OnSolve(const delpi::LpSolver& lp_solver, const delpi::LpResult result, const std::vector<mpq_class>& x,
23 const std::vector<mpq_class>&, const mpq_class& obj_lb, const mpq_class& obj_ub) {
24 if (lp_solver.config().silent()) return;
25
26 const mpq_class actual_delta = obj_ub - obj_lb;
27 const delpi::Config& config = lp_solver.config();
28 const delpi::LpStats& stats = lp_solver.stats();
29 DELPI_ASSERT(actual_delta <= config.delta(), "Expected actual delta to be <= delta");
30
31 if (config.csv()) {
32 fmt::println(CSV_FORMAT, config.filename(), config.lp_solver(), result, config.delta(), actual_delta.get_d(),
33 stats.precision, stats.solver_stats.iterations(), stats.refinements, obj_lb.get_d(), obj_ub.get_d(),
34 stats.parser_stats.timer().seconds(), stats.solver_stats.timer().seconds(), global_timer.seconds());
35 return;
36 }
37 switch (result) {
39 DELPI_ASSERT(actual_delta == 0, "Expected actual delta to be 0");
40 fmt::println("{}, objective value = {} ( = {})", result, obj_lb, obj_lb.get_d());
41 break;
43 DELPI_ASSERT(actual_delta > 0, "Expected actual delta to be > 0");
44 fmt::println("{} with delta = {} ( = {}), range = [{}, {}] ( = [{}, {}])", result, actual_delta.get_d(),
45 actual_delta, obj_lb, obj_ub, obj_lb.get_d(), obj_ub.get_d());
46 break;
47 default:
48 fmt::println("{}", result);
49 }
50 if (config.with_timings()) {
51 fmt::println("\tafter {} seconds\n{}\n{}", global_timer.seconds(), stats.parser_stats, stats.solver_stats);
52 }
53 if (config.produce_models()) fmt::println("Model: {}", lp_solver.model(x));
54 std::cout << std::flush;
55}
56
57bool OnPartialSolve(const delpi::LpSolver& lp_solver, const delpi::LpResult result, const std::vector<mpq_class>& x,
58 const std::vector<mpq_class>&, const mpq_class& obj_lb, const mpq_class& obj_ub) {
59 if (lp_solver.config().silent()) return true;
60
61 const mpq_class actual_delta = obj_ub - obj_lb;
62 const delpi::Config& config = lp_solver.config();
63 const delpi::LpStats& stats = lp_solver.stats();
64 DELPI_ASSERT(actual_delta > lp_solver.config().delta(), "Expected diff to be > delta");
65
66 if (config.csv()) {
67 fmt::println(CSV_PARTIAL_FORMAT, config.filename(), config.lp_solver(), result, actual_delta.get_d(),
68 actual_delta.get_d(), stats.precision, stats.solver_stats.iterations(), stats.refinements,
69 obj_lb.get_d(), obj_ub.get_d(), stats.parser_stats.timer().seconds(),
70 stats.solver_stats.timer().seconds(), global_timer.seconds());
71 return true;
72 }
73 fmt::println("PARTIAL: {} with delta = {} ( = {}), range = [{}, {}]", result, actual_delta.get_d(), actual_delta,
74 obj_lb, obj_ub);
75 if (config.with_timings()) {
76 fmt::println("\tafter {} seconds\n{}\n{}", global_timer.seconds(), stats.parser_stats, stats.solver_stats);
77 }
78 if (config.produce_models()) fmt::println("Model: {}", lp_solver.model(x));
79 std::cout << std::flush;
80 return true;
81}
82
83void OnInterrupt(const delpi::LpSolver& lp_solver, const delpi::LpResult result) {
84 if (lp_solver.config().silent()) return;
85
86 const delpi::Config& config = lp_solver.config();
87 const delpi::LpStats& stats = lp_solver.stats();
88
89 if (config.csv()) {
90 fmt::println(CSV_PARTIAL_FORMAT, config.filename(), config.lp_solver(), result, "", "", stats.precision,
91 stats.solver_stats.iterations(), stats.refinements, "", "", stats.parser_stats.timer().seconds(),
92 stats.solver_stats.timer().seconds(), global_timer.seconds());
93 return;
94 }
95 fmt::println("Interrupted: {}", result);
96 if (config.with_timings()) {
97 fmt::println("\tafter {} seconds\n{}\n{}", global_timer.seconds(), stats.parser_stats, stats.solver_stats);
98 }
99 std::cout << std::flush;
100}
101
102int main(const int argc, const char* argv[]) {
103 // Initialize the command line parser.
104 delpi::ArgParser parser{};
105 // Parse the command line arguments.
106 parser.Parse(argc, argv);
107 // Get the configuration from the command line arguments.
108 const delpi::Config config = parser.ToConfig();
109
110 delpi::TimerGuard timer_guard{&global_timer, config.with_timings()};
111
112 // Setup the infinity values.
113 const std::unique_ptr lp_solver{delpi::LpSolver::GetInstance(config)};
114 lp_solver->m_solve_cb() = &OnSolve;
115 lp_solver->m_partial_solve_cb() = &OnPartialSolve;
116
117 if (!lp_solver->Parse()) {
118 std::cerr << "Error parsing the input" << std::endl;
119 return EXIT_FAILURE;
120 }
121
122 // If csv output is enabled, print the header
123 if (config.csv()) std::cout << CSV_HEADER << std::endl;
124
125 if (config.dry_run()) {
126 DELPI_INFO("Dry run enabled, skipping solving the LP problem");
127 OnInterrupt(*lp_solver, delpi::LpResult::UNSOLVED);
128 return EXIT_SUCCESS;
129 }
130
131 // Run the solver
132 mpq_class delta{config.delta()};
133 const delpi::LpResult result = config.dry_run() ? delpi::LpResult::UNSOLVED : lp_solver->Solve();
134
135 if (config.silent()) return ExitCode(result);
136
137 // Print additional information about the result
138 if (!lp_solver->CheckAgainstExpected(result)) {
139 std::cerr << "WARNING: Expected " << lp_solver->expected() << " but got " << result << std::endl;
140 }
141 if (config.verify() && IsFeasible(result)) {
142 if (lp_solver->Verify())
143 std::cout << "Model correctly satisfies the input" << std::endl;
144 else
145 std::cerr << "WARNING: Model does not satisfy the input" << std::endl;
146 }
147
148 return ExitCode(result);
149}
Used to parse command line arguments and produce a corresponding Config object to be used throughout ...
Definition ArgParser.h:26
void Parse(int argc, const char **argv)
Parse the command line arguments.
Definition ArgParser.cpp:77
Config ToConfig() const
Convert the parser to a Config.
Simple dataclass used to store the configuration of the program.
Definition Config.h:36
Facade class that hides the underlying LP solver used by delpi.
Definition LpSolver.h:60
The TimeGuard wraps a timer object and pauses it when the guard object is destructed.
Definition Timer.h:132
Timer class using the a steady clock.
Definition Timer.h:95
LpResult
Possible outcomes of the LP solver.
Definition LpResult.h:14
@ DELTA_OPTIMAL
The delta-relaxation of the problem is optimal.
Definition LpResult.h:17
@ OPTIMAL
The problem is optimal.
Definition LpResult.h:16
@ UNSOLVED
The solver has not yet been run.
Definition LpResult.h:15
bool IsFeasible(const LpResult result)
Check if the result obtained by the LpSolver implies that the problem is feasible.
Definition LpResult.cpp:43
int ExitCode(const LpResult result)
Convert the result in.
Definition LpResult.cpp:53
Collection of statistics for the LP solver.
Definition LpStats.h:17
IterationStats solver_stats
Time spent in the solver and number of iterations.
Definition LpStats.h:23
std::size_t precision
Number of bits of precision used in the last iteration.
Definition LpStats.h:26
std::size_t refinements
Number of iterative refinements. Only meaningful for iterative refinement solvers.
Definition LpStats.h:25
Stats parser_stats
Time spent in the parser.
Definition LpStats.h:24