lilypond-1.1.21
[lilypond.git] / lily / ineq-constrained-qp.cc
blobf0e66c0793b5e522f9c966a8c6fead403d3b547b
1 /*
2 ineq-constrained-qp.cc -- implement Ineq_constrained_qp
4 source file of the GNU LilyPond music typesetter
6 (c) 1996, 1997--1998 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include "ineq-constrained-qp.hh"
9 #include "qlpsolve.hh"
10 #include "debug.hh"
11 #include "choleski.hh"
12 #include "main.hh"
15 May be this also should go into a library
18 const int MAXITER=100; // qlpsolve.hh
20 const int MAXDEGEN=5;
23 assume x (idx) == value, and adjust constraints, lin and quad accordingly
25 TODO: add const_term
27 void
28 Ineq_constrained_qp::eliminate_var (int idx, Real value)
30 Vector row (quad_.row (idx));
31 row*= value;
33 quad_.delete_row (idx);
35 quad_.delete_column (idx);
37 lin_.del (idx);
38 row.del (idx);
39 lin_ +=row ;
41 for (int i=0; i < cons_.size(); i++)
43 consrhs_[i] -= cons_[i](idx) *value;
44 cons_[i].del (idx);
48 void
49 Ineq_constrained_qp::add_inequality_cons (Vector c, double r)
51 cons_.push (c);
52 consrhs_.push (r);
55 Ineq_constrained_qp::Ineq_constrained_qp (int novars):
56 quad_ (novars),
57 lin_ (novars),
58 const_term_ (0.0)
62 void
63 Ineq_constrained_qp::OK() const
65 #if !defined (NDEBUG) && defined (PARANOID)
66 assert (cons_.size() == consrhs_.size ());
67 Matrix Qdif= quad_ - quad_.transposed();
68 assert (Qdif.norm()/quad_.norm () < EPS);
69 #endif
73 Real
74 Ineq_constrained_qp::eval (Vector v)
76 return v * quad_ * v + lin_ * v + const_term_;
80 int
81 min_elt_index (Vector v)
83 Real m=infinity_f;
84 int idx=-1;
85 for (int i = 0; i < v.dim(); i++)
87 if (v (i) < m)
89 idx = i;
90 m = v (i);
92 assert (v (i) <= infinity_f);
94 return idx;
98 /**the numerical solving. Mordecai Avriel, Nonlinear Programming: analysis and methods (1976)
99 Prentice Hall.
101 Section 13.3
103 This is a "projected gradient" algorithm. Starting from a point x
104 the next point is found in a direction determined by projecting
105 the gradient onto the active constraints. (well, not really the
106 gradient. The optimal solution obeying the active constraints is
107 tried. This is why H = Q^-1 in initialisation))
111 Vector
112 Ineq_constrained_qp::constraint_solve (Vector start) const
114 if (!dim())
115 return Vector (0);
117 Active_constraints act (this);
118 act.OK();
121 Vector x (start);
122 Vector gradient=quad_*x+lin_;
125 // Real fvalue = x*quad_*x/2 + lin*x + const_term;// it's no use.
126 Vector last_gradient (gradient);
127 int iterations=0;
129 while (iterations++ < MAXITER && act.degenerate_count_i_ < MAXDEGEN)
131 //#ifdef PARANOID
132 if (experimental_features_global_b)
133 assert_solution (x);
134 //#endif
136 Vector direction= - act.find_active_optimum (gradient);
138 DOUT << "gradient "<< gradient<< "\ndirection " << direction<< '\n';
140 if (direction.norm() > EPS)
142 DOUT << act.status() << '\n';
144 Real unbounded_alfa = 1.0;
145 Real minalf = unbounded_alfa;
147 Inactive_iter minidx (act);
151 we know the optimum on this "hyperplane". Check if we
152 bump into the edges of the simplex
155 for (Inactive_iter ia (act); ia.ok(); ia++)
157 Real dot = ia.vec() * direction;
158 if (dot >= 0)
159 continue;
162 Real numerator = ia.rhs () - ia.vec()*x;
163 if (numerator >= 0)
165 if (numerator > EPS)
167 warning (_f ("Ineq_constrained_qp::solve (): Constraint off by %f", numerator));
168 act.degenerate_count_i_ ++;
170 minalf = -numerator;
171 minidx = ia;
172 break;
175 Real alfa = numerator / dot;
178 if (minalf > alfa)
180 minidx = ia;
181 minalf = alfa;
185 Real optimal_step = minalf;
187 Vector deltax = direction * optimal_step;
188 x += deltax;
189 gradient += optimal_step * (quad_ * deltax);
191 DOUT << "step = " << optimal_step << " (|dx| = " <<
192 to_str (deltax.norm()) << ")\n";
194 if (minalf < unbounded_alfa)
196 /* bumped into an edge. try again, in smaller space. */
197 act.add_constraint (minidx.idx());
198 DOUT << "adding cons "<< minidx.idx () << '\n';
199 continue;
201 /*ASSERT: we are at the optimal solution for this "plane"*/
204 Vector lagrange_mult=act.get_lagrange (gradient);
205 int m= min_elt_index (lagrange_mult);
207 if (m>=0 && lagrange_mult (m) > 0)
209 break; // optimal sol.
211 else if (m<0)
213 assert (gradient.norm() < EPS) ;
215 break;
218 DOUT << "dropping cons " << m << '\n';
219 act.drop_constraint (m);
221 if (iterations >= MAXITER)
222 WARN << _ ("didn't converge!") << '\n';
223 if (act.degenerate_count_i_ >= MAXDEGEN)
224 WARN << _ ("Too much degeneracy. ") << '\n';
225 DOUT << ": found " << x << " in " << iterations <<" iterations\n";
226 assert_solution (x);
227 return x;
231 Vector
232 Ineq_constrained_qp::solve (Vector start) const
234 /* no hassle if no constraints*/
235 if (! cons_.size())
237 Choleski_decomposition chol (quad_);
238 return - chol.solve (lin_);
240 else
242 return constraint_solve (start);
247 Ineq_constrained_qp::dim () const
249 return lin_.dim();
255 void
256 Ineq_constrained_qp::assert_solution (Vector sol) const
258 bool sol_b=true;
260 for (int i=0; sol_b && i < cons_.size(); i++)
262 Real R=cons_[i] * sol- consrhs_[i];
263 if (R> -EPS)
264 sol_b = false;
268 void
269 Ineq_constrained_qp::print() const
271 #ifndef NPRINT
272 DOUT << "Quad " << quad_;
273 DOUT << "lin " << lin_ << '\n'
274 << "const " << const_term_<< '\n';
275 for (int i=0; i < cons_.size(); i++)
277 DOUT << "constraint["<<i<<"]: " << cons_[i] << " >= " << consrhs_[i];
278 DOUT << '\n';
280 #endif