summaryrefslogtreecommitdiff
path: root/src/linespace.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/linespace.cc')
-rw-r--r--src/linespace.cc264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/linespace.cc b/src/linespace.cc
new file mode 100644
index 0000000000..6b16c9afab
--- /dev/null
+++ b/src/linespace.cc
@@ -0,0 +1,264 @@
+#include <math.h>
+#include "linespace.hh"
+#include "debug.hh"
+#include "qlp.hh"
+#include "unionfind.hh"
+
+const Real COLFUDGE=1e-3;
+//#define COLFUDGE 1e-3
+bool
+Spacing_problem::contains(const PCol *w)
+{
+ for (int i=0; i< cols.sz(); i++)
+ if (cols[i].pcol_ == w)
+ return true;
+ return false;
+}
+
+int
+Spacing_problem::col_id(const PCol *w)const
+{
+ for (int i=0; i< cols.sz(); i++)
+ if (cols[i].pcol_ == w)
+ return i;
+ assert(false);
+}
+
+void
+Spacing_problem::OK() const
+{
+#ifndef NDEBUG
+ Union_find connected(cols.sz());
+ svec<int> fixed;
+ for (int i=0; i < ideals.sz(); i++) {
+ assert(ideals[i]->hooke > 0);
+ int l = col_id(ideals[i]->left);
+ int r = col_id(ideals[i]->right);
+ connected.connect(l,r);
+ }
+ for (int i = 0; i < cols.sz(); i++)
+ if (cols[i].fixed)
+ fixed.add(i);
+ for (int i = 0; i < cols.sz(); i++) {
+ bool c=false;
+ for (int j =0; j<fixed.sz(); j++)
+ c |= connected.equiv(j,i);
+ assert(c);
+ }
+#endif
+}
+
+bool
+Spacing_problem::check_constraints(Vector v) const
+{
+ int dim=v.dim();
+ // mtor << "checking solution " << v << '\n';
+ for (int i=0; i < dim; i++) {
+
+ if (cols[i].fixed&& ABS(cols[i].fixpos - v(i)) > COLFUDGE) {
+ return false;
+ }
+ if (!i)
+ continue;
+
+ Real mindist=cols[i-1].minright()
+ +cols[i].minleft();
+
+ // ugh... compares
+ Real dif =v(i) - v(i-1)- mindist;
+ bool b = (dif > - COLFUDGE);
+
+
+#if 1
+ if (!b)
+ return false;
+
+#else
+ mtor << "dif= "<<dif<<" fudge= " << COLFUDGE<< " dif >fudge= "<<
+ b << "\n";
+
+ /* fucks up for unknown reasons */
+ if (dif < -COLFUDGE)
+ return false;
+#endif
+
+ }
+ return true;
+}
+
+bool
+Spacing_problem::check_feasible() const
+{
+ Vector sol(try_initial_solution());
+ return check_constraints(sol);
+}
+
+// generate a solution which obeys the min distances and fixed positions
+Vector
+Spacing_problem::try_initial_solution() const
+{
+ int dim=cols.sz();
+ Vector initsol(dim);
+ for (int i=0; i < dim; i++) {
+ if (cols[i].fixed) {
+ initsol(i)=cols[i].fixpos;
+ } else {
+ Real mindist=cols[i-1].minright()
+ +cols[i].minleft();
+ assert(mindist >= 0.0);
+ initsol(i)=initsol(i-1)+mindist;
+
+ //nog niet
+ //if (i>0)
+ // assert(initsol(i) > initsol(i-1));
+ }
+ }
+
+ return initsol;
+}
+Vector
+Spacing_problem::find_initial_solution() const
+{
+ Vector v(try_initial_solution());
+ assert(check_constraints(v));
+ return v;
+}
+// generate the matrices
+void
+Spacing_problem::make_matrices(Matrix &quad, Vector &lin, Real &c) const
+{
+ quad.fill(0);
+ lin.fill(0);
+ for (int j=0; j < ideals.sz(); j++){
+ Idealspacing const*i=ideals[j];
+ int l = col_id(i->left);
+ int r = col_id(i->right);
+
+ quad(r,r) += i->hooke;
+ quad(r,l) -= i->hooke;
+ quad(l,r) -= i->hooke;
+ quad(l,l) += i->hooke;
+
+ lin(r) -= i->space*i->hooke;
+ lin(l) += i->space*i->hooke;
+
+ c += sqr(i->space);
+ }
+}
+
+// put the constraints into the LP problem
+void
+Spacing_problem::make_constraints(Mixed_qp& lp) const
+{
+ int dim=cols.sz();
+ for (int j=0; j < dim; j++) {
+ Colinfo *c=&(cols[j]);
+ if (c->fixed) {
+ lp.add_fixed_var(j,c->fixpos);
+ }
+ if (j > 0){
+ Vector c1(dim);
+
+
+ c1(j)=1.0 ;
+ c1(j-1)=-1.0 ;
+ lp.add_inequality_cons(c1, cols[j-1].minright() +
+ cols[j].minleft());
+ }
+ }
+}
+
+svec<Real>
+Spacing_problem::solve() const
+{
+ print();
+ OK();
+ assert(check_feasible());
+
+
+ /* optimalisatiefunctie */
+ Mixed_qp lp(cols.sz());
+ make_matrices(lp.quad,lp.lin, lp.const_term);
+ make_constraints(lp);
+ Vector start=find_initial_solution();
+ Vector sol(lp.solve(start));
+ if (!check_constraints(sol)) {
+ WARN << "solution doesn't satisfy constraints.\n" ;
+ }
+
+
+ svec<Real> posns(sol);
+ posns.add(lp.eval(sol));
+ return posns;
+}
+
+/*
+ add one column to the problem.
+*/
+void
+Spacing_problem::add_column(const PCol *col, bool fixed, Real fixpos)
+{
+ Colinfo c;
+ c.fixed=fixed;
+ c.fixpos=fixpos;
+ assert(col);
+ c.pcol_=col;
+ cols.add(c);
+}
+
+void
+Spacing_problem::add_ideal(const Idealspacing *i)
+{
+ const PCol *l =i->left;
+ const PCol *r= i->right;
+
+ if (!contains(l) || !contains(r)) {
+ return;
+ }
+ ideals.add(i);
+}
+
+void
+Spacing_problem::print_ideal(const Idealspacing*id)const
+{
+#ifndef NPRINT
+ int l = col_id(id->left);
+ int r = col_id(id->right);
+
+ mtor << "between " << l <<","<<r<<":" ;
+#endif
+}
+
+void
+Spacing_problem::print() const
+{
+#ifndef NPRINT
+ for (int i=0; i < cols.sz(); i++) {
+ mtor << "col " << i<<' ';
+ cols[i].print();
+ }
+ for (int i=0; i < ideals.sz(); i++) {
+ print_ideal(ideals[i]);
+ }
+#endif
+
+}
+
+void
+Colinfo::print() const
+{
+#ifndef NPRINT
+ mtor << "column { ";
+ if (fixed)
+ mtor << "fixed at " << fixpos<<", ";
+ assert(pcol_);
+ mtor << "[" << minleft() << ", " << minright() << "]";
+ mtor <<"}\n";
+#endif
+}
+
+Colinfo::Colinfo()
+{
+ fixed=false;
+ pcol_=0;
+}