ZonoOpt v1.0.0
Loading...
Searching...
No Matches
ConZono.hpp
Go to the documentation of this file.
1#ifndef ZONOOPT_CONZONO_HPP_
2#define ZONOOPT_CONZONO_HPP_
3
15#include "HybZono.hpp"
16
17namespace ZonoOpt
18{
19
20using namespace detail;
21
32class ConZono : public HybZono
33{
34 public:
35
36 // constructors
37
42 ConZono() { sharp = true; }
43
53 ConZono(const Eigen::SparseMatrix<zono_float>& G, const Eigen::Vector<zono_float, -1>& c,
54 const Eigen::SparseMatrix<zono_float>& A, const Eigen::Vector<zono_float, -1>& b,
55 const bool zero_one_form=false)
56 {
57 set(G, c, A, b, zero_one_form);
58 sharp = true;
59 }
60
61 // virtual destructor
62 ~ConZono() override = default;
63
67 HybZono* clone() const override
68 {
69 return new ConZono(*this);
70 }
71
72 // set method
82 void set(const Eigen::SparseMatrix<zono_float>& G, const Eigen::Vector<zono_float, -1>& c,
83 const Eigen::SparseMatrix<zono_float>& A, const Eigen::Vector<zono_float, -1>& b,
84 bool zero_one_form=false);
85
92 virtual void constraint_reduction();
93
94 // generator conversion between [-1,1] and [0,1]
95 void convert_form() override;
96
97 // over-approximate as zonotope
98
103 virtual std::unique_ptr<Zono> to_zono_approx() const;
104
105 // display methods
106 std::string print() const override;
107
108 protected:
109
110 OptSolution qp_opt(const Eigen::SparseMatrix<zono_float>& P, const Eigen::Vector<zono_float, -1>& q,
111 zono_float c, const Eigen::SparseMatrix<zono_float>& A, const Eigen::Vector<zono_float, -1>& b,
112 const OptSettings &settings=OptSettings(), OptSolution* solution=nullptr) const;
113
114 Eigen::Vector<zono_float, -1> do_optimize_over(
115 const Eigen::SparseMatrix<zono_float> &P, const Eigen::Vector<zono_float, -1> &q, zono_float c,
116 const OptSettings &settings, OptSolution* solution) const override;
117
118 Eigen::Vector<zono_float, -1> do_project_point(const Eigen::Vector<zono_float, -1>& x,
119 const OptSettings &settings, OptSolution* solution) const override;
120
121 bool do_is_empty(const OptSettings &settings, OptSolution* solution) const override;
122
123 zono_float do_support(const Eigen::Vector<zono_float, -1>& d, const OptSettings &settings,
124 OptSolution* solution) override;
125
126 bool do_contains_point(const Eigen::Vector<zono_float, -1>& x, const OptSettings &settings,
127 OptSolution* solution) const override;
128
129 Box do_bounding_box(const OptSettings &settings, OptSolution*) override;
130
131 std::unique_ptr<HybZono> do_complement(zono_float delta_m, bool, const OptSettings&,
132 OptSolution*, int, int) override;
133};
134
135// forward declarations
136
146std::unique_ptr<ConZono> vrep_2_conzono(const Eigen::Matrix<zono_float, -1, -1> &Vpoly);
147
148
149// implementation
150inline void ConZono::set(const Eigen::SparseMatrix<zono_float>& G, const Eigen::Vector<zono_float, -1>& c,
151 const Eigen::SparseMatrix<zono_float>& A, const Eigen::Vector<zono_float, -1>& b,
152 const bool zero_one_form)
153{
154 // check dimensions
155 if (G.rows() != c.size() || A.rows() != b.size() || G.cols() != A.cols())
156 {
157 throw std::invalid_argument("ConZono: inconsistent dimensions.");
158 }
159
160 // conzono parameters
161 this->G = G;
162 this->A = A;
163 this->c = c;
164 this->b = b;
165 this->nG = static_cast<int>(G.cols());
166 this->nC = static_cast<int>(A.rows());
167 this->n = static_cast<int>(G.rows());
168 this->zero_one_form = zero_one_form;
169
170 // abstract zono parameters
171 this->nGc = this->nG;
172 this->nGb = 0;
173 this->Gc = this->G;
174 this->Gb.resize(this->n, 0);
175 this->Ac = this->A;
176 this->Ab.resize(0, 0);
177}
178
180{
181 Eigen::Vector<zono_float, -1> c, b;
182 Eigen::SparseMatrix<zono_float> G, A;
183
184 if (!this->zero_one_form) // convert to [0,1] generators
185 {
186 c = this->c - this->G*Eigen::Vector<zono_float, -1>::Ones(this->nG);
187 b = this->b + this->A*Eigen::Vector<zono_float, -1>::Ones(this->nG);
188 G = 2.0*this->G;
189 A = 2.0*this->A;
190
191 set(G, c, A, b, true);
192 }
193 else // convert to [-1,1] generators
194 {
195 c = this->c + 0.5*this->G*Eigen::Vector<zono_float, -1>::Ones(this->nG);
196 b = this->b - 0.5*this->A*Eigen::Vector<zono_float, -1>::Ones(this->nG);
197 G = 0.5*this->G;
198 A = 0.5*this->A;
199
200 set(G, c, A, b, false);
201 }
202}
203
204inline std::string ConZono::print() const
205{
206 std::stringstream ss;
207 ss << "ConZono: " << std::endl;
208 ss << "n: " << this->n << std::endl;
209 ss << "nG: " << this->nG << std::endl;
210 ss << "nC: " << this->nC << std::endl;
211 ss << "G: " << Eigen::Matrix<zono_float, -1, -1>(this->G) << std::endl;
212 ss << "c: " << this->c << std::endl;
213 ss << "A: " << Eigen::Matrix<zono_float, -1, -1>(this->A) << std::endl;
214 ss << "b: " << this->b << std::endl;
215 ss << "zero_one_form: " << this->zero_one_form;
216 return ss.str();
217}
218
219inline Eigen::Vector<zono_float, -1> ConZono::do_optimize_over(
220 const Eigen::SparseMatrix<zono_float> &P, const Eigen::Vector<zono_float, -1> &q, const zono_float c,
221 const OptSettings &settings, OptSolution* solution) const
222{
223 // check dimensions
224 if (P.rows() != this->n || P.cols() != this->n || q.size() != this->n)
225 {
226 throw std::invalid_argument("Optimize over: inconsistent dimensions.");
227 }
228
229 // cost
230 Eigen::SparseMatrix<zono_float> P_fact = this->G.transpose()*P*this->G;
231 Eigen::Vector<zono_float, -1> q_fact = this->G.transpose()*(P*this->c + q);
232 zono_float delta_c = (0.5*this->c.transpose()*P*this->c + q.transpose()*this->c)(0);
233
234 // solve QP
235 OptSolution sol = this->qp_opt(P_fact, q_fact, c+delta_c, this->A, this->b, settings, solution);
236
237 // check feasibility and return solution
238 if (sol.infeasible)
239 return Eigen::Vector<zono_float, -1>(this->nG);
240 else
241 return this->G*sol.z + this->c;
242}
243
244inline Eigen::Vector<zono_float, -1> ConZono::do_project_point(const Eigen::Vector<zono_float, -1>& x,
245 const OptSettings& settings, OptSolution* solution) const
246{
247 // check dimensions
248 if (this->n != x.size())
249 {
250 throw std::invalid_argument("Point projection: inconsistent dimensions.");
251 }
252
253 // cost
254 Eigen::SparseMatrix<zono_float> P = this->G.transpose()*this->G;
255 Eigen::Vector<zono_float, -1> q = this->G.transpose()*(this->c-x);
256
257 // solve QP
258 const OptSolution sol = this->qp_opt(P, q, 0, this->A, this->b, settings, solution);
259
260 // check feasibility and return solution
261 if (sol.infeasible)
262 throw std::invalid_argument("Point projection: infeasible");
263 else
264 return this->G*sol.z + this->c;
265}
266
267inline bool ConZono::do_is_empty(const OptSettings& settings, OptSolution* solution) const
268{
269 // trivial case
270 if (this->n == 0)
271 return true;
272
273 // cost
274 Eigen::SparseMatrix<zono_float> P (this->nG, this->nG);
275 P.setIdentity();
276 Eigen::Vector<zono_float, -1> q = Eigen::Vector<zono_float, -1>::Zero(this->nG);
277
278 // solve QP
279 OptSolution sol = this->qp_opt(P, q, 0, this->A, this->b, settings, solution);
280
281 // check infeasibility flag
282 return sol.infeasible;
283}
284
285inline zono_float ConZono::do_support(const Eigen::Vector<zono_float, -1>& d,
286 const OptSettings& settings, OptSolution* solution)
287{
288 // check dimensions
289 if (this->n != d.size())
290 {
291 throw std::invalid_argument("Support: inconsistent dimensions.");
292 }
293
294 // cost
295 Eigen::SparseMatrix<zono_float> P (this->nG, this->nG);
296 Eigen::Vector<zono_float, -1> q = -this->G.transpose()*d;
297
298 // solve QP
299 const OptSolution sol = this->qp_opt(P, q, 0, this->A, this->b, settings, solution);
300
301 // check feasibility and return solution
302 if (sol.infeasible) // Z is empty
303 throw std::invalid_argument("Support: infeasible");
304 else
305 return d.dot(this->G*sol.z + this->c);
306}
307
308inline bool ConZono::do_contains_point(const Eigen::Vector<zono_float, -1>& x,
309 const OptSettings& settings, OptSolution* solution) const
310{
311 // check dimensions
312 if (this->n != x.size())
313 {
314 throw std::invalid_argument("Contains point: inconsistent dimensions.");
315 }
316
317 // build QP for ADMM
318 Eigen::SparseMatrix<zono_float> P (this->nG, this->nG);
319 P.setIdentity();
320 Eigen::Vector<zono_float, -1> q (this->nG);
321 q.setZero(); // zeros
322 Eigen::SparseMatrix<zono_float> A = vcat<zono_float>(this->A, this->G);
323 Eigen::Vector<zono_float, -1> b (this->nC + this->n);
324 b.segment(0, this->nC) = this->b;
325 b.segment(this->nC, this->n) = x-this->c;
326
327 const OptSolution sol = this->qp_opt(P, q, 0, A, b, settings, solution);
328
329 // check feasibility and return solution
330 return !(sol.infeasible);
331}
332
333inline OptSolution ConZono::qp_opt(const Eigen::SparseMatrix<zono_float>& P, const Eigen::Vector<zono_float, -1>& q,
334 const zono_float c, const Eigen::SparseMatrix<zono_float>& A, const Eigen::Vector<zono_float, -1>& b,
335 const OptSettings &settings, OptSolution* solution) const
336{
337 // setup QP
338 Eigen::Vector<zono_float, -1> xi_lb (this->nG);
339 if (this->zero_one_form)
340 xi_lb.setZero();
341 else
342 xi_lb.setConstant(-1);
343 const Eigen::Vector<zono_float, -1> xi_ub = Eigen::Vector<zono_float, -1>::Ones(this->nG);
344
345 const auto data = std::make_shared<ADMM_data>(P, q, A, b, xi_lb, xi_ub, c, settings);
346 ADMM_solver solver(data);
347
348 // solve
349 OptSolution sol = solver.solve();
350 if (solution != nullptr)
351 *solution = sol;
352 return sol;
353}
354
355// bounding box
357{
358 // make sure dimension is at least 1
359 if (this->n == 0)
360 {
361 throw std::invalid_argument("Bounding box: empty set");
362 }
363
364 // init search direction for bounding box
365 Eigen::Vector<zono_float, -1> d (this->n);
366 d.setZero();
367
368 // declarations
369 Box box (this->n); // init
370 // declare
371 zono_float s_neg, s_pos;
372
373 // build QP for ADMM
374 const Eigen::SparseMatrix<zono_float> P (this->nG, this->nG);
375 Eigen::Vector<zono_float, -1> q = -this->G.transpose()*d;
376
377 // convex solution
378 Eigen::Vector<zono_float, -1> xi_lb, xi_ub;
379 if (this->zero_one_form)
380 xi_lb = Eigen::Vector<zono_float, -1>::Zero(this->nG);
381 else
382 xi_lb = -1.0*Eigen::Vector<zono_float, -1>::Ones(this->nG);
383
384 xi_ub = Eigen::Vector<zono_float, -1>::Ones(this->nG);
385
386 // build ADMM object
387 const auto data = std::make_shared<ADMM_data>(P, q, this->A, this->b, xi_lb, xi_ub, zero, settings);
388 ADMM_solver solver(data);
389
390 // get support in all box directions
391 for (int i=0; i<this->n; i++)
392 {
393 // negative direction
394
395 // update QP
396 d.setZero();
397 d(i) = -1;
398 data->q = -this->G.transpose()*d;
399
400 // solve
401 OptSolution sol = solver.solve();
402 if (sol.infeasible)
403 throw std::invalid_argument("Bounding box: Z is empty");
404 else
405 s_neg = -d.dot(this->G*sol.z + this->c);
406
407 // positive direction
408
409 // update QP
410 d.setZero();
411 d(i) = 1;
412 data->q = -this->G.transpose()*d;
413
414 // solve
415 sol = solver.solve();
416 if (sol.infeasible)
417 throw std::invalid_argument("Bounding box: Z is empty");
418 else
419 s_pos = d.dot(this->G*sol.z + this->c);
420
421 // store bounds
422 box[i] = Interval(s_neg, s_pos);
423 }
424
425 return box;
426}
427
428
429
430} // namespace ZonoOpt
431
432
433#endif
Hybrid zonotope class for ZonoOpt library.
Box (i.e., interval vector) class.
Definition Intervals.hpp:718
Constrained zonotope class.
Definition ConZono.hpp:33
void set(const Eigen::SparseMatrix< zono_float > &G, const Eigen::Vector< zono_float, -1 > &c, const Eigen::SparseMatrix< zono_float > &A, const Eigen::Vector< zono_float, -1 > &b, bool zero_one_form=false)
Reset constrained zonotope object with the given parameters.
Definition ConZono.hpp:150
virtual void constraint_reduction()
Execute constraint reduction algorithm from Scott et. al. 2016.
Definition PolymorphicFunctions.hpp:1757
std::unique_ptr< HybZono > do_complement(zono_float delta_m, bool, const OptSettings &, OptSolution *, int, int) override
Definition PolymorphicFunctions.hpp:1021
HybZono * clone() const override
Clone method for polymorphic behavior.
Definition ConZono.hpp:67
ConZono()
Default constructor for ConZono class.
Definition ConZono.hpp:42
ConZono(const Eigen::SparseMatrix< zono_float > &G, const Eigen::Vector< zono_float, -1 > &c, const Eigen::SparseMatrix< zono_float > &A, const Eigen::Vector< zono_float, -1 > &b, const bool zero_one_form=false)
ConZono constructor.
Definition ConZono.hpp:53
void convert_form() override
Converts the set representation between -1-1 and 0-1 forms.
Definition ConZono.hpp:179
OptSolution qp_opt(const Eigen::SparseMatrix< zono_float > &P, const Eigen::Vector< zono_float, -1 > &q, zono_float c, const Eigen::SparseMatrix< zono_float > &A, const Eigen::Vector< zono_float, -1 > &b, const OptSettings &settings=OptSettings(), OptSolution *solution=nullptr) const
Definition ConZono.hpp:333
Box do_bounding_box(const OptSettings &settings, OptSolution *) override
Definition ConZono.hpp:356
bool do_contains_point(const Eigen::Vector< zono_float, -1 > &x, const OptSettings &settings, OptSolution *solution) const override
Definition ConZono.hpp:308
~ConZono() override=default
bool do_is_empty(const OptSettings &settings, OptSolution *solution) const override
Definition ConZono.hpp:267
std::string print() const override
Returns set information as a string.
Definition ConZono.hpp:204
virtual std::unique_ptr< Zono > to_zono_approx() const
Compute outer approximation of constrained zonotope as zonotope using SVD.
Definition PolymorphicFunctions.hpp:1957
Eigen::Vector< zono_float, -1 > do_optimize_over(const Eigen::SparseMatrix< zono_float > &P, const Eigen::Vector< zono_float, -1 > &q, zono_float c, const OptSettings &settings, OptSolution *solution) const override
Definition ConZono.hpp:219
zono_float do_support(const Eigen::Vector< zono_float, -1 > &d, const OptSettings &settings, OptSolution *solution) override
Definition ConZono.hpp:285
Eigen::Vector< zono_float, -1 > do_project_point(const Eigen::Vector< zono_float, -1 > &x, const OptSettings &settings, OptSolution *solution) const override
Definition ConZono.hpp:244
Hybrid zonotope class.
Definition HybZono.hpp:44
int nC
number of constraints
Definition HybZono.hpp:482
int n
set dimension
Definition HybZono.hpp:470
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
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
#define zono_float
Defines the floating-point type used in ZonoOpt.
Definition ZonoOpt.hpp:43
std::unique_ptr< ConZono > vrep_2_conzono(const Eigen::Matrix< zono_float, -1, -1 > &Vpoly)
Builds a constrained zonotope from a vertex representation polytope.
Definition PolymorphicFunctions.hpp:1547
Definition ADMM.hpp:41
Interval class.
Definition Intervals.hpp:372
Settings for optimization routines in ZonoOpt library.
Definition SolverDataStructures.hpp:26
Solution data structure for optimization routines in ZonoOpt library.
Definition SolverDataStructures.hpp:153
Eigen::Vector< zono_float, -1 > z
solution vector
Definition SolverDataStructures.hpp:157