ZonoOpt v1.0.0
Loading...
Searching...
No Matches
Zono.hpp
Go to the documentation of this file.
1#ifndef ZONOOPT_ZONO_HPP_
2#define ZONOOPT_ZONO_HPP_
3
15#include "ConZono.hpp"
16
17namespace ZonoOpt
18{
19
20using namespace detail;
21
32class Zono : public ConZono
33{
34 public:
35
36 // constructors
41 Zono() { sharp = true; }
42
50 Zono(const Eigen::SparseMatrix<zono_float>& G, const Eigen::Vector<zono_float, -1>& c,
51 const bool zero_one_form=false)
52 {
54 sharp = true;
55 }
56
57 // virtual destructor
58 ~Zono() override = default;
59
60 // set method
68 void set(const Eigen::SparseMatrix<zono_float>& G, const Eigen::Vector<zono_float, -1>& c,
69 bool zero_one_form=false);
70
74 HybZono* clone() const override
75 {
76 return new Zono(*this);
77 }
78
85 std::unique_ptr<Zono> reduce_order(int n_o);
86
95
96 // generator conversion between [-1,1] and [0,1]
97 void convert_form() override;
98
99 // display methods
100 std::string print() const override;
101
102 protected:
103
104 bool do_is_empty(const OptSettings&, OptSolution*) const override;
105
106 Box do_bounding_box(const OptSettings&, OptSolution*) override;
107
108 zono_float do_support(const Eigen::Vector<zono_float, -1>& d, const OptSettings&,
109 OptSolution*) override;
110};
111
112// forward declarations
120std::unique_ptr<Zono> interval_2_zono(const Box& box);
121
132std::unique_ptr<Zono> make_regular_zono_2D(zono_float radius, int n_sides, bool outer_approx=false, const Eigen::Vector<zono_float, 2>& c=Eigen::Vector<zono_float, 2>::Zero());
133
134// utilities
135namespace detail
136{
137
138 // generated by Gemini
139 template<typename T>
140 void combinations_util(const std::vector<T>& elements, const size_t k, const size_t start_index,
141 std::vector<T>& current_combination,
142 std::vector<std::vector<T>>& result)
143 {
144 // Base case: Combination is complete (size k reached)
145 if (current_combination.size() == k)
146 {
147 result.push_back(current_combination);
148 return;
149 }
150
151 // Recursive step: Iterate over available elements
152 for (size_t i = start_index; i < elements.size(); ++i)
153 {
154 // 🌟 Pruning optimization: stop if there aren't enough elements left to form a k-combination
155 if (elements.size() - i < k - current_combination.size())
156 {
157 return;
158 }
159
160 // 1. Include elements[i]
161 current_combination.push_back(elements[i]);
162
163 // 2. Recurse (start from i + 1 to prevent repeats)
164 combinations_util(elements, k, i + 1, current_combination, result);
165
166 // 3. Backtrack (remove element to try the next possibility)
167 current_combination.pop_back();
168 }
169 }
170
171 // generated by Gemini
172 template<typename T>
173 std::vector<std::vector<T>> get_combinations(const std::vector<T>& input_set, const size_t k)
174 {
175 if (k > input_set.size())
176 {
177 return {}; // Cannot choose k elements from a smaller set
178 }
179
180 // Copy set elements to a vector. std::set ensures they are already sorted.
181 std::vector<T> elements(input_set.begin(), input_set.end());
182
183 std::vector<std::vector<T>> result;
184 std::vector<T> current_combination;
185
186 // Start the recursive process from the first element (index 0)
187 combinations_util(elements, k, 0, current_combination, result);
188 return result;
189 }
190
191} // namespace detail
192
193
194// implementation
195inline void Zono::set(const Eigen::SparseMatrix<zono_float>& G, const Eigen::Vector<zono_float, -1>& c,
196 const bool zero_one_form)
197{
198 // check dimensions
199 if (G.rows() != c.size())
200 {
201 throw std::invalid_argument("Zono: inconsistent dimensions.");
202 }
203
204 // zonotope parameters
205 this->G = G;
206 this->c = c;
207 this->nG = static_cast<int>(this->G.cols());
208 this->n = static_cast<int>(this->G.rows());
209 this->zero_one_form = zero_one_form;
210
211 // abstract zono parameters
212 this->nGc = this->nG;
213 this->nGb = 0;
214 this->nC = 0;
215 this->Gc = this->G;
216 this->Gb.resize(this->n, 0);
217 this->A.resize(0, this->nG);
218 this->Ac = this->A;
219 this->Ab.resize(0, 0);
220 this->b.resize(0);
221}
222
224{
225 Eigen::Vector<zono_float, -1> c;
226 Eigen::SparseMatrix<zono_float> G;
227
228 if (!this->zero_one_form) // convert to [0,1] generators
229 {
230 c = this->c - this->G*Eigen::Vector<zono_float, -1>::Ones(this->nG);
231 G = 2.0*this->G;
232
233 set(G, c, true);
234 }
235 else // convert to [-1,1] generators
236 {
237 c = this->c + 0.5*this->G*Eigen::Vector<zono_float, -1>::Ones(this->nG);
238 G = 0.5*this->G;
239
240 set(G, c, false);
241 }
242}
243
244inline std::string Zono::print() const
245{
246 std::stringstream ss;
247 ss << "Zono: " << std::endl;
248 ss << "n: " << this->n << std::endl;
249 ss << "nG: " << this->nG << std::endl;
250 ss << "G: " << Eigen::Matrix<zono_float, -1, -1>(this->G) << std::endl;
251 ss << "c: " << this->c << std::endl;
252 ss << "zero_one_form: " << this->zero_one_form;
253 return ss.str();
254}
255
256inline bool Zono::do_is_empty(const OptSettings&, OptSolution*) const
257{
258 if (this->n == 0)
259 return true;
260 else
261 return false;
262}
263
265{
266 // convert to [-1,1] form
267 if (this->zero_one_form) this->convert_form();
268
269 // init bounds
270 Eigen::Vector<zono_float, -1> l = this->c;
271 Eigen::Vector<zono_float, -1> u = this->c;
272
273 // compute bounds
274 for (int i=0; i<this->nG; ++i)
275 {
276 l -= this->G.col(i).cwiseAbs();
277 u += this->G.col(i).cwiseAbs();
278 }
279
280 // return zonotope bounding box
281 return {l, u};
282}
283
284inline std::unique_ptr<Zono> Zono::reduce_order(const int n_o)
285{
286 // check validity
287 if (n_o < this->n)
288 throw std::invalid_argument("Zono reduce_order: desired order is less than dimension of set");
289
290 // trivial case
291 if (this->nG <= n_o)
292 return std::make_unique<Zono>(*this);
293
294 // convert to [-1,1] form
295 if (this->zero_one_form) this->convert_form();
296
297 // sort columns by decreasing 2-norm
298
299 // vector of 2-norms and indices
300 std::vector<std::pair<int, zono_float>> sort_vec;
301 for (int i=0; i<this->nG; ++i)
302 {
303 sort_vec.emplace_back(i, this->G.col(i).norm());
304 }
305
306 // sort
307 auto comp = [](const std::pair<int, zono_float>& a, const std::pair<int, zono_float>& b) -> bool
308 {
309 return a.second > b.second;
310 };
311 std::sort(sort_vec.begin(), sort_vec.end(), comp);
312
313 // zonotope to keep
314 const int n_K = n_o - this->n;
315 Eigen::SparseMatrix<zono_float> G_K (this->n, n_K);
316 std::vector<Eigen::Triplet<zono_float>> triplets;
317 for (int i=0; i < n_K; ++i)
318 {
319 const int k = sort_vec[static_cast<size_t>(i)].first; // column
320 for (Eigen::SparseMatrix<zono_float>::InnerIterator it(this->G, k); it; ++it)
321 {
322 triplets.emplace_back(static_cast<int>(it.row()), i, it.value());
323 }
324 }
325 G_K.setFromSortedTriplets(triplets.begin(), triplets.end());
326 const Zono K (G_K, this->c);
327
328 // zonotope to over-approximate
329 Eigen::SparseMatrix<zono_float> G_L (this->n, this->nG - n_K);
330 triplets.clear();
331 for (int i=n_K; i < this->nG; ++i)
332 {
333 const int k = sort_vec[static_cast<size_t>(i)].first; // column
334 for (Eigen::SparseMatrix<zono_float>::InnerIterator it(this->G, k); it; ++it)
335 {
336 triplets.emplace_back(static_cast<int>(it.row()), i-n_K, it.value());
337 }
338 }
339 G_L.setFromSortedTriplets(triplets.begin(), triplets.end());
340 Zono L (G_L, Eigen::Vector<zono_float, -1>::Zero(this->n));
341
342 // get bounding box
343 const auto L_R = interval_2_zono(L.bounding_box());
344
345 // minkowski sum
346 auto Z = minkowski_sum(K, *L_R);
347
348 // check that dynamic cast is valid
349 if (!Z->is_zono())
350 throw std::runtime_error("In Zono::ReduceOrder, return type is not a zonotope?");
351
352 // cast to zono and return
353 return std::unique_ptr<Zono>(dynamic_cast<Zono*>(Z.release()));
354}
355
356inline zono_float Zono::do_support(const Eigen::Vector<zono_float, -1>& d, const OptSettings&, OptSolution*)
357{
358 if (this->zero_one_form) this->convert_form();
359
360 zono_float h = d.dot(this->c);
361 const Eigen::Matrix<zono_float, -1, -1> Gd = this->G.toDense();
362 for (int i=0; i<this->nG; ++i)
363 {
364 h += std::abs(d.dot(Gd.col(i)));
365 }
366 return h;
367}
368
369
371{
372 // require [0,1] form
373 if (!this->zero_one_form) this->convert_form();
374
375 // get dense form of generator matrix
376 const Eigen::Matrix<zono_float, -1, -1> Gd = this->G.toDense();
377
378 // get cols of generator matrix
379 std::vector<int> cols;
380 cols.reserve(static_cast<size_t>(this->nG));
381 for (int i=0; i<this->nG; ++i)
382 {
383 cols.push_back(i);
384 }
385
386 // get combinations
387 const auto combs = get_combinations<int>(cols, static_cast<size_t>(this->n));
388
389 // get determinants
390 zono_float det_sum = zero;
391 Eigen::LDLT<Eigen::Matrix<zono_float, -1, -1>> ldlt;
392
393 for (const auto& comb : combs)
394 {
395 const Eigen::Matrix<zono_float, -1, -1> G_comb = Gd(Eigen::placeholders::all, comb);
396 const Eigen::Matrix<zono_float, -1, -1> GT_G = G_comb.transpose()*G_comb;
397 ldlt.compute(GT_G);
398 const Eigen::Vector<zono_float, -1> D = ldlt.vectorD();
399 det_sum += std::sqrt(D.prod());
400 }
401
402 // volume is det_sum
403 return det_sum;
404}
405
406
407
408} // namespace ZonoOpt
409
410#endif
Constrained zonotope class for ZonoOpt library.
Box (i.e., interval vector) class.
Definition Intervals.hpp:718
Constrained zonotope class.
Definition ConZono.hpp:33
Hybrid zonotope class.
Definition HybZono.hpp:44
int nC
number of constraints
Definition HybZono.hpp:482
int n
set dimension
Definition HybZono.hpp:470
friend std::unique_ptr< HybZono > minkowski_sum(const HybZono &Z1, HybZono &Z2)
Computes Minkowski sum of two sets Z1 and Z2.
Definition PolymorphicFunctions.hpp:143
bool zero_one_form
flag to indicate whether the set is in 0-1 or -1-1 form
Definition HybZono.hpp:485
Eigen::SparseMatrix< zono_float > Gc
continuous generator matrix
Definition HybZono.hpp:449
Eigen::SparseMatrix< zono_float > Gb
binary generator matrix
Definition HybZono.hpp:452
int nG
total number of factors. nG = nGc + nGb
Definition HybZono.hpp:473
bool sharp
flag to indicate whether the set is known to be sharp (i.e., convex relaxation = convex hull)
Definition HybZono.hpp:488
Eigen::Vector< zono_float, -1 > c
center vector
Definition HybZono.hpp:464
int nGb
number of binary factors
Definition HybZono.hpp:479
Box bounding_box(const OptSettings &settings=OptSettings(), OptSolution *solution=nullptr)
Computes a bounding box of the set object as a Box object.
Definition HybZono.hpp:398
Eigen::SparseMatrix< zono_float > A
constraint matrix A = [Ac, Ab]
Definition HybZono.hpp:455
Eigen::Vector< zono_float, -1 > b
constraint vector
Definition HybZono.hpp:467
Eigen::SparseMatrix< zono_float > Ab
binary constraint matrix
Definition HybZono.hpp:461
Eigen::SparseMatrix< zono_float > Ac
continuous constraint matrix
Definition HybZono.hpp:458
Eigen::SparseMatrix< zono_float > G
generator matrix G = [Gc, Gb]
Definition HybZono.hpp:446
int nGc
number of continuous factors
Definition HybZono.hpp:476
Zonotope class.
Definition Zono.hpp:33
bool do_is_empty(const OptSettings &, OptSolution *) const override
Definition Zono.hpp:256
std::string print() const override
Returns set information as a string.
Definition Zono.hpp:244
zono_float do_support(const Eigen::Vector< zono_float, -1 > &d, const OptSettings &, OptSolution *) override
Definition Zono.hpp:356
HybZono * clone() const override
Clone method for polymorphic behavior.
Definition Zono.hpp:74
~Zono() override=default
std::unique_ptr< Zono > reduce_order(int n_o)
Perform zonotope order reduction.
Definition Zono.hpp:284
void set(const Eigen::SparseMatrix< zono_float > &G, const Eigen::Vector< zono_float, -1 > &c, bool zero_one_form=false)
Reset zonotope object with the given parameters.
Definition Zono.hpp:195
Zono(const Eigen::SparseMatrix< zono_float > &G, const Eigen::Vector< zono_float, -1 > &c, const bool zero_one_form=false)
Zono constructor.
Definition Zono.hpp:50
zono_float get_volume()
Get volume of zonotope.
Definition Zono.hpp:370
Box do_bounding_box(const OptSettings &, OptSolution *) override
Definition Zono.hpp:264
Zono()
Default constructor for Zono class.
Definition Zono.hpp:41
void convert_form() override
Converts the set representation between -1-1 and 0-1 forms.
Definition Zono.hpp:223
#define zono_float
Defines the floating-point type used in ZonoOpt.
Definition ZonoOpt.hpp:43
std::unique_ptr< Zono > interval_2_zono(const Box &box)
Builds a zonotope from a Box object.
Definition PolymorphicFunctions.hpp:1575
std::unique_ptr< Zono > make_regular_zono_2D(const zono_float radius, const int n_sides, const bool outer_approx, const Eigen::Vector< zono_float, 2 > &c)
Builds a 2D regular zonotope with a given radius and number of sides.
Definition PolymorphicFunctions.hpp:1594
Definition ADMM.hpp:41
Settings for optimization routines in ZonoOpt library.
Definition SolverDataStructures.hpp:26
Solution data structure for optimization routines in ZonoOpt library.
Definition SolverDataStructures.hpp:153