ZonoOpt v2.0.1
Loading...
Searching...
No Matches
MI_Solver.hpp
Go to the documentation of this file.
1#ifndef ZONOOPT_MI_SOLVER_
2#define ZONOOPT_MI_SOLVER_
3
15#include <thread>
16#include <atomic>
17#include <mutex>
18#include <condition_variable>
19#include <sstream>
20#include <iomanip>
21#include <variant>
22#include <memory_resource>
23#include <cmath>
24
25#include "MI_DataStructures.hpp"
27#include "ADMM.hpp"
28
29namespace ZonoOpt::detail {
30
31 class MI_Solver
32 {
33 public:
34 explicit MI_Solver(const MI_data& data);
35
36 // solve
37 OptSolution solve();
38
39 // branch and bound where all possible solutions are returned
40 std::pair<std::vector<OptSolution>, OptSolution> multi_solve(int max_sols = std::numeric_limits<int>::max());
41
42
43 private:
44
45 struct NodeDeleter
46 {
47 std::pmr::synchronized_pool_resource* pool_ptr;
48
49 explicit NodeDeleter(std::pmr::synchronized_pool_resource* pool_ptr) : pool_ptr(pool_ptr) {}
50
51 void operator()(Node* node) const
52 {
53 if (node)
54 {
55 node->~Node();
56 pool_ptr->deallocate(node, sizeof(Node), alignof(Node));
57 }
58 }
59 };
60
61 struct NodeCompare
62 {
63 bool operator()(const std::unique_ptr<Node, NodeDeleter>& n1, const std::unique_ptr<Node, NodeDeleter>& n2) const
64 {
65 return n1->solution.J > n2->solution.J;
66 }
67 };
68
69 const MI_data data;
70 std::pmr::synchronized_pool_resource pool;
71 NodeCompare comp;
72
73 PriorityQueuePrunable<std::unique_ptr<Node, NodeDeleter>, NodeCompare> node_queue; // priority queue for nodes
74 mutable std::mutex pq_mtx;
75 std::condition_variable pq_cv_bnb; // condition variables for branch-and-bound threads
76
77 bool multi_sol = false;
78 std::shared_ptr<ADMM_data> bnb_data; // data for branch-and-bound threads
79
80 std::atomic<bool> converged = false;
81 std::atomic<bool> done = false;
82 std::atomic<bool> feasible = false; // feasible solution found
83 std::atomic<long int> qp_iter = 0; // number of QP iterations
84 std::atomic<int> iter = 0; // number of iterations
85 std::atomic<zono_float> J_max = std::numeric_limits<zono_float>::infinity(); // upper bound
86 ThreadSafeAccess<Eigen::Vector<zono_float, -1>> z, x, u; // solution vector
87 std::atomic<zono_float> primal_residual = std::numeric_limits<zono_float>::infinity();
88 std::atomic<zono_float> dual_residual = std::numeric_limits<zono_float>::infinity();
89 ThreadSafeIncrementable<double> total_startup_time{0.0};
90 ThreadSafeIncrementable<double> total_run_time{0.0};
91 ThreadSafeMultiset J_threads; // threads for J values
92 ThreadSafeVector<OptSolution> solutions; // solutions found
93
94 // allocate nodes
95 std::unique_ptr<Node, NodeDeleter> make_node(const std::shared_ptr<ADMM_data>& data);
96
97 std::unique_ptr<Node, NodeDeleter> clone_node(const std::unique_ptr<Node, NodeDeleter>& other);
98
99 // solver core
100 std::variant<OptSolution, std::pair<std::vector<OptSolution>, OptSolution>> solver_core(
101 int max_sols = std::numeric_limits<int>::max());
102
103 // solve node and branch
104 void solve_and_branch(const std::unique_ptr<Node, NodeDeleter>& node);
105
106 // check if integer feasible, xb is vector of relaxed binary variables
107 bool is_integer_feasible(Eigen::Ref<const Eigen::Vector<zono_float,-1>> xb) const;
108
109 // most fractional branching
110 void branch_most_frac(const std::unique_ptr<Node, NodeDeleter>& node);
111
112 // loop for multithreading
113 void worker_loop();
114
115 // push node to queue
116 void push_node(std::unique_ptr<Node, NodeDeleter>&& node);
117
118 // prune
119 void prune(zono_float J_max);
120
121 // check if 2 solutions correspond to the same binaries
122 bool check_bin_equal(const OptSolution& sol1, const OptSolution& sol2) const;
123
124 };
125
126} // namespace ZonoOpt::detail
127
128
129
130
131#endif
ADMM implementation used within ZonoOpt.
Data structures for mixed-integer optimization in ZonoOpt library.
Optimization settings and solution data structures for ZonoOpt library.
#define zono_float
Defines the floating-point type used in ZonoOpt.
Definition ZonoOpt.hpp:45