From: Han-Wen Nienhuys <hanwen@xs4all.nl>
Date: Tue, 21 Feb 2006 12:48:51 +0000 (+0000)
Subject: * lily/tie-column.cc (calc_positioning_done): support for
X-Git-Tag: release/2.7.36~23
X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=849ed54c1a272dac222d975e3c8d3e532aaa8f27;p=lilypond.git

* lily/tie-column.cc (calc_positioning_done): support for
tie-score debugging

* lily/tie-formatting-problem.cc
(generate_extremal_tie_variations): factor out.
(score_ties_configuration): annotate all tie
(print_ties_configuration): new routine.
(generate_configuration): nudge extremal ties outside of the head
Y extents.
(score_ties_configuration): oops. convert to staff-space before
determining position symmetry.
---

diff --git a/ChangeLog b/ChangeLog
index b9bb367ce2..49dee875c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,23 @@
+2006-02-21  Han-Wen Nienhuys  <hanwen@xs4all.nl>
+
+	* lily/tie-column.cc (calc_positioning_done): support for
+	tie-score debugging
+
+	* lily/tie-formatting-problem.cc
+	(generate_extremal_tie_variations): factor out.
+	(score_ties_configuration): annotate all tie 
+	(print_ties_configuration): new routine.
+	(generate_configuration): nudge extremal ties outside of the head
+	Y extents.
+	(score_ties_configuration): oops. convert to staff-space before
+	determining position symmetry.
+
 2006-02-20  Graham Percival  <gpermus@gmail.com>
 
-	* Documentation/user/ *-notation.itely: misc minor editing,
+	* Documentation/user/*-notation.itely: misc minor editing,
 	shifting doc sections around.
 
-	* Documentation/user/ *-notation-itely, global.itely,
+	* Documentation/user/*-notation-itely, global.itely,
 	changing-defaults.itely: added new stuff from NEWS.
 
 2006-02-20  Heikki Junes  <hjunes@cc.hut.fi>
diff --git a/input/regression/tie-chord-debug.ly b/input/regression/tie-chord-debug.ly
new file mode 100644
index 0000000000..62bc16dc91
--- /dev/null
+++ b/input/regression/tie-chord-debug.ly
@@ -0,0 +1,17 @@
+\header {
+
+  texidoc = "Switching on debug-tie-scoring annotates the tie scoring
+decisions made."
+  
+}
+  
+\paper
+{
+  ragged-right = ##t
+  debug-tie-scoring = ##t
+}
+
+\relative g' {
+  <a b e f> ~
+  <a b e f>
+}
diff --git a/lily/beam-quanting.cc b/lily/beam-quanting.cc
index 3bfa11dfd1..e4cec84364 100644
--- a/lily/beam-quanting.cc
+++ b/lily/beam-quanting.cc
@@ -19,6 +19,7 @@ using namespace std;
 #include "staff-symbol-referencer.hh"
 #include "stem.hh"
 #include "warn.hh"
+#include "main.hh"
 
 Real
 get_detail (SCM alist, SCM sym, Real def)
@@ -61,7 +62,7 @@ struct Quant_score
   Real yr;
   Real demerits;
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
   string score_card_;
 #endif
 };
@@ -234,7 +235,7 @@ Beam::quanting (SCM smob, SCM posns)
 				xstaff, &parameters);
       qscores[i].demerits += d;
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
       qscores[i].score_card_ += to_string ("S%.2f", d);
 #endif
     }
@@ -255,7 +256,7 @@ Beam::quanting (SCM smob, SCM posns)
 					 edge_beam_counts, ldir, rdir, &parameters);
 	qscores[i].demerits += d;
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
 	qscores[i].score_card_ += to_string (" F %.2f", d);
 #endif
       }
@@ -270,16 +271,16 @@ Beam::quanting (SCM smob, SCM posns)
 				     qscores[i].yl, qscores[i].yr, &parameters);
 	qscores[i].demerits += d;
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
 	qscores[i].score_card_ += to_string (" L %.2f", d);
 #endif
       }
 
   int best_idx = best_quant_score_idx (qscores);
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
   SCM inspect_quants = me->get_property ("inspect-quants");
-  if (to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting")))
+  if (to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring")))
       && scm_is_pair (inspect_quants))
     {
       Drul_array<Real> ins = ly_scm2interval (inspect_quants);
@@ -311,9 +312,9 @@ Beam::quanting (SCM smob, SCM posns)
 					  qscores[best_idx].yr);
     }
   
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
   if (best_idx >= 0
-      && to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"))))
+      && to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring"))))
     {
       qscores[best_idx].score_card_ += to_string ("i%d", best_idx);
 
diff --git a/lily/beam.cc b/lily/beam.cc
index 1919d38312..aea4796543 100644
--- a/lily/beam.cc
+++ b/lily/beam.cc
@@ -28,6 +28,7 @@
 
 #include "beaming.hh"
 #include "directional-element-interface.hh"
+#include "main.hh"
 #include "international.hh"
 #include "interval-set.hh"
 #include "item.hh"
@@ -41,7 +42,7 @@
 #include "stem.hh"
 #include "warn.hh"
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
 #include "text-interface.hh" // debug output.
 #include "font-interface.hh" // debug output.
 #endif
@@ -489,9 +490,9 @@ Beam::print (SCM grob)
 			   X_AXIS);
   the_beam.translate_axis (pos[LEFT], Y_AXIS);
 
-#if (DEBUG_QUANTING)
+#if (DEBUG_BEAM_SCORING)
   SCM quant_score = me->get_property ("quant-score");
-  SCM debug = me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"));
+  SCM debug = me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring"));
   if (to_boolean (debug) && scm_is_string (quant_score))
     {
 
diff --git a/lily/include/beam.hh b/lily/include/beam.hh
index 44460905e8..e79b2705d9 100644
--- a/lily/include/beam.hh
+++ b/lily/include/beam.hh
@@ -97,9 +97,6 @@ private:
   static int forced_stem_count (Grob *);
 };
 
-#ifndef NDEBUG
-#define DEBUG_QUANTING 1
-#endif
 
 #endif /* BEAM_HH */
 
diff --git a/lily/include/main.hh b/lily/include/main.hh
index 329be3f77b..5369507628 100644
--- a/lily/include/main.hh
+++ b/lily/include/main.hh
@@ -61,5 +61,7 @@ extern const char *LILYPOND_DATADIR;
 */
 
 #define DEBUG_SLUR_SCORING 1
+#define DEBUG_TIE_SCORING 1
+#define DEBUG_BEAM_SCORING 1
 
 #endif /* MAIN_HH */
diff --git a/lily/include/slur-configuration.hh b/lily/include/slur-configuration.hh
index de6a54ca37..f9ebea2a7d 100644
--- a/lily/include/slur-configuration.hh
+++ b/lily/include/slur-configuration.hh
@@ -23,9 +23,7 @@ public:
 
   int index_;
 
-#if DEBUG_SLUR_SCORING
   string score_card_;
-#endif
 
   Slur_configuration ();
 
diff --git a/lily/include/tie-configuration.hh b/lily/include/tie-configuration.hh
index 999d1ea8b6..1e48922d68 100644
--- a/lily/include/tie-configuration.hh
+++ b/lily/include/tie-configuration.hh
@@ -10,6 +10,7 @@
 #ifndef TIE_CONFIGURATION_HH
 #define TIE_CONFIGURATION_HH
 
+#include "main.hh"
 #include "lily-proto.hh"
 #include "direction.hh"
 #include "interval.hh"
@@ -18,14 +19,24 @@
 
 class Tie_configuration
 {
+#if DEBUG_SLUR_SCORING
+  string score_card_;
+#endif
+  Real score_;
+  bool scored_;
+  friend class Tie_formatting_problem;
 public:
+  Real score () const { return score_; }
+  string card () const { return score_card_; }
+
   int position_;
   Direction dir_;
   Real delta_y_;
 
   /* computed. */
   Interval attachment_x_;
-  
+
+  void add_score (Real, string);
   Tie_configuration ();
   void center_tie_vertically (Tie_details const &);
   Bezier get_transformed_bezier (Tie_details const &) const;
@@ -40,7 +51,23 @@ public:
 
 INSTANTIATE_COMPARE (Tie_configuration, Tie_configuration::compare);
 
-typedef vector<Tie_configuration> Ties_configuration;
+class Ties_configuration : public vector<Tie_configuration>
+{
+  Real score_;
+  string score_card_;
+  bool scored_;
+  vector<string> tie_score_cards_;
+
+  friend class Tie_formatting_problem;
+public:
+  Ties_configuration ();
+  void add_score (Real amount, string description);
+  void add_tie_score (Real amount, int i, string description);
+  Real score () const;
+  void reset_score ();
+  string card () const; 
+  string tie_card (int i) const { return tie_score_cards_[i]; }
+};
 
 #endif /* TIE_CONFIGURATION_HH */
 
diff --git a/lily/include/tie-formatting-problem.hh b/lily/include/tie-formatting-problem.hh
index 8296f4dee1..18eafec4f0 100644
--- a/lily/include/tie-formatting-problem.hh
+++ b/lily/include/tie-formatting-problem.hh
@@ -1,5 +1,5 @@
 /*
-  tie-formatting-problem.hh -- declare
+  tie-formatting-problem.hh -- declare Tie_formatting_problem
 
   source file of the GNU LilyPond music typesetter
 
@@ -15,42 +15,11 @@
 #include "skyline.hh"
 #include "lily-proto.hh"
 #include "tie-configuration.hh"
+#include "tie-details.hh"
 
 #include <map>
 #include <set>
 
-struct Tie_details
-{
-  Real height_limit_;
-  Real ratio_;
-  Real staff_space_;
-  Real x_gap_;
-  Real stem_gap_; 
-  Real between_length_limit_;
-  Real wrong_direction_offset_penalty_;
-  Real min_length_penalty_factor_;
-  Real min_length_;
-  Real tip_staff_line_clearance_;
-  Real center_staff_line_clearance_;
-  Real staff_line_collision_penalty_;
-  Real dot_collision_clearance_;
-  Real dot_collision_penalty_;
-  Real tie_column_monotonicity_penalty_;
-  Real tie_tie_collision_penalty_;
-  Real tie_tie_collision_distance_;
-  Real horizontal_distance_penalty_factor_;
-  Real vertical_distance_penalty_factor_;
-  Real intra_space_threshold_;
-  Real outer_tie_length_symmetry_penalty_factor_;
-  Real outer_tie_vertical_distance_symmetry_penalty_factor_;
-
-  Grob *staff_symbol_referencer_;
-  
-  Tie_details ();
-  void from_grob (Grob *);
-};
-
-
 typedef map< pair<int, int>, Tie_configuration *> Tie_configuration_map;
 
 struct Tie_specification
@@ -78,6 +47,7 @@ class Tie_formatting_problem
 {
   Drul_array< vector<Skyline_entry> > chord_outlines_;
   Drul_array< Box > stem_extents_;
+  Drul_array< Box > head_extents_;
   set<int> dot_positions_;
   Interval dot_x_;
   vector<Tie_specification> specifications_;
@@ -87,21 +57,26 @@ class Tie_formatting_problem
   Grob *x_refpoint_;
 
   
-  Tie_configuration *get_configuration (int position, Direction dir);
+  Tie_configuration *get_configuration (int position, Direction dir) const;
   Tie_configuration *generate_configuration (int position, Direction dir) const;
-  vector<Tie_configuration_variation> get_variations (Ties_configuration const &ties);
-
-  Real score_configuration (Tie_configuration const &) const;
-  Real score_aptitude (Tie_configuration const &, Tie_specification const &) const;
-  Real score_ties_aptitude (Ties_configuration const &ties) const;
-  Real score_ties_configuration (Ties_configuration const &ties) const;
+  vector<Tie_configuration_variation> generate_collision_variations (Ties_configuration const &ties) const;
+  vector<Tie_configuration_variation> generate_extremal_tie_variations (Ties_configuration const &ties) const;
+
+  void score_configuration (Tie_configuration *) const;
+  Real score_aptitude (Tie_configuration *, Tie_specification const &,
+		       Ties_configuration *, int) const;
+  void score_ties_aptitude (Ties_configuration *ties) const;
+  void score_ties_configuration (Ties_configuration *ties) const;
   void set_ties_config_standard_directions (Ties_configuration *tie_configs_ptr);
-  Real score_ties (Ties_configuration const&) const;
-  Ties_configuration generate_base_chord_configuration ();
+  void score_ties (Ties_configuration *) const;
   
+  Ties_configuration generate_base_chord_configuration ();
+  Ties_configuration find_best_variation (Ties_configuration const &base,
+					  vector<Tie_configuration_variation> vars);
+
 public:
   Tie_details details_;
-
+  void print_ties_configuration (Ties_configuration const *);
 public:
   Tie_formatting_problem ();
   ~Tie_formatting_problem ();
diff --git a/lily/include/tie.hh b/lily/include/tie.hh
index 6ca5d3da04..5b3706dafd 100644
--- a/lily/include/tie.hh
+++ b/lily/include/tie.hh
@@ -24,13 +24,7 @@ public:
   static Grob *head (Grob *, Direction);
   static int get_column_rank (Grob *, Direction);
   static int get_position (Grob *);
-  static Direction get_default_dir (Grob *);
-
-#if 0
-  static void get_configuration (Grob *, Tie_configuration *,
-				 Tie_formatting_problem const &);
-#endif
-  
+  static Direction get_default_dir (Grob *);  
   static void set_control_points (Grob *, Grob *,
 				  Tie_configuration const&,
 				  Tie_details const&);
diff --git a/lily/tie-column.cc b/lily/tie-column.cc
index 68639605d3..e8384f1855 100644
--- a/lily/tie-column.cc
+++ b/lily/tie-column.cc
@@ -10,6 +10,7 @@
 
 #include <cmath>
 
+#include "output-def.hh"
 #include "skyline.hh"
 #include "warn.hh"
 #include "paper-column.hh"
@@ -100,6 +101,25 @@ Tie_column::calc_positioning_done (SCM smob)
 			       problem.details_);
       set_grob_direction (ties[i],
 			  base[i].dir_);
+
+#if DEBUG_TIE_SCORING
+      if (to_boolean (me->layout ()
+		      ->lookup_variable (ly_symbol2scm ("debug-tie-scoring"))))
+	{
+	  string card = to_string ("%d (%.2f): ", base[i].position_, base[i].delta_y_)
+	    + base[i].card () + base.tie_card (i);
+
+	  
+	  if (i == 0)
+	    card += base.card ();
+	  if (i == base.size () - 1)
+	    card += to_string ("TOTAL=%.2f", base.score ());
+	  
+	  ties[i]->set_property ("quant-score",
+				 scm_makfrom0str (card.c_str ()));
+	}
+#endif
+      
     }
   return SCM_BOOL_T;
 }
diff --git a/lily/tie-configuration.cc b/lily/tie-configuration.cc
index 1f0b388db2..c8f9da20de 100644
--- a/lily/tie-configuration.cc
+++ b/lily/tie-configuration.cc
@@ -27,6 +27,8 @@ Tie_configuration::Tie_configuration ()
   dir_ = CENTER;
   position_ = 0;
   delta_y_ = 0.0;
+  score_ = 0.0;
+  scored_ = false;
 }
 
 
@@ -83,6 +85,16 @@ Tie_configuration::distance (Tie_configuration const &a,
     return d + (2 + (a.dir_ - b.dir_));
 }
 
+
+void
+Tie_configuration::add_score (Real s, string desc)
+{
+  assert (!scored_);
+  score_ += s;
+  if (s)
+    score_card_ += to_string ("%s=%.2f ", desc.c_str (), s);
+}
+
 Real
 Tie_configuration::height (Tie_details const &details) const
 {
@@ -92,3 +104,53 @@ Tie_configuration::height (Tie_details const &details) const
 		     details.height_limit_,
 		     details.ratio_).curve_point (0.5)[Y_AXIS]; 
 }
+
+Ties_configuration::Ties_configuration()
+{
+  score_ = 0.0;
+  scored_ = false;
+}
+
+void
+Ties_configuration::reset_score ()
+{
+  score_ = 0.0;
+  scored_ = false;
+  score_card_ = "";
+  tie_score_cards_.clear ();
+}
+
+void
+Ties_configuration::add_tie_score (Real s, int i, string desc)
+{
+  assert (!scored_);
+  score_ += s;
+  if (s)
+    {
+      while (tie_score_cards_.size () < size ())
+	tie_score_cards_.push_back ("");
+
+      tie_score_cards_[i] += to_string ("%s=%.2f ", desc.c_str (), s);
+    }
+}
+
+void
+Ties_configuration::add_score (Real s, string desc)
+{
+  assert (!scored_);
+  score_ += s;
+  if (s)
+    score_card_ += to_string ("%s=%.2f ", desc.c_str (), s);
+}
+
+Real
+Ties_configuration::score () const
+{
+  return score_;
+}
+
+string
+Ties_configuration::card () const
+{
+  return score_card_;
+}
diff --git a/lily/tie-formatting-problem.cc b/lily/tie-formatting-problem.cc
index 9e2252e3f7..f1fc922441 100644
--- a/lily/tie-formatting-problem.cc
+++ b/lily/tie-formatting-problem.cc
@@ -32,6 +32,20 @@ Real peak_around (Real epsilon,  Real threshold, Real x)
   return max (- epsilon * (x - threshold) / ((x + epsilon)  * threshold), 0.0);
 }
 
+void
+Tie_formatting_problem::print_ties_configuration (Ties_configuration const *ties)
+{
+  for (vsize i = 0; i < ties->size (); i++)
+    {
+      char const *man_pos = (specifications_[i].has_manual_position_) ? "(M)" : "";
+      char const *man_dir = (specifications_[i].has_manual_dir_) ? "(M)" : "";
+      char const *dir = (ties->at (i).dir_ == UP) ? "up" : "dn";
+      
+      printf ("(P%d%s, %s%s) ", ties->at (i).position_, man_pos, dir, man_dir);
+    }
+  printf ("\n");
+}
+
 Interval
 Tie_formatting_problem::get_attachment (Real y) const
 {
@@ -60,7 +74,7 @@ Tie_formatting_problem::~Tie_formatting_problem ()
 
 void
 Tie_formatting_problem::set_chord_outline (vector<Item*> bounds,
-					   Direction d)
+					   Direction dir)
 {
   Real staff_space = Staff_symbol_referencer::staff_space (bounds[0]);
 
@@ -86,7 +100,7 @@ Tie_formatting_problem::set_chord_outline (vector<Item*> bounds,
       boxes.push_back (Box (x, y));
 
       Grob *dots = Rhythmic_head::get_dots (head);
-      if (d == LEFT && dots)
+      if (dir == LEFT && dots)
 	{
 	  Interval x = dots->extent (x_refpoint_, X_AXIS);
 	  int p = int (Staff_symbol_referencer::get_position (dots));
@@ -101,16 +115,16 @@ Tie_formatting_problem::set_chord_outline (vector<Item*> bounds,
 	}
     }
 
-  chord_outlines_[d] = empty_skyline (-d);
+  chord_outlines_[dir] = empty_skyline (-dir);
   if (bounds[0]->break_status_dir ())
     {
-      Real x = robust_relative_extent (bounds[0],  x_refpoint_, X_AXIS)[-d];
-      chord_outlines_[d].at (0).height_ = x; 
+      Real x = robust_relative_extent (bounds[0],  x_refpoint_, X_AXIS)[-dir];
+      chord_outlines_[dir].at (0).height_ = x; 
     }
 	  
   for (vsize i = 0; i < boxes.size (); i++)
-    insert_extent_into_skyline (&chord_outlines_[d]  ,
-				boxes[i], Y_AXIS, -d);
+    insert_extent_into_skyline (&chord_outlines_[dir]  ,
+				boxes[i], Y_AXIS, -dir);
 
   if (stem
       && !Stem::is_invisible (stem))
@@ -125,16 +139,16 @@ Tie_formatting_problem::set_chord_outline (vector<Item*> bounds,
       y.add_point (Stem::head_positions (stem)[-stemdir]
 		   * staff_space * .5);
 	  
-      insert_extent_into_skyline (&chord_outlines_[d], Box (x,y), Y_AXIS, -d);
+      insert_extent_into_skyline (&chord_outlines_[dir], Box (x,y), Y_AXIS, -dir);
 
-      stem_extents_[d].unite (Box (x,y));
+      stem_extents_[dir].unite (Box (x,y));
 
-      if (d == LEFT)
+      if (dir == LEFT)
 	{
 	  Box flag_box = Stem::get_translated_flag (stem).extent_box ();
 	  flag_box.translate( Offset (x[RIGHT], X_AXIS));
-	  insert_extent_into_skyline (&chord_outlines_[d], flag_box,
-				      Y_AXIS, -d);
+	  insert_extent_into_skyline (&chord_outlines_[dir], flag_box,
+				      Y_AXIS, -dir);
 	}
     }
   
@@ -147,17 +161,23 @@ Tie_formatting_problem::set_chord_outline (vector<Item*> bounds,
 	{
 	  Box b = boundary (head_boxes, updowndir, 0);
 	  x = b[X_AXIS];
-	  x[-d] =  b[X_AXIS].linear_combination (-d / 2);
+	  x[-dir] =  b[X_AXIS].linear_combination (-dir / 2);
 	  y[-updowndir] = b[Y_AXIS][updowndir];
 	  y[updowndir] = updowndir * infinity_f;
 	}
 
       if (!x.is_empty ())
-	insert_extent_into_skyline (&chord_outlines_[d],
+	insert_extent_into_skyline (&chord_outlines_[dir],
 				    Box (x,y),
-				    Y_AXIS, -d);
+				    Y_AXIS, -dir);
     }
   while (flip (&updowndir) != DOWN);
+  
+  head_extents_[dir].set_empty ();
+  for (vsize i = 0; i < head_boxes.size (); i++)
+    {
+      head_extents_[dir].unite (head_boxes[i]);
+    }
 }
 
 
@@ -289,7 +309,7 @@ Tie_formatting_problem::get_tie_specification (int i) const
 
 
 Tie_configuration*
-Tie_formatting_problem::get_configuration (int pos, Direction dir) 
+Tie_formatting_problem::get_configuration (int pos, Direction dir) const
 {
   pair<int,int> key (pos, dir);
   Tie_configuration_map::const_iterator f = possibilities_.find (key);
@@ -301,7 +321,7 @@ Tie_formatting_problem::get_configuration (int pos, Direction dir)
 
   
   Tie_configuration *conf = generate_configuration (pos, dir);
-  possibilities_[key] = conf;
+  ((Tie_formatting_problem*) this)->possibilities_[key] = conf;
   return conf;
 }
 
@@ -313,31 +333,31 @@ Tie_formatting_problem::generate_configuration (int pos, Direction dir) const
   conf->dir_ = dir;
   Real y = conf->position_ * 0.5 * details_.staff_space_;
 
+
+  bool y_tune = true;
   if (dot_positions_.find (pos) != dot_positions_.end ())
     {
       conf->delta_y_ += 0.25 * details_.staff_space_;
+      y_tune = false;
     }
+		
+	   
   
-  conf->attachment_x_ = get_attachment (y + conf->delta_y_);
-
-  Real h =  conf->height (details_);
-
-  if (h <  details_.intra_space_threshold_ * 0.5 * details_.staff_space_)
+  if (y_tune
+      && max (fabs (head_extents_[LEFT][Y_AXIS][dir] - y),
+	      fabs (head_extents_[RIGHT][Y_AXIS][dir] - y)) < 0.25
+      && !Staff_symbol_referencer::on_line (details_.staff_symbol_referencer_, pos))
     {
-      /*
-	This is less sensible for long ties, since those are more
-	horizontal.
-      */
-      Interval close_by = get_attachment (y
-					  + conf->delta_y_
-					  + (dir * details_.intra_space_threshold_ * 0.25
-					     * details_.staff_space_));
-      
-      conf->attachment_x_.intersect (close_by);
+      conf->delta_y_ =
+	(head_extents_[LEFT][Y_AXIS][dir] - y)
+	+ dir * details_.outer_tie_vertical_gap_;
     }
-  
-  if (!conf->delta_y_)
+
+  if (y_tune)
     {
+      conf->attachment_x_ = get_attachment (y + conf->delta_y_);
+      Real h =  conf->height (details_);
+      
       /*
 	TODO:
 
@@ -378,11 +398,21 @@ Tie_formatting_problem::generate_configuration (int pos, Direction dir) const
 	}
     }
   
-  /*
-    we don't recompute attachment_x_ to take changed Y (through
-    delta_Y) into account. Doing would make ties go into small holes between heads, which
-    means we get collisions with neighboring heads.
-   */
+  conf->attachment_x_ = get_attachment (y + conf->delta_y_);
+  if (conf->height (details_) < details_.intra_space_threshold_ * 0.5 * details_.staff_space_)
+    {
+      /*
+	This is less sensible for long ties, since those are more
+	horizontal.
+      */
+      Interval close_by = get_attachment (y
+					  + conf->delta_y_
+					  + (dir * details_.intra_space_threshold_ * 0.25
+					     * details_.staff_space_));
+      
+      conf->attachment_x_.intersect (close_by);
+    }
+
   conf->attachment_x_.widen ( - details_.x_gap_);
 
   Direction d = LEFT;
@@ -401,19 +431,34 @@ Tie_formatting_problem::generate_configuration (int pos, Direction dir) const
   return conf;
 }
 
+/**
+   TIE_IDX and TIES_CONF are optional.
+ */
 Real
-Tie_formatting_problem::score_aptitude (Tie_configuration const &conf,
-					Tie_specification const &spec) const
+Tie_formatting_problem::score_aptitude (Tie_configuration *conf,
+					Tie_specification const &spec,
+					Ties_configuration *ties_conf, int tie_idx) const
 {
   Real penalty = 0.0;
-  Real curve_y = conf.position_ * details_.staff_space_ * 0.5 + conf.delta_y_;
+  Real curve_y = conf->position_ * details_.staff_space_ * 0.5 + conf->delta_y_;
   Real tie_y = spec.position_ * details_.staff_space_ * 0.5;
-  if (sign (curve_y - tie_y) != conf.dir_)
-    penalty += details_.wrong_direction_offset_penalty_;
-
-  penalty += details_.vertical_distance_penalty_factor_ * fabs (curve_y - tie_y);
-
+  if (sign (curve_y - tie_y) != conf->dir_)
+    {
+      Real p =  details_.wrong_direction_offset_penalty_;
+      if (ties_conf)
+	ties_conf->add_tie_score (p, tie_idx, "wrong dir");
+      else
+	penalty += p;
+    }
 
+  {
+    Real p = details_.vertical_distance_penalty_factor_ * fabs (curve_y - tie_y);
+    if (ties_conf)
+      ties_conf->add_tie_score (p, tie_idx, "vdist");
+    else
+      penalty += p; 
+  }
+  
   Direction d = LEFT;
   do
     {
@@ -421,49 +466,64 @@ Tie_formatting_problem::score_aptitude (Tie_configuration const &conf,
 	continue;
       
       Interval head_x = spec.note_head_drul_[d]->extent (x_refpoint_, X_AXIS);
-      Real dist = head_x.distance (conf.attachment_x_[d]);
-      penalty += details_.horizontal_distance_penalty_factor_ * dist;
+      Real dist = head_x.distance (conf->attachment_x_[d]);
+
+      /*
+	TODO: flatten with log or sqrt.
+       */
+      Real p = details_.horizontal_distance_penalty_factor_ * dist;
+      if (ties_conf)
+	ties_conf->add_tie_score (p, tie_idx,
+				  (d == LEFT) ? "lhdist" : "rhdist");
+      else
+	penalty += p;
     }
-  while  (flip (&d) != LEFT);
+  while (flip (&d) != LEFT);
 
   return penalty;
 }
 
-Real
-Tie_formatting_problem::score_configuration (Tie_configuration const &conf) const
+void
+Tie_formatting_problem::score_configuration (Tie_configuration *conf) const
 {
-  Real penalty = 0.0;
-  Real length = conf.attachment_x_.length ();
-
-  penalty +=
-    details_.min_length_penalty_factor_
-    * peak_around (0.33 * details_.min_length_, details_.min_length_, length);
+  if (conf->scored_)
+    {
+      return ;
+    }
+  
+  Real length = conf->attachment_x_.length ();
 
-  Real tip_pos = conf.position_ + conf.delta_y_ / 0.5 * details_.staff_space_;
+  conf->add_score (details_.min_length_penalty_factor_
+		   * peak_around (0.33 * details_.min_length_, details_.min_length_, length),
+		   "minlength");
+  
+  Real tip_pos = conf->position_ + conf->delta_y_ / 0.5 * details_.staff_space_;
   Real tip_y = tip_pos * details_.staff_space_ * 0.5;
-  Real height =  conf.height (details_);
+  Real height =  conf->height (details_);
 
-  Real top_y = tip_y + conf.dir_ * height;
+  Real top_y = tip_y + conf->dir_ * height;
   Real top_pos = 2 * top_y / details_.staff_space_;
   Real round_top_pos = rint (top_pos);
   if (Staff_symbol_referencer::on_line (details_.staff_symbol_referencer_,
 						int (round_top_pos))
       && Staff_symbol_referencer::staff_radius (details_.staff_symbol_referencer_) > top_y)
     {
-      penalty +=
+      conf->add_score (
 	details_.staff_line_collision_penalty_
 	* peak_around (0.1 * details_.center_staff_line_clearance_,
 		     details_.center_staff_line_clearance_,
-		     fabs (top_pos - round_top_pos));
+		       fabs (top_pos - round_top_pos)),
+	"line center");
     }
   
   if (Staff_symbol_referencer::on_line (details_.staff_symbol_referencer_,
 					int (rint (tip_pos))))
     {
-      penalty += details_.staff_line_collision_penalty_
-	* peak_around (0.1 * details_.tip_staff_line_clearance_,
-		       details_.tip_staff_line_clearance_,
-		       fabs (tip_pos - rint (tip_pos)));
+      conf->add_score (details_.staff_line_collision_penalty_
+		       * peak_around (0.1 * details_.tip_staff_line_clearance_,
+				      details_.tip_staff_line_clearance_,
+				      fabs (tip_pos - rint (tip_pos))),
+		       "tipline");
     }
 
   if (!dot_x_.is_empty ())
@@ -471,7 +531,7 @@ Tie_formatting_problem::score_configuration (Tie_configuration const &conf) cons
       /* use left edge? */
       Real x = dot_x_.center ();
       
-      Bezier b = conf.get_transformed_bezier (details_);
+      Bezier b = conf->get_transformed_bezier (details_);
       if (b.control_point_extent (X_AXIS).contains (x))
 	{
 	  Real y = b.get_other_coordinate (X_AXIS, x);
@@ -480,16 +540,16 @@ Tie_formatting_problem::score_configuration (Tie_configuration const &conf) cons
 	       i != dot_positions_.end (); i ++)
 	    {
 	      int dot_pos = (*i);
-	      penalty +=
-		details_.dot_collision_penalty_
+	      conf->add_score (details_.dot_collision_penalty_
 		* peak_around (.1 * details_.dot_collision_clearance_,
 			       details_.dot_collision_clearance_,
-			       fabs (dot_pos * details_.staff_space_ * 0.5 - y)); 
+			       fabs (dot_pos * details_.staff_space_ * 0.5 - y)),
+			       "dot collision");
 	    }
 	}
     }
-  
-  return penalty;
+
+  conf->scored_ = true;
 }
 
 Tie_configuration
@@ -500,8 +560,7 @@ Tie_formatting_problem::find_optimal_tie_configuration (Tie_specification const
   int pos = spec.position_;
   Direction dir = spec.manual_dir_;
 
-  int region_size = 3;
-  for (int i = 0; i < region_size; i ++)
+  for (int i = 0; i < details_.single_tie_region_size_; i ++)
     {
       confs.push_back (generate_configuration (pos + i * dir, dir));
     }
@@ -512,9 +571,9 @@ Tie_formatting_problem::find_optimal_tie_configuration (Tie_specification const
   Real best_score = 1e6;
   for (vsize i = 0; i < confs.size (); i ++)
     {
-      Real score = 0.0;
-      score += score_configuration (*confs[i]);
-      score += score_aptitude (*confs[i], spec);
+      score_configuration (confs[i]);
+      Real score = score_aptitude (confs[i], spec, 0, 0)
+	+ confs[i]->score ();
 
       if (score < best_score)
 	{
@@ -542,43 +601,45 @@ Tie_specification::Tie_specification ()
 }
 
 
-Real
-Tie_formatting_problem::score_ties_aptitude (Ties_configuration const &ties) const
+void
+Tie_formatting_problem::score_ties_aptitude (Ties_configuration *ties) const
 {
-  Real score = 0.0;
-  if  (ties.size () != specifications_.size ())
+  if  (ties->size () != specifications_.size ())
     {
       programming_error ("Huh? Mismatch between sizes.");
-      return infinity_f;
+      return;
     }
 
-  for (vsize i = 0; i < ties.size (); i++)
-    score += score_aptitude (ties[i], specifications_[i]);
-
-  return score;
+  for (vsize i = 0; i < ties->size (); i++)
+    score_aptitude (&ties->at (i), specifications_[i],
+		    ties, i);
 }
 
-Real
-Tie_formatting_problem::score_ties (Ties_configuration const &ties) const
+void
+Tie_formatting_problem::score_ties (Ties_configuration *ties) const
 {
-  return score_ties_configuration (ties)
-    + score_ties_aptitude (ties);
+  if (ties->scored_)
+    return;
+  
+  score_ties_configuration (ties);
+  score_ties_aptitude (ties);
+  ties->scored_ = true;
 }
 
-Real
-Tie_formatting_problem::score_ties_configuration (Ties_configuration const &ties) const
+void
+Tie_formatting_problem::score_ties_configuration (Ties_configuration *ties) const
 {
-  Real score = 0.0;
-  for (vsize i = 0; i < ties.size (); i++)
+  for (vsize i = 0; i < ties->size (); i++)
     {
-      score += score_configuration (ties[i]);
+      score_configuration (&ties->at (i));
+      ties->add_tie_score (ties->at (i).score (), i, "conf");
     }
-
+  
   Real last_edge = 0.0;
   Real last_center = 0.0;
-  for (vsize i = 0; i < ties.size (); i++)
+  for (vsize i = 0; i < ties->size (); i++)
     {
-      Bezier b (ties[i].get_transformed_bezier (details_));
+      Bezier b (ties->at (i).get_transformed_bezier (details_));
 	
       Real center = b.curve_point (0.5)[Y_AXIS];
       Real edge = b.curve_point (0.0)[Y_AXIS];
@@ -586,40 +647,38 @@ Tie_formatting_problem::score_ties_configuration (Ties_configuration const &ties
       if (i)
 	{
 	  if (edge <= last_edge)
-	    score += details_.tie_column_monotonicity_penalty_;
+	    ties->add_score (details_.tie_column_monotonicity_penalty_, "monoton edge");
 	  if (center <= last_center)
-	    score += details_.tie_column_monotonicity_penalty_;
-
-	  score +=
-	    details_.tie_tie_collision_penalty_ *
-	    peak_around (0.1 * details_.tie_tie_collision_distance_,
-			 details_.tie_tie_collision_distance_,
-			 fabs (center - last_center));
-	  score +=
-	    details_.tie_tie_collision_penalty_ *
-	    peak_around (0.1 * details_.tie_tie_collision_distance_,
-			 details_.tie_tie_collision_distance_,
-			 fabs (edge - last_edge));
+	    ties->add_score (details_.tie_column_monotonicity_penalty_, "monoton cent");
+
+	  ties->add_score (details_.tie_tie_collision_penalty_ *
+			   peak_around (0.1 * details_.tie_tie_collision_distance_,
+					details_.tie_tie_collision_distance_,
+					fabs (center - last_center)),
+			   "tietie center");
+	  ties->add_score (details_.tie_tie_collision_penalty_ *
+			   peak_around (0.1 * details_.tie_tie_collision_distance_,
+					details_.tie_tie_collision_distance_,
+					fabs (edge - last_edge)), "tietie edge");
 	}
 
       last_edge = edge;
       last_center = center;
     }
 
-
-  score +=
-    details_.outer_tie_length_symmetry_penalty_factor_
-    * fabs (ties[0].attachment_x_.length () - ties.back ().attachment_x_.length ());
-  
-  score +=
-    details_.outer_tie_vertical_distance_symmetry_penalty_factor_
-    * (fabs (specifications_[0].position_
-	     - (ties[0].position_ * 0.5 * details_.staff_space_ + ties[0].delta_y_))
-       -
-       fabs (specifications_.back ().position_
-	     - (ties.back ().position_ * 0.5 * details_.staff_space_ + ties.back ().delta_y_)));
+  ties->add_score (details_.outer_tie_length_symmetry_penalty_factor_
+		   * fabs (ties->at (0).attachment_x_.length () - ties->back ().attachment_x_.length ()),
+		   "length symm");
   
-  return score;
+  ties->add_score (details_.outer_tie_vertical_distance_symmetry_penalty_factor_
+		   * fabs (fabs (specifications_[0].position_ * 0.5 * details_.staff_space_
+				 - (ties->at (0).position_ * 0.5 * details_.staff_space_
+				    + ties->at (0).delta_y_))
+			   -
+			   fabs (specifications_.back ().position_ * 0.5 * details_.staff_space_
+				 - (ties->back ().position_ * 0.5 * details_.staff_space_
+				    + ties->back ().delta_y_))),
+		   "pos symmetry");
 }
 
 /*
@@ -678,33 +737,48 @@ Tie_formatting_problem::generate_base_chord_configuration ()
 }
 
 Ties_configuration
-Tie_formatting_problem::generate_optimal_chord_configuration ()
+Tie_formatting_problem::find_best_variation (Ties_configuration const &base,
+					     vector<Tie_configuration_variation> vars)
 {
-  Ties_configuration base = generate_base_chord_configuration ();
-  vector<Tie_configuration_variation> vars = get_variations (base);
-
   Ties_configuration best = base;
-  Real best_score = score_ties (best);
-
+  
   /*
     This simply is 1-opt: we have K substitions, and we try applying
     exactly every one for each.
   */
   for (vsize i = 0; i < vars.size (); i++)
     {
-      Ties_configuration variant = base;
+      Ties_configuration variant (base);
       variant[vars[i].index_] = *vars[i].suggestion_;
 
-      Real score = score_ties (variant);
-      if (score < best_score)
+      variant.reset_score ();
+      score_ties (&variant);
+      
+      if (variant.score () < best.score ())
 	{
 	  best = variant;
-	  best_score = score;
 	}
     }
 
   return best;
 }
+  
+				       
+
+Ties_configuration
+Tie_formatting_problem::generate_optimal_chord_configuration ()
+{
+  
+  Ties_configuration base = generate_base_chord_configuration ();
+  vector<Tie_configuration_variation> vars = generate_collision_variations (base);
+  
+  score_ties (&base);
+  Ties_configuration best = find_best_variation (base, vars);
+  vars = generate_extremal_tie_variations (best);
+  best = find_best_variation (best, vars);
+
+  return best;
+}
 
 void
 Tie_formatting_problem::set_ties_config_standard_directions (Ties_configuration *tie_configs)
@@ -756,7 +830,31 @@ Tie_configuration_variation::Tie_configuration_variation ()
 }
 
 vector<Tie_configuration_variation>
-Tie_formatting_problem::get_variations (Ties_configuration const &ties) 
+Tie_formatting_problem::generate_extremal_tie_variations (Ties_configuration const &ties) const
+{
+  vector<Tie_configuration_variation> vars;
+  Direction d = DOWN;
+  do
+    {
+      if (boundary (ties, d, 0).dir_ == d
+	  && !boundary (specifications_, d, 0).has_manual_position_)
+	for (int i = 1; i <= details_.multi_tie_region_size_; i++)
+	  {
+	    Tie_configuration_variation var;
+	    var.index_ = (d == DOWN) ? 0 : ties.size () - 1;
+	    var.suggestion_ = get_configuration (boundary (ties, d, 0).position_
+						 + d * i, d);
+	    vars.push_back (var);
+	  }
+    }
+  while (flip (&d) !=  DOWN);
+
+  return vars;
+}
+
+
+vector<Tie_configuration_variation>
+Tie_formatting_problem::generate_collision_variations (Ties_configuration const &ties) const
 {
   Real center_distance_tolerance = 0.25;
   
@@ -793,6 +891,25 @@ Tie_formatting_problem::get_variations (Ties_configuration const &ties)
 
 		  vars.push_back (var);
 		}
+
+	      if (i == 1 && !specifications_[i-1].has_manual_position_
+		  && ties[i-1].dir_ == DOWN)
+		{
+		  Tie_configuration_variation var;
+		  var.index_ = i-1;
+		  var.suggestion_ = get_configuration (specifications_[i-1].position_
+						       - 1, DOWN);
+		  vars.push_back (var);
+		}
+	      if (i == ties.size() && !specifications_[i].has_manual_position_
+		  && ties[i].dir_ == UP)
+		{
+		  Tie_configuration_variation var;
+		  var.index_ = i;
+		  var.suggestion_ = get_configuration (specifications_[i].position_
+						       + 1, UP);
+		  vars.push_back (var);
+		}
 	    }
 	  else if (dot_positions_.find (ties[i].position_) != dot_positions_.end ()
 		   && !specifications_[i].has_manual_position_)
@@ -809,20 +926,6 @@ Tie_formatting_problem::get_variations (Ties_configuration const &ties)
       last_center = center;
     }
 
-  /* TODO: switch off? */
-  Direction d = DOWN;
-  do
-    {
-      if (boundary (ties, d, 0).dir_ == d)
-	{
-	  Tie_configuration_variation var;
-	  var.index_ = (d == DOWN) ? 0 : ties.size () - 1;
-	  var.suggestion_ = get_configuration (boundary (ties, d, 0).position_
-					       + d, d);
-	  vars.push_back (var);
-	}
-    }
-  while (flip (&d) !=  DOWN);
 
   return vars;
 }
diff --git a/lily/tie-helper.cc b/lily/tie-helper.cc
index 00c8bea035..e69de29bb2 100644
--- a/lily/tie-helper.cc
+++ b/lily/tie-helper.cc
@@ -1,67 +0,0 @@
-/*
-  tie-helper.cc -- implement Tie_configuration, Tie_details
-
-  source file of the GNU LilyPond music typesetter
-
-  (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
-
-*/
-
-#include "tie.hh"
-#include "bezier.hh"
-#include "grob.hh"
-#include "staff-symbol-referencer.hh"
-#include "warn.hh"
-#include "tie-formatting-problem.hh"
-
-
-/*
-  this is a macro because we want ly_symbol2scm() 
- */
-#define get_real_detail(src, defvalue) \
-  robust_scm2double(ly_assoc_get (ly_symbol2scm (src), details, SCM_EOL), defvalue)
-
-void
-Tie_details::from_grob (Grob *me)
-{
-  staff_symbol_referencer_ = me;
-  staff_space_ = Staff_symbol_referencer::staff_space (me);
-
-  SCM details = me->get_property ("details");
-
-  height_limit_ = get_real_detail("height-limit", 0.75);
-  ratio_ = get_real_detail("ratio", .333);  
-  between_length_limit_ = get_real_detail ("between-length-limit", 1.0);
-  
-  wrong_direction_offset_penalty_ = get_real_detail("wrong-direction-offset-penalty", 10);
-  
-  min_length_ = get_real_detail("min-length", 1.0);
-  min_length_penalty_factor_ = get_real_detail("min-length-penalty-factor", 1.0);
-
-
-  // in half-space
-  center_staff_line_clearance_ = get_real_detail ("center-staff-line-clearance", 0.4);
-  tip_staff_line_clearance_ = get_real_detail ("tip-staff-line-clearance", 0.4);
-  staff_line_collision_penalty_ = get_real_detail("staff-line-collision-penalty", 5);
-  dot_collision_clearance_ = get_real_detail ( "dot-collision-clearance", 0.25);
-  dot_collision_penalty_ = get_real_detail ( "dot-collision-penalty", 0.25);
-  x_gap_ = get_real_detail ("note-head-gap", 0.2);
-  stem_gap_ = get_real_detail ("stem-gap", 0.3);
-  tie_column_monotonicity_penalty_ = get_real_detail ("tie-column-monotonicity-penalty", 100);
-  tie_tie_collision_penalty_ = get_real_detail ("tie-tie-collision-penalty", 30);
-  tie_tie_collision_distance_ = get_real_detail ("tie-tie-collision-distance", .25);
-  horizontal_distance_penalty_factor_ = get_real_detail ("horizontal-distance-penalty-factor", 5);
-  vertical_distance_penalty_factor_ = get_real_detail ("vertical-distance-penalty-factor", 5);
-  intra_space_threshold_ = get_real_detail ("intra-space-threshold", 1.0);
-  outer_tie_length_symmetry_penalty_factor_ = get_real_detail ("outer-tie-length-symmetry-penalty-factor", 3.0);
-  outer_tie_vertical_distance_symmetry_penalty_factor_ = get_real_detail ("outer-tie-vertical-distance-symmetry-penalty-factor", 3.0);
-  
-}
-
-Tie_details::Tie_details ()
-{
-  staff_space_ = 1.0; 
-  height_limit_ = 1.0;
-  ratio_ = .333;   
-}
-
diff --git a/lily/tie.cc b/lily/tie.cc
index e0c17aa912..e14074dc4f 100644
--- a/lily/tie.cc
+++ b/lily/tie.cc
@@ -7,22 +7,25 @@
 */
 
 #include "tie.hh"
-#include "spanner.hh"
+
+#include "main.hh"
+#include "bezier.hh"
+#include "directional-element-interface.hh"
+#include "font-interface.hh"
+#include "grob-array.hh"
 #include "lookup.hh"
+#include "note-head.hh"
 #include "output-def.hh"
-#include "rhythmic-head.hh"
-#include "bezier.hh"
 #include "paper-column.hh"
-#include "warn.hh"
+#include "rhythmic-head.hh"
+#include "spanner.hh"
 #include "staff-symbol-referencer.hh"
-#include "directional-element-interface.hh"
-#include "bezier.hh"
 #include "stem.hh"
-#include "note-head.hh"
+#include "text-interface.hh"
 #include "tie-column.hh"
-#include "grob-array.hh"
-#include "tie-formatting-problem.hh"
 #include "tie-configuration.hh"
+#include "tie-formatting-problem.hh"
+#include "warn.hh"
 
 
 int
@@ -248,6 +251,24 @@ Tie::print (SCM smob)
 		      get_grob_direction (me) * base_thick,
 		      line_thick);
 
+#if DEBUG_TIE_SCORING
+  SCM quant_score = me->get_property ("quant-score");
+
+  if (to_boolean (me->layout ()
+		  ->lookup_variable (ly_symbol2scm ("debug-tie-scoring")))
+      && scm_is_string (quant_score))
+    {
+      string str;
+      SCM properties = Font_interface::text_font_alist_chain (me);
+
+      Stencil tm = *unsmob_stencil (Text_interface::interpret_markup
+				    (me->layout ()->self_scm (), properties,
+				     quant_score));
+      tm.translate_axis (b.control_[0][Y_AXIS]*2, Y_AXIS);
+      a.add_at_edge (X_AXIS, RIGHT, tm, 1.0, 0);
+    }
+#endif
+
   return a.smobbed_copy ();
 }
 
diff --git a/python/convertrules.py b/python/convertrules.py
index ad4ab9ae1d..9f3a492ea0 100644
--- a/python/convertrules.py
+++ b/python/convertrules.py
@@ -2739,3 +2739,10 @@ def conv (str):
 
 conversions.append (((2, 7, 32), conv,
 		     """foobar -> foo-bar for \paper, \layout"""))
+
+def conv (str):
+	str = re.sub ('debug-beam-quanting', 'debug-beam-scoring', str)
+	return str
+
+conversions.append (((2, 7, 32), conv,
+		     """debug-beam-quanting -> debug-beam-scoring"""))
diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm
index fcd6efa237..5cf7e49080 100644
--- a/scm/define-grob-properties.scm
+++ b/scm/define-grob-properties.scm
@@ -507,7 +507,15 @@ where this is set in.")
      (heads ,ly:grob-array? "List of note heads.")
      (items-worth-living ,ly:grob-array? "A list of interesting items. If
 empty in a particular staff, then that staff is erased.")
-     (details ,list? "alist of parameters for detailed grob behavior.")
+     (details ,list? "alist of parameters for detailed grob behavior.
+
+more information on the allowed parameters can be found by inspecting
+lily/slur-scoring.cc, lily/beam-quanting.cc, and
+lily/tie-formatting-problem.cc.  Setting @code{debug-tie-scoring},
+@code{debug-beam-scoring} or @code{debug-slur-scoring} also provides
+useful clues.
+
+")
      (note-heads ,ly:grob-array? "List of note head grobs")
      (note-head ,ly:grob? "A single note head")
      (side-support-elements ,ly:grob-array? "the support, a list of grobs.")
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index 5435161434..c76015ce9b 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -21,11 +21,9 @@
      . (
 	(avoid-slur . inside)
 	(cautionary-style . parentheses)
-
 	(stencil . ,ly:accidental-interface::print)
 	(after-line-breaking
 	 . ,ly:accidental-interface::after-line-breaking)
-					
 	(meta . ((class . Item)
 		 (interfaces . (accidental-interface
 				font-interface))))))
@@ -70,7 +68,6 @@
 	(axes . (0 1))
 	(X-extent . ,ly:axis-group-interface::width)
 	(X-extent . ,ly:axis-group-interface::height)
-
 	(space-alist . (
 			(clef . (extra-space . 0.5))
 			(key-signature . (extra-space . 0.0))
@@ -87,13 +84,10 @@
 
     (AmbitusLine
      . (
-
 	(stencil . ,ly:ambitus::print)
-
 	(join-heads . #t)
 	(thickness . 2)
 	(X-offset . ,ly:self-alignment-interface::centered-on-x-parent)
-
 	(meta . ((class . Item)
 		 (interfaces . (ambitus-interface
 				staff-symbol-referencer-interface
@@ -105,11 +99,9 @@
 	(X-offset . ,ly:side-position-interface::x-aligned-side)
 	(direction . ,LEFT)
 	(cautionary-style . parentheses)
-
 	(stencil . ,ly:accidental-interface::print)
 	(after-line-breaking . ,ly:accidental-interface::after-line-breaking)
 	(side-axis . ,X)
-	
 	(meta . ((class . Item)
 		 (interfaces . (item-interface
 				accidental-interface
@@ -120,10 +112,8 @@
     (AmbitusNoteHead
      . (
 	(duration-log . 2)
-
 	(stencil . ,ly:note-head::print)
 	(glyph-name . ,note-head::calc-glyph-name)
-	
 	(Y-offset . ,ly:staff-symbol-referencer::callback)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
@@ -209,9 +199,7 @@
 
     (BassFigure
      . (
-	;
 	(stencil . ,ly:text-interface::print)
-
 	(meta . ((class . Item)
 		 (interfaces . (text-interface
 				rhythmic-grob-interface
@@ -624,11 +612,8 @@
 	(breakable . #t)
 	(X-extent . #f)
 	(Y-extent . #f)
-
 	(stencil . ,ly:line-spanner::print)
 	(after-line-breaking . ,ly:line-spanner::after-line-breaking)
-	
-
 	(meta . ((class . Spanner)
 		 (interfaces . (line-interface
 				line-spanner-interface))))))
@@ -646,8 +631,10 @@
 	(stencil . ,ly:grid-line-interface::print)
 	(self-alignment-X . ,CENTER)
 	(X-offset . ,(ly:make-simple-closure
-		      `(,+  ,(ly:make-simple-closure (list ly:self-alignment-interface::centered-on-x-parent))
-			    ,(ly:make-simple-closure (list ly:self-alignment-interface::x-aligned-on-self)))))
+		      `(,+  ,(ly:make-simple-closure
+			      (list ly:self-alignment-interface::centered-on-x-parent))
+			    ,(ly:make-simple-closure
+			      (list ly:self-alignment-interface::x-aligned-on-self)))))
 	(layer . 0)
 	(meta . ((class . Item)
 		 (interfaces . (self-alignment-interface
@@ -757,9 +744,7 @@
     (LedgerLineSpanner
      . (
 	(springs-and-rods . ,ly:ledger-line-spanner::set-spacing-rods)
-
 	(stencil . ,ly:ledger-line-spanner::print)
-
 	(X-extent . #f)
 	(Y-extent . #f)
 	(minimum-length-fraction . 0.25)
@@ -818,9 +803,7 @@
 	(minimum-distance . 0.1)
 	(padding . 0.07)
 	(springs-and-rods . ,ly:hyphen-spanner::set-spacing-rods)
-	
 	(stencil . ,ly:hyphen-spanner::print)
-
 	(Y-extent . (0 . 0))
 	(meta . ((class . Spanner)
 		 (interfaces . (lyric-interface
@@ -830,9 +813,7 @@
 
     (LyricExtender
      . (
-
 	(stencil . ,ly:lyric-extender::print)
-
 	(thickness . 0.8) ; line-thickness
 	(minimum-length . 1.5)
 	(Y-extent . (0 . 0))
@@ -871,9 +852,7 @@
      . (
 	(Y-offset . ,ly:side-position-interface::y-aligned-side)
 	(side-axis . ,Y)
-
 	(stencil . ,ly:measure-grouping::print)
-
 	(padding . 2)
 	(direction . ,UP)
 	(thickness . 1)
@@ -893,7 +872,6 @@
 	(thickness . 1.4)
 	(flexa-width . 2.0)
 	(stencil . ,ly:mensural-ligature::print)
-
 	(meta . ((class . Spanner)
 		 (interfaces . (mensural-ligature-interface
 				font-interface))))))
@@ -939,7 +917,6 @@
 			   ,(ly:make-simple-closure (list ly:self-alignment-interface::x-centered-on-y-parent)))))
 	(Y-offset . ,ly:side-position-interface::y-aligned-side)
 	(side-axis . ,Y)
-
 	(self-alignment-X . 0)
 	(direction . ,UP)
 	(padding . 0.4)
@@ -975,11 +952,9 @@
     (NoteCollision
      . (
 	(axes . (0 1))
-
 	(X-extent . ,ly:axis-group-interface::width)
 	(Y-extent . ,ly:axis-group-interface::height)
 	(positioning-done . ,ly:note-collision-interface::calc-positioning-done)
-	
 	(meta . ((class . Item)
 		 (interfaces . (note-collision-interface
 				axis-group-interface))))))
@@ -989,14 +964,12 @@
 	(axes . (0 1))
 	(X-extent . ,ly:axis-group-interface::width)
 	(Y-extent . ,ly:axis-group-interface::height)
-
 	(meta . ((class . Item)
 		 (interfaces . (axis-group-interface
 				note-column-interface))))))
 
     (NoteHead
      . (
-
 	(stencil . ,ly:note-head::print)
 	(stem-attachment . ,ly:note-head::calc-stem-attachment)
 	(glyph-name . ,note-head::calc-glyph-name) 
@@ -1017,16 +990,13 @@
 	;; Changed this from 0.75.
 	;; If you ever change this back, please document! --hwn
 	(knee-spacing-correction . 1.0)
-
 	(meta . ((class . Item)
 		 (interfaces . (spacing-interface
 				note-spacing-interface))))))
 
     (NoteName
      . (
-
 	(stencil . ,ly:text-interface::print)
-
 	(meta . ((class . Item)
 		 (interfaces . (note-name-interface
 				text-interface
@@ -1041,10 +1011,8 @@
 			   ,(ly:make-simple-closure (list ly:self-alignment-interface::centered-on-x-parent)))))
 	
 	(Y-offset . ,ly:side-position-interface::y-aligned-side)
-
 	(stencil . ,ly:text-interface::print)
 
-
 	;; no Y dimensions, because of lyrics under tenor clef.
 	(Y-extent . (0 . 0))
 	(font-shape . italic)
@@ -1060,9 +1028,7 @@
     (OttavaBracket
      . (
 	(Y-offset . ,ly:side-position-interface::y-aligned-side)
-
 	(stencil . ,ly:ottava-bracket::print)
-
 	(font-shape . italic)
 	(shorten-pair . (0.0 . -0.6))
 	(staff-padding . 1.0)
@@ -1106,14 +1072,11 @@
 	      ))
     (PhrasingSlur
      . ((details . ,default-slur-details)
-
 	(control-points . ,ly:slur::calc-control-points)
 	(direction . ,ly:slur::calc-direction)
 	(springs-and-rods . ,ly:spanner::set-spacing-rods)
 	(Y-extent . ,ly:slur::height)
 	(stencil . ,ly:slur::print)		      
-	
-
 	(thickness . 1.1)
 	(minimum-length . 1.5)
 	(height-limit . 2.0)
@@ -1124,7 +1087,6 @@
     (NonMusicalPaperColumn
      . (
 	(axes . (0))
-
 	(before-line-breaking . ,ly:paper-column::before-line-breaking)
 	(X-extent . ,ly:axis-group-interface::width)
 	;;		      (stencil . ,ly:paper-column::print)
@@ -1141,10 +1103,8 @@
 
     (PercentRepeat
      . (
-
 	(springs-and-rods . ,ly:multi-measure-rest::set-spacing-rods)
 	(stencil . ,ly:multi-measure-rest::percent)
-
 	(slope . 1.0)
 	(thickness . 0.48)
 	(font-encoding . fetaMusic)
@@ -1175,9 +1135,7 @@
     ;; an example of a text spanner
     (PianoPedalBracket
      . (
-
 	(stencil . ,ly:piano-pedal-bracket::print)
-
 	(style . line)
 	(bound-padding . 1.0)
 	(direction . ,DOWN)
@@ -1240,7 +1198,6 @@
      . (
 	(minimum-distance . 0.75)
 	(positioning-done . ,ly:rest-collision::calc-positioning-done)
-					
 	(meta . ((class . Item)
 		 (interfaces . (rest-collision-interface))))))
 
@@ -1258,7 +1215,6 @@
 
 	(stencil . ,ly:script-interface::print)
 	(direction . ,ly:script-interface::calc-direction)
-
 	(font-encoding . fetaMusic)
 	(meta . ((class . Item)
 		 (interfaces . (script-interface
@@ -1267,9 +1223,7 @@
 
     (ScriptColumn
      . (
-
 	(before-line-breaking . ,ly:script-column::before-line-breaking)
-
 	(meta . ((class . Item)
 		 (interfaces . (script-column-interface))))))
 
@@ -1283,9 +1237,7 @@
 
     (SeparatingGroupSpanner
      . (
-
 	(springs-and-rods . ,ly:separating-group-spanner::set-spacing-rods)
-
 	(meta . ((class . Spanner)
 		 (interfaces . (only-prebreak-interface
 				spacing-interface
@@ -1293,17 +1245,14 @@
 
     (Slur
      . ((details . ,default-slur-details)
-
 	(control-points . ,ly:slur::calc-control-points)
 	(direction . ,ly:slur::calc-direction)
 	(springs-and-rods . ,ly:spanner::set-spacing-rods)
 	(Y-extent . ,ly:slur::height)
 	(stencil . ,ly:slur::print)
-	
 	(thickness . 1.2)
 	(line-thickness . 0.8)
 	(minimum-length . 1.5)
-					; ly:slur::height)
 	(height-limit . 2.0)
 	(ratio . 0.25)
 	(meta . ((class . Spanner)
@@ -1311,7 +1260,6 @@
 
     (SpacingSpanner
      . (
-
 	(springs-and-rods . ,ly:spacing-spanner::set-springs)
 	(average-spacing-wishes . #t)
 	(grace-space-factor . 0.6)
@@ -1328,7 +1276,6 @@
 	(Y-extent . ())
 	(layer . 0)
 	(breakable . #t)
-
 	(stencil . ,ly:span-bar::print)
 	(bar-size . ,ly:span-bar::calc-bar-size)
 	(X-extent . ,ly:span-bar::width)
@@ -1352,7 +1299,6 @@
     (StanzaNumber
      . (
 	(stencil . ,ly:text-interface::print)
-
 	(font-series . bold)
 	(padding . 1.0)
 	(X-offset . ,ly:side-position-interface::x-aligned-side)
@@ -1366,9 +1312,7 @@
 
     (StringNumber
      . (
-
 	(stencil . ,print-circled-text-callback)
-
 	(padding . 0.5)
 	(staff-padding . 0.5)
 	(self-alignment-X . 0)
@@ -1395,9 +1339,7 @@
 
     (SostenutoPedal
      . (
-
 	(stencil . ,ly:text-interface::print)
-
 	(direction . ,RIGHT)
 	(X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
 	(no-spacing-rods . #t)
@@ -1412,12 +1354,9 @@
     (SostenutoPedalLineSpanner
      . (
 	(axes . (1))
-
 	(X-extent . ,ly:axis-group-interface::height)
-
 	(Y-offset . ,ly:side-position-interface::y-aligned-side)
 	(side-axis . ,Y)
-
 	(padding . 1.2)
 	(minimum-space . 1.0)
 	(direction . ,DOWN)
@@ -1447,9 +1386,7 @@
 	(X-extent . ,ly:stem::width)
 	(Y-extent . ,ly:stem::height)
 	(length . ,ly:stem::calc-length)
-	
 	(thickness . 1.3)
-
 	(details
 	 . (
 	    ;; 3.5 (or 3 measured from note head) is standard length
@@ -1600,7 +1537,6 @@
 
     (TabNoteHead
      . (
-
 	(stencil . ,ly:text-interface::print)
 	(Y-offset . ,ly:staff-symbol-referencer::callback)
 	(font-size . -2)
@@ -1659,6 +1595,7 @@
 	(avoid-slur . inside)
 	(direction . ,ly:tie::calc-direction)
 	(stencil . ,ly:tie::print)
+	(font-size . -6)
 	(details . (
 		    ;; for a full list, see tie-helper.cc
 		    (ratio . 0.333)
@@ -1674,6 +1611,8 @@
 		    (intra-space-threshold . 1.25)
 		    (outer-tie-vertical-distance-symmetry-penalty-factor . 10)
 		    (outer-tie-length-symmetry-penalty-factor . 10)
+		    (outer-tie-vertical-gap . 0.25)
+		    (multi-tie-region-size . 1)
 		    (between-length-limit . 1.0)))
 	(thickness . 1.2)
 	(line-thickness . 0.8)