KHE diary for 2014
------------------

1 Jan 2014.  Written beautiful implementations of the time repair
  limit idle times and limit busy times augment functions.  Not
  tested yet.  I haven't done one for avoid clashes; demand augment
  is probably handling them for us.  Cluster busy times is still to
  do, and it's not obvious what to do about it.  Some kind of move of
  several meets, something like repairing avoid clashes constraints.

  First results of all this on IT-I4-96:

    KheGeneralSolve2014 at end (268.97 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 6.00556)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     3       3.00000
      AvoidUnavailableTimesMonitor           22       3.00090
      LimitIdleTimesMonitor                  24       0.00048
      LimitBusyTimesMonitor                   7       0.00418
      -------------------------------------------------------
      Total                                  56       6.00556
    ]

  Very slow, and not competitive with the result posted on
  Gerhard's web site, which has cost 0.00057.  Best of 8:

    KheGeneralSolve2014 at end (146.19 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 5, cost 1.00593)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor           28       0.00114
      LimitIdleTimesMonitor                  30       0.00055
      LimitBusyTimesMonitor                   8       0.00424
      -------------------------------------------------------
      Total                                  67       1.00593
    ]

  It's quite a lot better, but still a long way short.

2 Jan 2014.  Looking into the poor results for IT-I4-96.  I've
  discovered that KheLayerMatchMake does OK but that then
  KheLayerMatchImproveNodeRegularity introduces infeasibility,
  which surely was not the aim.  The problem arises when there
  are some zones but not every time is in a zone:  the NULL zone
  is not handled properly.  Fixed that now, essentially by
  making the NULL zone into a zone, and so KheLayerMatchAssignTimes
  is now assigning every meet, as it should always have done.  But
  what effect does that have on the overall performance?

  Perhaps it would be better to look through the layers and
  build and artificial set of zones that cover every time,
  then match every layer (even the first one) to those zones.

  Anyway here is the result of the fixed version:

    KheGeneralSolve2014 at end (360.23 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 2.01193)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor           28       0.00126
      LimitIdleTimesMonitor                  30       0.00049
      LimitBusyTimesMonitor                  13       0.01018
      -------------------------------------------------------
      Total                                  73       2.01193
    ]

  and here is the best of 8:

    KheGeneralSolve2014 at end (274.14 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.01059)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           25       0.00202
      LimitIdleTimesMonitor                  24       0.00045
      LimitBusyTimesMonitor                   9       0.00812
      -------------------------------------------------------
      Total                                  58       0.01059
    ]

  So there is an improvement, but there is still a long way to go.

3 Jan 2014.  Have documented and set up a stub version of function
  KheNodeCompleteZones, which takes the existing zones and extends
  them so that every offset has a reasonable zone.  Still to implement.

  I inadvertently used a chunkier zoning and got this (best of 1):

    KheGeneralSolve2014 at end (285.87 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.01267)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           29       0.00308
      LimitIdleTimesMonitor                  24       0.00041
      LimitBusyTimesMonitor                   9       0.00918
      -------------------------------------------------------
      Total                                  62       0.01267
    ]

  which suggests that I might be on the right track.  But the
  chunkier zoning was grossly incomplete.

4 Jan 2014.  Received news today that the troublesome limit
  busy times constraint in IT-I4-96 will be replaced by a
  cluster busy times constraint.

  Fixed the problem with the limit busy times constraint in
  IT-I4-96 by deciding that limit idle times, cluster busy,
  and limit busy times costs just mislead the layer matching
  anyway because it works with the cost of assigning single
  meets.  So I'm now detaching all these monitors for the
  resources of the layer, and reattaching them at the end.

  Added KheLayerMeetCount and did some reorganizing of the
  layers documentation.  Now using

      duration - meet_count

  as the primary sort key for layer sorting, to encourage layers
  of long duration, but allow the longest to be overtaken if it
  has many meets, which must then be small individually.  This
  will not change the Australian instances, but it does pick a
  better first layer in IT-I4-96, which has varying durations,
  the longest having many small meets.

  Current result (best of 1, but also best of 8):

    KheGeneralSolve2014 at end (520.89 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 2.00463)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor           26       1.00105
      LimitIdleTimesMonitor                  24       0.00040
      LimitBusyTimesMonitor                   6       0.00318
      -------------------------------------------------------
      Total                                  57       2.00463
    ]

  There is a big improvement in soft cost.

5 Jan 2014.  Discovered that node meet splitting and node meet
  merging are not always inverses, so I've removed them from
  the vizier node handling for the moment.  I needed to to
  this so that KheNodeExtendZones always gets either the cycle
  node or else a vizier node which is an exact image of the
  cycle node.

  Implemented and tested KheNodeExtendZones, it seems to be
  doing a fair job.  Here's the current best of 1:

    KheGeneralSolve2014 at end (210.66 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 1.00659)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor           25       0.00296
      LimitIdleTimesMonitor                  29       0.00045
      LimitBusyTimesMonitor                   6       0.00318
      -------------------------------------------------------
      Total                                  61       1.00659
    ]

  Best of 8 was

    [ Soln (instance "IT-I4-96", diversifier 3, cost 1.00640)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor           21       0.00181
      LimitIdleTimesMonitor                  25       0.00147
      LimitBusyTimesMonitor                   5       0.00312
      -------------------------------------------------------
      Total                                  52       1.00640
    ]

  Some of the avoid unavailable times constraint violations in
  IT-I4-96 are inevitable.  For example, classes 3A and 3B have
  a total of 32 periods each, so in a cycle of 6 6-period days,
  at least two of these must occur during the last time of the
  day, which is penalized by "Avoid lessons at last hour".  There
  is a soft cost of 3 for a weekday period 6, and a soft cost of
  100 for a saturday period 6.

  Added KheMonitorLowerBound(m) and used it in ejection chains,
  all done and documented.  All lower bounds are 0 at the moment
  except for avoid unavailable times monitors, where better bounds
  are documented and implemented.  It turns out that 3A and 3B
  are the only resources to benefit from this, and even there
  the lower bound is soft 3 rather than soft 6, because the
  Saturday unavailable time is not being taken into account.

  I ended up with the same solution, it took a bit longer:

    KheGeneralSolve2014 at end (211.21 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 1.00659)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor           25       0.00296
      LimitIdleTimesMonitor                  29       0.00045
      LimitBusyTimesMonitor                   6       0.00318
      -------------------------------------------------------
      Total                                  61       1.00659
    ]

  Added optional total rows to the stats table package, and
  used it in the last two patat paper tables, the ones that
  show the remaining defects.

6 Jan 2014.  Found a wonderful case of a very short ejection chain
  which repairs a cost 100 limit busy times defect.  It is not
  being found because it requires a Kempe-step meet move followed
  by a meet assignment, not one Kempe meet move.  This led me
  to rethink the set of repair operations and how they are used
  to repair defects.  I've expressed the fruit of these thoughts 
  by revising the PATAT paper.

7 Jan 2014.  Reorganized meet assignment operations today.
  I've done the documentation and implementation, including
  khe_transaction.c, and verified that I get the same soln
  on IT-I4-96.  Working on tasks now, I've got khe.h and
  the documentation done.  Implementation is next.

8 Jan 2014.  Reorganized task assignment operations today.
  Added the obvious lower bound for limit workload constraints.
  Removed KheTaskPreassign, it is redundant and is not used.
  During the cleanup phase, trying deassigning and reassigning
  every unpreassigned meet and task.  If any are better off
  unassigned, leave it that way.  Optimized limit busy times
  time repair so that it does not try to repair when the set
  of times is empty or is the whole cycle.

9 Jan 2014.  Implemented and documented ejecting meet moves, not
  tested yet, and added the "basic" parameter to the Kempe meet
  move function.

10 Jan 2014.  Working on ejection chain repair operations today.
  Rewrote the PATAT section to be precise about what is done
  during time assignment vs what is done during resource assignment.
  Simplified the ejector interface by not requiring a declaration of
  each combination of augment type and repair type.

11 Jan 2014.  Finished the ejection chain code, both for time
  repair and resource repair, including a careful audit to ensure
  that it agrees with the description in the PATAT14 paper.  Not
  tested yet.  Also revised the Kempe and ejecting task move parts
  of the code and documentation.

12 Jan 2014.  First results from the rewrite.

    KheGeneralSolve2014 at end (232.08 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 12.01243)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignTimeMonitor                       8      10.00000
      SpreadEventsMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor           32       0.00244
      LimitIdleTimesMonitor                  33       0.00187
      LimitBusyTimesMonitor                   9       0.00812
      -------------------------------------------------------
      Total                                  84      12.01243
    ]

  There should not be any assign time defects, so something is wrong.
  The hard spread defects were bumping the assign time defects, so
  I added a limit_gm for assign time defects and got this:

    KheGeneralSolve2014 at end (51.44 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00601)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            8       0.00030
      LimitIdleTimesMonitor                  32       0.00059
      LimitBusyTimesMonitor                   7       0.00512
      -------------------------------------------------------
      Total                                  47       0.00601
    ]

  It seems to be the best so far, and the time is less too.  I
  did fix another thing as well, it was putting the resource
  monitors for all resources into start_gm for the layer repair,
  when really only the resource monitors for that layer's resources
  were wanted.  That seems to have been the source of the speed
  problem.  Best of 8 (0.00320, 0.00601, 0.00601, 0.00338, 0.00601,
  0.00320, 0.00601, 0.00109):

    [ Soln (instance "IT-I4-96", diversifier 5, cost 0.00109)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  36       0.00070
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  45       0.00109
    ]

  There is a noticeable lack of diversity here.  AU-BG-98:

    KheGeneralSolve2014 at end (32.59 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 7.00683)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       6.00000
      AvoidSplitAssignmentsMonitor           51       0.00600
      SpreadEventsMonitor                    47       0.00047
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  15       0.00036
      -------------------------------------------------------
      Total                                 117       7.00683
    ]

  This is a fairly standard result, e.g. a previous was 5.00640.
  Best of 8 was the same, and the others were quite a lot worse,
  so there is work to do here.

  Documented a new way to add and remove vizier nodes.  It solves
  all the vizier node problems, and allows an ejection chain time
  repair algorithm to add and remove a vizier node at will.  Wrote
  KheNodeVizierSplit and audited it; it looks OK, but it's risky
  because it violates many invariants along the way.  Did most of
  KheNodeVizierMerge too.

13 Jan 2014.  Finished KheNodeVizierMerge, not tested yet.  Also
  organized the rest of KHE to use vizier nodes in the new way,
  i.e. as temporary structures inserted during repair.  Spent a
  remarkably long time fiddling with time solver options and
  their documentation.

  Big troubles with KheNodeVizierSplit and KheNodeVizierMerge.
  I don't think going behind the scenes was such a good idea
  after all.  I've fixed many bugs but more keep coming, and
  the current one looks very nasty indeed.  The basic aim was
  to avoid detaching and reattaching a lot of demand monitors;
  I'll have to look for a more principled way to do that.

14 Jan 2014.  Got KheNodeVizierMerge and KheNodeVizierSplit
  working.  I stayed below the invariant and just kept slogging.
  Printed the zones before and after viziers, they seem fine.

  Removed the sorting from KheNodeChildLayersMake, since this has
  already led to one case of inconsistency.  Checked up on all
  uses of KheNodeChildLayersMake to see whether they need sorting:
  
    KheNodePrintTimetable is basically only for debugging anyway.
    KheCoordinateLayers treats each layer more or less independently,
      so their order should not matter.  It's only for reducing the
      duration of oversized layers anyway.
    KheNodeLayeredAssignTimes is the inconsistency referred to.
    KheLayerNodeMatchingNodeRepairTimes creates and uses layers
      but it seems to be only interested in which layers each
      child node is in; the order of the layers does not matter.
    KheRunaroundNodeAssignTimes uses layers in order.  Not sure
      how important order is.  Let's wait and see what happens.

  Current result on AU-BG-98 is 7.00471, not wonderful but in the
  ballpark. I've eyeballed the solution, the problems are the usual
  suspects.  Run time 24.27 secs is a worry.  Best of 8:

    [ Soln (instance "AU-BG-98", diversifier 1, cost 4.00670)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       3.00000
      AvoidSplitAssignmentsMonitor           52       0.00590
      SpreadEventsMonitor                    30       0.00030
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  23       0.00050
      -------------------------------------------------------
      Total                                 108       4.00670
    ]
  
  Not the best ever (3.00517), but in the ballpark.  IT-I4-96:

    KheGeneralSolve2014 at end (59.37 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00325)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           12       0.00045
      LimitIdleTimesMonitor                  31       0.00068
      LimitBusyTimesMonitor                   4       0.00212
      -------------------------------------------------------
      Total                                  47       0.00325
    ]

  This is the best so far for best of 1.  Best of 8:

    [ Soln (instance "IT-I4-96", diversifier 3, cost 0.00302)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            8       0.00030
      LimitIdleTimesMonitor                  30       0.00060
      LimitBusyTimesMonitor                   4       0.00212
      -------------------------------------------------------
      Total                                  42       0.00302
    ]

  Not as good as what I had before.  Needs more work.

  Added more diversity to KheLayerMatchMake, got this:

  "AU-BG-98": 7.00471 5.00399 8.00460 9.00491 5.00494 6.00528 6.00491 4.00665
  "IT-I4-96": 0.00409 0.00325 0.00540 0.00347 0.00306 0.00219 0.00325 0.00347

  which does indeed seem to be more diverse, and there are some good
  results here, notably

    [ Soln (instance "IT-I4-96", diversifier 4, cost 0.00219)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           11       0.00042
      LimitIdleTimesMonitor                  35       0.00065
      LimitBusyTimesMonitor                   3       0.00112
      -------------------------------------------------------
      Total                                  49       0.00219
    ]

  It seems like basic meet moves are more effective than ejecting
  meet moves on AU-BG-98, perhaps because they are fallbacks after
  Kempe moves.  Here is what happens when I change to them:

  "AU-BG-98": 8.00432 6.00590 7.00540 5.00456 2.00388 8.00488 6.00683 9.00686

    [ Soln (instance "AU-BG-98", diversifier 5, cost 2.00388)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       1.00000
      AvoidSplitAssignmentsMonitor           30       0.00320
      SpreadEventsMonitor                    12       0.00012
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  23       0.00056
      -------------------------------------------------------
      Total                                  67       2.00388
    ]

  But actually the results are similar overall, with just a lucky
  outlier being better.  And on IT-I4-96 the results are much worse:

  "IT-I4-96": 1.02745 2.01877 4.02523 1.03156 1.02049 4.02557 4.02523 1.03156

    [ Soln (instance "IT-I4-96", diversifier 5, cost 1.02049)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor           31       0.00535
      LimitIdleTimesMonitor                  39       0.00296
      LimitBusyTimesMonitor                  11       0.01218
      -------------------------------------------------------
      Total                                  82       1.02049
    ]

  Evidently IT-I4-96 really needs those ejecting moves.

15 Jan 2014.  Added KheWorkloadDemandMonitorOriginatingMonitor
  function to workload demand monitors, including a lot of
  stuff to get it working correctly.  So solvers can now
  retrieve the link between a workload demand monitor and
  the resource monitor which gave rise to it.

  Added grouping of workload demand monitors by originating
  monitor to KheSolnPrimaryEventGroupMonitorsMake.

  Reorganized the Guide a bit, got rid of the Monitor Grouping and
  Tracing chapter (which was always an awkward amalgam of platform
  and solver sections), and moved primary and secondary groupings
  to the Structural Solvers chapter, where there is now a section
  ready to receive the documentation of functions for detaching
  redundant resource monitors, still to do.

16 Jan 2014.  Wrote the section about detaching redundant resource
  monitors, and implemented the two functions it defines.  Also
  fiddled with the PATAT14 paper.  So the next job is to implement
  repairs as it describes them.

17 Jan 2014.  Got the PATAT14 paper into good enough shape to serve
  as the spec for the next revision of ejection chain grouping,
  detaching, and augment functions.

18 Jan 2014.  Looked over the PATAT14 paper once again.  Now it
  really is ready to implement.  Implemented turning off maximum
  monitoring in limit busy times and limit workload monitors.  It
  turned out to be easy:  detach, change what's monitored, attach.

  Have reorganized the guide and am now revising it, including
  adding specifications of the new functions needed for the new
  plan.  I've completed the time repair section.

19 Jan 2014.  The guide is in reasonable shape now, although not
  the details of how the augment functions work.  I've also done
  yet another reorganization of it, and also reorganized the
  grouping functions.

20 Jan 2014.  Added detaching and attaching of resource monitors to
  KheTimeRepairPrepareMonitors and KheTimeRepairUnPrepareMonitors.
  Wrote KheDisconnectAllDemand, it disconnects all demand monitors
  from the solution without detaching them.  Decided to scrap
  KheSolnDetachAllResourceMonitors and KheSolnAttachAllResourceMonitors.

21 Jan 2014.  After some bug fixing, but no changes to augment
  functions yet, I got this very standard solution:

    KheGeneralSolve2014 at end (41.23 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 6.00571)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       4.00000
      AvoidSplitAssignmentsMonitor           50       0.00510
      SpreadEventsMonitor                     5       0.00005
      AvoidClashesMonitor                     1       2.00000
      LimitBusyTimesMonitor                  26       0.00056
      -------------------------------------------------------
      Total                                  86       6.00571
    ]
  
  Changed the interface for getting competitors, and changed
  the implementation in khe_matching.c.

  Implemented new time repairs for demand monitors, using the
  same code for ordinary demand and workload demand.  Got this:

    KheGeneralSolve2014 at end (55.30 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 6.00409)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       4.00000
      AvoidSplitAssignmentsMonitor           33       0.00350
      SpreadEventsMonitor                    21       0.00027
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  14       0.00032
      -------------------------------------------------------
      Total                                  74       6.00409
    ]

  Best of 8:

    all solns of "AU-BG-98": 6.00452 9.00442 4.00448 6.00409
      8.00520 4.00474 7.00502 7.00521
    [ Soln (instance "AU-BG-98", diversifier 1, cost 4.00448)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       2.00000
      AvoidSplitAssignmentsMonitor           38       0.00410
      SpreadEventsMonitor                     4       0.00004
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  13       0.00034
      -------------------------------------------------------
      Total                                  58       4.00448
    ]

  IT-I4-96:

    KheGeneralSolve2014 at end (63.04 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00316)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            9       0.00036
      LimitIdleTimesMonitor                  32       0.00068
      LimitBusyTimesMonitor                   4       0.00212
      -------------------------------------------------------
      Total                                  45       0.00316
    ]

    "IT-I4-96": 0.00227 0.00416 0.00316 0.00428 1.00219 0.00112 0.00227 0.00316
    best solutions:
    [ Soln (instance "IT-I4-96", diversifier 4, cost 0.00112)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           10       0.00036
      LimitIdleTimesMonitor                  32       0.00064
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  44       0.00112
    ]

  These are pretty good solutions, not outstanding, but they
  suggest that things are basically working as intended.

22 Jan 2014.  Now excluding moves at vizier nodes when repairing
  meet defects that don't have a workload demand competitor:

    KheGeneralSolve2014 at end (27.55 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 8.00503)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   5       6.00000
      AvoidSplitAssignmentsMonitor           41       0.00450
      SpreadEventsMonitor                     3       0.00003
      AvoidClashesMonitor                     1       2.00000
      LimitBusyTimesMonitor                  19       0.00050
      -------------------------------------------------------
      Total                                  69       8.00503
    ]

    KheGeneralSolve2014 at end (62.92 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00316)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            9       0.00036
      LimitIdleTimesMonitor                  32       0.00068
      LimitBusyTimesMonitor                   4       0.00212
      -------------------------------------------------------
      Total                                  45       0.00316
    ]

  AU-BG-98 runs in half the time, and principle the result should
  be just as good, although in this case it has turned out to be
  worse.  IT-I4-96 is only marginally faster, and gives the same
  solution.  Presumably the changed kind of repair did not happen
  very often anyway.  Best of 8:

    "AU-BG-98": 11.00469 5.00644 8.00503 5.00550 7.00499 10.00453 9.00496 11.00467
    best solutions:
    [ Soln (instance "AU-BG-98", diversifier 1, cost 5.00550)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       5.00000
      AvoidSplitAssignmentsMonitor           44       0.00450
      SpreadEventsMonitor                    24       0.00024
      LimitBusyTimesMonitor                  29       0.00076
      -------------------------------------------------------
      Total                                 101       5.00550
    ]

  After fiddling with limit idle times repair:

    KheGeneralSolve2014 at end (69.97 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00505)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           10       0.00133
      LimitIdleTimesMonitor                  34       0.00060
      LimitBusyTimesMonitor                   5       0.00312
      -------------------------------------------------------
      Total                                  49       0.00505
    ]

  Judging by the running time it's working, but I suppose I
  should really do a proper debug run to make sure.  Best of 8:

    0.00394 0.00408 0.00505 0.00506 0.00190 0.00296 0.00505 0.00394
    [ Soln (instance "IT-I4-96", diversifier 4, cost 0.00190)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            6       0.00024
      LimitIdleTimesMonitor                  32       0.00054
      LimitBusyTimesMonitor                   3       0.00112
      -------------------------------------------------------
      Total                                  41       0.00190
    ]

  This is actually very promising:  just think where we would
  be if those 3 limit busy times defects were got rid of.

23 Jan 2014.  Added compactness requirement for limit idle times
  constraints to HSEval and its documentation.

  Implemented an option for omitting Kempe moves.  Added tests
  to the PATAT14 paper comparing
  Kempe/ejecting : Kempe/basic : Ejecting only : Basic only.

  Did a long test run, had to walk away from it in the end
  it was taking so long.  Got bogged down in NL-KP-03.

24 Jan 2014.  Working on NL-KP-03, initially aiming to avoid
  getting bogged down.  I've found one problem so far: a
  structural thing which is currently causing KheLayerTreeMake to
  build a poor layer tree.  See to_gerhard06 and NL-KP-03_analysis
  for the details.

  Problem may be not so much with the layer tree as with
  finding similarities between layers.  There seems to be
  a tendency to make larger nodes children of smaller ones.

  Basically the problem is that meets from the same course
  get put in a node even though they are linked to heterogeneous
  meets and so the same resources are not present throughout.

  We probably need a rule like this:  every preassigned
  resource which is present anywhere in a node is present at
  every offset of every meet of that node.  It will mean more
  nodes and smaller nodes but it makes things clearer.

25 Jan 2014.  Written and documented the code to apply the rule
  above when merging nodes.  Fortunately, node merging is a
  post-processing step and I don't need to delve into the main
  algorithm.  There was no node merging in AU-BG-98; I got this:

    KheGeneralSolve2014 at end (27.59 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 8.00503)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   5       6.00000
      AvoidSplitAssignmentsMonitor           41       0.00450
      SpreadEventsMonitor                     3       0.00003
      AvoidClashesMonitor                     1       2.00000
      LimitBusyTimesMonitor                  19       0.00050
      -------------------------------------------------------
      Total                                  69       8.00503
    ]

  There was a lot of node merging in IT-I4-96, but the result
  is pretty much what I usually get:

    KheGeneralSolve2014 at end (70.13 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00505)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           10       0.00133
      LimitIdleTimesMonitor                  34       0.00060
      LimitBusyTimesMonitor                   5       0.00312
      -------------------------------------------------------
      Total                                  49       0.00505
    ]

  So it seems I've done no harm with these changes.  But
  kp03 is still running for hours.  The first node ejection
  chain started with cost 20.26469 and 904 defects, and ended
  with cost 15.13228 and 707 defects.  The second node ejection
  chain repair was given those 707 defects, including these
  assign time defects which need looking into:

      [ A1 AssignTimeMonitor             1.00000 "WI (L1HV1)_6001" ]
      [ A1 AssignTimeMonitor             1.00000 "WI (L1TH1)_800" ]
      [ A1 AssignTimeMonitor             1.00000 "AK (L1TH3)_4500" ]
      [ A1 AssignTimeMonitor             1.00000 "NE (L2G1)_66601" ]
      [ A1 AssignTimeMonitor             1.00000 "FA (L2HV2)_17601" ]
      [ A1 AssignTimeMonitor             1.00000 "NE (L2T1)_12700" ]
      [ A1 AssignTimeMonitor             1.00000 "LO (L2T1)_14200" ]
      [ A1 AssignTimeMonitor             1.00000 "NE (L3H2)_72302" ]
      [ A1 AssignTimeMonitor             1.00000 "EN (L4H3)_45302" ]
      [ A1 AssignTimeMonitor             1.00000 "NE (L4T2)_53602" ]
      [ A1 AssignTimeMonitor             1.00000 "WI (L4T_F)_138103" ]
      [ A1 AssignTimeMonitor             1.00000 "EN (L5H3)_159701" ]
      [ A1 AssignTimeMonitor             1.00000 "D1 (L5V1)_26200" ]

  They were removed in the end; why were they ever present at all?

  There are also hundreds (literally) of avoid idle times defects.
  If they are uncorrectable but are being tried again and again,
  I guess they could explain the bizarrely long run time.

    KheGeneralSolve2014 at end (17444.55 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.04473)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            3       0.00150
      LimitIdleTimesMonitor                 277       0.00653
      ClusterBusyTimesMonitor                17       0.02300
      LimitBusyTimesMonitor                  52       0.01370
      -------------------------------------------------------
      Total                                 349       0.04473
    ]

  This is 4.8 hours.  Gerhard's page claims that a solution
  exists with cost 0.01410.  If that is a good solution, then
  there are many small defects that will never be removed, and
  these are a problem for running time.

  NB I've placed op2 into NL-KP-03_op2 for safety.

26 Jan 2014.  Looking into life with and without vizier nodes.
  Found some anomalies in runaround timetabling - it hasn't
  kept up with the options.

  Redid the options for repairing layers, involved quite a
  lot of fiddling with options and rejigging stuff, all
  done and documented now.

  Am now running without the long repair after each layer and
  without vizier nodes.  Here's the result on IT-I4-96:

    KheGeneralSolve2014 at end (5.69 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00516)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           12       0.00045
      LimitIdleTimesMonitor                  29       0.00059
      LimitBusyTimesMonitor                   6       0.00412
      -------------------------------------------------------
      Total                                  47       0.00516
    ]

  Best of 8:

    "IT-I4-96": 0.00413 0.00514 0.00516 0.00421 0.00307 0.00196 0.00516 0.00413
    [ Soln (instance "IT-I4-96", diversifier 4, cost 0.00196)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           11       0.00039
      LimitIdleTimesMonitor                  25       0.00045
      LimitBusyTimesMonitor                   3       0.00112
      -------------------------------------------------------
      Total                                  39       0.00196
    ]

  These are typical results, can't say that the lack of the
  two options is doing much harm.

  Got through NL-KP-03.  It's still slow, about 4 minutes:

    KheGeneralSolve2014 at end (245.50 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.05460)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00200
      LimitIdleTimesMonitor                 392       0.01820
      ClusterBusyTimesMonitor                19       0.02200
      LimitBusyTimesMonitor                  46       0.01240
      -------------------------------------------------------
      Total                                 461       0.05460
    ]

  Compare with Gerhard's claim to have a soln with cost 0.01410.

27 Jan 2014.  Started work on repairing cluster busy times 
  defects, by adding some diagnostic functions to cluster
  busy times monitors.  I've also documented repair operations
  in the PATAT paper which need to be implemented now.

28 Jan 2014.  Wrote the cluster busy times defects augment
  function today, both underloads and overloads.  Results:

    KheGeneralSolve2014 at end (286.84 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.04571)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            6       0.00300
      LimitIdleTimesMonitor                 385       0.01561
      ClusterBusyTimesMonitor                16       0.01600
      LimitBusyTimesMonitor                  46       0.01110
      -------------------------------------------------------
      Total                                 453       0.04571
    ]

  Evidently it's working, only it's not working miracles.
  With defect promotion:

    KheGeneralSolve2014 at end (490.21 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.03743)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00350
      LimitIdleTimesMonitor                 375       0.00833
      ClusterBusyTimesMonitor                15       0.01500
      LimitBusyTimesMonitor                  47       0.01060
      -------------------------------------------------------
      Total                                 444       0.03743
    ]

  It does seem to have helped, although it is much slower.
  But on AU-BG-98 things seem worse:

    KheGeneralSolve2014 at end (24.55 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 12.00491)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   7       9.00000
      AvoidSplitAssignmentsMonitor           42       0.00440
      SpreadEventsMonitor                     9       0.00009
      AvoidClashesMonitor                     1       3.00000
      LimitBusyTimesMonitor                  18       0.00042
      -------------------------------------------------------
      Total                                  77      12.00491
    ]

    13.00497 13.00556 7.00525 12.00491 11.00418 4.00524 12.00687 11.00616
    [ Soln (instance "AU-BG-98", diversifier 7, cost 4.00524)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           42       0.00450
      SpreadEventsMonitor                    30       0.00030
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  18       0.00044
      -------------------------------------------------------
      Total                                  94       4.00524
    ]

  This is OK actually.

    KheGeneralSolve2014 at end (7.86 secs so far):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00399)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            9       0.00036
      LimitIdleTimesMonitor                  27       0.00051
      LimitBusyTimesMonitor                   5       0.00312
      -------------------------------------------------------
      Total                                  41       0.00399
    ]

    "IT-I4-96": 0.00209 0.00399 0.00315 0.00802 0.00521 0.00296 0.00399 0.00315
    best solutions:
    [ Soln (instance "IT-I4-96", diversifier 2, cost 0.00209)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           11       0.00045
      LimitIdleTimesMonitor                  27       0.00052
      LimitBusyTimesMonitor                   3       0.00112
      -------------------------------------------------------
      Total                                  41       0.00209
    ]

  This too is OK.

  Look at this amazing thing from NL-KP-03:

    initial defects:
      [ G0 LayerTimeRepairGroupMonitor  2.00160 (sub_tag 10) 4 defects
	[ A1 SpreadEventsMonitor          1.00000 gr_Course_WI-L2G1_674 ]
	[ A1 SpreadEventsMonitor          1.00000 gr_Course_WA-L6V_G_1586 ]
	[ A1 LimitIdleTimesMonitor        0.00080 (min 0, max 2, idle 4) ]
	[ A1 LimitIdleTimesMonitor        0.00080 (min 0, max 1, idle 3) ]
      ]
    final defects:
      [ G0 LayerTimeRepairGroupMonitor  0.00100 (sub_tag 10) 23 defects
	[ A1 LimitBusyTimesMonitor        0.00050 Teacher_ZOM (min 3) sep 2:1 ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitBusyTimesMonitor        0.00010 Teacher_LNF (min 5) sep 1 ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitIdleTimesMonitor        0.00001 (min 0, max 1, idle 2) ]
	[ A1 LimitBusyTimesMonitor        0.00020 Teacher_ZOM (min 2) sep 1 ]
      ]

  To repair two spread events defects it inserted about a million limit
  idle times defects.  The result of this kind of thing is that by the
  time it gets to the final node repair, there are 713 defects.  No wonder
  it's taking so long.
    
  Found that I had omitted to put limit_gm into the node repair ejection
  chains solver, and that as a result it was permitting some assign time
  defects.  I've fixed this now.  After the fix things got worse:

    KheGeneralSolve2014 at end (704.01 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.05127)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            5       0.00250
      LimitIdleTimesMonitor                 355       0.00907
      ClusterBusyTimesMonitor                22       0.02500
      LimitBusyTimesMonitor                  46       0.01470
      -------------------------------------------------------
      Total                                 428       0.05127
    ]

  Hit on a brilliant idea for grouping the resource monitors of
  resources which must follow the same timetable, because they
  are preassigned only, and to the same meets.  All implemented,
  but the results seem quite disappointing:

    KheGeneralSolve2014 at end (721.47 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.05127)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            5       0.00250
      LimitIdleTimesMonitor                 355       0.00907
      ClusterBusyTimesMonitor                22       0.02500
      LimitBusyTimesMonitor                  46       0.01470
      -------------------------------------------------------
      Total                                 428       0.05127
    ]

   Actually I think the primary group monitors are not going
   into the secondary monitor at this point, so nothing's changed.

   This is not necessarily an error (it's solution cost that is supposed
   to be decreasing), but it's unusual.  Has something been left out?

   [ Layer: 15 nodes, meets 23 durn 23 (Teacher_HJO) ]
      initial defects:
	[ G0 LayerTimeRepairGroupMonitor       0.00300 (sub_tag 20) 5 defects
	  ...
	]
      final defects:
	[ G0 LayerTimeRepairGroupMonitor       0.00482 (sub_tag 20) 23 defects
	  ...
	]

  On the big repair we are now repairing 639 defects instead of 700+.
  Not as big a reduction as I'd hoped, but something.

    KheGeneralSolve2014 at end (719.71 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.04335)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            8       0.00400
      LimitIdleTimesMonitor                 344       0.00805
      ClusterBusyTimesMonitor                15       0.01800
      LimitBusyTimesMonitor                  43       0.01330
      -------------------------------------------------------
      Total                                 410       0.04335
    ]

  Something queer here, it's only the second layer and yet there are two
  spread events defects.  How can that possibly be?  Here:

      [ Layer: 18 nodes, meets 29 durn 33 (Class_L1HV1, Teacher__XXY) ]
      initial defects:
	[ G0 LayerTimeRepairGroupMonitor 3.01600 (sub_tag 20) 3 defects
	  [ A1 SpreadEventsMonitor         2.00000 gr_Course_WI-L1HV1_60 ]
	  [ A1 SpreadEventsMonitor         1.00000 gr_Course_AK-L1HV1_73 ]
	  [ A1 LimitIdleTimesMonitor       0.01600 Class_L1HV1 (max 0, idle 4) ]
	]
      final defects:
	[ G0 LayerTimeRepairGroupMonitor 3.00000 (sub_tag 20) 2 defects
	  [ A1 SpreadEventsMonitor         2.00000 gr_Course_WI-L1HV1_60 ]
	  [ A1 SpreadEventsMonitor         1.00000 gr_Course_AK-L1HV1_73 ]
	]

29 Jan 2014.  Changed layer sort function to give greater weight to
  duration.  It seems to have produced a better spread in the layers.
  Should really take spread events constraints into account when
  deciding which layer to use, it would pick out class layers and
  be better in principle.  Got this:

    KheGeneralSolve2014 at end (176.29 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.04774)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00200
      LimitIdleTimesMonitor                 317       0.01074
      ClusterBusyTimesMonitor                17       0.02300
      LimitBusyTimesMonitor                  49       0.01200
      -------------------------------------------------------
      Total                                 387       0.04774
    ]

  Slightly worse in cost, but that's just chance; the run time
  is very much better (3 mins).  574 defects to repair on the
  first big repair run.  Best of 8:

    0.04354 0.04774 0.04090 0.05143 0.04523 0.03919 0.04370
    [ Soln (instance "NL-KP-03", diversifier 4, cost 0.03919)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00350
      LimitIdleTimesMonitor                 334       0.00839
      ClusterBusyTimesMonitor                15       0.01500
      LimitBusyTimesMonitor                  51       0.01230
      -------------------------------------------------------
      Total                                 407       0.03919
    ]

  So we are basically stuck in a slow, poor local minimum here.
  I've eyeballed the solution and it's hard to see what to do
  about it.  With many preassigned resources in each event,
  each with its own timetable, moves are hard, indeed it's
  hard to see why there are no clashes.  Using ejecting moves
  only, not Kempe moves:

    KheGeneralSolve2014 at end (282.29 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.03340)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            5       0.00250
      LimitIdleTimesMonitor                 293       0.00880
      ClusterBusyTimesMonitor                12       0.01200
      LimitBusyTimesMonitor                  44       0.01010
      -------------------------------------------------------
      Total                                 354       0.03340
    ]

  This is better but it has not solved the basic problem.
  Back with Kempe moves, but ignoring node regularity gives this:

    KheGeneralSolve2014 at end (77.62 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.03825)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            3       0.00150
      LimitIdleTimesMonitor                 350       0.01045
      ClusterBusyTimesMonitor                13       0.01600
      LimitBusyTimesMonitor                  43       0.01030
      -------------------------------------------------------
      Total                                 409       0.03825
    ]

  and ignoring node regularity best of 8 gives this:

    0.03533 0.03825 0.04355 0.04788 0.04712 0.03191 0.03329 0.03563
    [ Soln (instance "NL-KP-03", diversifier 3, cost 0.03191)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00200
      LimitIdleTimesMonitor                 280       0.00731
      ClusterBusyTimesMonitor                13       0.01300
      LimitBusyTimesMonitor                  47       0.00960
      -------------------------------------------------------
      Total                                 344       0.03191
    ]

  It seems likely that the best hope here is in limiting event
  domains during construction so that cluster busy times defects
  cannot be violated.  This will fix limit busy times defects
  too because many of them are underloads, not overloads.  It
  could get us into the ballpark of Gerhard's 0.01410 solution.

  Implemented and documented lower bounds for group monitors.

  Started designing a structural solver for cluster busy times
  constraints, but got into a bit of a pickle; it needs more
  thought.

30 Jan 2014.  Added hash tables indexed by lsets, and am
  using them when constructing solution groups.  Also I've
  brought the specification of the cluster-buster to a state
  where it can be implemented.

  I've implemented the initial part of the cluster thing which
  reduces meet domains to reflect unavailable times.  Got this:

    KheGeneralSolve2014 at end (176.83 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.04774)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00200
      LimitIdleTimesMonitor                 317       0.01074
      ClusterBusyTimesMonitor                17       0.02300
      LimitBusyTimesMonitor                  49       0.01200
      -------------------------------------------------------
      Total                                 387       0.04774
    ]

  which is no different really.  So press on.

31 Jan 2014.  Redid yesterday's work with a better data structure.
  I'm working on solving each component now.

1 Feb 2014.  Got the cluster code going.  The first attempt put
  the reduced domains in and left them there, which caused some
  demand defects and ultimately produced this:

    KheGeneralSolve2014 at end (1957.41 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 14.03226)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignTimeMonitor                       3       3.00000
      SpreadEventsMonitor                     9      10.00000
      AvoidClashesMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor            7       0.00350
      LimitIdleTimesMonitor                 482       0.02186
      LimitBusyTimesMonitor                  39       0.00690
      -------------------------------------------------------
      Total                                 541      14.03226
    ]

  It's bad and slow, but there are no cluster busy times defects;
  the new feature did do what it set out to do.  Now I'm removing
  the reduced domains after the first node repair, along with other
  time-structural stuff (zones and interior nodes).  I get this:

    KheGeneralSolve2014 at end (503.73 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.02804)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            2       0.00100
      LimitIdleTimesMonitor                 338       0.00774
      ClusterBusyTimesMonitor                 9       0.00900
      LimitBusyTimesMonitor                  44       0.01030
      -------------------------------------------------------
      Total                                 393       0.02804
    ]

  This is the best cost result so far, and it has certainly
  had a big impact on cluster busy times defects.  Hurrah.
  Limit busy times defects are worse; why?

  Removed defect copying and defect sorting, now the ejector
  has its own array of defects which it has copied from
  ej->start_gm and sorted.

  Trying recent failure suppression.  Last run of BGHS98 without it:

    KheGeneralSolve2014 at end (24.36 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 12.00491)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   7       9.00000
      AvoidSplitAssignmentsMonitor           42       0.00440
      SpreadEventsMonitor                     9       0.00009
      AvoidClashesMonitor                     1       3.00000
      LimitBusyTimesMonitor                  18       0.00042
      -------------------------------------------------------
      Total                                  77      12.00491
    ]

  First run of BGHS98 with it:

    KheGeneralSolve2014 at end (17.83 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 9.00436)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       5.00000
      AvoidSplitAssignmentsMonitor           36       0.00360
      SpreadEventsMonitor                    26       0.00026
      AvoidClashesMonitor                     4       4.00000
      LimitBusyTimesMonitor                  23       0.00050
      -------------------------------------------------------
      Total                                  92       9.00436
    ]

  Faster and better.  Best of 8:

    8.00424 9.00487 9.00436 10.00475 12.00434 6.00531 9.00572 6.00464
    [ Soln (instance "AU-BG-98", diversifier 7, cost 6.00464)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       3.00000
      AvoidSplitAssignmentsMonitor           39       0.00410
      SpreadEventsMonitor                     2       0.00002
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  22       0.00052
      -------------------------------------------------------
      Total                                  68       6.00464
    ]

  Now for kp03:

    KheGeneralSolve2014 at end (1810.81 secs so far):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.03268)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00200
      LimitIdleTimesMonitor                 431       0.01318
      ClusterBusyTimesMonitor                 6       0.00600
      LimitBusyTimesMonitor                  47       0.01150
      -------------------------------------------------------
      Total                                 488       0.03268
    ]

  Compared with the 503.73 sec 0.02804 solution above, this is
  somewhat worse in cost and a lot slower.

2 Feb 2014.  Turned recent defect suppression off and confirmed
  that I got back to the previous solution of NL-KP-03 in the
  previous time.

  Submitted my other paper (on integrated student scheduling)
  to the PATAT conference web site.  It was Number 2.

3 Feb 2014.  Had a crash which was to do with dodgy handling
  of deleting time group neighbourhoods.  This sparked a big
  rewrite in that area, all done but not tested yet.

  When solving NL-KP-03, after 2016.29 secs had elapsed,
  7 of the 8 solves had completed, but the last did not
  complete until 4619.95 secs seconds had elapsed.

  The best of the 8 results for NL-KP-03 has cost 0.02462.
  This seems to be my best so far for NL-KP-03, which is
  some consolation for the enormous run time.

4 Feb 2014.  Naturally, all the bugs turn up when I'm trying
  to get a paper out.  Today's problem was the timer function,
  the static variable was tripping things up, as static
  variables usually do.  I've now documented and implemented
  timer objects which allow any number of independent timers
  to run without interference.

  Got the Lout version of the paper into good shape, 21 pages.
  Now for the LaTeX version.

5 Feb 2014.  Working on the LaTeX version of the paper today.
  I've done all the text, references, and the first table.  I
  need to add all the result tables and diagrams next.  Just
  begun to work on the code for generating LaTeX tables; is
  there HSEval code I can use for doing this?

6 Feb 2014.  Continuing with the LaTeX version of the paper
  today.  Done sample results tables, the two figures are
  next, then I'll be ready for the long final runs.

7 Feb 2014.  Paper is done, I'm just proof reading it and
  fiddling with the text now.  The 10 February deadline
  has been extended to 28 February, but I'll submit it
  asap and maybe revise the submission later on.

8 Feb 2014.  Took most of yesterday off.  Finished off my
  main PATAT14 paper and submitted it today.  I've also
  generated the khe14 and khe14x8 solution groups, put
  them on the web, and notified Gerhard.

9 Feb 2014.  Looking over resource packing with a view to
  getting it to give priority to assigning tasks in meets
  that are unlikely to be movable (that have high demand).
  It sorts resources dynamically by increasing demand durn
  (total duration of assignable task groups) minus supply
  duration (number of available times).  For each resource
  it sorts the available task groups by decreasing goodness,
  where goodness is twice the shared duration of the tasks,
  minus the excess of the number of qualified resources over
  the number of tasks - a static quantity.  The resource pack
  maximizes the total goodness of the tasks assigned.  Here
  is its performance alongside two alternatives:

    Goodness      Best of 1       Best of 8
    ---------------------------------------
    Current        12.00491         4.00524
    Duration       10.00499         4.00470
    Max Demand     11.00531         5.00421
    ---------------------------------------

  So it seems that max demand is in the ballpark, and it should
  encourage the resource packer to omit tasks in meets that can
  easily be moved.  Next job:  try moving them.

  I've written and am running the new kind of repair for avoid
  split assignments constraints.  It was a part of 13 successful
  chains when solving bghs98, and the result had a cost of
  6.00517 (compare with 11.00531 above); best of 8 was 

    12.00391 6.00517 13.00353 10.00410 11.00503 13.00448 14.00394 11.00519
    [ Soln (instance "AU-BG-98", diversifier 0, cost 6.00517)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       4.00000
      AvoidSplitAssignmentsMonitor           43       0.00430
      SpreadEventsMonitor                    37       0.00041
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  20       0.00046
      -------------------------------------------------------
      Total                                 103       6.00517
    ]

  so we don't seem to have made any progress overall.  Why not?
  This is the run without the new repair:

    KheGeneralSolve2014 at end (20.74 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 5.00556)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       4.00000
      AvoidSplitAssignmentsMonitor           46       0.00480
      SpreadEventsMonitor                    27       0.00028
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  19       0.00048
      -------------------------------------------------------
      Total                                  94       5.00556
    ]

  We have actually made some progress, just not a huge amount.
  I think the time assignment might have decayed a bit, perhaps
  by the removal of vizier nodes.

  Tried the new repair only not checking for availability:

    KheGeneralSolve2014 at end (19.33 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 7.00425)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       5.00000
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    35       0.00037
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  19       0.00048
      -------------------------------------------------------
      Total                                  92       7.00425
    ]

  Actually this is not bad.  Here is best of 8 this way:

    12.00437 7.00425 12.00433 12.00360 11.00511 12.00409 13.00363 9.00482
    [ Soln (instance "AU-BG-98", diversifier 0, cost 7.00425)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       5.00000
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    35       0.00037
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  19       0.00048
      -------------------------------------------------------
      Total                                  92       7.00425
    ]

  There may be a problem with the order of assignment of the
  layers, which is

  [ Layer: 10 nodes, meets 27 durn 40 (x09_1, x09_2, x09_3, x09_4, x09_5) ]
  [ Layer: 11 nodes, meets 28 durn 40 (x07C, x07K, x07O) ]
  [ Layer: 12 nodes, meets 25 durn 40 (x08C, x08K, x08O) ]
  [ Layer: 13 nodes, meets 26 durn 40 (x08A, x08S) ]
  [ Layer: 12 nodes, meets 29 durn 40 (x07A, x07S) ]

  Something queer here:
  [ Layer: 11 nodes, durn 40 meet 28 adur 5 (x07C, x07K, x07O) ]
  Why should these resources have assigned duration 5?  As far
  as I can see, their only preassignment is to Scripture; but a
  debug output gives this:

    [ layer assigned duration:
      [ Meet #1085# durn 2 {Mon1..Fri7} --> /Tue2/ ]
      [ Meet #1086# durn 1 {Mon1..Fri8} --> /Mon1/ ]
      [ Meet #1087# durn 1 {Mon1..Fri8} --> /Mon3/ ]
      [ Meet "x7_OptionalScripture_1" durn 1 {Tue8} --> /Tue8/ ]
    ]

  What are these preassigned meets?

10 Feb 2014.  Worked out that these queer preassigned meets are
  caused by the runaround repair algorithm going above its scope.
  So I've added an option whose value is a node that limits the
  scope of the repairs.  It seems to be working; I've checked
  that the layers are being done in the right order.  Best of 1:

    KheGeneralSolve2014 at end (26.33 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 11.00458)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   7      10.00000
      AvoidSplitAssignmentsMonitor           38       0.00390
      SpreadEventsMonitor                    13       0.00014
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  23       0.00054
      -------------------------------------------------------
      Total                                  82      11.00458
    ]

  Best of 8:

    6.00366 12.00420 12.00456 11.00458 15.00386 6.00540 13.00388 7.00508
    [ Soln (instance "AU-BG-98", diversifier 3, cost 6.00366)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       1.00000
      AvoidSplitAssignmentsMonitor           28       0.00280
      SpreadEventsMonitor                    28       0.00028
      AvoidClashesMonitor                     4       5.00000
      LimitBusyTimesMonitor                  23       0.00058
      -------------------------------------------------------
      Total                                  84       6.00366
    ]

  This is a fairly good result:  avoid split assignments defects
  are at a record low here.  The previous best was 30, but that
  was a long time ago and the overall result was worse:

    [OLD RESULT]
    KheGeneralSolve2014 at end (13.40 secs so far):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 9.00385)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       7.00000
      AvoidSplitAssignmentsMonitor           30       0.00320
      SpreadEventsMonitor                     7       0.00007
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  25       0.00058
      -------------------------------------------------------
      Total                                  67       9.00385
    ]

  Here's a test of trying node swaps before meet moves:

    KheGeneralSolve2014 at end (26.26 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 8.00394)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   5       6.00000
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    16       0.00016
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  15       0.00038
      -------------------------------------------------------
      Total                                  72       8.00394
    ]

  And here's the best of 8:

    5.00392 8.00394 13.00472 14.00429 12.00399 8.00408 9.00417 15.00554
    [ Soln (instance "AU-BG-98", diversifier 3, cost 5.00392)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       2.00000
      AvoidSplitAssignmentsMonitor           36       0.00360
      SpreadEventsMonitor                    10       0.00010
      AvoidClashesMonitor                     3       3.00000
      LimitBusyTimesMonitor                  11       0.00022
      -------------------------------------------------------
      Total                                  61       5.00392
    ]

  Another pretty good result, although not striking.  3.00494
  is the best result on Gerhard's web site.  We're well below
  that on soft constraints, but two short on hard.  Keep trying!
  Best of 32:

    6.00366 12.00420 12.00456 11.00458 6.00540 15.00386 13.00388 7.00508
    8.00383 8.00417 8.00325 13.00411 5.00334 16.00382 11.00475 11.00384
    8.00423 11.00462 21.00434 12.00485 9.00321 14.00425 11.00371 11.00445
    16.00430 16.00473 7.00477 7.00392 14.00433 13.00411 11.00458 8.00517
    [ Soln (instance "AU-BG-98", diversifier 13, cost 5.00334)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       4.00000
      AvoidSplitAssignmentsMonitor           29       0.00290
      SpreadEventsMonitor                    12       0.00012
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  15       0.00032
      -------------------------------------------------------
      Total                                  60       5.00334
    ]

  Tried an arrangement for swapping layers as I assign them, so
  that each layer gets one chance to be assigned one step earlier
  than previously.  Best of 1:

    KheGeneralSolve2014 at end (29.79 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 8.00383)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   5       7.00000
      AvoidSplitAssignmentsMonitor           32       0.00320
      SpreadEventsMonitor                    19       0.00021
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  19       0.00042
      -------------------------------------------------------
      Total                                  76       8.00383
    ]

  Best of 8:

    8.00383 15.00343 9.00382 14.00448 4.00374 9.00518 9.00304 13.00374
    [ Soln (instance "AU-BG-98", diversifier 5, cost 4.00374)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       3.00000
      AvoidSplitAssignmentsMonitor           29       0.00310
      SpreadEventsMonitor                    12       0.00012
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  23       0.00052
      -------------------------------------------------------
      Total                                  67       4.00374
    ]

  My best so far, still not as good as the one on Gerhard's
  web site, but very close indeed.  Best of 32 (why not?):

    8.00383 15.00343 9.00382 14.00448 4.00374 9.00518 9.00304 13.00374
    12.00425 4.00505 7.00363 13.00450 3.00400 6.00506 15.00409 8.00504
    4.00497 13.00528 9.00423 13.00512 8.00531 24.00467 13.00436 9.00504
    9.00376 16.00510 12.00416 13.00498 7.00360 12.00438 8.00384 16.00497
    [ Soln (instance "AU-BG-98", diversifier 12, cost 3.00400)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       3.00000
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    26       0.00026
      LimitBusyTimesMonitor                  15       0.00034
      -------------------------------------------------------
      Total                                  77       3.00400
    ]

  I've sent this to Gerhard, and he has posted it.

11 Feb 2014.  Tidied up KheBenchmark and its documentation, checked
  KheOptions, and revised the stats module's documentation.

12 Feb 2014.  Fiddled with monitor grouping and documentation, it
  now takes all monitors, not just attached ones, and it looks for
  parents, not ancestors.  These changes make things simpler in
  preparation for grouping for resource/time repair.

13 Feb 2014.  I now have a complete description of a unified
  ejection chain algorithm in alg_paper_extended.  It should
  be implementable from here.  I've started work on documenting
  it in khe/khe/doc.  Done the primary grouping and detaching
  subsection so far.

14 Feb 2014.  Working on unified ejection chains.  Currently
  renaming and unifying the augment functions in file
  khe_se_solvers.c.  Done most of it, there are three
  repair types whose unification is still to do.  Also need
  to compare with the description in tt/patat14/*extended.
  Have just written KheResourceLoadDefectAugment, using it
  (three times over) is next.

15 Feb 2014.  Calling KheResourceLoadDefectAugment now, on
  workload demand defects as well, which is progress.  Wrote a
  section of the Guide discussing the problem of ejection chain
  calls going out of scope, in the course of which I implemented
  the ejector_repair_times and ejector_repair_resources options.

16 Feb 2014.  Tidied up the doc and code.  Tested it; it works,
  except that there is a problem with limit workload monitors:
  they are being detached because they give rise to at least
  one workload demand monitor, but workload demand monitors
  are not exact, and so during repair there are workload limit
  overloads created but not noticed or repaired.  The effect is
  visible in the following, where the first print is at the end
  of KheEjectionChainRepairResources just before the monitors are
  reattached, and the second is just after they are reattached:

    KheEjectionChainRepairResources before UnPrepare:
    [ Soln (instance "AU-BG-98", diversifier 0, cost 1512.00027)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                 353    1507.00000
      SpreadEventsMonitor                    13       0.00013
      LimitBusyTimesMonitor                   6       0.00014
      OrdinaryDemandMonitor                   5       5.00000
      -------------------------------------------------------
      Total                                 377    1512.00027
    ]
    KheEjectionChainRepairResources after UnPrepare:
    [ Soln (instance "AU-BG-98", diversifier 0, cost 2513.00027)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                 353    1507.00000
      SpreadEventsMonitor                    13       0.00013
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                   6       0.00014
      LimitWorkloadMonitor                    1    1000.00000
      OrdinaryDemandMonitor                   5       5.00000
      -------------------------------------------------------
      Total                                 379    2513.00027
    ]

  Sure enough, a limit workload monitor with non-zero cost
  has emerged.  Not sure why this was not happening before.

17 Feb 2014.  Thought about it overnight, and realized that
  previously I was not detaching limit workload demand
  monitors during resource assignment, whereas now I am.
  Have to get back to where I was before, with demand
  monitors in the limit_gm *only* during resource assignment,
  and limit workload monitors not detached then.  Working on
  a section of the Guide which explains all this.

18 Feb 2014.  Finished the new section of the Guide, ready
  to implement.  I don't seem to have ever detached demand
  monitors before; I've removed them as limit monitors, but
  they have always contributed to cost.  Not good.  Finished
  off the primary grouping (khe_se_primary.c).

19 Feb 2014.  Looked over all the new code and docs, it seems
  to be ready for testing.  KheTaskingGroupMonitorMake is a
  bit dodgy as documented below, but the way forward seems to
  be to test as is, then try replacing all continue group
  monitors by the soln object and see how that goes.

  Did some testing, got a reasonable solution for bghs98 of
  cost 10.something.  Here is best of 8:

    6.00571 10.00421 6.00432 6.00421 7.00519 10.00372 6.00431 9.00505
    [ Soln (instance "AU-BG-98", diversifier 3, cost 6.00421)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       2.00000
      AvoidSplitAssignmentsMonitor           34       0.00350
      SpreadEventsMonitor                    19       0.00021
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  22       0.00050
      -------------------------------------------------------
      Total                                  79       6.00421
    ]

  Not wonderful but in the ballpark.  Last time I tried best of 8:
  8.00383 15.00343 9.00382 14.00448 4.00374 9.00518 9.00304 13.00374
  we are now better than this except for the lucky 4.00374.

  Here is what happens if KheResourceRepairMeetAndTaskMoveAugment
  moves its meets only to times when its resource is available:

    KheGeneralSolve2014 at end (33.39 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 11.00403)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       6.00000
      AvoidSplitAssignmentsMonitor           34       0.00350
      SpreadEventsMonitor                    16       0.00017
      AvoidClashesMonitor                     4       4.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  17       0.00036
      -------------------------------------------------------
      Total                                  76      11.00403
    ]

  And here is the same thing, best of 8:

    6.00515 11.00403 6.00421 8.00362 10.00410 7.00519 6.00441 9.00418
    [ Soln (instance "AU-BG-98", diversifier 3, cost 6.00421)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       2.00000
      AvoidSplitAssignmentsMonitor           34       0.00350
      SpreadEventsMonitor                    19       0.00021
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  22       0.00050
      -------------------------------------------------------
      Total                                  79       6.00421
    ]

  The best solution seems to be the same, but the other solutions
  were slightly better before, so we'll go with not requiring the
  resource to be free.

  Begun documenting the augment functions in khe/khe/doc

20 Feb 2014.  Changing over continue monitors to be the whole
  solution.  When I changed the time ones, nothing changed.
  When I changed the resource one, the run went from this:

    KheGeneralSolve2014 at end (32.92 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 10.00421)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       6.00000
      AvoidSplitAssignmentsMonitor           37       0.00370
      SpreadEventsMonitor                    16       0.00017
      AvoidClashesMonitor                     3       3.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  15       0.00034
      -------------------------------------------------------
      Total                                  76      10.00421
    ]

  to this:

    KheGeneralSolve2014 at end (91.15 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 10.00373)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       6.00000
      AvoidSplitAssignmentsMonitor           31       0.00320
      SpreadEventsMonitor                    21       0.00021
      AvoidClashesMonitor                     3       4.00000
      LimitBusyTimesMonitor                  14       0.00032
      -------------------------------------------------------
      Total                                  73      10.00373
    ]

  This is pretty clear evidence that the new repair for avoid
  split assignments constraints is working, but the cost in run
  time is very high.  I'll stick with it, however, and try to
  get the run time down later, somehow.  Best of 8:

    8.00395 10.00373 7.00401 5.00420 10.00401 6.00432 9.00486 6.00414
    [ Soln (instance "AU-BG-98", diversifier 1, cost 5.00420)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       4.00000
      AvoidSplitAssignmentsMonitor           33       0.00330
      SpreadEventsMonitor                    57       0.00064
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  12       0.00026
      -------------------------------------------------------
      Total                                 105       5.00420
    ]

  Best of 32, with layer swapping:

    6.00335 4.00510 8.00268 3.00430 8.00404 8.00417 8.00341 6.00389
    8.00407 6.00502 7.00334 15.00386 8.00458 7.00341 6.00488 9.00316
    10.00316 9.00449 7.00402 13.00409 11.00432 8.00478 4.00487 4.00369
    19.00394 11.00446 15.00498 5.00398 7.00437 7.00502 8.00268 14.00451
    [ Soln (instance "AU-BG-98", diversifier 2, cost 3.00430)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           37       0.00380
      SpreadEventsMonitor                    19       0.00020
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  12       0.00030
      -------------------------------------------------------
      Total                                  71       3.00430
    ]

  This has actually turned out inferior to the previous best,
  which was 3.00400:

    [ Soln (instance "AU-BG-98", diversifier 12, cost 3.00400)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       3.00000
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    26       0.00026
      LimitBusyTimesMonitor                  15       0.00034
      -------------------------------------------------------
      Total                                  77       3.00400
    ]

  I seem to have brought the ejection chains chapter of
  khe/khe/doc up to date at last.  Quite a slog.

  The excessive running time seems to be going in repairing
  teacher assignments:

    after Class assignment (parts 1 and 2) (8.56 secs)
    after Teacher assignment (parts 1 and 2) (90.37 secs)

  It's funny though that the part 3 call is much faster; it
  seems that the teacher assignment repairs are actually
  getting somewhere, hence taking such a long time.  I
  need to look in detail at what is being found during
  these teacher repairs, to get ideas for speeding up.

  OK, so here are some tests.

  (1) Follow the new plan.  As above, this gives

    KheGeneralSolve2014 at end (91.15 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 10.00373)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       6.00000
      AvoidSplitAssignmentsMonitor           31       0.00320
      SpreadEventsMonitor                    21       0.00021
      AvoidClashesMonitor                     3       4.00000
      LimitBusyTimesMonitor                  14       0.00032
      -------------------------------------------------------
      Total                                  73      10.00373
    ]

  (2) Try the time assignment plan during resource assignment:

    KheGeneralSolve2014 at end (126.83 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 23.00303)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                  13      19.00000
      AvoidSplitAssignmentsMonitor           25       0.00260
      SpreadEventsMonitor                    15       0.00015
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  11       0.00028
      -------------------------------------------------------
      Total                                  67      23.00303
    ]

    The LimitWorkloadMonitor problems arise again here, I saw
    one in a listing above this one.  Not surprising of course.

  (3) Try the time assignment plan during resource assignment,
  but without detaching limit workload monitors:

    KheGeneralSolve2014 at end (75.50 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 10.00305)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       7.00000
      AvoidSplitAssignmentsMonitor           26       0.00260
      SpreadEventsMonitor                    20       0.00021
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  11       0.00024
      -------------------------------------------------------
      Total                                  64      10.00305
    ]

  This is the best of these three results.  Best of 8:

    5.00311 7.00418 10.00305 6.00397 10.00296 6.00518 4.00406 12.00394
    [ Soln (instance "AU-BG-98", diversifier 7, cost 4.00406)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       1.00000
      AvoidSplitAssignmentsMonitor           29       0.00310
      SpreadEventsMonitor                    75       0.00076
      AvoidClashesMonitor                     3       3.00000
      LimitBusyTimesMonitor                   8       0.00020
      -------------------------------------------------------
      Total                                 116       4.00406
    ]

  Best of 32, with layer time swaps:

    3.00311 6.00296 9.00243 4.00356 11.00397 7.00384 11.00311 10.00359
    8.00409 8.00370 14.00426 11.00389 5.00261 6.00362 6.00440 12.00252
    11.00412 9.00440 10.00353 8.00389 10.00467 8.00380 6.00427 5.00283
    17.00393 12.00476 7.00358 18.00438 7.00223 8.00409 9.00243 11.00329
    [ Soln (instance "AU-BG-98", diversifier 2, cost 3.00311)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           24       0.00250
      SpreadEventsMonitor                    25       0.00025
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  13       0.00036
      -------------------------------------------------------
      Total                                  65       3.00311
    ]

  This is a new best.  Eyeballing it is pretty amazing:  just 2
  split assignments in the Maths faculty.  The clash is a Languages
  teacher, the 2 unassigned event resources are Art.

  Had a brilliant idea for disentangling limit workload overload
  monitors from their workload demand monitors:  find the lowest
  workload at which the workload demand monitors kick in, and modify
  the limit workload monitor so that it kicks out at that point.
  Then small overloads will be detected by the limit workload
  monitor, and larger ones will be detected by the workload
  demand monitors, but the repairs will be the same in both
  cases.  This will solve all the correlation problems and allow
  the exact same primary grouping/detaching to be used in both
  time assignment and resource assignment.

21 Feb 2014.  Documented yesterday's brilliant idea for handling
  limit workload monitors, including expressing it in a concrete
  form ready for implementation.  I've implemented most of it.

22 Feb 2014.  Finished off the implementation of the brilliant
  idea.  This presumably concludes the unification drive that
  I began on 13 February, a bit over one week ago.  It seems to
  be working correctly, although it's slow:

    KheGeneralSolve2014 at end (74.62 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 10.00500)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       7.00000
      AvoidSplitAssignmentsMonitor           42       0.00450
      SpreadEventsMonitor                    24       0.00024
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  11       0.00026
      -------------------------------------------------------
      Total                                  84      10.00500
    ]

  Most of the time goes on resource repair.  Best of 8:

    6.00481 6.00393 10.00500 10.00409 6.00491 10.00306 13.00467 5.00405
    [ Soln (instance "AU-BG-98", diversifier 7, cost 5.00405)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           31       0.00310
      SpreadEventsMonitor                    74       0.00077
      AvoidClashesMonitor                     3       3.00000
      LimitBusyTimesMonitor                   8       0.00018
      -------------------------------------------------------
      Total                                 118       5.00405
    ]

  These are OK.  Best of 32 with node swapping:

    3.00346 9.00237 6.00274 4.00462 11.00368 11.00280 10.00260 10.00307
    8.00395 7.00408 5.00272 13.00390 12.00418 11.00391 11.00299 12.00502
    9.00364 9.00383 8.00369 12.00472 9.00372 9.00430 6.00298 6.00366
    12.00455 16.00375 20.00446 8.00389 7.00400 8.00348 9.00237 13.00388
    [ Soln (instance "AU-BG-98", diversifier 2, cost 3.00346)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           29       0.00290
      SpreadEventsMonitor                    26       0.00026
      AvoidClashesMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  11       0.00030
      -------------------------------------------------------
      Total                                  68       3.00346
    ]

  Not quite as good as my best (3.00311), but close, and the aim
  was to tidy up the code, not to improve solution quality.  All
  but two of these solutions have distinct cost, so it seems that
  the diversifier is working.

  Setting time_repair to false during resource repair produces

    KheGeneralSolve2014 at end (20.47 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 13.00428)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       3.00000
      AvoidSplitAssignmentsMonitor           34       0.00360
      SpreadEventsMonitor                    20       0.00020
      AvoidClashesMonitor                     5       7.00000
      AvoidUnavailableTimesMonitor            2       3.00000
      LimitBusyTimesMonitor                  17       0.00048
      -------------------------------------------------------
      Total                                  81      13.00428
    ]

  which is faster but worse.  Best of 8 produces

    3.00532 13.00428 7.00428 7.00684 10.00530 10.00563 12.00557 9.00584
    [ Soln (instance "AU-BG-98", diversifier 2, cost 3.00532)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           43       0.00460
      SpreadEventsMonitor                    10       0.00010
      AvoidClashesMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  24       0.00062
      -------------------------------------------------------
      Total                                  79       3.00532
    ]

  which is remarkable but is actually just luck, considering
  the second best has cost 7.00428.  We're doing time repairs
  during resource assignment to fix split assignments, and it's
  clear that the number here, 43, is a lot worse than the 29 in
  the previous best of 8, or the 24 in the overall best.

  Still, this option might be a useful way to speed up testing
  while fiddling with other things.

  Tried suppress_recent again, since it worked well before on bghs98.
  This time around it was much slower:

    KheGeneralSolve2014 at end (102.52 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 8.00261)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       5.00000
      AvoidSplitAssignmentsMonitor           19       0.00200
      SpreadEventsMonitor                    32       0.00033
      AvoidClashesMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  12       0.00028
      -------------------------------------------------------
      Total                                  68       8.00261
    ]

  although the cost is quite good.  But there is no clear
  signal, so it looks like I can cross that bright idea off.

  Let's make a first attempt at making the most likely
  repairs first, by sorting meets by increasing demand.
  Here is the standard run (except that time repair during
  resource repair is turned off) without sorting meets:

    KheGeneralSolve2014 at end (20.42 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 13.00428)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       3.00000
      AvoidSplitAssignmentsMonitor           34       0.00360
      SpreadEventsMonitor                    20       0.00020
      AvoidClashesMonitor                     5       7.00000
      AvoidUnavailableTimesMonitor            2       3.00000
      LimitBusyTimesMonitor                  17       0.00048
      -------------------------------------------------------
      Total                                  81      13.00428
    ]

  And here it is with sorting meets:

    KheGeneralSolve2014 at end (27.76 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 14.00633)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       7.00000
      AvoidSplitAssignmentsMonitor           54       0.00570
      SpreadEventsMonitor                     3       0.00003
      AvoidClashesMonitor                     4       5.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  26       0.00060
      -------------------------------------------------------
      Total                                  91      14.00633
    ]

  Curiously enough, the results are quite a lot worse.  Best of 8:

    16.00452 14.00633 9.00625 11.00485 6.00614 12.00608 4.00571 8.00602
    [ Soln (instance "AU-BG-98", diversifier 7, cost 4.00571)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           47       0.00500
      SpreadEventsMonitor                    13       0.00013
      AvoidClashesMonitor                     1       1.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  23       0.00058
      -------------------------------------------------------
      Total                                  87       4.00571
    ]

  No clear signal.  But let's persevere with trying the most
  likely repairs first.  It might pay off somewhere else.

23 Feb 2014.  Started work on a new interface for the ejector.
  Eventually I will extend it behind the scenes to accumulate
  repairs and choose the best; but the initial aim is just to
  get the current functionality with the new interface.

24 Feb 2014.  Got the new interface going, here's the first run,
  including time repair during resource repair:

    KheGeneralSolve2014 at end (67.05 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 20.00437)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       9.00000
      AvoidSplitAssignmentsMonitor           36       0.00370
      SpreadEventsMonitor                    43       0.00045
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            4       9.00000
      LimitBusyTimesMonitor                  11       0.00022
      -------------------------------------------------------
      Total                                 100      20.00437
    ]

  This is very slow and very bad - has something gone wrong?
  Best of 8:

    20.00437 17.00309 17.00446 10.00393 9.00480 21.00421 10.00450 19.00391
    [ Soln (instance "AU-BG-98", diversifier 5, cost 9.00480)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       1.00000
      AvoidSplitAssignmentsMonitor           38       0.00400
      SpreadEventsMonitor                    44       0.00046
      AvoidClashesMonitor                     4       5.00000
      AvoidUnavailableTimesMonitor            1       3.00000
      LimitBusyTimesMonitor                  16       0.00034
      -------------------------------------------------------
      Total                                 104       9.00480
    ]

  Something is wrong here.  Is it demand limits?

25 Feb 2014.  Discovered that I was doing layer swaps yesterday.
  which explains the long run times.  Also found the bug; the
  new code was not enforcing limit monitors, even though it
  seemed to be.  Result now is:

    KheGeneralSolve2014 at end (75.06 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 10.00500)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       7.00000
      AvoidSplitAssignmentsMonitor           42       0.00450
      SpreadEventsMonitor                    24       0.00024
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  11       0.00026
      -------------------------------------------------------
      Total                                  84      10.00500
    ]

  Best of 8 is:

    6.00481 6.00393 10.00500 10.00409 6.00491 10.00306 13.00467 5.00405
    [ Soln (instance "AU-BG-98", diversifier 7, cost 5.00405)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           31       0.00310
      SpreadEventsMonitor                    74       0.00077
      AvoidClashesMonitor                     3       3.00000
      LimitBusyTimesMonitor                   8       0.00018
      -------------------------------------------------------
      Total                                 118       5.00405
    ]

  So we're back in the ballpark.  These are the same results as
  obtained on 22 Feb 2014, as they should be.  The running time for
  one solution then was 74.62 secs, as compared with 75.06 secs
  today, so there are no new speed problems with the new code.

  Wrote code to get the ejector to accumulate and sort repairs.
  Needs a careful audit, perhaps a rewrite, and then test.

26 Feb 2014.  New version of ejector is ready for testing.
  First results:

    KheGeneralSolve2014 at end (83.17 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 11.00470)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       6.00000
      AvoidSplitAssignmentsMonitor           40       0.00430
      SpreadEventsMonitor                    17       0.00018
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       3.00000
      LimitBusyTimesMonitor                  11       0.00022
      -------------------------------------------------------
      Total                                  75      11.00470
    ]

  Best of 8:

    7.00341 11.00470 18.00353 9.00303 15.00260 12.00354 9.00396 6.00385
    [ Soln (instance "AU-BG-98", diversifier 7, cost 6.00385)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           32       0.00330
      SpreadEventsMonitor                    27       0.00029
      AvoidClashesMonitor                     2       3.00000
      AvoidUnavailableTimesMonitor            1       3.00000
      LimitBusyTimesMonitor                  11       0.00026
      -------------------------------------------------------
      Total                                  73       6.00385
    ]

  These are not completely disastrous, but there has been no
  speedup at all, which is a shame.

27 Feb 2014.  Decided to make sorting an option.  I've implemented
  the combined version; here is the run with sorting:

    KheGeneralSolve2014 at end (140.84 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 14.00395)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   6       8.00000
      AvoidSplitAssignmentsMonitor           36       0.00360
      SpreadEventsMonitor                     9       0.00009
      AvoidClashesMonitor                     3       3.00000
      AvoidUnavailableTimesMonitor            1       3.00000
      LimitBusyTimesMonitor                  12       0.00026
      -------------------------------------------------------
      Total                                  67      14.00395
    ]

  On this run there are limit workload defects which are being
  repaired by task deassignments at the end, hence the 6 assign
  resource defects.  And here it is without sorting:

    KheGeneralSolve2014 at end (94.26 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 5.00411)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       4.00000
      AvoidSplitAssignmentsMonitor           33       0.00330
      SpreadEventsMonitor                    47       0.00047
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  15       0.00034
      -------------------------------------------------------
      Total                                  99       5.00411
    ]

  This is quite a lot better, basically because the limit
  workload defects are not appearing.  It presumably runs
  faster because it isn't doing everything twice.  Best of 8:

    14.00326 5.00411 4.00438 4.00468 11.00237 17.00366 7.00293 6.00519
    [ Soln (instance "AU-BG-98", diversifier 3, cost 4.00438)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       1.00000
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    62       0.00068
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  14       0.00030
      -------------------------------------------------------
      Total                                 114       4.00438
    ]

  The wide variation is basically due to limit workload defects
  coming up and being corrected by resource deassignments at
  the end.

  Here is a first attempt at varying the starting point of
  searches more or less randomly (using the number of augments
  so far as a shift), applied to ejecting task moves within
  function KheResourceLoadDefectAugment.  It is to be compared
  with the 5.00411 solution above:

    KheGeneralSolve2014 at end (59.11 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 5.00431)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   3       4.00000
      AvoidSplitAssignmentsMonitor           33       0.00350
      SpreadEventsMonitor                    46       0.00049
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  14       0.00032
      -------------------------------------------------------
      Total                                  97       5.00431
    ]

  It's a lot faster and somewhat better - very interesting.  Now
  here is that change plus the same kind of shifting applied to
  ejecting meet moves within KheResourceLoadDefectAugment:

    KheGeneralSolve2014 at end (69.43 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 4.00454)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       3.00000
      AvoidSplitAssignmentsMonitor           35       0.00360
      SpreadEventsMonitor                    54       0.00056
      AvoidClashesMonitor                     1       1.00000
      LimitBusyTimesMonitor                  18       0.00038
      -------------------------------------------------------
      Total                                 110       4.00454
    ]

  Somewhat slower, but the solution is better.  Looks like
  this might be worth doing.  Here is all of the above plus
  doing it for selecting the parent meet in KheTimeAugment:

    KheGeneralSolve2014 at end (55.44 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 14.00407)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       9.00000
      AvoidSplitAssignmentsMonitor           33       1.00340
      SpreadEventsMonitor                    49       0.00049
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                   9       0.00018
      -------------------------------------------------------
      Total                                  98      14.00407
    ]

  It went bad because the limit workload monitor problem came
  up.  I really need to do something about that.  Best of 8
  was 3.00432, close to my best result so far.  Now for shifting
  when trying KheTaskEjectingMoveResourceGroup.

    KheGeneralSolve2014 at end (83.83 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 15.00364)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       9.00000
      AvoidSplitAssignmentsMonitor           25       0.00280
      SpreadEventsMonitor                    60       0.00062
      AvoidClashesMonitor                     4       4.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  10       0.00022
      -------------------------------------------------------
      Total                                 104      15.00364
    ]

  Best of 8:

    3.00384 6.00474 6.00386 15.00364 11.00361 18.00532 6.00477 10.00379
    [ Soln (instance "AU-BG-98", diversifier 3, cost 3.00384)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           32       0.00330
      SpreadEventsMonitor                    20       0.00022
      AvoidClashesMonitor                     1       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  16       0.00032
      -------------------------------------------------------
      Total                                  70       3.00384
    ]

  Another really good result, better than my first posted result of
  3.00400 but not than my second posted result of 3.00311.  Here is
  what happens if you turn off time repair during resource repair:

    KheGeneralSolve2014 at end (17.13 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 13.00642)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   4       9.00000
      AvoidSplitAssignmentsMonitor           51       0.00550
      SpreadEventsMonitor                    44       0.00044
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       2.00000
      LimitBusyTimesMonitor                  20       0.00048
      -------------------------------------------------------
      Total                                 122      13.00642
    ]

  This confirms that most of the long running time is being
  devoted to time repair during resource repair.  After putting
  the shift into everything, and going back to otherwise
  standard stuff (no layer swaps), I got this:

    6.00430 10.00367 7.00340 6.00568 3.00281 10.00448 12.00531 5.00275
    [ Soln (instance "AU-BG-98", diversifier 5, cost 3.00281)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           23       0.00240
      SpreadEventsMonitor                    12       0.00013
      AvoidClashesMonitor                     2       3.00000
      LimitBusyTimesMonitor                  13       0.00028
      -------------------------------------------------------
      Total                                  50       3.00281
    ]

  Another new best, hurrah!  Best of 32:

    6.00430 10.00367 7.00340 6.00568 3.00281 10.00448 12.00531 4.00467
    5.00275 11.00408 8.00351 6.00506 6.00277 5.00342 2.00340 3.00404
    10.00414 13.00359 14.00400 10.00456 10.00478 11.00442 10.00481 9.00454
    14.00304 13.00324 18.00243 7.00457 8.00472 8.00303 10.00367 7.00340
    [ Soln (instance "AU-BG-98", diversifier 14, cost 2.00340)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       2.00000
      AvoidSplitAssignmentsMonitor           27       0.00280
      SpreadEventsMonitor                    30       0.00032
      LimitBusyTimesMonitor                  13       0.00028
      -------------------------------------------------------
      Total                                  71       2.00340
    ]

  Eureka, easily the best ever.  Posted on my web site and
  email sent to Gerhard.

28 Feb 2014.  Did nothing today except try the same thing with
  layer swapping, which gave this:

    3.00430 14.00385 6.00382 12.00362 5.00475 11.00373 11.00319 10.00419
    10.00335 14.00371 7.00335 8.00298 13.00463 8.00324 5.00442 4.00433
    9.00546 5.00413 21.00417 15.00472 11.00418 7.00378 17.00317 2.00426
    7.00310 15.00303 13.00464 8.00341 10.00391 13.00375 3.00430 12.00362
    [ Soln (instance "AU-BG-98", diversifier 24, cost 2.00426)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           34       0.00350
      SpreadEventsMonitor                    35       0.00036
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  13       0.00040
      -------------------------------------------------------
      Total                                  84       2.00426
    ]

  It's a good solution but not as good as yesterday's.

29 Feb 2014.  Have decided to give some time to IT-I4-96.  It
  runs quite quickly and there are cluster busy times defects
  to work with.  Here is the starting point:

    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.01038)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           20       0.00281
      LimitIdleTimesMonitor                  28       0.00045
      ClusterBusyTimesMonitor                 6       0.00700
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  56       0.01038
    ]
  
  And best of 8:

    0.01077 0.00821 0.01454 0.01038 0.01062 1.00639 0.01035 0.00717
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00717)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           18       0.00169
      LimitIdleTimesMonitor                  19       0.00036
      ClusterBusyTimesMonitor                 4       0.00500
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  43       0.00717
    ]

  There is only one cluster busy times constraint in IT-I4-96,
  the one that requests every class to be busy on the first
  time each day.  It cannot be overloaded, so these cluster
  busy times defects are all underload defects.

  Realized what the underload problem was:  it was assuming
  that the times in the cluster times constraint cover the
  cycle, when in the case of IT-I4-96 they don't.  After
  fixing it I got this:

    KheGeneralSolve2014 at end (12.86 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00652)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           25       0.00184
      LimitIdleTimesMonitor                  30       0.00056
      ClusterBusyTimesMonitor                 4       0.00400
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  61       0.00652
    ]

  Best of 8:

    0.00652 0.00432 1.00226 0.00520 0.00630 0.00526 0.00436 0.00464
    [ Soln (instance "IT-I4-96", diversifier 3, cost 0.00432)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           17       0.00060
      LimitIdleTimesMonitor                  29       0.00054
      ClusterBusyTimesMonitor                 3       0.00300
      LimitBusyTimesMonitor                   3       0.00018
      -------------------------------------------------------
      Total                                  52       0.00432
    ]

  So there has been a definite improvement, but the remaining
  3 or 4 cluster busy times defects are a real spanner in the
  works here.  Without them I would have a competitive soln.
  Best of 32:

    0.00432 0.00652 1.00226 0.00520 0.00630 0.00526 0.00436 0.00464
    0.01152 0.00672 0.00333 0.00444 0.00533 0.00241 0.01032 0.00449
    0.00746 0.00737 1.00607 0.00520 0.00244 1.00544 0.00543 0.00733
    0.00652 0.00432 0.00520 1.00226 0.00464 0.00630 0.00526 0.00436
    [ Soln (instance "IT-I4-96", diversifier 13, cost 0.00241)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           22       0.00075
      LimitIdleTimesMonitor                  27       0.00054
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  52       0.00241
    ]

  This is quite a lot better but more work is needed.  Got this
  next one by allowing moves that just move the hole around, and
  by trying Kempe meet moves, not just ejecting meet moves:

    KheGeneralSolve2014 at end (13.14 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00341)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           17       0.00166
      LimitIdleTimesMonitor                  33       0.00063
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  53       0.00341
    ]

  Best of 8:

    0.00439 0.00310 0.00341 0.00223 0.00331 0.00341 0.00154 0.00531
    [ Soln (instance "IT-I4-96", diversifier 5, cost 0.00154)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           22       0.00084
      LimitIdleTimesMonitor                  24       0.00058
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  48       0.00154
    ]

  This is quite a lot better.   There are no cluster busy times
  defects at all.  Best of 32:

    0.00439 0.00310 0.00341 0.00223 0.00331 0.00341 0.00154 0.00531
    0.00536 0.00334 0.00128 1.00564 0.00338 0.00636 0.00745 0.00430
    0.00348 0.00125 0.00138 0.00426 0.00221 0.00356 0.00437 0.00456
    0.00341 0.00223 0.00310 0.00439 0.00331 0.00154 0.00341 0.00531
    [ Soln (instance "IT-I4-96", diversifier 16, cost 0.00125)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           17       0.00060
      LimitIdleTimesMonitor                  26       0.00053
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  45       0.00125
    ]

  Not bad, we need to target these other defects now.  Allowing
  Kempe meet moves for load defects:

    KheGeneralSolve2014 at end (14.53 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00423)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           15       0.00057
      LimitIdleTimesMonitor                  28       0.00048
      ClusterBusyTimesMonitor                 3       0.00300
      LimitBusyTimesMonitor                   3       0.00018
      -------------------------------------------------------
      Total                                  49       0.00423
    ]

  This is worse, although some things are better.  Best of 8:

    0.00233 0.00424 0.00423 0.00242 0.00654 0.00253 0.00207 0.00333
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00207)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           14       0.00151
      LimitIdleTimesMonitor                  26       0.00044
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  42       0.00207
    ]

  Also worse.  Best of 32 was the same, 0.00207.  Returning to

    KheGeneralSolve2014 at end (13.14 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00341)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           17       0.00166
      LimitIdleTimesMonitor                  33       0.00063
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  53       0.00341
    ]

  and then favouring available times gave this:

    KheGeneralSolve2014 at end (12.25 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00232)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           20       0.00166
      LimitIdleTimesMonitor                  26       0.00054
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  48       0.00232
    ]

  Best of 8:

    0.00238 0.00232 0.00550 0.00417 0.00255 0.00457 0.00219 2.00641
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00219)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           17       0.00160
      LimitIdleTimesMonitor                  25       0.00047
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  44       0.00219
    ]

  Best of 32 was also 0.00219.  So I've taken away trying
  available times first.  Belatedly realized that I can use
  KheResourceLoadDefectAugment to repair cluster underloads.
  So I've now changed to doing that, giving:

    KheGeneralSolve2014 at end (11.49 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00432)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           23       0.00178
      LimitIdleTimesMonitor                  22       0.00042
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  49       0.00432
    ]

  Best of 8:

    0.00432 0.00446 0.00222 0.00624 0.00661 0.00437 1.00428 0.00639
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.00222)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           19       0.00160
      LimitIdleTimesMonitor                  25       0.00050
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  46       0.00222
    ]

  Best of 32 was also 0.00222.

2 Mar 2014.  Implemented overlap testing, so that meets are
  moved only when that would increase or decrease the overlap
  with a given time group, whichever is required.

    KheGeneralSolve2014 at end (12.27 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00400)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            8       0.00033
      LimitIdleTimesMonitor                  30       0.00055
      ClusterBusyTimesMonitor                 3       0.00300
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  43       0.00400
    ]

  Best of 8:

    0.00400 0.00206 0.00507 0.00299 0.00213 0.00231 1.00120 1.00199
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.00206)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            9       0.00033
      LimitIdleTimesMonitor                  31       0.00061
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  43       0.00206
    ]

  These are slightly better than yesterday, which is all to the
  good, but not world-beating.  Best of 32:

    0.00400 0.00206 0.00507 0.00299 0.00213 0.00231 1.00120 1.00199
    0.00497 0.00322 0.00313 0.00307 0.00440 0.00312 0.00214 0.00414
    0.00413 0.00400 0.00101 0.00321 0.00114 0.00420 0.00099 0.00593
    0.00400 0.00206 0.00299 0.00507 0.00213 1.00120 0.00231 1.00199
    [ Soln (instance "IT-I4-96", diversifier 22, cost 0.00099)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            6       0.00024
      LimitIdleTimesMonitor                  30       0.00063
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  38       0.00099
    ]

  This is my best so far, but still not as good as the best so far.
  Looks like more work is required on idle times.

  Installed a new version of HSEval today, one that accepts both
  sets of cost functions, and let Gerhard know.

  Returning to the 0.00400 solution above, trying Kempe moves gives

    KheGeneralSolve2014 at end (8.60 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00174)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           10       0.00036
      LimitIdleTimesMonitor                  17       0.00026
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  30       0.00174
    ]

  Gosh, what an improvement!  Best of 8:

    0.00386 0.00076 0.00174 0.00263 0.00071 0.00185 0.00181 0.00067
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00067)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  20       0.00028
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  29       0.00067
    ]

  Thank you, God!  Best of 32:

    0.00386 0.00076 0.00174 0.00263 0.00071 0.00185 0.00181 0.00067
    0.00302 0.00375 0.00185 0.00289 0.00285 0.00187 0.00199 0.00287
    0.00577 0.00290 0.00266 1.00284 0.00285 0.00205 0.00296 0.00168
    0.00174 0.00076 0.00263 0.00386 0.00185 0.00181 0.00071 0.00067
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00067)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  20       0.00028
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  29       0.00067
    ]

  I've posted this on the KHE web page; although it is not a new
  best, it's close.  I also tried best of 128 and got this same
  solution.

  Tried a new visit number for each time group in the limit idle
  times augment function (depth 1 only).  Results were slightly
  worse until I tried best of 32, when I got this:

    0.00186 0.00172 0.00171 0.00375 0.00473 0.00099 0.00173 0.00188
    0.00289 0.00385 0.00280 0.00380 0.00186 0.00274 0.00175 0.00283
    0.00182 0.00368 0.00079 0.00398 0.00081 0.00192 0.00470 0.00186
    0.00171 0.00375 0.00061 0.00172 0.00473 0.00099 0.00188 0.00173
    [ Soln (instance "IT-I4-96", diversifier 23, cost 0.00061)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            6       0.00024
      LimitIdleTimesMonitor                  19       0.00025
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  27       0.00061
    ]

  It's probably just chance, but anyway it's the best so far.  This
  was also the best of 128.  Tried one more major phase, since the
  augment functions are nondeterministic now:

    KheGeneralSolve2014 at end (8.65 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00387)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           13       0.00048
      LimitIdleTimesMonitor                  17       0.00027
      ClusterBusyTimesMonitor                 3       0.00300
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  35       0.00387
    ]

  This is a bit better, actually.  Best of 8:

    0.00387 1.00286 0.00498 0.00171 0.00100 0.00294 0.00281 0.00069
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00069)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            9       0.00033
      LimitIdleTimesMonitor                  17       0.00024
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  28       0.00069
    ]

  This is worse, by 1, than before.  Best of 32 is the same.  I
  could try combinations of these ideas but I won't, because I'm
  looking for clear signals, not random noise.

3 Mar 2014.  Finished the coding that makes limit idle times
  repairs exact, i.e. they move a meet exactly when that move
  would reduce the number of idle times.  Also added shifting
  to cluster underload repair, overlooked before.  Best of 1:

    KheGeneralSolve2014 at end (12.70 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00397)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           18       0.00063
      LimitIdleTimesMonitor                  15       0.00022
      ClusterBusyTimesMonitor                 3       0.00300
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  38       0.00397
    ]

  Best of 8:

    0.00165 0.00397 0.00398 0.00067 0.00191 0.00401 0.00180 0.00286
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.00067)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  21       0.00028
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  30       0.00067
    ]

  Best of 32 was the same, 0.00067.

4 Mar 2014.  Wrote a detailed description of "tree search layer
  reassignment", a VLSN search that reassigns the meets of one
  layer.  Started the implementation, in khe_st_tree_repair.c.

5 Mar 2014.  Working on tree search layer reassignment today.
  Have added all the exclusions (using a couple of shortcuts
  that I've documented as deserving removal later), plus a
  few small things.  Also done some testing which seems to
  show that the exclusions are being calculated correctly.
  So I'm ready to write the recursive search now.

  Wrote the search and tested it, and it found 4 improvements,
  which altogether reduced the cost from 0.00397 to 0.00390.
  This is with an assignment limit of 10000, which seems to
  be a good value.  (With a limit of 1000000, it found one
  more improvement, reducing the cost of 0.00389).  Best of 8:

    0.00160 0.00390 0.00392 0.00067 0.00190 0.00398 0.00284 0.00178
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.00067)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  21       0.00028
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  30       0.00067
    ]

  Comparing with the previous best of 8 we see that every soln
  has been improved - except the best one.  Best of 32:

    0.00160 0.00390 0.00392 0.00067 0.00190 0.00398 0.00284 0.00178
    0.00283 1.00287 0.00278 0.00286 0.00081 0.00288 0.00192 0.00075
    0.00397 0.00284 0.00282 0.00373 0.00163 2.00192 0.00281 0.00174
    0.00390 0.00160 0.00392 0.00067 0.00190 0.00398 0.00284 0.00178
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.00067)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  21       0.00028
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  30       0.00067
    ]

  Tried a test without the exclusions, and it found 3 improvements
  instead of 4 and ran several times more slowly.  So that's good.

  Started work on a complex repair for limit idle times defects.
  Got the complete code written and compiled, now it needs an
  audit and some testing on IT-I4-96.

7 Mar 2014.  Got the complex repair for limit idle times defects
  working.  Best of 1:

    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00277)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           10       0.00039
      LimitIdleTimesMonitor                  18       0.00026
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  32       0.00277
    ]

  Best of 8:

    0.00180 1.00305 1.00187 0.00277 0.00272 0.00084 0.00378 0.00393
    [ Soln (instance "IT-I4-96", diversifier 5, cost 0.00084)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           11       0.00042
      LimitIdleTimesMonitor                  19       0.00030
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  32       0.00084
    ]

  Best of 32:

    0.00180 1.00305 0.00277 1.00187 0.00272 0.00084 0.00378 0.00393
    1.00588 0.00172 0.00285 0.00291 0.00168 0.00193 1.00272 0.00176
    0.00402 0.00085 0.00287 1.00083 0.00194 0.00277 1.00296 0.00072
    0.00180 0.00277 1.00187 1.00305 0.00272 0.00084 0.00393 0.00378
    [ Soln (instance "IT-I4-96", diversifier 23, cost 0.00072)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            8       0.00030
      LimitIdleTimesMonitor                  20       0.00030
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  30       0.00072
    ]

  New global visit for each time group (best of 8):

    0.00269 0.00179 0.00071 0.00161 0.00481 0.00277 1.00165 0.00287
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.00071)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  20       0.00032
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  29       0.00071
    ]

  New global visit for each time group (best of 32):

    0.00085 0.00173 0.00093 0.00180 0.00272 0.00075 0.00064 0.00476
    0.00183 0.00268 1.00175 0.00380 0.00266 0.00187 1.00383 0.00174
    0.00172 0.00493 0.00069 0.00160 0.00075 0.00169 0.00175 0.00173
    0.00093 0.00180 0.00085 0.00272 1.00069 0.00476 0.00075 0.00064
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00064)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            6       0.00024
      LimitIdleTimesMonitor                  14       0.00028
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  22       0.00064
    ]

  This was also the best of 128.  Adding new global visits for
  limit busy times defects produced this (best of 8):

    0.00064 0.00176 0.00269 0.00174 0.00276 0.00082 0.00080 0.00069
    [ Soln (instance "IT-I4-96", diversifier 3, cost 0.00064)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            8       0.00030
      LimitIdleTimesMonitor                  15       0.00022
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  25       0.00064
    ]

  There is a really good average cost here.  Adding new global
  visits for cluster underloads produced this (best of 8):

    0.00178 0.00177 0.00067 0.00074 0.00076 0.00066 0.00082 0.00074
    [ Soln (instance "IT-I4-96", diversifier 5, cost 0.00066)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            9       0.00033
      LimitIdleTimesMonitor                  13       0.00021
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  24       0.00066
    ]

  Slightly worse but the average is remarkably good: nothing
  over 0.00178.  Adding new global visits in all cases where
  they seem to apply produced the same result for best of 8.

    0.00178 0.00177 0.00067 0.00074 0.00076 0.00066 0.00074 0.00082
    0.00176 0.00278 0.00082 0.00183 0.00172 0.00283 0.00175 0.00184
    0.00282 0.00490 0.00164 0.00167 0.00080 0.00285 0.00292 0.00060
    0.00067 0.00074 0.00177 0.00178 0.00076 0.00066 0.00074 0.00082
    [ Soln (instance "IT-I4-96", diversifier 23, cost 0.00060)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            6       0.00024
      LimitIdleTimesMonitor                  16       0.00024
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  24       0.00060
    ]

  Best so far, now posted on my web page.

  Tried AU-BG-98, best of 32 was 2.00431, slightly worse than
  my best (2.00340), but still pretty darn good.

  The lower bound of 27 given for IT-I4-96 on the web site is trivial
  to calculate, based on comparing the workloads of these resources
  with their constraints:

      Resource     Lower bound
      ------------------------
      palest1                6
      palest2                6
      2G                     3
      3A                     6
      3B                     6
      ------------------------
      Total                 27

  I've been looking at the defects in the cost 60 solution in detail.
  One of them, where 5B is busy with event FR-5B_3 at the end of the
  day, has cost 3 and can be fixed as follows:

      Event       From     To     Defects change
      -----------------------------------------------
      FR-5B_3     tu5      tu1    +1 cutrone idle tu3
      LT-5B_5     tu1      mo1    0 buccico
      LT-5B_1     mo1      tu3    0 buccico
      MT-5B_1     mo4      we5    +1 pucciar idle mo4
      -----------------------------------------------

  It is easy to verify that 5B has no defects after these changes,
  so the only possible defects are in the teachers.  This gives
  a net improvement of 1, and leaves open the possibility that
  these two new defects could be repaired later.

  This repair could be found by a VLSN search which redoes the 5B
  timetable for two days, except that MT-5B_1 ends up on we5.  The
  beauty of this is that we are just reassigning the meets of one
  resource, 5B.  Can we build a suitable VLSN neighbourhood around
  the FR-5B_3 defect?  We don't want to redo everything, since that
  is KheTreeSearchRepairTimes, and experience shows that it takes
  too long - unless we can speed it up somehow.

8 Mar 2014.  Documented a better version of the Kempe meet move.
  I now need to audit the new spec carefully, then implement it.

9 Mar 2014.  Implemented the revised Kempe meet move today.  All
  done, although not tested, and the code for initializing frames
  needs a very careful audit.

10 Mar 2014.  Auditing Kempe code, I spotted a nasty special case
  where the combined block special case does not apply in the usual
  way, but the ordinary case can't be made to work either, because
  the from and to blocks overlap.  Now have a new specification
  which handles this problem, ready to implement.

11 Mar 2014.  Yet another new version of the Kempe code written.
  Looked into the obscure problem of skipping the first competitor,
  decided not to, and changed the code accordingly.  Everything is
  carefully audited and ready for testing.  I should do some serious
  debug output as part of the testing.

12 Mar 2014.  Testing the new Kempe meet move today.  Seemed to
  work first time; I observed a case where a durn 1 meet moved
  ->, a durn 2 <-, and then a second durn 1 ->, which is good.
  But there was a bug, which I subsequently fixed.  to IT-I4-96:

    KheGeneralSolve2014 at end (58.20 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00073)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor           12       0.00042
      LimitIdleTimesMonitor                  14       0.00019
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  28       0.00073
    ]

  This is pretty good for one shot.  Best of 8:

    0.00165 0.00073 0.00183 0.00188 0.00167 0.00059 0.00069 0.00066
    [ Soln (instance "IT-I4-96", diversifier 5, cost 0.00059)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  12       0.00020
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  21       0.00059
    ]

  This is my best so far.  Best of 32 is the same:

    0.00165 0.00073 0.00183 0.00188 0.00167 0.00059 0.00069 0.00066
    0.00263 0.00153 0.00181 0.00069 0.00065 0.00170 0.00076 0.00160
    0.00062 0.00169 1.00056 0.00060 0.00263 1.00163 0.00064 2.00072
    0.00073 0.00183 0.00165 0.00188 0.00167 0.00059 0.00069 0.00066
    [ Soln (instance "IT-I4-96", diversifier 5, cost 0.00059)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  12       0.00020
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  21       0.00059
    ]

  and best of 128 is also the same.

  Turning now to AU-BG-98:

    KheGeneralSolve2014 at end (49.39 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 4.00283)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       3.00000
      AvoidSplitAssignmentsMonitor           22       0.00230
      SpreadEventsMonitor                    31       0.00031
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  10       0.00022
      -------------------------------------------------------
      Total                                  66       4.00283
    ]

  This is not bad for one shot.  Best of 8:

    11.00327 4.00283 6.00356 7.00355 8.00375 8.00432 12.00354 3.00491
    [ Soln (instance "AU-BG-98", diversifier 5, cost 3.00491)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   1       1.00000
      AvoidSplitAssignmentsMonitor           42       0.00430
      SpreadEventsMonitor                    26       0.00027
      AvoidClashesMonitor                     2       2.00000
      LimitBusyTimesMonitor                  15       0.00034
      -------------------------------------------------------
      Total                                  86       3.00491
    ]

  Not bad, although I've seen better.  Best of 32:

    11.00327 4.00283 6.00356 7.00355 8.00375 8.00432 12.00354 6.00398
    3.00491 5.00295 8.00247 3.00271 4.00313 2.00399 5.00353 8.00403
    8.00347 6.00395 11.00538 7.00380 6.00411 4.00458 6.00294 12.00333
    14.00358 10.00384 6.00526 2.00434 8.00411 5.00382 4.00283 7.00355
    [ Soln (instance "AU-BG-98", diversifier 13, cost 2.00399)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           36       0.00370
      SpreadEventsMonitor                    18       0.00019
      LimitBusyTimesMonitor                   5       0.00010
      -------------------------------------------------------
      Total                                  61       2.00399
    ]

  This is also the best of 128.  It's pretty good, but not my best
  ever, which was 2.00340, best of

    6.00430 10.00367 7.00340 6.00568 3.00281 10.00448 12.00531 4.00467
    5.00275 11.00408 8.00351 6.00506 6.00277 5.00342 2.00340 3.00404
    10.00414 13.00359 14.00400 10.00456 10.00478 11.00442 10.00481 9.00454
    14.00304 13.00324 18.00243 7.00457 8.00472 8.00303 10.00367 7.00340

  It's noticeable however that in this list there are some quite large
  costs, including 14 over 10.00000, whereas in the latest list there are
  only 5 over 10.00000.  So we missed the peak but did better generally.

  Returning to IT-I4-96, I installed a lower bound calculation for
  limit busy times constraints, and managed to head off some useless
  repairs which gave the following result for best of 8:

    0.00063 0.00165 0.00156 0.00072 0.00162 0.00164 0.00165 0.00058
    [ Soln (instance "IT-I4-96", diversifier 4, cost 0.00058)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  15       0.00019
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  24       0.00058
    ]

  This is my best so far.  Best of 32 and best of 128 were the same.

  2H has an Avoid Unavailable Times Constraint violation of cost
  3 which could conceivably be removed (somehow).  Ditto 3I, 5E,
  and 5G.  So there is a potential reduction of up to 12 there,
  giving a solution of cost 46.  Plus miscellaneous limit idle
  times violations in the teachers which seem fairly hopeless.

  There is a rearrangement of the timetable of 3E which would do
  the job, just 4 meets have to change their times:

      IN-5E_2 -> th1 (this is the meet with the cost)
      LT-5E_4 -> mo1
      LT-5E_1 -> th3
      MT-5E_2 -> sa4

  Sadly, this isn't an ejection chain.  But it's pretty small.
  Also, many of the meets (the LT-5E_* meets) are taken by
  martine, and they are his only workload.  So provided a
  spot is left for them on each day (not sat, martine is
  unavailable then), they don't constrain things very much.

  Another look at VLSN rearrangement of one resource's timetable?
  Eureka, it found something, so now I have a new world record:

    0.00154 0.00058 0.00062 0.00068 0.00162 0.00164 0.00165 0.00056
    [ Soln (instance "IT-I4-96", diversifier 4, cost 0.00056)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            6       0.00024
      LimitIdleTimesMonitor                  15       0.00020
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  23       0.00056
    ]

  This was also the best of 128.

13 Mar 2014.  Looking through the remaining defects of IT-I4-96
  today, to see if I can drum up any ideas for further improvements.
  In the timetable of class 5G, the following changes reduce cost:

      DN3-5G   -> sa5
      LT-5G_1  -> sa2
      LT-5G_4  -> tu1
      MT-5G_1  -> sa1

  But here is something even easier that should have been found:

      MT-5G_1  -> sa1
      LT-5G_4  -> sa2

  Why wasn't this found?  Perhaps a new visit number at each
  level would find it.  Indeed, a new visit number does help:

    0.00059 0.00054 1.00157 0.00160 0.00158 0.00075 0.00164 0.00061
    [ Soln (instance "IT-I4-96", diversifier 3, cost 0.00054)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            7       0.00027
      LimitIdleTimesMonitor                  12       0.00015
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  21       0.00054
    ]

  I turned off KheTreeSearchRepairTimes and still got this, so
  I am running without KheTreeSearchRepairTimes now.  And look
  at this phenomenal solution to AU-BG-98:

    13.00230 12.00413 6.00355 1.00386 9.00363 10.00398 8.00387 2.00329
    [ Soln (instance "AU-BG-98", diversifier 0, cost 1.00386)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           33       0.00330
      SpreadEventsMonitor                    30       0.00032
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  11       0.00024
      -------------------------------------------------------
      Total                                  75       1.00386
    ]

  I didn't think I'd live to see the day.  This is also the best of 32.

  Added a somewhat unlikely lower bound to avoid clashes monitors.
  Currently adding lower bound diagnosis to HSEval.

13 Mar 2014.  Finished adding lower bound diagnosis to HSEval.

  Decided to work on BR-SA-00 for a while.  According to
  Gerhard's web site, there is a lower bound of 5, and the
  Danes have found a solution with cost 5.  Best of 8:

    1.00054 1.00066 1.00060 1.00057 1.00066 1.00066 1.00051 1.00066
    [ Soln (instance "BR-SA-00", diversifier 6, cost 1.00051)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidClashesMonitor                     1       1.00000
      LimitIdleTimesMonitor                   8       0.00033
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  11       1.00051
    ]

  This instance runs very quickly, but this solution is a long
  way from 5.  So I need to look into this.

  The hard cost 1 is caused by a defective split of the events
  of class S6.  One of the doubles needs to be split into two
  singles; as it its the existing doubles do not pack into the
  days, all of which have duration 5.

  Actually that's not quite right, because the prefer times
  constraints are soft with weight 1, so we could in fact
  span a day boundary with a double, at little cost.  So the
  layer tree is not packing events into days at all; but it
  then struggles to get rid of clashes like the one for S6.

  Something seems to be seriously wrong with the bin packing.
  After ensuring that I had five days of duration 5 each, and
  checking that the bin packer knew that, I found that it never
  seemed to be attempting to pack the entire layer of S6 meets
  into the cycle.  Why not?

  In op2, KheSplitForestTryAddToResource(sf, T13-S6, S6) does
  build partition (2 2 2 2 2 2 2 2 2 2 2 1 1 1) and try
  unsuccessfully to pack it into (5 5 5 5 5); but the
  consequence is not that it splits some more, but rather
  it rejects a class from a layer when clearly, since it
  contains S6, it needs to be in that layer.  So are the
  priorities wrong?  These layers should have been built
  before any jobs caused the min partition to contain
  doubles.

  OK, I discovered the problem:  the priority field of the layer
  tree jobs had type int, not KHE_COST, so that wrecked the sorting.
  After fixing that I got back into normal territory, and got this
  eminently reasonable solution:

    KheGeneralSolve2014 at end (2.73 secs elapsed):
    [ Soln (instance "BR-SA-00", diversifier 0, cost 0.00068)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00002
      LimitIdleTimesMonitor                   8       0.00030
      ClusterBusyTimesMonitor                 3       0.00036
      -------------------------------------------------------
      Total                                  12       0.00068
    ]

  Best of 8:

    0.00086 0.00083 0.00080 0.00068 0.00083 0.00074 1.00074 0.00077
    [ Soln (instance "BR-SA-00", diversifier 0, cost 0.00068)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00002
      LimitIdleTimesMonitor                   8       0.00030
      ClusterBusyTimesMonitor                 3       0.00036
      -------------------------------------------------------
      Total                                  12       0.00068
    ]

  The distribute split events defect is inevitable for S6
  (should make a lower bound on this?).  The limit idle times
  and cluster busy times defects are in teachers' timetables.
  I'm a very long way from the 5 on Gerhard's web site.

15 Mar 2014.  Gerhard reported a bug in file reading.  KHE was
  detecting that the same Id was being used twice, but making a
  mess of reporting the error.  I've mailed off a workaround,
  but now I have to check the reading of everything with an Id
  and make sure it's reporting the error properly.

  Fixed the bug and found it was the only case!  Installed
  new version and let Gerhard know.  Back to BR-SA-00 now.

  Calling KheSolnClusterMeetDomains produced this:

    8.00020 15.00011 15.00007 10.00014 11.00019 11.00020 19.00010 22.00005
    [ Soln (instance "BR-SA-00", diversifier 1, cost 8.00020)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignTimeMonitor                       4       5.00000
      DistributeSplitEventsMonitor            1       0.00002
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitIdleTimesMonitor                   4       0.00018
      -------------------------------------------------------
      Total                                  12       8.00020
    ]

  It removed the cluster defects, but the price was high.  So
  we'll leave that path unexplored for now.

  T5-S6 is a problem.  Its constraints say "at least 2 doubles"
  but I am currently getting 4 singles, and then there is a max
  of 1 per day which is queering the clustering of teacher T5.
  In fact, it can't have two doubles, but it could have one
  double.  Its duration is relatively long, it should be done first.
  So tried sorting the distribute split events points of application
  by decreasing duration, and got this:

    0.00068 0.00083 0.00074 1.00056 1.00056 0.00074 0.00074 0.00065
    [ Soln (instance "BR-SA-00", diversifier 4, cost 0.00065)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00002
      LimitIdleTimesMonitor                  10       0.00036
      ClusterBusyTimesMonitor                 3       0.00027
      -------------------------------------------------------
      Total                                  14       0.00065
    ]

  T5-S6 is getting its two doubles now, which is good.  So there
  is one small step forward.  But actually the problem has just
  been shifted from T5-S6 to T2-S6.

  This is because T5-S6 and T2-S6 are in a different constraint
  from the others, and the sorting by decreasing duration is one
  constraint at a time.  So I've changed the interfaces so that
  multiple constraints with equal priorities and tags get handled
  together, and altered the handling of distribute split assignments
  constraints to take that into account.  That gave this:

    0.00055 0.00085 0.00076 0.00088 0.00073 0.00073 1.00067 0.00079
    [ Soln (instance "BR-SA-00", diversifier 1, cost 0.00055)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00001
      LimitIdleTimesMonitor                   8       0.00036
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  11       0.00055
    ]

  so it seems to have been worth doing, although looking at the
  spread there is not much improvement.

  Tried KheTreeSearchRepairTimes but it did no good at all.
  Tried every option that seemed vaguely relevant, but 55 is
  still my best score.  Actually it's an outlier, the next
  best is 67.  Not surprising since the defects mostly have
  weight 3.  It's even the best of 32.  Best of 128 is:

    [ Soln (instance "BR-SA-00", diversifier 73, cost 0.00052)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00001
      LimitIdleTimesMonitor                  10       0.00033
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  13       0.00052
    ]

  which is better but only marginally.

  The sad truth is that the repair set I currently have is not
  able to remove these defects.  I've done some inspections, and
  there just don't seem to be any ejection chains that will do it.

  I tried a tree search repair for all resources, so that it would
  re-timetable S1-S6, and set the node limit to 1,000,000, which
  gave quite a slow run.  Only three improvements were found:

    KheTreeSearchLayerRepairTimes returning true (0.00085 -> 0.00082)
    KheTreeSearchLayerRepairTimes returning true (0.00088 -> 0.00085)
    KheTreeSearchLayerRepairTimes returning true (2.00067 -> 0.00112)

  and there was no improvement on the best of 8.  When re-timetabling
  S1-S6 many of the searches did not get to the end.  So I increased
  the node limit to 10,000,000, which is too many nodes really, and
  tried again.  Most of the S1-S6 retimetablings reached the end now,
  so this is a good test of what is possible by retimetabling them.
  But the same three improvements were the only ones found.

  I've taken a look at the Lectio solution of cost 5.  All 5 are
  distribute split events violations, so they've got there by
  splitting up more events and getting more freedom that way.
  It's a sound strategy but I don't see how I could emulate it.
  Haroldo's solution has cost 38 and 17 distribute split events
  violations.  Good as it its, it's basically in the same ballpark
  as I'm in now, but the Lectio solution is something else again.

16 Mar 2014.  Still fiddling with BR-SA-00.  Tried more new
  global visit numbers when repairing limit idle times defects,
  but they didn't help so I took them away again.

  Working on KheMeetSetSolve, which reassigns an arbitrary set
  of meets using a tree search.  Written the code, although I
  guess it needs an audit.  Also I need to write an application
  of it; I have an idea for a "fuzzy meet move" operation that
  moves a meet from one place to another, calling KheMeetSetSolve
  to rearrange everything in the vicinity.

17 Mar 2014.  Wrote KheFuzzyMeetMove, and rather cleverly added
  it to KheTimeAugment.  But the first results are disappointing:

    0.00079 0.00118 0.00082 0.00067 0.00148 1.00106 0.00058 0.00061
    [ Soln (instance "BR-SA-00", diversifier 6, cost 0.00058)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00001
      LimitIdleTimesMonitor                   8       0.00039
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  11       0.00058
    ]

  cf 0.00055 0.00085 0.00076 0.00088 0.00073 0.00073 1.00067 0.00079.
  I think I need fewer calls, but better targeted, and wider in scope.
  Limiting to just at the end of time assignment gives this:

    0.00076 0.00055 0.00088 0.00115 0.00058 1.00070 0.00076 0.00103
    [ Soln (instance "BR-SA-00", diversifier 3, cost 0.00055)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00001
      LimitIdleTimesMonitor                   9       0.00036
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  12       0.00055
    ]

  I've tried various combinations of width and depth, but
  nothing seems to work well, and this despite the fact
  that over 8 parallel runs, 267 out of 26344 calls to
  KheFuzzyMeetMove were successful.  So I tried two calls
  to the ejector at the end of time assignment, the first
  without, and the second with fuzzy meet moves, and got
  this, which is an improvement on average:

    0.00085 0.00055 0.00070 0.00073 0.00073 0.00082 0.00079 0.00145
    [ Soln (instance "BR-SA-00", diversifier 1, cost 0.00055)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            1       0.00001
      LimitIdleTimesMonitor                   8       0.00036
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  11       0.00055
    ]

  It ran quite quickly too, encouraging me to try various wider
  neighbourhoods, which ran quite slowly and gave

    0.00085 0.00070 0.00055 0.00073 0.00073 0.00082 0.00079 0.00145
    0.00085 0.00070 0.00055 0.00073 0.00073 0.00082 0.00079 0.00145
    0.00070 0.00055 0.00073 0.00067 0.00073 0.00076 0.00064 0.00064
    0.00070 0.00055 0.00073 0.00067 0.00073 0.00076 0.00064 0.00064
    0.00055 0.00076 0.00067 0.00070 0.00073 0.00073 0.00064 0.00064

  There is some improvement towards the end, but no sign that the
  0.00055 outlier is in any danger of being bettered.

  Did some exploratory work to see if breaking a randomly chosen
  moderate number of distribute split events constraints would
  help, and indeed it has (best of 32):

    0.00058 0.00085 0.00061 0.00085 0.00057 0.00058 0.00051 0.00061
    0.00064 0.00061 0.00079 0.00051 0.00059 0.00052 0.00080 0.00058
    0.00052 0.00062 0.00082 0.00051 0.00055 0.00061 0.00076 0.00139
    0.00037 0.00079 0.00074 0.00030 0.00049 0.00074 0.00061 0.00054
    [ Soln (instance "BR-SA-00", diversifier 25, cost 0.00030)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            9       0.00009
      LimitIdleTimesMonitor                   4       0.00012
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                  14       0.00030
    ]

  This is also the best of 128.  Without fuzzy meet moves the
  best of 128 is 0.00037, and you get it very quickly.

18 Mar 2014.  Added a split-and-move repair to KheTimeAugment.
  It seems to be working; some repairs, at least, are successful,
  and when finding best of 128, 778 of these repairs lay on
  successful chains.  The best of 128 was 0.00041.  After
  removing the old ad-hoc stuff, however, the best of 128 was

    [ Soln (instance "BR-SA-00", diversifier 113, cost 0.00028)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            7       0.00007
      LimitIdleTimesMonitor                   4       0.00012
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                  12       0.00028
    ]

  which is probably good enough.  Run time 43 secs.  I've posted
  this.  This is also the best of 256.  I also tried allowing
  split moves at any depth, which took 65 secs but produced a
  worse result (0.00031).

20 Mar 2014.  Started thinking about ejection trees, and wrote
  a tentative section of the ejection chains chapter about them.

21 Mar 2014.  	Implemented an ejection trees variant of ejection
  chains.  It looks great from the outside but the implementation
  is a bit rough.  Made a first attempt (also pretty rough) to
  repair cluster defects by reducing the domains of all meets
  assigned the defective resource to remove one day (depth 1 only).
  Without this repair, best of 1 produces:

    KheGeneralSolve2014 at end (0.80 secs elapsed):
    [ Soln (instance "BR-SA-00", diversifier 0, cost 0.00058)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            7       0.00007
      LimitIdleTimesMonitor                   5       0.00015
      ClusterBusyTimesMonitor                 4       0.00036
      -------------------------------------------------------
      Total                                  16       0.00058
    ]

  With this repair, best of 1 produces

    KheGeneralSolve2014 at end (1.03 secs elapsed):
    [ Soln (instance "BR-SA-00", diversifier 0, cost 0.00042)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            6       0.00006
      LimitIdleTimesMonitor                   6       0.00018
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  14       0.00042
    ]

  despite there being no cases of a successful ejection tree
  repair.  Seems to be just luck.  Best of 128 produces

    [ Soln (instance "BR-SA-00", diversifier 59, cost 0.00025)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            4       0.00004
      LimitIdleTimesMonitor                   5       0.00021
      -------------------------------------------------------
      Total                                   9       0.00025
    ]

  Over all runs there are 5 successful multi-repairs here.  I've
  saved this; it's my best so far.  It's also the best of 256.
  After tidying up I lost it, current best of 128 is

    [ Soln (instance "BR-SA-00", diversifier 33, cost 0.00029)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            8       0.00008
      LimitIdleTimesMonitor                   4       0.00012
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                  13       0.00029
    ]

  So I need to slow down, keep working.  Starting a new global
  visit number for each sub-chain (if depth is 1) gave this
  for best of 128:

    [ Soln (instance "BR-SA-00", diversifier 110, cost 0.00027)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor           12       0.00012
      LimitIdleTimesMonitor                   4       0.00015
      -------------------------------------------------------
      Total                                  16       0.00027
    ]

  Still not as good as the one I had earlier and lost.

  The logical next step is to repair distribute split events
  defects.  This requires two new ideas:  ability to undo
  a meet merge, and analysis of these defects to work out
  how to repair them.

22 Mar 2014.  Reviewing transactions.  KheTransactionCopy is called
  from only one place and could be removed.  KheTransactionRedo is
  called twice, in both cases starting from the same state that the
  original transaction started from.

  Quite a lot of code that saves a transaction so as to be able
  to undo something later is likely to break if meet splits and
  merges are allowed in between.  Those transactions do things
  to specific meets, which may well not exist later on.

  So for correctness as much as anything else, I have to get rid
  of KheTransactionUndo and KheTransactionRedo.  Instead, a marking
  scheme as used for matchings is the go.  Implement that, do as
  much as possible using it, and then see what's left.

  There is a common usage where I remove a lot of assignments,
  and enclose that in a transaction, which can be undone later
  to get back to the initial state if things don't work out.
  This is basically an error-prone structure unless I can prove
  that the solution has returned to its previous state.

  Invented "marks and paths" and documented them in the Guide.
  Should be able to implement them in parallel with transactions,
  then remove transactions afterwards.

23 Mar 2014.  Reviewed the new marks and paths documentation, did
  an off-site backup, and started implementing.  Going steadily.
  Task incrementing is next (can it really be independent of meet
  incrementing?), have done one hard function:  KheMarkAddPath;
  KheMarkBegin, KheMarkEnd, and KhePathDelete are the main things
  still to do, plus the internals of khe_meet.c and khe_task.c.


  How to handle object deletion with paths and marks
  --------------------------------------------------

  In each object that could be deleted along a path (each
  meet, task, and node), place these two fields:

     int path_count;
     bool path_in_use;

  and offer internal operations

    void KheEntityPathCountInc(KHE_ENTITY e);
    void KheEntityPathCountDec(KHE_ENTITY e);
    void KheEntityPathInUseSet(KHE_ENTITY e);
    void KheEntityPathInUseClear(KHE_ENTITY e);

  Let a "structural reference" to e be a reference to e, lying
  in a path, within an operation that creates or deletes e.
  The first field records the total number of structural
  references to e in all paths.  The second records whether e
  is in use (not deleted) in the current state of the solution.

  When adding an operation to the main path, or copying a path,
  increment e's path_count each time a structural reference to
  e is added to any path.  When deleting a path, or removing an
  operation from the main path, decrement e's path_count each
  time a structural reference to e is removed from a path.

  When creating e, check that path_in_use is false before the
  creation (or if newly created) and set it to true.  When
  deleting e, check that path_in_use is true before the operation
  and set it to false.

  If, at the end of any of these updates, path_count is 0 and
  path_in_use is false, e may be freed.  This could happen when
  path_count drops to 0, or when path_in_use is set to false.

  For space efficiency we will combine both fields into one by
  incrementing and decrementing by 2 and using the low bit for
  path_in_use.  So the memory cost is one int per object.  The
  time cost is small and basically only incurred when there are
  creation and deletion operations on paths.

24 Mar 2014.  Documented the above in an appendix of the Guide
  which also defines a kernel layer for the platform, each
  operation of which comes in three forms:  Op, OpUndo, and
  OpRedo, the latter two called from the path undo and redo
  operations.

  Split the new stuff into khe_mark.c and khe_path.c, and
  did a lot of useful miscellaneous work including finishing
  khe_mark.c.  Not too much more to do in these files, the
  main job now is to write the many kernel object operations.

25 Mar 2014.  Finished khe_path.c.  But now there are a million
  kernel undo and redo operations to write.  Still, at least it
  is looking clean and tidy, in a way transactions never did.

  Kernel operations involve no checking.  That is already done.
  Implemented KheMeetKernelMove, KheMeetKernelMoveUndo, and
  KheMeetKernelMoveRedo.  It went pretty well.  Also did
  KheMeetKernelAssignFix and its undo and redo, and
  KheMeetKernelAssignUnFix and its undo and redo.  These also
  went well although there is some code duplication, since,
  for example, undoing a fix and redoing an unfix are the same.

27 Mar 2014.  Order of operations for each kernel operation:

  ---------------------------------------------------------------
  Helper functions (e.g. KheEntityDoOp)
  KheEntityKernelOp, KheEntityKernelOpUndo, KheEntityKernelOpRedo
  KheEntityOpCheck, KheEntityOp, and other public functions
  ---------------------------------------------------------------

  Have done most of the easy kernel operations.  I've also made
  quite a good job of the task creation and deletion operations,
  by dividing them into Make, Add, Delete, and Free; only Add
  and Delete are kernel operations.  Working on documenting this.

28 Mar 2014.  Documented the current state of the kernel code.
  Did a careful check of khe_task.c.  I had to fix a few things,
  but it is now all in order.  Also worked on khe_meet.c, got
  make, free, add, and delete more or less working, and did
  some tidying up.

29 Mar 2014.  Worked on khe_meet.c today.  Audited it, all is
  in order except splitting and merging, and there I have a
  clean compile of the new code, with a couple of unresolved
  issues, and a need for a very careful audit.

30 Mar 2014.  Sorted out task permuting; have to do it both
  when checking and when doing, but no great problem; if it
  is done twice, it will be very fast the second time.  Made
  an argument for why Do and Redo must be identical, which
  seems fairly convincing, and removed Redo.
  
  Puzzlement over creation/deletion has led me to extend
  the treatment of these operations in the documentation,
  leading to a new arrangement of eight functions altogether.
  I've documented this and implemented it for tasks.

31 Mar 2014.  Finished off all the meet and task creation and
  deletion code, and carefully audited everything so far.  Apart
  from a few minor points noted below, and splits and merges,
  it is all in good order.

1 Apr 2014.  Giving myself a day or two off, reviewing papers.
  But I did make setting back pointers into kernel operations.

3 Apr 2014.  On my to-do list it said

    "Placing tasks on the free list is problematical when they
    lie in dormant meets.  Only when a meet goes on the free
    list should its tasks go on the free list."

  When a meet is dormant, it will be so because of a call to
  KheMeetDelete.  Before deleting the meet, this function calls
  KheTaskDelete to delete all its tasks.  So task_delete references
  to these tasks will be on the solution path before the meet_delete
  reference to the meet.  For the meet to be created, an undo will
  have to be performed, and that will undo the task deletions after
  undoing the meet deletion.  In short, there is no problem.

7 Apr 2014.  Had a few days off, refereeing papers but also
  bludging.  Back at work this afternoon.  Changed the split
  check to check recursive splits properly.  Did the kernel
  task split and merge operations, which seemed to go OK,
  although I have not tried to call them yet.

8 Apr 2014.  Working on meet splitting and merging today.  Have
  a clean compile of what is allegedly the full implementation.
  Needs auditing and testing.

  Anyway, it seems to be working, although I am not using paths
  yet, only transactions.  But I ran 128 solves of BR-SA-00 and
  got cost 0.00027, which is where I was up to before.  There
  must have been a fair amount of splitting and merging in that.

  Started work on removing KHE_TRANSACTION.  Replaced the old
  KheAtomicTransactionBegin and KheAtomicTransactionEnd using
  transactions with KheAtomicOperationBegin and KheAtomicOperationEnd.
  They turned out a lot simpler.

9 Apr 2014.  Working through KHE, removing all usage of transactions.
  What are the possibilities for the domains of the tasks of a tasking?

  (1) They could have their initial values, consisting of the full
      resource type (or singleton if preassigned); this is also the
      domain set by KheTaskingEnlargeDomains;

  (2) They could have the values installed, apparently inadvertently,
      by KheEventInSolnMakeCompleteRepresentation, namely
      KheEventResourceHardDomain(er);

  (3) They could have KheEventResourceHardAndSoftDomain(er);

  (4) As in khe_sr_task_tree.c, installed by KheTaskTightenDomain,
      they could have their previous domain reduced to a partition
      (KhePartitionAcceptsTask), or reduced to a prefer resources
      contstraint (KheTaskingDoPreferResourcesConstraintJob), or
      reduced by KheTaskingDoAvoidSplitAssignmentsConstraintJob 
      for consistency with other tasks.

  Altogether it seems that we do need to store the old domains
  and restore them.  A transaction would be ideal.  Perhaps a
  path with an UnsafeUndo operation?  But this is just what we
  are trying to get away from.

11 Apr 2014.  Discovered a bug in khe_se_ejector.c:  a single
  trace object is not enough, because as we traverse it we
  are recursing and re-using it.  Probably not a big problem in
  practice, since we only really recurse on one of its monitors.
  However what it does is unpredictable.  Fixed now.

  Sorted out the problem of RepairEnd is not handling immediately
  successful repairs correctly.  Re-introduced a stack of records
  with three fields:  mark, trace, success.

  Redid khe_st_tree_repair.c to make good use of marks and paths.

12 Apr 2014.  Finished and audited khe_st_tree_repair.c.  Done
  some testing, fixed some bugs.  I'm now getting results for
  BR-SA-00 (which I know did some splitting and merging) and
  IT-I4-96.  These are in the ballpark given that some code
  (especially code for handling clustering) is turned off, so it
  looks like the new stuff is working.  Started marks and paths
  on 22 Mar, which is exactly three weeks ago, although I have
  done some other jobs along the way.

  Problems areas now:

  (1) KheTaskingTightenToPartition, called from KheCycleNodeAssignTimes,
      which calls KheTaskTightenDomain on every task, and is being
      undone by a transaction undo which fails in principle when
      tasks are split and merged.  So there is an error here.

  (2) KheSolnClusterMeetDomains, called from KheCycleNodeAssignTimes,
      which calls KheMeetSetDomain to tighten the domains of meets.
      Again, it is being undone by an unsafe transaction undo.

  Drafted a new task domains section.

13 Apr 2014.  Redesigned task bounds and rewrote the task domains
  section.  Cloned it into a new meet domains section, and also
  updated the automatic meet domains section.  All this seems to
  be ready to implement now.

14 Apr 2014.  Added code to keep resource groups in a hash table
  indexed by their bit sets, as time groups are kept now.

15 Apr 2014.  Produced some new documentation in doc/impl, describing
  the organization of the source code, for ordering submodules and
  for implementint relations between objects.  Also implemented the
  new KHE_MEET_BOUND and KHE_MEET_BOUND_GROUP types following this
  organization.

16 Apr 2014.  Slogging away through the reorganization.  Working
  through khe_meet.c; the new structure is all there, now I am
  working on meet domains and bounds.

17 Apr 2014.  Still working on khe_meet.c, going steadily.

18 Apr 2014.  Meet splitting all done, starting on merging now.
  It's basically greenfield as far as checking goes.  I've
  written what looks to be a pretty solid and realistic spec.

20 Apr 2014.  Took yesterday off, meet merging today.  Done meet
  merge checking, based on the newly revised spec, and meet merging,
  and incredibly the rest seems to be OK, so meet splitting and
  merging are done at last.  Audited meet bounds code, it is all
  ready in khe_meet.c for being made into kernel operations.  Added
  the kernel operations, marks, and paths for adding and deleting
  time bounds, and removed those for setting domains.

21 Apr 2014.  Sorted out automatic domains.  Should be right now,
  except that KheMeetSetAutoDomainCheck is still to do.  Setting
  and removing an automatic domain is now a kernel operation.

  Have a clean compile now for everything but khe_sl_split_class.c,
  and that is going to require more thought, since it is where we
  really want to make proper use of the duration parameter of
  KheMeetBoundMake, and where preassigned events must give rise
  to singleton time domains.

22 Apr 2014.  KheMeetSetAutoDomainCheck done, khe_sl_split_class.c
  done, giving a clean compile.  Started marks and paths on 22 Mar,
  which is a month ago now, and I'm still hacking away at it.
  Calling KheSolnClusterMeetDomains again in khe_st_combined.c.
  Revised task bounds documentation and began work on adding task
  bounds.  Have done everything except khe_task.c itself, and I've
  begun work on that.

23 Apr 2014.  I seem to have finished khe_task.c.  I've reintroduced
  KheMeetIsPreassigned and KheTaskIsPreassigned functions, and vowed
  to stick to a simpler definition of what it means for a meet or task
  to be preassigned from now on.  All the task bounds stuff is done.
  Added KheMeetBoundGroupKernelAdd and KheMeetBoundGroupKernelDelete.

24 Apr 2014.  Decided on a KheEjectorRepairOnSuccess function which
  may be called any time between KheEjectorRepairBegin and
  KheEjectorRepairEnd, and which passes a function and its parameter
  to associate with the repair, and which are called on success.
  This will involve a fair bit of rewriting in khe_se_solvers.c,
  but it's the only way to handle this problem consistent with
  the delayed decision on whether to use the repair or not.

  Revised doc to describe "adjustment on success" and am now
  implementing it in khe_se_solvers.c.  All done and has a
  clean compile, but needs a careful audit.

25 Apr 2014.  Audited khe_se_solvers.c, seems to be in pretty good
  shape now,  including the new "adjustment on success".  Revised
  the ejection chain documentation - the entire chapter, except
  not the last section which describes the particular solvers
  implemented using ejection chains.  Re-implemented the complex
  cluster repair in khe_se_solvers.c/KheClusterOverloadAugment.

  First results of testing the last month's rewrite:

    KheGeneralSolve2014 at end (21.53 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00265)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            9       0.00036
      LimitIdleTimesMonitor                  12       0.00017
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  25       0.00265
    ]

  Best of 8:

    0.00170 0.00167 0.00155 0.00265 0.00068 0.00260 0.00056 0.00081
    [ Soln (instance "IT-I4-96", diversifier 7, cost 0.00056)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            8       0.00030
      LimitIdleTimesMonitor                  10       0.00014
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  20       0.00056
    ]

  So it's basically working, but it looks like the cluster busy
  times repairs (which generate the 100+, 200+ costs) are not.
  Actually, the queer cluster contraint which enforces first
  period of each day is at fault here - it's an underload.  This
  solution is also the best of 32.  My best ever solution has
  cost 54, and is also the best of 8 runs, so there is not much
  wrong here.  Now for BR-SA-00:

    KheGeneralSolve2014 at end (0.84 secs elapsed):
    [ Soln (instance "BR-SA-00", diversifier 0, cost 1.00115)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignTimeMonitor                       1       1.00000
      DistributeSplitEventsMonitor            1       0.00001
      LimitIdleTimesMonitor                   6       0.00024
      ClusterBusyTimesMonitor                 9       0.00090
      -------------------------------------------------------
      Total                                  17       1.00115
    ]

  Best of 8:

    2.00100 1.00082 1.00115 0.00106 0.00098 0.00100 1.00106 0.00105
    [ Soln (instance "BR-SA-00", diversifier 6, cost 0.00098)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            2       0.00002
      LimitIdleTimesMonitor                   5       0.00024
      ClusterBusyTimesMonitor                 7       0.00072
      -------------------------------------------------------
      Total                                  14       0.00098
    ]

  Best of 128:

    [ Soln (instance "BR-SA-00", diversifier 118, cost 0.00075)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            3       0.00003
      LimitIdleTimesMonitor                   3       0.00018
      ClusterBusyTimesMonitor                 5       0.00054
      -------------------------------------------------------
      Total                                  11       0.00075
    ]

  Need to investigate the cluster busy times defects here.

26 Apr 2014.  Problem with cluster busy times defects is very
  simple indeed:  the domains are fixed and refuse to change.
  I could unfix them, but it would be better to audit all
  fix operations and remove as many as possible.

     KheMeetSplitFix
     KheMeetAssignFix
     KheMeetDomainFix
     KheTaskAssignFix
     KheTaskDomainFix

  In fact, it would be best to remove all of these, but it is
  probably only feasible (initially at least) to remove
  KheMeetSplitFix (which produces no real savings anyway),
  KheMeetDomainFix, and KheTaskDomainFix.

27 Apr 2014.  Commented out all occurrences of KheMeetSplitFix,
  KheMeetDomainFix, and KheTaskDomainFix and their opposites in
  the code and documentation.  BR-SA-00 best of 32 is now

    [ Soln (instance "BR-SA-00", diversifier 14, cost 0.00047)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            5       0.00005
      LimitIdleTimesMonitor                   5       0.00015
      ClusterBusyTimesMonitor                 3       0.00027
      -------------------------------------------------------
      Total                                  13       0.00047
    ]

  There was one successful cluster multi-repair, but it looks
  like more work is needed there.  Best of 128 is now

    [ Soln (instance "BR-SA-00", diversifier 84, cost 0.00037)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            4       0.00004
      LimitIdleTimesMonitor                   5       0.00015
      ClusterBusyTimesMonitor                 2       0.00018
      -------------------------------------------------------
      Total                                  11       0.00037
    ]

  which is a falling off from the 0.00025 solution of 21 March 2014,
  because of the two cluster defects.  So they are the next target.

  Implemented the simplified cost functions, including updating
  the documentation of HSEval.

  We can't reasonably define parts in every monitor.  Very often,
  there is some total, but the question is whether it falls short
  of some minimum value or exceeds some maximum value.  So giving
  all the things that contribute to the total will overestimate.

28 Apr 2014.  Decided that the whole idea of the parts of a
  deviation was flawed, and that what was wanted was a string
  description of how a deviation is calculated, one which is
  free to adapt itself to however a constraint works.  Started
  and finished implementing a "KheMonitorDeviationDescription"
  function for this, and updated HSeval to use it.  Still to test.

  Made these changes to function names:

    KheLimitBusyTimesDefectCount ->
      KheLimitBusyTimesMonitorDefectiveTimeGroupCount
    KheLimitBusyTimesDefect -> KheLimitBusyTimesMonitorDefectiveTimeGroup
    KheLimitWorkloadDefect -> KheLimitWorkloadMonitorWorkloadAndLimits

29 Apr 2014.  Standardized the deviation descriptions:

    <description>  ::=  "0"
                   ::=  <dev> [ ":" <item> { ";" <item> } ]
                   ::=  <item>
    <item>         ::=  <dev> <details>

  where <dev> is an integer, and <details> is arbitrary, but
  typically looks something like

    <details>      ::= "too few"
                   ::= "too many"

  and so on.  The key points are that the deviation comes first,
  that the format is simplified when the deviation is 0 or there
  is just one item, and <details> is kept as brief as possible.

  Carried out a careful audit of KheClusterOverloadAugment.  It
  all seems to be working correctly, including the domain stuff.

30 Apr 2014.  Comparing runs today and best so far:

  Instance      Today                      Best
  ---------------------------------------------------------------
  BR-SA-00      0.00037 (best of 128)      0.00025 (best of 128)
  IT-I4-96      0.00057 (best of 8)        0.00054 (best of 8)
  AU-BG-98      4.00383 (best of 8)        1.00386 (best of 8)
  ---------------------------------------------------------------

  While testing AU-BG-98, I found and fixed several stupid bugs,
  introduced in the last month.  Run time is quite slow, and the
  results are not wonderful either.  The AU-BG-98 costs are poor:
  9.00268 6.00429 6.00432 13.00324 5.00453 10.00325 7.00267 4.00383

  I've done a careful audit of the first solution of BR-SA-00,
  with cost 69, and there really doesn't seem to be any way to
  improve it.  So I think I am going to need something fundamental
  there.

  By adding more visit number resets I found this for BR-SA-00:

    0.00067 0.00051 0.00063 0.00068 0.00051 0.00082 0.00071 0.00050
    0.00054 0.00051 0.00065 0.00066 0.00091 0.00022 0.00059 0.00077
    0.00069 0.00052 0.00033 0.00071 0.00059 0.00077 0.00064 0.00044
    0.00056 0.00042 0.00094 0.00062 0.00077 0.00056 0.00065 0.00066
    [ Soln (instance "BR-SA-00", diversifier 12, cost 0.00022)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            4       0.00004
      LimitIdleTimesMonitor                   3       0.00009
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                   8       0.00022
    ]

  It's my best so far, so I've put it on the web, but it seems to
  be a fluke, judging by the wide range of scores.  Also found

    0.00148 0.00261 0.00059 0.00063 0.00058 0.00154 0.00067 0.00062
    0.00155 0.00061 0.00158 0.00062 0.00145 0.00053 0.00069 0.00271
    0.00068 0.00062 0.00060 0.00165 0.00066 0.00054 0.00061 0.00062
    0.00059 0.00148 0.00063 0.00261 0.00058 0.00154 0.00067 0.00062
    [ Soln (instance "IT-I4-96", diversifier 13, cost 0.00053)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            5       0.00021
      LimitIdleTimesMonitor                  13       0.00020
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  20       0.00053
    ]

  which is a new world record, although again the wide range of
  costs does not engender confidence.  This is also best of 128.

1 May 2014.  Reported my cost 53 solution of IT-I4-96 to Gerhard.
  Added an "ejector_fresh_visits" option which gives every repair
  at the top level a fresh visit number.  Tested it by finding
  best of 8 without it (30-40 secs per soln):

    0.00148 0.00261 0.00059 0.00063 0.00058 0.00154 0.00067 0.00062

  and with it (about the same run time)

    0.00159 0.00064 0.00071 0.00055 0.00260 0.00061 0.00060 0.00062

  Best of 128 gave a new best (cost 50) which I have posted on
  the web and reported to Gerhard.
  
6 May 2014.  Away for a few days, back at work today, cleaning up
  for a release of KHE and HSEval.  Getting invalid solutions:

  line 41073 col 13: "Thu_1_2" conflicts with preassigned time "Thu_1_6"
  line 51232 col 13: "Fri4" conflicts with preassigned time "Tue1"
  
  Now fixed - there were two bad blunders in KheMeetMoveCheck,
  where the wrong variable was referenced.

  Found a really good solution to AU-SA-96 without trying:

    1.00015 1.00027 0.00024 3.00030 3.00022 5.00018 2.00017 3.00012
    [ Soln (instance "AU-SA-96", diversifier 3, cost 0.00024)
      Soln                              Defects          Cost
      -------------------------------------------------------
      SpreadEventsMonitor                    21       0.00022
      LimitBusyTimesMonitor                   1       0.00002
      -------------------------------------------------------
      Total                                  22       0.00024
    ]

7 May 2014.  Released new versions of KHE and HSEval today, and let
  Gerhard know about the new HSEval.  Here's the blurb for the new
  release of KHE:

    Releases of KHE are not guaranteed to be backward compatible,
    because KHE is a research vehicle as well as a production
    system, so it must be able to incorporate new ideas freely.
    The current release (7 May 2014) has several significant
    incompatibilities, including support for the three new cost
    functions only, the replacement of transactions by "marks and
    paths", and the replacement of direct setting of meet and task
    domains by the indirect "meet bounds" and "task bounds".
    KheGeneralSolve2014, the standard solver, is more effective
    but slower than the previous version, so may be less useful
    now as the first step in other solvers.

  KheMeetAddUnavailableBound, KheMeetAddUnavailableBounds, and
  KheSolnAddUnavailableBounds documented, implemented, and audited.
  Revised the documentation of KheSolnClusterMeetDomains.

8 May 2014.  Revised the documentation of KheSolnClusterMeetDomains
  again, implemented the revised version.  Have also updated
  KheCycleNodeAssignTimes to use the new interfaces, but doing
  what it was doing before.

    0.00056 0.00148 0.00062 0.00051 0.00148 0.00255 0.00048 0.00050
    [ Soln (instance "IT-I4-96", diversifier 5, cost 0.00048)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            3       0.00015
      LimitIdleTimesMonitor                  18       0.00021
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  23       0.00048
    ]

  This is the best solution to IT-I4-96 so far.  Best of 128:

    [ Soln (instance "IT-I4-96", diversifier 66, cost 0.00040)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            3       0.00015
      LimitIdleTimesMonitor                  10       0.00013
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  15       0.00040
    ]

  Wow, this is great.

9 May 2014.  Replaced KHE_NO_DURATION by KHE_ANY_DURATION.
  Documented recursive meet merging.

11 May 2014.  Took yesterday off.  Implemented recursive meet
  merging today; actually it wasn't very hard in the end.

12 May 2014.  Reorganized nodes code today, with the aim of moving
  everything non-kernel, including vizier nodes, to new solver files
  khe_ss_nodes.c and khe_st_helper.c.  All done, including updating
  the Guide, except that the vizier code still needs to be moved
  from khe_node.c to khe_ss_nodes.c.

13 May 2014.  Decided to move KheNodeMerge and KheNodeSplit out of
  the kernel, then decided to delete KheNodeSplit since it is not
  very useful and is not currently used.  All documented and
  implemented.  Also unified the way in which old meet assignments
  are remembered by these functions.  This will be useful for
  vizier nodes, which are next.

14 May 2014.  Did some tidying up of the "extras" chapter, and
  reacquainted myself with the details of layers and zones, in
  preparation for reimplementing vizier nodes.
  
  Currently working on the design of a revised vizier node solver.
  Have more or less decided to make the original node the vizier,
  since in that way its child layers and zones can be preserved.
  But this means that an operation for moving the "cycleness" of
  a meet from one meet to another is needed.

15 May 2014.  Finally produced a workable plan for vizier nodes,
  and documented it.  Implemented KheNodeSwapChildNodesAndLayers
  so far; the rest should not take long.

16 May 2014.  Have clean compile of new vizier code.  Audited
  it and got part way through the testing.

18 May 2014.  Took yesterday off.  Today I found and fixed a
  nasty bug: when splitting a meet with a NULL domain, the new
  split fragment did not.  Anyway vizier nodes seem to be
  working now, although the results they give are not great.

  Turned off vizier nodes, got a new best for BR-SA-00 (best of 128):

    [ Soln (instance "BR-SA-00", diversifier 72, cost 0.00020)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            5       0.00005
      LimitIdleTimesMonitor                   4       0.00015
      -------------------------------------------------------
      Total                                   9       0.00020
    ]

  I put this up on my web site.

19 May 2014.  Most of day lost to jobs.  Added KheNodeAddMeet
  and KheNodeDeleteMeet to kernel.

20 May 2014.  Made all the layer operations into kernel operations.
  Tidied up the path code, got everything into canonical order.
  Added the two task bound group operations to the kernel; they
  were forgotten before.  Tidied up the Implementation Notes
  appendix.  Moved KheLayerInstallZonesInParent from khe_layer.c
  to khe_ss_zones.c, since, as it says itself, it is really a
  solver, and reorganized the documentation accordingly.

21 May 2014.  Tidied up khe_zone.c, and added its operations to
  the kernel.  This completed work on the kernel, so I revised
  the Guide, removing all references to its incompleteness, and
  adding the complete list of kernel operations to the appendix.

22 May 2014.  Tidied up the layered time assignment parts of the
  Guide and khe.h.  Did some function name changing.  Had an idea
  for how the multi_repair option in ejectors can be defined more
  clearly.

23 May 2014.  Wrote a new version of the ejection trees sub-section
  of the Guide.  Ready to implement.

24 May 2014.  Most of day lost to jobs.  Currently pondering the
  implementation of ejection trees.  Have discovered that the
  current implementation does not offer a combination of
  save_and_sort with ejection trees.  This is seriously dumb.

  A sort of plan: beef up the KHE_EJECTOR_AUGMENT abstraction
  -----------------------------------------------------------
  Put curr_target_cost and test_limits into ea
  Define KheEjectorAugmentBegin and KheEjectorAugmentEnd
    and other useful operations on augment objects.

25 May 2014.  Reorganized khe_se_ejector.c today.

26 May 2014.  Continued the reorganization of khe_se_ejector.c today.
  Revised the solve type interface, moving them to minor schedules and 
  making the names of their values shorter.  Sorted out test_limits
  (now renamed success_is_final).  Revised the RepairBegin and
  RepairEnd interface so that we only use repair objects when they
  are really needed, by save_and_sort.  Added KheEjectorSoln.

28 May 2014.  Working on the main part of the solver, specifically
  a revised form of the abstract Augment function.

29 May 2014.  Finished what seems to be a workable new version of
  the abstract Augment function.  Need to implement it now.

30 May 2014.  Working on the implementation of the revised ejector
  today.  Have clean compile, needs audit, and needs a rethink of
  statistics and what happens at the end of successful chains.

31 May 2014.  Finished new ejector code and tested it, although
  statistics still to do.  Fixed a rogue value for max_sub_chains,
  and some missing reference count increments in khe_path.c, but
  otherwise no bugs.  BR-SA-00 best of 32 (and also of 128):

    [ Soln (instance "BR-SA-00", diversifier 15, cost 0.00026)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            5       0.00005
      LimitIdleTimesMonitor                   3       0.00012
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                   9       0.00026
    ]

  My previous best of 32 was 22, and best of 128 was 20.  So
  this is competitive.  IT-I4-96 best of 1:

    KheGeneralSolve2014 at end (30.75 secs elapsed):
    [ Soln (instance "IT-I4-96", diversifier 0, cost 0.00055)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            5       0.00021
      LimitIdleTimesMonitor                  16       0.00022
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  23       0.00055
    ]

  This is quite good for best of 1.  Best of 8:

    0.00145 0.00152 0.00055 0.00050 0.00155 0.00143 0.00055 0.00153
    [ Soln (instance "IT-I4-96", diversifier 2, cost 0.00050)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00018
      LimitIdleTimesMonitor                  18       0.00020
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  24       0.00050
    ]

  This is better than my previous best of 8 (55).  Best of 128:

    [ Soln (instance "IT-I4-96", diversifier 8, cost 0.00042)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00018
      LimitIdleTimesMonitor                  10       0.00012
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  16       0.00042
    ]

  Previous best of 128 was 40.  So this is near enough to
  declare that the new code is working.  AU-BG-98 best of 1:

    KheGeneralSolve2014 at end (335.14 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 3.00381)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    19       0.00019
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  10       0.00022
      -------------------------------------------------------
      Total                                  66       3.00381
    ]

  Good result, shockingly slow run time.  As before, it all
  goes on teacher assignment repair.

1 Jun 2014.  Moved on to statistics today.  I've rewritten the
  statistics section of the documentation, hopefully improving
  it quite a lot.  Implemented these new function names:

  Old name			New name
  ------------------------------------------------------------
  KheEjectorChainCount		KheEjectorImprovementCount
  KheEjectorChainLength		KheEjectorImprovementNumberOfRepairs
  KheEjectorChainTime		KheEjectorImprovementTime
  KheEjectorChainCost		KheEjectorImprovementCost
  KheEjectorChainDefects	KheEjectorImprovementDefects
  KheEjectorChainHistoMax	KheEjectorImprovementHistoMax
  KheEjectorChainHistoFrequency	KheEjectorImprovementHistoFrequency
  KheEjectorChainHistoTotal	KheEjectorImprovementHistoTotal
  KheEjectorChainHistoAverage	KheEjectorImprovementHistoAverage
  ------------------------------------------------------------

  From here on my rate of progress is affected by a family crisis.
  I lost one week completely and worked part-time after that.

9 Jun 2014.  Lost a week owing to a family crisis.  Back at work
  today.  I've picked up the threads of the statistics revision,
  and written the new code for counting the number of repairs
  in one improvement.  Also sorted out the problem of whether
  or not cost limits should be reduced dynamically, by offering
  both options.

10 Jun 2014.  Reorganized the doc to group all time repair solvers
  together under one section.

14 Jun 2014.  Removed "Beyond the first success" and disruption
  from the code and doc.  The former is not compatible with
  ejection trees, and the latter has limited utility without it.

15 Jun 2014.  Audited solution files today, to make sure that they
  have a clear submodules structure and that the relations between
  objects are implemented in the standard manner.  All is in order
  now, except that there is no parent_node_index field in nodes,
  but that doesn't matter very much.

16 Jun 2014.  Reviewed resource solvers chapter, found a few small
  problems, now corrected.  Results for AU-BG-98:

    KheGeneralSolve2014 at end (339.93 secs elapsed):
    [ Soln (instance "AU-BG-98", diversifier 0, cost 3.00381)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidSplitAssignmentsMonitor           34       0.00340
      SpreadEventsMonitor                    19       0.00019
      AvoidClashesMonitor                     2       2.00000
      AvoidUnavailableTimesMonitor            1       1.00000
      LimitBusyTimesMonitor                  10       0.00022
      -------------------------------------------------------
      Total                                  66       3.00381
    ]

  Verified that resource packing was using meet demand and that
  meet demand includes all meets assigned to a given meet.

17 Jun 2014.  Compared augment functions with documentation
  and brought the two into agreement.  All good now.  Began
  to think about repairs for split events and distribute
  split events defects.

18 Jun 2014.  Planned out split and merge repairs today, more
  or less completely.  Added grouping of split events and
  distribute split events monitors to the primary groupings.
  Also added simple functions to these monitors which return
  their attributes.

19 Jun 2014.  Worked on split repairs today, in khe_se_solvers.c.
  Going steadily, lots more to do.

20 Jun 2014.  Set up a "split analyser" type which returns
  suggestions for splits and merges.  Done the interface,
  made a new file khe_ss_splits.c, done everything except
  KheSplitAnalyserAnalyse, which does the actual analysis.

21 Jun 2014.  Mostly finished the split analyser.

22 Jun 2014.  Finished off the split analyser code, added a
  split analyser object to KHE_OPTIONS, and did some analysis
  (but not repair) of BR-SA-00.  There are 27 analyses, and
  they all suggest Merge(1 + 1 -> 2), which seems reasonable.
  Working on the repairs now.

23 Jun 2014.  Fixed a stupid bug (uncleared array).  Here are
  the first results for BR-SA-00:

    KheGeneralSolve2014 at end (2.15 secs elapsed):
    [ Soln (instance "BR-SA-00", diversifier 0, cost 0.00040)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            4       0.00004
      LimitIdleTimesMonitor                   3       0.00009
      ClusterBusyTimesMonitor                 3       0.00027
      -------------------------------------------------------
      Total                                  10       0.00040
    ]

24 Jun 2014.  After fixing another stupid bug (reference count
  increment came too late) I got this best of 32:

    0.00053 0.00044 0.00059 0.00062 0.00040 0.00056 0.00058 0.00077
    0.00045 0.00040 0.00038 0.00051 0.00063 0.00039 0.00065 0.00029
    0.00030 0.00052 0.00046 0.00050 0.00045 0.00043 0.00030 0.00062
    0.00043 0.00057 0.00040 0.00032 0.00048 0.00070 0.00065 0.00044
    [ Soln (instance "BR-SA-00", diversifier 15, cost 0.00029)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            5       0.00005
      LimitIdleTimesMonitor                   3       0.00015
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                   9       0.00029
    ]

  Best of 128:

    [ Soln (instance "BR-SA-00", diversifier 42, cost 0.00021)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            6       0.00006
      LimitIdleTimesMonitor                   2       0.00006
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                   9       0.00021
    ]

  My previous best of 32 was 22, and best of 128 was 20.  So
  this is competitive.

25 Jun 2014.  Sorted out task bounds during split and merge.
  Results on BR-SA-00 for 32 and 128 are as above.  Documented
  split and merge moves.

27 Jun 2014.  Yesterday and today I worked carefully through
  the conference paper, condensing old parts and adding some
  new material.  Implemented split move repairs based on the
  split analyser's suggestions.  Changed the cluster repair
  so that it is unified, and got this:

    KheGeneralSolve2014 at end (1.39 secs elapsed):
    [ Soln (instance "BR-SA-00", diversifier 0, cost 0.00041)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            5       0.00005
      LimitIdleTimesMonitor                   2       0.00009
      ClusterBusyTimesMonitor                 3       0.00027
      -------------------------------------------------------
      Total                                  10       0.00041
    ]

  Best of 32:

    0.00041 0.00069 0.00046 0.00059 0.00053 0.00032 0.00045 0.00084
    0.00044 0.00065 0.00039 0.00046 0.00058 0.00045 0.00039 0.00038
    0.00055 0.00059 0.00060 0.00062 0.00048 0.00053 0.00031 0.00055
    0.00073 0.00048 0.00064 0.00041 0.00046 0.00061 0.00047 0.00060
    [ Soln (instance "BR-SA-00", diversifier 22, cost 0.00031)
      Soln                              Defects          Cost
      -------------------------------------------------------
      DistributeSplitEventsMonitor            4       0.00004
      LimitIdleTimesMonitor                   5       0.00018
      ClusterBusyTimesMonitor                 1       0.00009
      -------------------------------------------------------
      Total                                  10       0.00031
    ]

  This is also best of 128.  It seems to have not removed the
  last cluster defect, and to have made idle times defects worse.

27 Jun 2014.  Revised the cluster repair to remove unused time
  groups from meet domains, as well as the day we are trying to
  get rid of.  Here are the results of this revised method:

     Best of   Old            New    Revised
     ---------------------------------------
       1       0.00053    0.00041    0.00052
      32       0.00029    0.00031    0.00028
     128       0.00021    0.00031    0.00027
     ---------------------------------------

  Not ideal but the revised version is clearly the one to go with.
  The variations are presumably chance, and it's a better method.
  Documented it in the Guide and in the revised PATAT paper.

29 Jun 2014.  Posted AU-TE-99 solution with cost 0.00125 on my
  web page and notified Gerhard - it's a new best.  Implemented
  an upper limit on the number of augments per main defect, but
  on reflection it's probably not a good way to go, because we
  already use the visited flags to limit augments.  But it does
  highlight a basic question:  why is ejection chain repair
  taking so long?  Looking at AU-BG-98, we get this:

    FV:  KheOptionsEjectorFreshVisits(options)
    RT:  KheOptionsEjectorRepairTimes(options) during resource repair

    For AU-BG-98:

    FV     RT       C:KHE14   T:KHE14   C:KHE14x8
    ---------------------------------------------
    false  false    8.00479    14.22    6.00586
    false  true     6.00281    49.56    6.00281
    true   false    8.00413    59.15    4.00693
    true   true     3.00357   390.04    3.00357
    ---------------------------------------------

  So it seems we can afford one or the other but not both.
  What about when there is no resource assignment?

    For IT-I4-96:

    FV     RT       C:KHE14   T:KHE14   C:KHE14x8
    -------------------------------------------------
    false  false    0.00258    14.25    0.00052
    false  true     0.00258    14.70    0.00052
    true   false    0.00258    14.22    0.00052
    true   true     0.00258    14.68    0.00052
    -------------------------------------------------

  Found and fixed a bug in the domain calculations when
  splitting meets.  It caused a crash but does not seem
  to have done any harm otherwise.

30 Jun 2014.  Discovered that DK-FG-12.xml contains an empty
  Order Events constraint which is causing the odd crash in
  the solvers.  Reloaded XHSTT-2014.xml from Gerhard's site,
  and discovered that it has since been removed.  But decided
  to make the code run with it anyway.

  Implemented a new avoid split assignments repair which is
  structurally the same as the cluster busy times repair.

1 July 2014.  Tested the new avoid split assignments ejection
  tree repair.  It's working, finding 60 improvements at depth
  1, but the overall results on AU-BG-98 are not striking.

  Allowing task assignment repairs to move times.

  Posted new best (0.01032) for NL-KP-03 on the KHE page and
  notified Gerhard.

  Tidied up khe_se_solvers.c.  Might be worth thinking about
  a more radical reorganization, one that distributes repair
  operations closer to the augment functions that use them.

3 July 2014.  Revised the cluster underload repair operation,
  making it do what the documentation says it does.  Best of 1
  was a bit better, best of 8 was a bit worse.  Best of 128:

    [ Soln (instance "IT-I4-96", diversifier 119, cost 0.00054)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            5       0.00021
      LimitIdleTimesMonitor                  16       0.00021
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  23       0.00054
    ]

  Previous best of 128 was 40, so there is some loss of quality
  here, perhaps due to simplifying the repair functions.

  Fixed a bug in the diagnosis (not calculation) of limit busy
  times monitors.

  Started looking at what is taking NL-KP-03 so long.  I've
  established that a success could come at any point along
  the main loop.  The next question is whether it could come
  at any point through the number of nodes visited by repair.

  Tried an experiment concerning ejector_promote_defects:

               With it                 Without it
  -----------------------------------------------------------
  NL-KP-03     0.01939 (879.09 secs)   0.01605 (4938.48 secs)
  -----------------------------------------------------------

  Looks like we need ejector_promote_defects.  But this also
  gives a hint of how wide a variation in running time the
  ejection chain code is capable of, when things are changed.

4 July 2014.  Built a histogram showing the frequency of success
  on the i'th call to Augment, for all i.  This showed that
  success after about 100 augments was very rare, so I've
  tried limiting the number of augments:

           No limit         Limit 150        Limit 120        Limit 80
  ----------------------------------------------------------------------------
  AU-BG-98 7.00561/13.93s   5.00454/7.93s    5.00622/8.00s    7.00559/9.50s
  IT-I4-96 0.00251/10.38s   0.00255/10.19s   1.00663/10.82s   0.00357/9.72s
  NL-KP-03 0.01939/879.09s  0.01727/1096.32s 0.01471/815.46s  0.01248/1319.24s
  ----------------------------------------------------------------------------

  It's balancing act, evidently, and the effect is not huge, but
  it may be useful as a safety mechanism.  The best choice seems
  to be 120, except for IT-I4-96, so here is the best of 8 for
  IT-I4-96 with 120:

    0.00260 0.00257 1.00663 0.00070 0.00358 0.00168 0.00463 0.00260
    [ Soln (instance "IT-I4-96", diversifier 1, cost 0.00070)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            5       0.00021
      LimitIdleTimesMonitor                  20       0.00037
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  27       0.00070
    ]

  It seems OK.  Best of 128 is

    [ Soln (instance "IT-I4-96", diversifier 18, cost 0.00055)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00018
      LimitIdleTimesMonitor                  18       0.00025
      LimitBusyTimesMonitor                   2       0.00012
      -------------------------------------------------------
      Total                                  24       0.00055
    ]

  which is basically the same as the previous best of 128.

  Added a column to HSEval's report about instances, giving the
  total number of points of application of each constraint.

  AU-BG-98 best of 8 is 5.00622 with limit 120.  Unlimited best
  of 8 is 6.00650, no real difference.

5 July 2014.  Implemented and documented code for gathering statistics
  about Kempe moves, including a KHE_OPTIONS option.  Carried out a
  few tests with unsurprising results:  about 3 meets move on average
  (median 2), and there are some outliers of 20 or more moves.

            !suppress_recent   suppress_recent
  ------------------------------------------------------------
  AU-BG-98  5.00622/8.00s      7.00600/7.89s
  IT-I4-96  1.00663/10.82s     0.00270/8.68s
  NL-KP-03  0.01471/815.46s    0.01390/617.25s
  ------------------------------------------------------------

  On this evidence, suppress_recent is worth keeping, but there
  is probably more noise than signal in these figures.
  0.01390 is also the best of 8 for NL-KP-03+suppress_recent;
  it seemed to run very slowly indeed.  Best of 8:

            !suppress_recent   suppress_recent
  ------------------------------------------------------------
  AU-BG-98  5.00622/22.52s     5.00541/23.14s
  IT-I4-96  0.00070/22.14s     0.00159/20.40s
  NL-KP-03  0.01023/3034.67s   0.01390/2380.27s
  ------------------------------------------------------------

  There is no clear pattern here, but on the whole it suggests
  not using suppress_recent - so I won't from now on.

6 July 2014.  Tried for a steeper descent by lowering the target
  cost slightly when possible.

            ordinary descent   steeper descent
  ------------------------------------------------------------
  AU-BG-98  5.00622/8.00s      7.00460/9.24s
  IT-I4-96  1.00663/10.82s     0.00276/9.87s
  NL-KP-03  0.01471/815.46s    0.02342/995.44s
  ------------------------------------------------------------

  So steeper descent runs faster, but there is a noticeable
  drop in quality.

            Kempe moves        no Kempe moves  
  ------------------------------------------------------------
  AU-BG-98  5.00622/8.00s      18.00656/14.78s
  IT-I4-96  1.00663/10.82s      0.00265/10.27s
  NL-KP-03  0.01471/815.46s     0.01665/969.61s
  ------------------------------------------------------------

  There is no support here for abandoning Kempe meet moves.

  Best of 1  No fresh visits    Fresh visits       
  ------------------------------------------------------------
  AU-BG-98   5.00622/8.00s      12.00651/13.14s
  IT-I4-96   1.00663/10.82s      0.00455/13.88s
  NL-KP-03   0.01471/815.46s     0.01567/984.14s
  ------------------------------------------------------------

  Best of 8  No fresh visits    Fresh visits       
  ------------------------------------------------------------
  AU-BG-98   5.00622/22.52s     3.00645/35.45s
  IT-I4-96   0.00070/22.14s     0.00052/40.55s
  NL-KP-03   0.01023/3034.67s   0.01113/3937.37s
  ------------------------------------------------------------

  So fresh visits are probably useful, but they do take longer.

  AU-BG-98 best of 128, fresh visits: 3.00470/640.38s
  AU-BG-98 best of 256, fresh visits: 2.00553/1291.07s

  Wrote a new repair for limit busy times underloads:  it
  excludes all meets from the time group in question.

  Best of 1  Without new repair  With new repair  (new visit num)
  ---------------------------------------------------------------
  AU-BG-98   5.00622/8.00s       5.00622/8.07s
  IT-I4-96   1.00663/10.82s      0.00670/9.45s
  NL-KP-03   0.01471/815.46s     0.01948/1202.65s 0.01491/1341.17s
  ------------------------------------------------------------

  Best of 8  Without new repair  With new repair   
  ------------------------------------------------------------
  AU-BG-98   5.00622/22.52s      5.00622/22.78s
  IT-I4-96   0.00070/22.14s      0.00154/21.91s
  NL-KP-03   0.01023/3034.67s    0.00890/2856.58s
  ------------------------------------------------------------

  This 0.00890 is a new best solution for NL-KP-03.

7 July 2014.  Realized that the new repair for limit busy times
  underload defects could be applied both at depth 1 and when
  only one meet needs to be moved, as for cluster defects.  So
  I've modified the code accordingly.  Also revised the cluster
  underload repair, it was not quite right before.

  Best of 1  Before changes      After changes
  ---------------------------------------------------------------
  AU-BG-98   5.00622/8.07s       5.00622/8.03s
  IT-I4-96   0.00670/9.45s       0.00068/10.27s
  NL-KP-03   0.01491/1341.17s    0.01469/951.15s
  ------------------------------------------------------------

  Best of 8  Before changes      After changes
  ------------------------------------------------------------
  AU-BG-98   5.00622/22.78s      5.00622/22.55s
  IT-I4-96   0.00154/21.91s      0.00056/25.11s
  NL-KP-03   0.00890/2856.58s    0.00866/2762.18s
  ------------------------------------------------------------

  This 0.00866 solution is a new best - hurrah!

  Best of 1  KHE_OPTIONS_KEMPE_YES  KHE_OPTIONS_KEMPE_AUTO
  ---------------------------------------------------------------
  AU-BG-98   5.00622/8.07s          4.00538/8.33s
  IT-I4-96   0.00068/10.27s         0.00059/13.89s
  NL-KP-03   0.01469/951.15s        0.01016/1064.04s
  ------------------------------------------------------------

  Best of 8  KHE_OPTIONS_KEMPE_YES  KHE_OPTIONS_KEMPE_AUTO
  ------------------------------------------------------------
  AU-BG-98   5.00622/22.55s         4.00538/22.92s
  IT-I4-96   0.00056/25.11s         0.00059/26.95s
  NL-KP-03   0.00866/2762.18s       0.01016/3737.73s
  ------------------------------------------------------------

  Altogether, KHE_OPTIONS_KEMPE_AUTO is a disappointment.

  AU-BG-98 best of 32 KHE_OPTIONS_KEMPE_YES:  4.00571/110.74s
  AU-BG-98 best of 32 KHE_OPTIONS_KEMPE_AUTO: 4.00538/108.36s

8 July 2014.  Documented KHE_OPTIONS_KEMPE_AUTO.

9 July 2014.  Thinking about layer matching today.  Realized that
  it can run much faster when all durations are equal to 1.  Added
  this as a special case; it springs sometimes in NL-KP-03, but not
  that often (22 out of 58 layers requiring assignment).

  Problem with diversification in IT-I4-96 when there is no node
  regularity.

  Best of 1  time_node_regularity   !time_node_regularity
  ---------------------------------------------------------------
  AU-BG-98   5.00622/8.07s          10.00648/12.89s
  IT-I4-96   0.00068/10.27s         0.00059/12.49s
  NL-KP-03   0.01469/951.15s        0.01541/1589.97s
  ------------------------------------------------------------

  Best of 8  time_node_regularity   !time_node_regularity
  ------------------------------------------------------------
  AU-BG-98   5.00622/22.55s         5.00665/25.18s
  IT-I4-96   0.00056/25.11s         0.00043/23.10s
  NL-KP-03   0.00866/2762.18s       0.00700/3845.47s
  ------------------------------------------------------------

  0.00700 is a new best, saved at save_NL-KP-03_soln3.xml.

    0.01075 0.01541 0.01329 0.01287 0.00700 0.01164 0.01231
    [ Soln (instance "NL-KP-03", diversifier 7, cost 0.00700)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 201       0.00340
      LimitBusyTimesMonitor                  33       0.00360
      -------------------------------------------------------
      Total                                 234       0.00700
    ]

  Despite this I am returning to time_node_regularity, because
  of the slow running time.

10 July 2014.  IT-I4-96 best of 128 is 0.00051.  There seems to
  be a diversity problem.  Added diversification to the layer
  sorting function and also to ejection chain, and there has
  been some improvement.

  Realized that I have mishandled precision in a few cases, and
  designed the corrections for that.

11 July 2014.  Realized that I had introduced a bug by calling
  KheEjectorCurrAugmentCount(ej) repeatedly inside loops; to
  visit every alternative, I need to call it just once, outside
  the loop.  All fixed now.

  Implemented the new version of spread events repairs, and did
  some testing on AU-BG-98.

  Best of 8:

    3.00556 11.00501 7.00466 10.00683 5.00681 10.00668 2.00584 12.00596
    [ Soln (instance "AU-BG-98", diversifier 5, cost 2.00584)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   2       2.00000
      AvoidSplitAssignmentsMonitor           48       0.00520
      SpreadEventsMonitor                    12       0.00012
      LimitBusyTimesMonitor                  24       0.00052
      -------------------------------------------------------
      Total                                  86       2.00584
    ]

  Which is pretty good, in 26.56 secs too.  This is also the
  best of 32.  IT-I4-96 best of 128 is 0.00045/435.07s, also
  pretty good, although more diversity is needed.

  Implemented a more precise limit idle times repair, one that
  carries out every move that would fill an idle time, but it
  did not really help.  It may try too many repairs, most of
  which just create idle times elsewhere.  There are some good
  results, but the average seems higher; for IT-I4-96, best of
  8 was 0.00067/22.58s, and best of 128 was 0.00050/385.03s.

  Tried a slightly different version where the starting time
  of the meet after the move has to be an idle time, and got
  for IT-I4-96, best of 8 of 0.00066/23.85s, and best of 128
  0.00054/365.74s.
  
  Best of 1   Old               New (overlap)     New (start)
  ---------------------------------------------------------------
  IT-I4-96    0.00056/10.45s    0.00160/10.03s    0.00176/10.03s
  NL-KP-03    0.01377/1032.40s  0.01610/2006.65s  0.01812/2022.28s
  ---------------------------------------------------------------

  Best of 8   Old               New (overlap)     New (start)
  ---------------------------------------------------------------
  IT-I4-96    0.00051/27.30s    0.00067/22.50s    0.00066/23.84s
  NL-KP-03    0.00877/3687.52s  0.00950/4077.00s  0.01031/4339.06s
  ---------------------------------------------------------------

  Best of 128 Old               New (overlap)     New (start)
  ---------------------------------------------------------------
  IT-I4-96    0.00045/430.73s   0.00050/384.33s   0.00054/367.17s
  ---------------------------------------------------------------

  In every case here, the old repair has performed better.  I
  guess it is just better targeted.

13 July 2014.  Belatedly realized that there is little point in
  worrying about limit idle times defects (or limit busy times
  underloads) during layer assignment.  These need to be detached
  until after their layer is assigned.  Added code for this (for
  limit idle times defects only so far) to KheNodeLayeredAssignTimes.

  Tested KheLimitIdleMeetBoundAugment (NB new attachment rules for
  limit idle times defects are in place here, so all numbers are
  changed).  Here's a blurb:

    "For each day d containing an idle time such that there is exactly
    one meet m running during the last busy time t of d, there is one
    repair.  It unassigns m, then reduces the domains of all the
    resource's meets to the union over all the resource's busy days
    of the set of times lying between the first and last busy time
    (inclusive) on each day, minus t.  Any non-clashing reassignment
    must have at least one less idle time.  Although this is not an
    ejection tree repair (there is just one unassignment), reducing
    the domains is slow, so it is only tried on main loop defects"

    Best of 1    Without           With
    ---------------------------------------------------------------
    IT-I4-96     0.00167/8.86s     0.00153/10.80s (1 hit)
    NL-KP-03     0.01028/1610.74s  0.01094/1188.59s
    ---------------------------------------------------------------

    Best of 8    Without           With
    ---------------------------------------------------------------
    IT-I4-96     0.00051/22.37s    0.00048/27.84s (7 hits overall)
    NL-KP-03     0.00863/3415.05s  0.00927/2353.35s
    ---------------------------------------------------------------

    Best of 128  Without           With
    ---------------------------------------------------------------
    IT-I4-96     0.00045/386.25s   0.00044/406.60s (hits not recorded)
    ---------------------------------------------------------------

  Unassigning limit idle times defects seems to be useful (the
  Without column).  The ejection tree repair (the With column)
  has some positives but not much.  Leave it out for now.

  Tried moving smaller duration meets first in IT-I4-96:

    IT-I4-96     Without           With smaller durations first
    ---------------------------------------------------------------
    Best of 1    0.00167/8.86s     0.00056/7.93s
    Best of 8    0.00051/22.37s    0.00053/21.09s
    Best of 128  0.00045/386.25s   0.00041/386.44s
    ---------------------------------------------------------------

  Tried a fresh visit number on every step:

    IT-I4-96     Without           Fresh visit number (depth 1)
    ---------------------------------------------------------------
    Best of 1    0.00056/7.93s     0.00164/10.27s
    Best of 8    0.00053/21.09s    0.00057/26.47s
    Best of 128  0.00041/386.44s   0.00042/455.54s
    ---------------------------------------------------------------

  Curious, it's actually inferior.  0.00041 is also the best of 256.

15 July 2014.  Decided to expand the layer match code into a set of
  files sharing a .h file.  I'll call the whole thing "Elm", for
  extended layer matching.  Types KHE_ELM_*, functions KheElm*.
  Wrote quite a lot of plausible documentation, still to implement.

16 July 2014.  Working on khe_st_elm_core.c, going steadily.  The
  plan is to get it into good shape and then split it up.

17 July 2014.  Going well on Elm.  KheElmUnevennessTimeGroupAdd now
  written; evenness has changed a lot, and needs a careful audit.
  Supply nodes' zones and zone_index_set fields are now kept up to
  date automatically.

19 July 2014.  Going well on Elm.  Worked out what to do with zones,
  and now have a clean compile of a tidied up khe_st_elm_node.c.
  Audited it and the rest; ready to test now.

20 July 2014.  Results with Elm:

             Best of 1        Best of 8       Best of 128
  ------------------------------------------------------------
  AU-BG-98   11.00499/12.35s  4.00618/33.91s  3.00637/532.67s
  IT-I4-96   0.00055/13.52s   0.00055/25.29s  0.00048/394.33s
  ------------------------------------------------------------

  These results seem a bit slower but otherwise OK.

21 July 2014.  Made a start on khe_st_elm_irregular.c, which
  is where I will put the stuff for handling limit idle times,
  cluster busy times, and limit busy times monitors.  I've
  modified the core module to hold an array of irregular monitors,
  and documented and implemented KheElmDetachIrregularMonitors
  and KheElmAttachIrregularMonitors so far.  Also wrote out
  a very interesting specification of how the reductions work.

22 July 2014.  Started work on yesterday's spec.  Implemented
  tables of exclusions and trials of cluster busy times monitors.
  Realized that the original plan for handling cluster busy times
  monitors is probably better, because it is all done at the start,
  before any layers are assigned, and it takes account of all
  cluster busy times monitors, not just those which monitor the
  resources used to define layers.  So does this mean that limit
  idle times monitors should be squeezed at the start too?

23 July 2014.  Wrote up a detailed spec of an enhanced version of
  KheSolnClusterMeetDomains which handles limit idle times monitors
  as well as cluster busy times monitors.  Doing the implementation
  now.  So far I've built monitor nodes for limit idle times monitors
  as well as cluster busy times monitors.

24 July 2014.  Wrote up a completely different and hopefully better
  specification, for both the cluster busy times monitor and limit
  idle times monitor aspects, based on graph colouring.

25 July 2014.  Begun implementing yesterday's specification.  Have
  the overlap graph built, with positive and negative evidence,
  then reduced to only those resources that have non-trivial
  cluster monitors.  Have also initialized lists of these
  cluster monitors and their time groups, and implemented the
  basic function which tries one exclusion.  The next step is
  to exclude time groups which are subsets of the resource's
  unavailable times.  After that I need a definition of the
  priority of a node, a priority queue of nodes, and a
  function for trying exclusions repeatedly in one node.

26 July 2014.  Rewrote the 14 July specification to emphasize
  that the nodes represent resources.  Ready to continue the
  implementation I started yesterday.

27 July 2014.  Taking a detour today into redesigning meet
  bounds.  Have multiple meets and time groups per meet bound,
  allow starting time bounds as an option.  All documented.

28 July 2014.  Implementing yesterday's redesign of meet bounds.
  Got to the end of the compilation but there are still some
  things missing, principally meet handling within meet bound
  objects, and everything needs a careful audit.

29 July 2014.  Finished and audited the meet bound implementation,
  including making new kernel operations.  Ready for testing.

30 July 2014.  Tested the new meet bound implementation today.
  After tracking down one nasty little bug, got virtually the
  same results for AU-BG-98 and IT-I4-96 as before, so seems OK.

  Rewrote and re-implemented "Exposing resource unavailability",
  to take advantage of occupancy meet bounds.

  Redid the design of task bounds to follow the style of the new
  design for meet bounds, and implemented it.  Not tested yet.

31 July 2014.  Tested the new task bound implementation today.
  Returned to khe_st_cluster_and_limit.c, renewed my acquaintance
  with the old stuff and tidied it up a bit, ready to do new work.

1 August 2014.  Implemented KheSolnClusterAndLimitMeetDomains, or
  rather the cluster part of it, today.  Needs an audit, then a
  test.

2 August 2014.  First results of the new cluster code on NL-KP-03:

    KheGeneralSolve2014 at end (1048.41 secs elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.00913)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 232       0.00393
      LimitBusyTimesMonitor                  45       0.00520
      -------------------------------------------------------
      Total                                 277       0.00913
    ]

  For best of one, this is pretty good, although the number to
  beat is 0.00700 (best of 8 from 11 July 2014).  I haven't
  begun to tackle idle times yet.  1048 seconds is 17.5 mins.

3 August 2014.  Removed competing cluster handlers and got this:

    KheGeneralSolve2014 at end (17.52 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.00913)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 232       0.00393
      LimitBusyTimesMonitor                  45       0.00520
      -------------------------------------------------------
      Total                                 277       0.00913
    ]

  which is exactly the same.  This is also the best of 8:

    0.00913 0.00992 0.01180 0.01206 0.01326 0.01327 0.01417 0.01488

  Started work on limit idle times monitors, got a lot of it done,
  the only gap at the moment is the function that tries exclusions
  for a given limit idle times monitor.

4 August 2014.  Decided to group resources with identical
  timetables, as done during ejection chain repair.  Working
  on khe_ss_time_equiv.c, which will make time-equivalent
  events and resources generally available.

5 August 2014.  Finished coding khe_ss_time_equiv.c, and added
  a time-equiv options to options.  It's turned out quite a lot
  better than the code inherited from khe_ss_primary.c.  Also
  tested it quickly, it seems to be working.

  Sorted out KheMeetFirstUnFixed (now called KheMeetFirstMovable)
  and KheMeetLastFixed.

7 August 2014.  Updated KheSolnClusterAndLimitMeetDomains to handle
  sets of time-equivalent resources, not individual resources.
  Working on the code generally at the moment.

8 August 2014.  Sorted out the limit idle monitors mess.  It did
  the right thing but led afterwards to a very slow solve:
  
    KheGeneralSolve2014 at end (46.53 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01107)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            2       0.00100
      LimitIdleTimesMonitor                 169       0.00207
      ClusterBusyTimesMonitor                 3       0.00300
      LimitBusyTimesMonitor                  42       0.00500
      -------------------------------------------------------
      Total                                 216       0.01107
    ]

  I still have a few tricks to try before giving up.

9 August 2014.  Added diversification to cluster and limit.
  Designed, documented, and implemented a slack parameter.
  Did some runs but did not get very good results.  Then I
  added propagation of idle limits across positive edges.
  Here we go with slack 1.5:

    KheGeneralSolve2014 at end (31.25 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01881)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            4       0.00200
      LimitIdleTimesMonitor                 216       0.00371
      ClusterBusyTimesMonitor                 6       0.00600
      LimitBusyTimesMonitor                  55       0.00710
      -------------------------------------------------------
      Total                                 281       0.01881
    ]

  And with slack 1.2 I aborted, because there were over 600
  demand defects at one stage, which is ridiculous.  Slack 1.8:

    KheGeneralSolve2014 at end (13.00 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.00992)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            1       0.00050
      LimitIdleTimesMonitor                 205       0.00442
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                  33       0.00400
      -------------------------------------------------------
      Total                                 240       0.00992
    ]

  That's more like it; although there are still quite a few
  demand defects along the way.  Best of 8:

    0.00828 0.00899 0.00992 0.00994 0.01266 0.01308 0.01395 0.01443
    [ Soln (instance "NL-KP-03", diversifier 7, cost 0.00828)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            1       0.00050
      LimitIdleTimesMonitor                 186       0.00328
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                  30       0.00350
      -------------------------------------------------------
      Total                                 218       0.00828
    ]
    KheArchiveParallelSolve returning (46.78 mins elapsed)

  Cost is good, run time less so.  Best of 8 without calling the
  fn at all:

    0.00963 0.01103 0.01264 0.01399 0.01493 0.01685 0.01737 0.01782
    [ Soln (instance "NL-KP-03", diversifier 4, cost 0.00963)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            2       0.00100
      LimitIdleTimesMonitor                 254       0.00443
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                  31       0.00320
      -------------------------------------------------------
      Total                                 288       0.00963
    ]
    KheArchiveParallelSolve returning (39.50 mins elapsed)

  This is significantly worse: clearly the function is doing some
  good.  Cluster only, slack 1.2:

    0.00902 0.00916 0.00961 0.00972 0.00976 0.01083 0.01109 0.01176
    [ Soln (instance "NL-KP-03", diversifier 2, cost 0.00902)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 203       0.00462
      LimitBusyTimesMonitor                  34       0.00440
      -------------------------------------------------------
      Total                                 237       0.00902
    ]
    KheArchiveParallelSolve returning (32.62 mins elapsed)

  So for this slack it's working better without idle than with
  it.  Slack 1.0:

    0.00902 0.00916 0.00961 0.00972 0.00976 0.01083 0.01109 0.01176
    [ Soln (instance "NL-KP-03", diversifier 2, cost 0.00902)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 203       0.00462
      LimitBusyTimesMonitor                  34       0.00440
      -------------------------------------------------------
      Total                                 237       0.00902
    ]
    KheArchiveParallelSolve returning (32.64 mins elapsed)

  No difference here.  Here's best of 8, with idle, slack 1.6:

    0.01174 0.01223 0.01330 0.01356 0.01407 0.01455 0.01485 0.01776
    [ Soln (instance "NL-KP-03", diversifier 4, cost 0.01174)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            1       0.00050
      LimitIdleTimesMonitor                 227       0.00454
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                  37       0.00470
      -------------------------------------------------------
      Total                                 267       0.01174
    ]
    KheArchiveParallelSolve returning (58.60 mins elapsed)

  Not good.  The best result for this run of tests was best of 8,
  with idle, slack 1.8.  Best of 8, slack 1.8, without idle:

    0.00947 0.00959 0.00963 0.00986 0.01074 0.01129 0.01140 0.01412
    [ Soln (instance "NL-KP-03", diversifier 7, cost 0.00947)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 233       0.00397
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                  38       0.00450
      -------------------------------------------------------
      Total                                 272       0.00947
    ]
    KheArchiveParallelSolve returning (28.72 mins elapsed)

  Best of 8, slack 1.8, with idle:

    0.00828 0.00899 0.00992 0.00994 0.01266 0.01308 0.01395 0.01443
    best solutions:
    [ Soln (instance "NL-KP-03", diversifier 7, cost 0.00828)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            1       0.00050
      LimitIdleTimesMonitor                 186       0.00328
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                  30       0.00350
      -------------------------------------------------------
      Total                                 218       0.00828
    ]

  These are the best results wrt cost, but run time is a bit
  below par.

11 August 2014.  Trying to save time by limiting the number of
  defects repaired during the main loop to MAX while repairing
  layers.  While repairing other things there is no limit.  I
  impose the limit by removing the defects at the end after the
  main loop sorts, so defects of minimum cost are dropped.

  MAX = 200 (presumably has no effect):

    KheGeneralSolve2014 at end (13.24 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.00992)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            1       0.00050
      LimitIdleTimesMonitor                 205       0.00442
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                  33       0.00400
      -------------------------------------------------------
      Total                                 240       0.00992
    ]

  MAX = 50.  This one certainly dropped some monitors, I have
  the debug output to prove it.

    KheGeneralSolve2014 at end (16.60 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01152)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            1       0.00050
      LimitIdleTimesMonitor                 273       0.00462
      ClusterBusyTimesMonitor                 1       0.00100
      LimitBusyTimesMonitor                  42       0.00540
      -------------------------------------------------------
      Total                                 317       0.01152
    ]

  But the result is worse and it took longer to get there,
  presumably because the earlier you repair something, the
  better.  So I'm scratching this idea.

  Actually the real problem is that repairing one defect can
  spawn a very large number of new defects.  After resurrecting
  old code that detached all idle monitors except those in the
  current and previous layers:

    KheGeneralSolve2014 at end (12.48 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01110)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            2       0.00100
      LimitIdleTimesMonitor                 173       0.00350
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                  42       0.00460
      -------------------------------------------------------
      Total                                 219       0.01110
    ]

  This has marginally better cost than the previous solution,
  and its run time is significantly better.  After altering
  the old code to ignore all limit idle times, cluster busy
  times, and limit busy times monitors in the same way:

    KheGeneralSolve2014 at end (9.74 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01304)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            1       0.00050
      LimitIdleTimesMonitor                 224       0.00584
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                  40       0.00470
      -------------------------------------------------------
      Total                                 267       0.01304
    ]

  It's certainly faster, but the particular solution is inferior.
  Same thing, best of 8:

    0.00941 0.01159 0.01209 0.01304 0.01321 0.01423 0.01479 0.01530
    [ Soln (instance "NL-KP-03", diversifier 1, cost 0.00941)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            2       0.00100
      LimitIdleTimesMonitor                 227       0.00391
      LimitBusyTimesMonitor                  40       0.00450
      -------------------------------------------------------
      Total                                 269       0.00941
    ]
    KheArchiveParallelSolve returning (28.53 mins elapsed)

  Best of 8, limiting the detaching to limit idle times monitors only:

    0.01110 0.01122 0.01220 0.01379 0.01471 0.01593 0.01595 0.01627
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01110)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AvoidUnavailableTimesMonitor            2       0.00100
      LimitIdleTimesMonitor                 173       0.00350
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                  42       0.00460
      -------------------------------------------------------
      Total                                 219       0.01110
    ]
    KheArchiveParallelSolve returning (32.91 mins elapsed)

  This is noticeably inferior in cost.  Best of 8, limiting the
  detaching to limit idle times and limit busy times monitors only
  (the rationale being that cluster overloads are real defects
  even in partial timetables):

    0.00835 0.00932 0.00962 0.01188 0.01310 0.01317 0.01321 0.01345
    [ Soln (instance "NL-KP-03", diversifier 4, cost 0.00835)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 204       0.00365
      LimitBusyTimesMonitor                  41       0.00470
      -------------------------------------------------------
      Total                                 245       0.00835
    ]
    KheArchiveParallelSolve returning (28.22 mins elapsed)

  This seems pretty good, better than eliminating all three kinds,
  same running time.

12 August 2014.  There are three dimensions here:  which monitors
  to omit from layers (apparely idle and busy are best), whether
  to reduce domains for idle or not, and the slack parameter.

    C = cluster busy times monitors   L = layer detaching
    I = limit idle times monitors     R = domain reductions
    B = limit busy times monitors     S = Slack (when R is used)

    L   R   S    NL-KP-03: Best of 8 (mins)
    --------------------------------------------------------------------
    IB  -   -    00844 01100 01130 01203 01339 01481 01551 01682 (30.78)
    IB  C   1.2  00924 01039 01044 01148 01164 01210 01321 01484 (32.68)
    IB  C   1.5
    IB  C   1.8  00711 00978 01082 01114 01185 01242 01320 01510 (25.69)
    IB  CI  1.2  00961 01181 01275 01293 01502 01565 01833 02193 (73.97)
    IB  CI  1.5
    IB  CI  1.8  00835 00932 00962 01188 01310 01317 01321 01345 (28.22)
    --------------------------------------------------------------------
    IBC -   -    01085 01130 01392 01439 01475 01538 01637 01782 (33.56)
    IBC C   1.2  00924 01039 01044 01148 01164 01210 01321 01484 (32.61)
    IBC C   1.5
    IBC C   1.8  00845 00958 00971 01173 01181 01222 01331 01528 (23.89)
    IBC CI  1.2  x
    IBC CI  1.5
    IBC CI  1.8  00941 01159 01209 01304 01321 01423 01479 01530 (28.27)
    --------------------------------------------------------------------

  Documented, implemented, and started testing KheElmReduceIrregularMonitors,
  my bright new idea for quickly finding better matchings during layer
  assignment.  The first results are not striking:

    KheGeneralSolve2014 at end (12.79 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01445)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 241       0.00535
      ClusterBusyTimesMonitor                 3       0.00300
      LimitBusyTimesMonitor                  48       0.00610
      -------------------------------------------------------
      Total                                 292       0.01445
    ]

14 August 2014.  Looking at the table above, it seems that R = CI and
  R = - are never competitive.  So KheElmReduceIrregularMonitors needs
  to be tested in the following cases:

    L   R   S    NL-KP-03 with ReduceIrregularMonitors: Best of 8 (mins)
    --------------------------------------------------------------------
    IB  -   -    00871 00902 00914 00999 01179 01193 01212 01213 (32.75)
    IB  C   1.2  00815 00968 01028 01230 01259 01271 01329 01402 (32.78)
    IB  C   1.8  00808 00873 00942 01020 01131 01147 01237 01260 (21.63) **
    --------------------------------------------------------------------
    IBC -   -    01074 01096 01436 01466 01482 01483 01603 01907 (35.94)
    IBC C   1.2  00815 00968 01028 01230 01259 01271 01329 01402 (32.90)
    IBC C   1.8  00957 01136 01147 01187 01270 01448 01658 01708 (23.79)
    --------------------------------------------------------------------
    IB  CI  1.8  00900 00965 01214 01239 01262 01263 01319 01337 (32.15)
    IBC CI  1.8  00861 01304 01388 01445 01562 01624 01626 01655 (26.59)

  KheElmReduceIrregularMonitors does seem to be helping.  Although the
  effect is not striking, IB-C-1.8 turned out very well.  Could perhaps
  go with that for now.

  After adding KheNodeChildLayersReduce:

    C = cluster busy times monitors   L = layer detaching
    I = limit idle times monitors     R = domain reductions
    B = limit busy times monitors     S = Slack (when R is used)

    L   R   S    NL-KP-03 ReduceIrreg+ChildLayersReduce Best of 8 (mins)
    --------------------------------------------------------------------
    IB  -   -    00909 01006 01067 01094 01276 01420 01491 01605 (30.06)
    IB  C   1.2  00839 00943 00950 01050 01212 01219 01395 01540 (30.91)
    IB  C   1.8  00775 00981 01041 01083 01091 01103 01149 01167 (22.69)
    --------------------------------------------------------------------
    IBC -   -    00946 01325 01333 01376 01421 01439 01686 01824 (34.07)
    IBC C   1.2  x
    IBC C   1.8  x
    --------------------------------------------------------------------
    IB  CI  1.8  00909 01200 01256 01279 01359 01788 01825 3.01738 (77.27) 
    IBC CI  1.8  x

  Once again, IB-C-1.8 seems to be leading the way.  Here it is without
  resorting after each layer:

    --------------------------------------------------------------------
    IB  C   1.8  00919 00998 01019 01056 01122 01193 01431 01672 (33.47)
    --------------------------------------------------------------------

  Not a great idea and not great results, so scratch that.  Also I
  will scratch KheNodeChildLayersReduce, since there is no clear
  signal.  This takes us back to ** above, as I have just verified:

    --------------------------------------------------------------------
    IB  C   1.8  00808 00873 00942 01020 01131 01147 01237 01260 (21.62)
    --------------------------------------------------------------------

  More good ideas would be welcome, starting from here say.
  Trying with khe_se_solvers.c/WITH_NEW_LIMIT_IDLE_REPAIR_OVERLAP:

    --------------------------------------------------------------------
    IB  C   1.8  00903 00980 01102 01119 01238 01321 01389 01390 (32.48)
    --------------------------------------------------------------------

  So getting rid of WITH_NEW_LIMIT_IDLE_REPAIR_OVERLAP now.

16 August 2014.  Tried a variant of suppress_recent, in which I keep
  a record of how many failures a defect has had since its last success,
  sort the main loop defects by increasing failures then decreasing cost.

    KheGeneralSolve2014 at end (9.60 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.01197)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 222       0.00497
      ClusterBusyTimesMonitor                 2       0.00200
      LimitBusyTimesMonitor                  48       0.00500
      -------------------------------------------------------
      Total                                 272       0.01197
    ]

  Not so good, although not bad either.  Best of 8:

    00876 00954 01082 01134 01197 01232 01359 01488 (23.59)
  
  The next step is to skip defects which have failed since their
  last success, whenever there has already been at least one
  success in the main loop:

    KheGeneralSolve2014 at end (7.32 mins elapsed):
    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.00881)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 174       0.00291
      LimitBusyTimesMonitor                  49       0.00590
      -------------------------------------------------------
      Total                                 223       0.00881
    ]

  Best of 8:

    00881 00991 01245 01372 01407 01462 01463 01609 (23.79)

  Disappointing - it seems that skipping is no better than
  not skipping, either in cost or in run time.

  I've realized that there is no point in trying to repair
  the same defect twice unless the solution has changed in
  between the two defects (or the schedule has changed), and
  I've implemented this idea by storing the visit number of
  the most recent attempt in each monitor, and the visit
  number of the most recent success in the ejector, and
  comparing them before trying a repair.  Best of 8:

    00807 01095 01175 01280 01315 01328 01335 01493 (25.80)

  Without the skipping we get this:

    00808 00873 00942 01020 01131 01147 01237 01260 (22.83)

  which is arguably a better result.  

  Just for a change, I tried new visit numbers.  Best of 8:

    00617 00897 00939 01063 01163 01198 01221 01250 (34.39)

  There is a new best here, now posted; I've notified Gerhard.
  NB this is with skipping turned off.

    [ Soln (instance "NL-KP-03", diversifier 0, cost 0.00617)
      Soln                              Defects          Cost
      -------------------------------------------------------
      LimitIdleTimesMonitor                 130       0.00187
      LimitBusyTimesMonitor                  37       0.00430
      -------------------------------------------------------
      Total                                 167       0.00617
    ]

  Limit busy times underloads for teachers are clearly the main
  obstacle to further improvement.  Focus on them!

17 August 2014.  Turned skipping back on, since I basically do
  believe in it.  Turned off OneMeetOnly.  Fresh visits, best of 8:

    00745 00883 00961 01085 01146 01205 01395 01472 (33.39)

  Turned on OneMeetOnly:

    00853 00969 01062 01080 01137 01152 01169 01365 (25.99)

  No clear signal.

  Tried extra limit busy times repairs, which clean out each
  time group of each limit busy times monitor.  Best of 8:

    00900 00920 01046 01087 01128 01144 01310 01711 (24.62)

  It succeeds about three or four times per instance, but the
  successes don't seem to help.  So abandoning this now.

  Kempe meet moves during resource underload repairs:

    00648 00826 00837 00916 01114 01207 01377 01421 (30.29)

  This does seem helpful, let's leave it.  The same, only
  with skipping turned off:

    00676 00835 00853 00960 01061 01085 01367 01621 (32.31)

  Random variations, evidently.  Let's leave skipping in.

18 August 2014.  Begun the end run for the revised version of
  the paper.  Found a personal best for BR-SA-00.xml, 0.00014,
  which is only 3 limit idle times defects away from the 0.00005
  solution claimed optimal.

  Took a fresh download of XHSTT-2014, and discovered that
  DK-HG-12 seems to have revised.  So I've removed it from
  the skip list and am working on it today.  From Gerhard's
  web site, the value to beat is 25.33844.

    KheGeneralSolve2014 at end (111.28 mins elapsed):
    [ Soln (instance "DK-HG-12", diversifier 0, cost 12.03124)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   5       5.00000
      AssignTimeMonitor                       5       5.00000
      SpreadEventsMonitor                    67       0.00664
      AvoidClashesMonitor                     1       2.00000
      LimitIdleTimesMonitor                  94       0.01129
      ClusterBusyTimesMonitor               173       0.00783
      LimitBusyTimesMonitor                  66       0.00548
      -------------------------------------------------------
      Total                                 411      12.03124
    ]

  Hurrah - posted it and informed Gerhard.  Wrote code to impose a
  soft time limit on each solve.  Even with a soft one-minute time
  limit we did pretty well:

    KheGeneralSolve2014 at end (9.62 mins elapsed):
    [ Soln (instance "DK-HG-12", diversifier 0, cost 12.04808)
      Soln                              Defects          Cost
      -------------------------------------------------------
      AssignResourceMonitor                   5       5.00000
      AssignTimeMonitor                       1       1.00000
      SpreadEventsMonitor                   122       0.01152
      AvoidClashesMonitor                     1       6.00000
      LimitIdleTimesMonitor                 156       0.01876
      ClusterBusyTimesMonitor               165       0.00824
      LimitBusyTimesMonitor                  90       0.00956
      -------------------------------------------------------
      Total                                 540      12.04808
    ]

  Worked over the PATAT14 paper with a view to producing the
  journal version this week.

19 August 2014.  Ran a long test overnight.  It got almost to the
  end and then got into an infinite loop while solving ZA-LW-09
  (diversifier 6).  I tracked down the problem to faulty meet
  bound deletion in KheMeetMerge, and fixed it.

  Sorted out how to get more parallelism into benchmarking:
  just call KheArchiveParallelSolve.  Added a running time
  attribute to solutions in preparation for this.  Next step is
  to implement helper function KheBenchmarkTestOptions, which
  calls KheArchiveParallelSolve once for each value of a set
  of alternative options settings, and does the table construction
  and so on.

  Told Gerhard that XHSTT-2014.xml has no Id attribute.

  Finished off the experiments for the revised PATAT paper.

20 August 2014.  Completed the final pass through the paper.

22 August 2014.  Off-site backup of KHE.  New bests by KHE14x8:

    DK-FG-12 0.03310
    DK-VG-09 2.04097 (actually KHE14, not KHE14x8)
    US-WS-09 0.00677

  Published these three solutions on my web site and notified
  Gerhard.  Also published my 19 August 2014 KHE14 and KHE14x8
  solutions to the XHSTT-2014 archive on my web site.

  Now allowing solutions to lie in multiple solution groups,
  and instances to lie in multiple archives.  Used this new
  flexibility to enhance the "-e" command line option so
  that it writes solutions as well as instances.

23 August 2014.  Made an off-site backup of the revised PATAT14
  paper, source and PDF, with a link to the PDF from the KHE page.
  Finalized overheads and put them on my home page.  Made itinerary
  and sent it to Steph.  Put overheads on two memory sticks.

24 August 2014.  Revising KHE Guide and making it consistent with
  khe.h today.

16 September 2014.  Finally back at work today after being away at
  PATAT 2014, a short holiday afterwards, and a week of doing odd
  jobs since I got back.  Posted a new version of KHE on my web
  site, and a new version of HSEval too.  Submitted revised versions
  of my two PATAT 2014 to the Annals of OR special issue.

17 September 2014.  Over the last week I have been writing a spec for
  a better evaluation page for HSEval.  Now I need to coordinate this
  with my previous proposal, sent out to Gerhard but not acted on,
  then send the result to Gerhard for comment.  I found the previous
  proposal in tt/methodology; it has a long history of back-and-forth
  with Gerhard.  I really need to take the union of the two things.

18 September 2014.  Sent a cut-through proposal on evaluation of
  timetabling solvers to Gerhard.  This is my only active work on
  timetabling at the moment; I'm finished with solving for now.

20 September 2014.  Had some very sensible email from Gerhard
  on evaluation.  Revised the HTML document today, posted the
  revised version, and asked Gerhard to comment.

3 October 2014.  Added <SolutionGroup>/<MetaData>/<Publication>
  and <Solution>/<RunningTime> to the spec, and updated KHE and
  HSEval accordingly, and published new versions of them.


  To do
  =====

  Keep thinking about adding variable weights to monitors, as
  suggested by Emir.  He says he doesn't need it right now,
  but might want to try it later.

  KheEjectionChainEjectorMake in khe.h and used in several
  places but not documented.  Need to work out what is
  going on here.

  Tests for paper:

    B % @ Include { /home/jeff/khe/test13/stats/tab:nodereg}
    G % @ Include { /home/jeff/khe/test13/stats/tab:chaintype}
    H % fig1.eps and fig2.eps (chain lengths, need to be copied into file)
    I % @ Include { /home/jeff/khe/test13/stats/tab:moves}
    H % @ Include { /home/jeff/khe/test13/stats/tab:chainaugment:time}
    H % @ Include { /home/jeff/khe/test13/stats/tab:chainaugment:resource}
    H % @ Include { /home/jeff/khe/test13/stats/tab:chainrepair:time}
    A % Include /home/jeff/khe/test13/stats/tab:khe14
    A % Include /home/jeff/khe/test13/stats/tab:khe14x8:defects:a
    A % Include /home/jeff/khe/test13/stats/tab:khe14x8:defects:b

  So we need tests A, B, G, H, and I.

  Look again at MAX_AUGMENT_COUNT.  Do we need it?

  Continue trying to improve the handling of idle, cluster, and
  limit busy times monitors.  Especially limit busy times underloads.
  Might make that the last thing before re-running the experiments
  and producing a hopefully final journal version of the patat14 paper.

  Continue testing KheSolnClusterAndLimitMeetDomains.

  Use khe_ss_time_equiv.c in khe_ss_primary.c.

  In khe_se_solvers, more unification is possible between the two
  meet bound repairs, at the cost of slowing down the limit idle
  repairs function marginally.

  DD-School_1 and so on in IT-I4-96 contain a single preassigned
  resource and no other resources or constraints.  But there does
  not seem to be much I can do to take advantage of this.

  Do some more work on AU-BG-98, try to get better solutions.

  A solver which repeatedly runs solvers in parallel until a
  given time limit runs out.  So it will find best of 4 for
  very slow instances, and best of a much larger number for
  very fast instances.

  What about copying paths when copying solutions?  It's doable.

  Need to get the ejection chain code to run faster.  Is
  there some way to not try everything over and over?  Can
  we push failed defects to the back of the queue somehow?
  I've tried one thing (suppress_recent), and it did a good
  job on bghs98 but made things worse on NL-KP-03.

  Centre the headings over the cost and time columns in
  LaTeX tables.

  Looking at NL-KP-03, I think the layer time assigment
  construction has to do a better job of satisfying spread
  events constraints and demand constraints while still
  doing the clustering.  But there remains the basic
  problem that the ejection chain solver is drowning in
  hundreds of avoid idle times monitors.

  Getting bogged down in NL-KP-05.

  Have made and documented a new specification of the value
  returned by a solver - it is to be true if the solver changed
  the solution.  The interfaces of the solvers are correct now,
  but many of them return true when they need to work harder to
  decide what to return.  I should audit this.

  Do some more experiments, keep going.

