lilypond-1.3.7
[lilypond.git] / lily / ineq-constrained-qp.cc
blob563199c93808fedb08a5332f3829b63a3d209d1f
1 /*
2 ineq-constrained-qp.cc -- implement Ineq_constrained_qp
4 source file of the GNU LilyPond music typesetter
6 (c) 1996, 1997--1999 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 if (experimental_features_global_b)
132 assert_solution (x);
134 Vector direction= - act.find_active_optimum (gradient);
136 DOUT << "gradient "<< gradient<< "\ndirection " << direction<< '\n';
138 if (direction.norm() > EPS)
140 DOUT << act.status() << '\n';
142 Real unbounded_alfa = 1.0;
143 Real minalf = unbounded_alfa;
145 Inactive_iter minidx (act);
149 we know the optimum on this "hyperplane". Check if we
150 bump into the edges of the simplex
153 for (Inactive_iter ia (act); ia.ok(); ia++)
155 Real dot = ia.vec() * direction;
156 Real mindot = (experimental_features_global_b)
157 ? -EPS
158 : 0;
160 if (dot >= mindot)
161 continue;
164 Real numerator = ia.rhs () - ia.vec()*x;
165 if (numerator >= 0)
167 if (numerator > EPS)
169 warning (_f ("Ineq_constrained_qp::solve (): Constraint off by %f", numerator));
170 act.degenerate_count_i_ ++;
172 minalf = -numerator;
173 minidx = ia;
174 break;
177 Real alfa = numerator / dot;
180 if (minalf > alfa)
182 minidx = ia;
183 minalf = alfa;
187 Real optimal_step = minalf;
189 Vector deltax = direction * optimal_step;
190 x += deltax;
191 gradient += optimal_step * (quad_ * deltax);
193 DOUT << "step = " << optimal_step << " (|dx| = " <<
194 to_str (deltax.norm()) << ")\n";
196 if (minalf < unbounded_alfa)
198 /* bumped into an edge. try again, in smaller space. */
199 act.add_constraint (minidx.idx());
200 DOUT << "adding cons "<< minidx.idx () << '\n';
201 continue;
203 /*ASSERT: we are at the optimal solution for this "plane"*/
206 Vector lagrange_mult=act.get_lagrange (gradient);
207 int m= min_elt_index (lagrange_mult);
209 if (m>=0 && lagrange_mult (m) > 0)
211 break; // optimal sol.
213 else if (m<0)
215 Real n =gradient.norm();
216 if (n >= EPS)
218 programming_error ("Huh? Gradient should be zero ");
219 act.degenerate_count_i_ ++;
221 else if (n <0)
223 programming_error ("Huh? Norm should be positive");
224 act.degenerate_count_i_++;
226 break;
229 DOUT << "dropping cons " << m << '\n';
230 act.drop_constraint (m);
232 if (iterations >= MAXITER)
233 WARN << _ ("Didn't converge!") << '\n';
234 if (act.degenerate_count_i_ >= MAXDEGEN)
235 WARN << _ ("too much degeneracy") << '\n';
236 DOUT << ": found " << x << " in " << iterations <<" iterations\n";
237 assert_solution (x);
238 return x;
242 Vector
243 Ineq_constrained_qp::solve (Vector start) const
245 /* no hassle if no constraints*/
246 if (! cons_.size())
248 Choleski_decomposition chol (quad_);
249 return - chol.solve (lin_);
251 else
253 return constraint_solve (start);
258 Ineq_constrained_qp::dim () const
260 return lin_.dim();
266 void
267 Ineq_constrained_qp::assert_solution (Vector sol) const
269 bool sol_b=true;
271 for (int i=0; sol_b && i < cons_.size(); i++)
273 Real R=cons_[i] * sol- consrhs_[i];
274 if (R> -EPS)
275 sol_b = false;
279 void
280 Ineq_constrained_qp::print() const
282 #ifndef NPRINT
283 DOUT << "Ineq_constrained_qp { " << '\n';
284 DOUT << "Quad " << quad_;
285 DOUT << "lin " << lin_ << '\n'
286 << "const " << const_term_<< '\n';
287 for (int i=0; i < cons_.size(); i++)
289 DOUT << "constraint["<<i<<"]: " << cons_[i] << " >= " << consrhs_[i];
290 DOUT << '\n';
292 DOUT << "}\n";
293 #endif