@Chapter
    @Title { Solution Monitoring }
    @Tag { monitoring }
@Begin
@LP
As a solution changes, it is continuously @I monitored by a
hand-tuned constraint network.
@BeginSections

@Section
    @Title { Measuring cost }
    @Tag { monitoring.cost }
@Begin
@LP
KHE measures the badness of a solution as a single integral value
called the @I { cost }, or sometimes the @I { combined cost }
because it includes the cost of both hard and soft constraint
deviations.  Storing costs in this way is convenient, because it
allows costs to be assigned using @C { = }, added using @C { + },
and compared using @C { < } and so on in the usual way.  The hard
cost is shifted left by 32 bits, to ensure that it is more
significant than any reasonable total soft cost, then added
to the soft cost.
@PP
The type of a combined cost is @C { KHE_COST }, a synonym for
the standard C 64-bit integer type @C { int64_t } (a fact best
forgotten).  To find the current combined cost of a solution, call
@ID @C {
KHE_COST KheSolnCost(KHE_SOLN soln);
}
This value is stored explicitly in @C { soln }, so this function
takes virtually no time to execute.  Call
@ID @C {
KHE_COST KheCost(int hard_cost, int soft_cost);
}
to create a combined cost.  The two components of a combined cost
may be accessed by
@ID @C {
int KheHardCost(KHE_COST combined_cost);
int KheSoftCost(KHE_COST combined_cost);
}
There is also the constant @C { KheCostMax }, which returns the
maximum value storable in a variable of type @C { KHE_COST } (a
synonym for @C { INT64_MAX }) and the function
@ID @C {
int KheCostCmp(KHE_COST cost1, KHE_COST cost2);
}
which returns an @C { int } which is less than, equal to, or
greater than zero if the first argument is respectively less
than, equal to, or greater than the second, as needed when
sorting items by cost.  The implementation does not make the
mistake of merely subtracting @C { cost2 } from @C { cost1 };
the result then would be a @C { KHE_COST } which will usually
overflow the @C { int } result.
@PP
The suggested way to display a combined cost is as a decimal
number with the hard cost before the decimal point and the
soft cost after.  Five decimal places are displayed, allowing
for soft costs up to 99999.  Larger soft costs are displayed
as 99999.  To assist with this, function
@ID @C {
double KheCostShow(KHE_COST combined_cost);
}
returns a value which, when printed with @C { printf } format
@C { "%.5f" }, prints the cost in this format.
# @PP
# By changing symbol @C { KHE_COST_SHOW_DIGITS } at the start of
# @C { khe.h }, the number of decimal places can be changed.  By
# default its value is 9999.  By changing it to, say, 99999, the
# value returned by @C { KheCostShow } will be suitable for
# printing with format @C { "%.5f" }, and so on.
@PP
These functions assume that both components of the cost are
non-negative.  There is no problem with negative combined
costs in themselves, but when a hard and soft cost are
combined together, if either is negative they may be
different if they are separated again.
@End @Section

@Section
    @Title { Monitors }
    @Tag { monitoring_monitors }
@Begin
@LP
A @I { monitor } is an object, of type @C { KHE_MONITOR }, that
monitors one part of a solution:  typically, one point of application
of one constraint.  It contains the usual back pointer and
visit number:
@ID -1px @Break @C {
void KheMonitorSetBack(KHE_MONITOR m, void *back);
void *KheMonitorBack(KHE_MONITOR m);
void KheMonitorSetVisitNum(KHE_MONITOR m, int num);
int KheMonitorVisitNum(KHE_MONITOR m);
bool KheMonitorVisited(KHE_MONITOR m, int slack);
void KheMonitorVisit(KHE_MONITOR m);
void KheMonitorUnVisit(KHE_MONITOR m);
}
Operations
@ID -1px @Break @C {
KHE_SOLN KheMonitorSoln(KHE_MONITOR m);
int KheMonitorSolnIndex(KHE_MONITOR m);
KHE_COST KheMonitorCost(KHE_MONITOR m);
KHE_COST KheMonitorLowerBound(KHE_MONITOR m);
}
return the enclosing solution, the index of @C { m } in that
solution, the cost of what @C { m } is monitoring (kept up to
date by KHE as the solution changes), and a constant lower
bound on @C { KheMonitorCost }, which is usually 0 but will
be non-zero when KHE can prove the lower bound easily.
@PP
Each monitor contains its own combined weight, used when
calculating its cost.  This is initially (and usually) the
combined weight of the constraint that the monitor is
derived from, but it is possible to set it independently:
@ID @C {
KHE_COST KheMonitorCombinedWeight(KHE_MONITOR m);
void KheMonitorSetCombinedWeight(KHE_MONITOR m,
  KHE_COST combined_weight);
void KheMonitorResetCombinedWeight(KHE_MONITOR m);
}
@C { KheMonitorCombinedWeight } returns the combined weight,
@C { KheMonitorSetCombinedWeight } sets it, and
@C { KheMonitorResetCombinedWeight } resets it to its
initial value, the value from @C { m }'s constraint.  (If
@C { m } is not derived from any constraint, for example
if it is one of the redundancy prefer resources monitors
described in Section {@NumberOf matchings.redundancy},
then @C { KheMonitorResetCombinedWeight } does nothing.
@PP
Any change to @C { m }'s weight is reflected immediately in
the costs of @C { m } and its ancestors, for example in
solution cost.  However @C { KheMonitorLowerBound } does
not change; it depends only on the initial combined weight.
# For example,
# an assign time monitor monitors one point of application of
# one assign time constraint (one event).  Its cost is the value
# of the cost function of its constraint applied to a number of
# deviations which is the total duration of meets derived from its
# event which are not assigned a time.
@PP
Here are two other functions related to cost:
@ID @C {
KHE_COST_FUNCTION KheMonitorCostFunction(KHE_MONITOR m);
KHE_COST KheMonitorDevToCost(KHE_MONITOR m, int dev);
}
@C { KheMonitorCostFunction } returns @C { m }'s cost function,
which is the same as @C { m }'s constraint's cost function.
@C { KheMonitorDevToCost } returns the cost that @C { m }
would report if it had deviation @C { dev }.  Apart from
@C { dev }, this depends only on @C { m }'s cost function
and combined weight.
@PP
Type @C { KHE_MONITOR } is the abstract supertype of many
concrete subtypes, with these tags:
# whose type is @C { KHE_MONITOR_TAG }:
@ID -1.5px @Break @C {
typedef enum {
  KHE_ASSIGN_RESOURCE_MONITOR_TAG,
  KHE_ASSIGN_TIME_MONITOR_TAG,
  KHE_SPLIT_EVENTS_MONITOR_TAG,
  KHE_DISTRIBUTE_SPLIT_EVENTS_MONITOR_TAG,
  KHE_PREFER_RESOURCES_MONITOR_TAG,
  KHE_PREFER_TIMES_MONITOR_TAG,
  KHE_AVOID_SPLIT_ASSIGNMENTS_MONITOR_TAG,
  KHE_SPREAD_EVENTS_MONITOR_TAG,
  KHE_LINK_EVENTS_MONITOR_TAG,
  KHE_ORDER_EVENTS_MONITOR_TAG,
  KHE_AVOID_CLASHES_MONITOR_TAG,
  KHE_AVOID_UNAVAILABLE_TIMES_MONITOR_TAG,
  KHE_LIMIT_IDLE_TIMES_MONITOR_TAG,
  KHE_CLUSTER_BUSY_TIMES_MONITOR_TAG,
  KHE_LIMIT_BUSY_TIMES_MONITOR_TAG,
  KHE_LIMIT_WORKLOAD_MONITOR_TAG,
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR_TAG,
  KHE_LIMIT_RESOURCES_MONITOR_TAG,
  KHE_EVENT_TIMETABLE_MONITOR_TAG,
  KHE_RESOURCE_TIMETABLE_MONITOR_TAG,
  KHE_ORDINARY_DEMAND_MONITOR_TAG,
  KHE_WORKLOAD_DEMAND_MONITOR_TAG,
  KHE_EVENNESS_MONITOR_TAG,
  KHE_GROUP_MONITOR_TAG,
  KHE_MONITOR_TAG_COUNT
} KHE_MONITOR_TAG;
}
Each monitor object contains a tag identifying its subtype, returned by
@ID @C {
KHE_MONITOR_TAG KheMonitorTag(KHE_MONITOR m);
}
Monitors of the first eighteen types monitor one point of application of
one constraint; their cost is the total cost of deviations at that point.
They are described in detail in later sections of this chapter.  Monitors
of the last six types (from @C { KHE_EVENT_TIMETABLE_MONITOR_TAG } onwards)
do not monitor constraints.  Timetable monitors hold the timetables of
events and resources (Section {@NumberOf monitoring_timetables})
Ordinary and workload demand monitors monitor matchings, and evenness
monitors monitor evenness (Chapter {@NumberOf matchings}).  Group monitors
group together other monitors (Section {@NumberOf monitoring.group}).
The last value is not a tag; it is a count of the number of monitor
types, allowing code of the form
@ID @C {
for( tag = 0;  tag < KHE_MONITOR_TAG_COUNT;  tag++ )
  ... do something for monitors of type tag ...
}
For those monitors that monitor a point of application of a constraint,
functions
@ID @C {
KHE_CONSTRAINT KheMonitorConstraint(KHE_MONITOR m);
char *KheMonitorAppliesToName(KHE_MONITOR m);
}
return the constraint and the name of the point of application
(if this point is an event resource, the name of the enclosing
event is returned).  For other monitors they return @C { NULL }.
It is quite dangerous to assume that the result of
@C { KheMonitorConstraint } is non-@C { NULL }; in
particular, there are prefer resources monitors for
which @C { KheMonitorConstraint } returns @C { NULL }
(Section {@NumberOf matchings.redundancy}).
@PP
@C { KheMonitorAppliesToName } is more or less obsolete; the
author prefers now to call
@ID @C {
char *KheMonitorPointOfApplication(KHE_MONITOR m);
}
which returns a more precise indication of the point of application.
Each constraint monitor also has functions which return the specific
constraint and point of application.
@PP
The result of @C { KheMonitorPointOfApplication(m) } is created
afresh on each call.  This is not very efficient, but if the
function is called only when generating evaluation tables, as is
the intention, that will not matter.
@PP
A similar function to @C { KheMonitorPointOfApplication } is
@ID @C {
char *KheMonitorId(KHE_MONITOR m);
}
It returns a string composed of two or three fields separated by @C { / }
characters.  Each field is an Id from the instance or an integer.  The
fields are supposed to uniquely identify the monitor, although in a
few cases this is doubtful.  The first field is always a constraint Id,
identifying the constraint that the monitor is derived from, and the
second is usually an event, event group, or resource Id, identifying
the point of application.  There may be a third field, holding a
second event Id (for order events monitors) or an offset (for resource
constraints with an @C { AppliesToTimeGroup } attribute).  When the
offset is 0 the offset field and preceding @C { / } are omitted.
A non-zero offset may be replaced by the Id of the first time of the
first monitored time group.
@PP
The result of @C { KheMonitorId(m) } is created when
@C { KheMonitorId(m) } is first called, and stored in @C { m } so that it
does not have to be created over and over.  If it is used
only for debugging, as is the intention, there is virtually no cost
in running time or memory when debugging is off.
# @PP
# The cost of a monitor is a function of a set of @I { deviations },
# which are non-negative integers.  A deviation could be 0, although
# the cost functions all have the property that adding or removing a
# 0 from a set of deviations does not change the cost.  The deviations
# can be obtained by calling
# @ID @C {
# int KheMonitorDeviationCount(KHE_MONITOR m);
# int KheMonitorDeviation(KHE_MONITOR m, int i);
# char *KheMonitorDeviationDescription(KHE_MONITOR m, int i);
# }
# The first two return the number of deviations and the @C { i }th
# deviation; the third returns a description of the @C { i }th deviation.
# These functions are intended for reporting, not solving, and may be slow.
# @PP
# Some monitors, for example timetable monitors and group monitors, do not
# monitor constraints or calculate deviations, and so they return 0 for
# @C { KheMonitorDeviationCount }.  Most monitors have one deviation,
# and they return 1 for @C { KheMonitorDeviationCount } and @C { NULL }
# for @C { KheMonitorDeviationDescription }.  A few monitors have
# multiple deviations:  avoid clashes monitors, which have one deviation
# for each time where there is a clash (described by the name of the
# time), and limit busy times and spread events monitors, which have
# one deviation for each time group monitored (described by the name
# of the time group).
@PP
The cost of a monitor is a function of its @I { deviation },
a non-negative integer:
@ID @C {
int KheMonitorDeviation(KHE_MONITOR m);
char *KheMonitorDeviationDescription(KHE_MONITOR m);
}
These functions are intended for reporting, not solving.
@C { KheMonitorDeviation } returns the deviation, and
@C { KheMonitorDeviationDescription } returns a description of it:
an expression, augmented with brief text, showing how it is calculated.
The result string does not necessarily lie in heap memory, and
should not be freed.
# The result string is stored in heap memory and may be freed by passing
# it to @C { MFree } (Appendix {@NumberOf modules.m}) after use.
@PP
For limit active intervals monitors, @C { KheMonitorDeviation } returns
the sum of the deviations of the active intervals.  Exceptionally, the
cost of the monitor is not a function of this deviation; instead, it
is the sum of the costs of the deviations of the active intervals
taken separately.
# @PP
# Although a deviation is a single integer, it can often be divided
# into a sum of @I { deviation parts }.  Just what one part consists
# of depends on the constraint type, and is not formally defined by
# KHE; deviation parts are intended for use only when reporting, to
# diagnose how a deviation came about, not for solving or calculating
# costs formally.  The following functions give access to the parts
# of a monitor's deviation:
# @ID @C {
# int KheMonitorDeviationPartCount(KHE_MONITOR m);
# void KheMonitorDeviationPart(KHE_MONITOR m, int i,
#   int *value, char **description);
# }
# @C { KheMonitorDeviationPartCount } returns the number of parts;
# @C { KheMonitorDeviationPart } sets @C { *value } to the value of the
# @C { i }'th part, and @C { *description } to a description of that part
# when there is one, and to @C { NULL } when there isn't.  For example,
# the description might be the Id of an event or time.  The sum of the
# values over all @C { i } equals @C { KheMonitorDeviation(m) }.  Some
# parts may have value 0, and it is usually best to skip those.
@PP
To visit the full set of monitors monitoring @C { soln }, call
@ID @C {
int KheSolnMonitorCount(KHE_SOLN soln);
KHE_MONITOR KheSolnMonitor(KHE_SOLN soln, int i);
}
Although KHE does not fully specify the order in which these monitors
appear, it does guarantee that the monitors which monitor constraints
will appear together in the list in the order that their constraints
appear in the input.  It is best to select these monitors by testing
whether the result of @C { KheMonitorConstraint } above is non-@C { NULL }.
@PP
There is also function
@ID @C {
bool KheSolnRetrieveMonitor(KHE_SOLN soln, char *id, KHE_MONITOR *m);
}
It searches for a monitor whose Id, as returned by @C { KheMonitorId }
above, is equal to @C { id }.  If it finds one, it returns @C { true }
with @C { *m } set to that monitor; otherwise it returns @C { false }
with @C { *m } set to @C { NULL }.
@PP
Although every monitor has an Id, at present @C { KheSolnRetrieveMonitor }
does not retrieve all monitors.  It retrieves resource monitors, and
event monitors that monitor a single event.
@PP
@C { KheSolnRetrieveMonitor } is intended for debugging and is not
very efficient.  It works by finding the entity (event, event group,
or resource) identified by the second field of @C { id } and searching
that entity's list of monitors for one for which @C { KheMonitorId }
returns @C { id }.
@PP
To debug a monitor @C { m } with a given verbosity and indent, call
@ID { 0.98 1.0 } @Scale @C {
void KheMonitorDebug(KHE_MONITOR m, int verbosity, int indent, FILE *fp);
}
There are also versions of this function for each of the specific
monitor types.  These all work in the same way.  The output starts
with a @C { G }, @F { A } or @F { D } indicating whether the monitor
is a group monitor, an attached non-group monitor, or a detached
non-group monitor.  This is followed by the number of paths up from
the monitor to the solution (Section {@NumberOf monitoring.group}),
usually 0 or 1.  Then comes the monitor's tag and cost, then other
information depending on the monitor type and verbosity.  There is also
@ID @C {
char *KheMonitorTagShow(KHE_MONITOR_TAG tag);
}
which returns a string representation of @C { tag }.  In practice
a more useful function is
@ID @C {
char *KheMonitorLabel(KHE_MONITOR m);
}
This returns @C { KheMonitorTagShow(KheMonitorTag(m)) } if @C { m }
is not a group monitor, and @C { m }'s subtag label if @C { m } is
a group monitor.
@End @Section

@Section
    @Title { Attaching, detaching, and provably zero fixed cost }
    @Tag { monitoring.attach }
@Begin
@LP
For a monitor to be updated when the solution changes, there must
be links from the appropriate points within the solution to the
monitor.  When these links are present, the monitor is said to be
@I { attached to the solution }, or just @I { attached }.  Most
monitors are attached to begin with, but they can be detached at
any time, and even reattached later, by calling
@ID @C {
void KheMonitorDetachFromSoln(KHE_MONITOR m);
void KheMonitorAttachToSoln(KHE_MONITOR m);
}
Even when detached, a monitor remembers which parts of the solution
it is supposed to monitor, so the attach operation does not have to
tell the monitor where to attach itself.  To find out whether a
monitor is currently attached or detached, call
@ID @C {
bool KheMonitorAttachedToSoln(KHE_MONITOR m);
}
Another function, highly recommended for calling at the end of a solve, is
# These three operations apply to all kinds of monitors.
# except the
# group monitors of Section {@NumberOf monitoring.group}, to which
# the concept of attachment to the solution does not apply.
@ID @C {
void KheSolnEnsureOfficialCost(KHE_SOLN soln);
}
This ensures that all constraint monitors are both attached to the
solution and reporting their cost to the solution, directly or
indirectly via group monitors, that the multipliers of all cluster
busy times monitors are 1 and their minimums have their original value,
and that all demand and evenness monitors are detached from the
solution.  This guarantees that the solution cost is the official cost.
@PP
While a monitor is detached, it receives no information about changes
to the solution, and, by definition, its deviation and cost are 0.
Detaching a monitor may therefore change its cost.  If there is a
change in cost, it is reported to the monitor's parents (if it has
any) as usual.  Conversely, attaching a monitor brings it up to date
with the current state of the solution, which again may change its
cost; and again, if there is a change in cost it is reported to its
parents (if it has any).
@PP
There are two main reasons for detaching a monitor.  First, the user
might make a deliberate choice to ignore some constraints.  For
example, a solver that works in two phases, first finding a solution
that satisfies the hard constraints, and then attacking the soft ones,
might detach the monitors for the soft constraints during its first
phase.  An example of this kind of deliberate choice is KHE's matching
feature (Chapter {@NumberOf matchings}), which is implemented with
monitors.  Unlike other monitors, matching monitors are detached
initially.  KHE makes this choice deliberately, on the grounds that
the cost of the matching is not officially part of the cost function.
@PP
The second reason for detaching a monitor is that it may be clear
that its cost will be zero for a long time.  In that case, detaching
it means that no time is spent keeping it up to date, yet it still
reports the correct cost.  For example, if the meets of one point
of application of a link events constraint are assigned to each
other and those assignments will not be removed, then it is safe
to save time by detaching the corresponding monitor.
@PP
This reasoning was formerly embodied in a function called
@C { KheMonitorAttachCheck }, which assumed that certain elements
of the solution were unlikely to change, and detached monitors
accordingly.  @C { KheMonitorAttachCheck } has been withdrawn;
the equivalent functionality is now obtained, more reliably, by
calling the @C { Fix } and @C { UnFix } functions, as follows.
# @PP
# This reasoning is embodied in function
# @ID @C {
# void KheMonitorAttach Check(KHE_MONITOR m);
# }
# It assumes that certain elements of the solution will not change
# for a long time:  the way that events are split into meets,
# non-@C { NULL } assignments to meets that do not lie in nodes,
# non-@C { NULL } assignments to follower tasks, and meet and task
# domains.  It checks whether, under that assumption, the cost of
# monitor @C { m } must be and remain 0.  If so, it detaches @C { m }
# unless it is already detached; if not, it attaches @C { m } unless
# it is already attached.
# @PP
# The assumption proves nothing about the future cost of monitors of
# most types.  For example, it does not prevent the next time or
# resource assignment from producing a clash (except in circumstances
# too rare to be worth checking for).  In these cases,
# @C { KheMonitorAttach Check } merely attaches @C { m } if it is not
# already attached.  For each monitor type where more is done, the
# details are given as part of the description of that monitor type
# later in this chapter.
# @PP
# Instead of calling @C { KheMonitorAttach Check }, it is easier and much
# more reliable to indicate that certain parts of the solution will not
# change soon by fixing them (Section {@NumberOf solutions.overview}).
# Fixing causes attached monitors whose cost is 0 and must remain 0
# while the current fixes are in place to be detached, and unfixing
# causes detached monitors whose cost need not be 0 given the unfixing
# to be attached.  For each monitor type where something is done in
# response to fixes and unfixes, the details appear as part of the
# description of that monitor type later in this chapter.
# @End @Section
# 
# @Section
#     @Title { Provably zero fixed cost and fixing }
#     @Tag { monitoring.zero }
# @Begin
# @LP
@PP
# A monitor has @I { provably zero fixed cost } if enough of the
# solution is currently fixed (by calls to @C { KheMeetSplitFix },
# @C { KheMeetAssignFix }, @C { KheMeetDomainFix }, @C { KheTaskAssignFix },
# and @C { KheTaskDomainFix }) to allow KHE to prove that the monitor must
A monitor has @I { provably zero fixed cost } if enough of the
solution is currently fixed (by calls to @C { KheMeetAssignFix }
and @C { KheTaskAssignFix }) to allow KHE to prove that the monitor must
have cost 0 while those fixes remain.  For each kind of monitor, either
a specific definition of when it has provably zero fixed cost is given
below, or else it never has provably zero fixed cost.
@PP
When one of the fixing operations just listed is called, after
doing the actual fixing KHE ensures that all monitors which did not
have provably zero fixed cost before but now do are detached.  When
one of the corresponding unfix operations is called, after
doing the actual unfixing it ensures that all monitors which had
provably zero fixed cost before but now do not are attached.  So
there is no risk that detaching these monitors could lead to cost
errors; as soon as unfixes make a non-zero cost possible, they are
attached again.
@End @Section

@Section
    @Title { Time ranges and sweep times }
    @Tag { monitoring.sweep_times }
@Begin
@LP
Function
@ID @C {
bool KheMonitorTimeRange(KHE_MONITOR m,
  KHE_TIME *first_time, KHE_TIME *last_time);
}
determines the times @C { t } such that the cost of @C { m } is
affected by what is happening at time @C { t }.  If there are
any such times, it sets @C { *first_time } to the first of them
and @C { *last_time } to the last of them, and returns @C { true }.
Otherwise it sets @C { *first_time } and @C { *last_time } to
@C { NULL } and returns @C { false }.
@PP
When @C { m } is a resource monitor, @C { KheMonitorTimeRange }
depends only on the instance; it just returns the first and last
times referenced (explicitly or implicitly) by @C { m }.  These
values are cached in @C { m }, so requesting them a second time
has virtually no cost.
@PP
When @C { m } is an event monitor, @C { KheMonitorTimeRange } depends
on the times assigned to the meets monitored by @C { m }.  When
@C { m } is an event resource monitor, @C { KheMonitorTimeRange }
depends on the times assigned to the meets containing the tasks
monitored by @C { m }.  In these cases the values are not cached;
they are recalculated each time they are requested.  Meets without
an assigned time are skipped and contribute nothing to the result.
@PP
The main use for @C { KheMonitorTimeRange } is in handling
sweep times, as explained now.
@PP
A @I { time sweep } algorithm is a resource assignment algorithm
that sweeps through a solution, assigning tasks in increasing order
of their assigned times.  A @I { sweep time } is a time @C { t }
representing the point that a time sweep has reached:  assignments
have been or are being made up to and including @C { t }, but not
later.  Or @C { t } may be @C { NULL }, meaning that the time sweep
is just beginning and the entire cycle is beyond where it has reached.
@PP
Now consider a limit active
intervals monitor which specifies a minimum limit of two on the number
of consecutive busy days.  Starting a new sequence of busy days during
a time sweep violates the minimum limit, and not starting one does not,
which is misleading.  The same problem afflicts cluster busy times
monitors:  a minimum limit can encourage a resource to
be busy at the start, when it could very well remain free until later.
@PP
So monitors should not report defects that could disappear later as
the time sweep proceeds.  We say that tasks and times beyond the
sweep time are {@I open}:  neither assigned nor unassigned.  The
cost reported by a monitor is the true cost when nothing relevant
is open, and a lower bound on the true cost otherwise, treating the
open parts as don't knows.
@PP
There is a connection here with the `history after' values of some
resource monitors.  These count notional time groups that lie beyond
the end of the cycle.  They are open in exactly the same way that times
beyond the sweep time are open.  However, they can never be not open.
@PP
Function
@ID @C {
void KheMonitorSetSweepTime(KHE_MONITOR m, KHE_TIME t);
}
tells @C { m } that the sweep time is @C { t } (possibly
@C { NULL } as above).  This may change the cost of @C { m }.
@PP
As an example of the use of @C { KheMonitorSetSweepTime }, suppose
a time sweep algorithm assigns one day at a time.  Initially it calls
@C { KheMonitorSetSweepTime(m, NULL) }, and then, before assigning
each day @M { d }, it calls @C { KheMonitorSetSweepTime(m, t) }, where
@C { t } is @M { d }'s last time.  On the last call, @C { t } is the
last time of the cycle; the time sweep has ended and nothing is open.
@PP
Behind the scenes, limit busy times and limit workload monitors
which need to know what resource @C { r } is doing during time
group @C { tg } share access to a private object that keeps track
of this information.  When they receive a new sweep time they pass
it on to this object.  Giving different sweep times to monitors
which share the same private object will not work, although it is
safe to change the sweep times of those monitors one by one to a
new common value, provided no affected costs are accessed until
the last change has been made.
@PP
It can be slow to call @C { KheMonitorSetSweepTime } for every monitor
and every time (or every day).  A basis for speeding things up is
provided by function
@ID @C {
bool KheMonitorSweepTimeRange(KHE_MONITOR m,
  KHE_TIME *first_time, KHE_TIME *last_time);
}
If the cost of @C { m } could possibly change when the sweep time
changes, this is the same as @C { KheMonitorTimeRange } above.  If
the cost of @C { m } can never change when the sweep time changes,
this sets @C { *first_time } and @C { *last_time } to @C { NULL }
and returns @C { false }.  In making this determination, it is
assumed that all tasks lying beyond the sweep time are unassigned.
@PP
Calling @C { KheMonitorSetSweepTime } with any time @C { t } preceding
@C { *first_time } is the same as calling it with @C { t } set to
@C { NULL }, and calling it with any time @C { t } following
@C { *last_time } is the same as calling it with @C { t } set to
@C { *last_time }.  So @C { m } needs only an initial call with
@C { t } set to @C { NULL }, then calls for times between
@C { *first_time } and @C { *last_time }, and finally, to bring the
monitor back to its usual state, a call with @C { t } set to
@C { *last_time } or any later time.  Or if @C { KheMonitorSweepTimeRange }
returns @C { false }, no @C { KheMonitorSetSweepTime } calls are needed.
@PP
All monitors have their own private versions of the functions defined
here, which these functions call on.  However, not all monitors are
affected by sweep times.  For those which are not, setting the sweep
time does nothing and the sweep time range function returns @C { false }.
# @PP
# Normally, every fragment of a solution, including every fragment
# of every monitor, has a definite value.  But sweep times put the
# fragments of the solution beyond the sweep time into a peculiar
# state which we refer to as @I { open }.  For example, suppose some
# task is monitored by an assign resource monitor and also by a prefer
# resources monitor with an empty preferred set.  Then usually one
# of those two monitors would have a non-zero cost, but when the
# task is open they both have cost 0.  In general, the cost reported
# by a monitor is the true cost when there is no time sweep, and a
# lower bound on the true cost when there is a time sweep, treating
# any open fragments as don't knows.
@PP
Sweep times are used by @C { KheTimeSweepAssignResources }
(Section {@NumberOf resource_solvers.matching.time.sweep}) and have
been added to support that solver.  @C { KheDynamicResourceSolverSolve }
(Section {@NumberOf resource_solvers.dynamic}) utilizes similar ideas,
but within a completely different and more thorough implementation.
@End @Section

@Section
    @Title { Event monitors }
    @Tag { monitoring.event_monitors }
@Begin
@LP
An @I { event monitor } monitors one or more events.  The set of
monitors (attached or unattached) which monitor a given event may
be found by calling
@ID @C {
int KheSolnEventMonitorCount(KHE_SOLN soln, KHE_EVENT e);
KHE_MONITOR KheSolnEventMonitor(KHE_SOLN soln, KHE_EVENT e, int i);
}
These return the number of monitors that monitor @C { e } in
@C { soln }, and the @C { i }th of these, as usual.  The timetable
monitor for event @C { e } (Section {@NumberOf monitoring_timetables})
is not visited by these functions; it may be retrieved by calling
@C { KheEventTimetableMonitor }.
@PP
The total cost of these monitors measures how well @C { e } is
timetabled.  Functions
@ID @C {
KHE_COST KheSolnEventCost(KHE_SOLN soln, KHE_EVENT e);
KHE_COST KheSolnEventMonitorCost(KHE_SOLN soln, KHE_EVENT e,
  KHE_MONITOR_TAG tag);
}
return the total cost of all the monitors monitoring @C { e },
and the total cost of all monitors monitoring @C { e } of a
specific type, defined by @C { tag }.  @C { KheSolnEventMonitorCost }
returns 0 when @C { tag } does not specify one of the monitor
types in the following subsections.
@PP
Each point of application of a spread events constraint or link
events constraint is one event group, and a monitor of these
kinds appears on the list of monitors of each of the events in
its event group.  Similarly, an order events monitor appears
on the list of monitors of both of the events it monitors.  If
@C { KheSolnEventCost(soln, e) } is summed over all events, the cost
of such monitors is counted repeatedly, and the total may exceed
the total cost of all event monitors.
@PP
Event monitors are unaffected by sweep times.  This is because
sweep times are concerned with time sweep resource assignment,
which assumes that assigned times are not changing.
@PP
The following subsections list the various kinds of event
monitors and the details specific to each of them.  Their types
(@C { KHE_SPLIT_EVENTS_MONITOR } and so on) may be obtained by
downcasting from @C { KHE_MONITOR } after checking the type tag.
@BeginSubSections

@SubSection
    @Title { Split events monitors }
@Begin
@LP
A split events monitor has tag @C { KHE_SPLIT_EVENTS_MONITOR_TAG }
and monitors an event which is one point of application of one
split events constraint.  Functions
@ID @C {
KHE_SPLIT_EVENTS_CONSTRAINT KheSplitEventsMonitorConstraint(
  KHE_SPLIT_EVENTS_MONITOR m);
KHE_EVENT KheSplitEventsMonitorEvent(KHE_SPLIT_EVENTS_MONITOR m);
}
return the split events constraint and event being monitored, and
@ID {0.97 1.0} @Scale @C {
void KheSplitEventsMonitorLimits(KHE_SPLIT_EVENTS_MONITOR m,
  int *min_duration, int *max_duration, int *min_amount, int *max_amount);
}
sets the four last variables to the corresponding attributes of the
monitor's constraint.  Function
@ID @C {
void KheSplitEventsMonitorDebug(KHE_SPLIT_EVENTS_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
# @PP
# Since the state of splitting is assumed by @C { KheMonitorAttach Check }
# to be fixed, all it needs to do here is ensure that @C { m } is attached,
# then detach it if its cost is 0.  In this case there is no efficiency
# gain from detaching @C { m }, since @C { m } only fires when events are
# split and merged.
# @PP
# When a call to @C { KheMeetSplitFix } takes the solution from a state in
# which meet splitting is not fixed in at least one meet derived from an
# event @C { e } to a state in which meet splitting is fixed in every meet
# derived from @C { e }, every attached split events monitor which monitors
# @C { e } and has cost 0 is detached.  When a call to @C { KheMeetSplitUnFix }
# takes a solution between those same two states in the opposite direction,
# every unattached split events monitor which monitors @C { e } is attached.
# @PP
# A split events monitor has provably zero fixed cost when splitting is fixed
# in all the meets derived from the event it monitors, and its cost is 0 when
# attached.  @C { KheMeetSplitFix } and @C { KheMeetSplitUnFix } may detach
# and attach split events monitors.
@End @SubSection

@SubSection
    @Title { Distribute split events monitors }
@Begin
@LP
A distribute split events monitor has tag
@C { KHE_DISTRIBUTE_SPLIT_EVENTS_MONITOR_TAG } and monitors
one point of application of a distribute split events constraint
(one event).  Functions
@ID @C {
KHE_DISTRIBUTE_SPLIT_EVENTS_CONSTRAINT
  KheDistributeSplitEventsMonitorConstraint(
  KHE_DISTRIBUTE_SPLIT_EVENTS_MONITOR m);
KHE_EVENT KheDistributeSplitEventsMonitorEvent(
  KHE_DISTRIBUTE_SPLIT_EVENTS_MONITOR m);
}
return the constraint and event being monitored, and
@ID @C {
void KheDistributeEventsMonitorLimits(
  KHE_DISTRIBUTE_SPLIT_EVENTS_MONITOR m,
  int *duration, int *minimum, int *maximum, int *meet_count);
}
sets @C { *duration }, @C { *minimum }, and @C { *maximum } to
the corresponding attributes of the monitor's constraint, and
@C { *meet_count } to the number of meets derived from the
monitored event whose duration is @C { *duration } (or to the
total number of meets if @C { *duration } is @C { KHE_ANY_DURATION }).
Function
@ID @C {
void KheDistributeSplitEventsMonitorDebug(
  KHE_DISTRIBUTE_SPLIT_EVENTS_MONITOR m, int verbosity,
  int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
# @C { KheMonitorAttach Check } behaves like it does for split events
# monitors:  it first ensures that @C { m } is attached, then detaches
# it if its cost is 0.
# @PP
# A distribute split events monitor has provably zero fixed cost when
# splitting is fixed in all the meets derived from the event it
# monitors, and its cost is 0 when attached.  @C { KheMeetSplitFix }
# and @C { KheMeetSplitUnFix } may detach and attach distribute
# split events monitors.
@End @SubSection

@SubSection
    @Title { Assign time monitors }
@Begin
@LP
An assign time monitor has tag @C { KHE_ASSIGN_TIME_MONITOR_TAG }
and monitors an event which is one point of application of one
assign time constraint.  Functions
@ID @C {
KHE_ASSIGN_TIME_CONSTRAINT KheAssignTimeMonitorConstraint(
  KHE_ASSIGN_TIME_MONITOR m);
KHE_EVENT KheAssignTimeMonitorEvent(KHE_ASSIGN_TIME_MONITOR m);
}
return the assign time constraint and event being monitored.
Function
@ID @C {
void KheAssignTimeMonitorDebug(KHE_ASSIGN_TIME_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@PP
An assign time monitor does not have provably zero fixed cost when
@C { KheMeetAssignFix } has been called for each of the meets
derived from the event it monitors and the monitor has cost 0 when
attached, because the assignments may be to other meets whose
assignments are not fixed.  The full assignment paths leading
out of the monitored meets would need to be fixed;  but that
would be awkward to implement and give no efficiency payoff,
because then the monitor would never be updated anyway.  So
an assign time monitor never has provably zero cost.
@End @SubSection

@SubSection
    @Title { Prefer times monitors }
@Begin
@LP
A prefer times monitor has tag @C { KHE_PREFER_TIMES_MONITOR_TAG }
and monitors an event which is one point of application of one
prefer times constraint.  Functions
@ID @C {
KHE_PREFER_TIMES_CONSTRAINT KhePreferTimesMonitorConstraint(
  KHE_PREFER_TIMES_MONITOR m);
KHE_EVENT KhePreferTimesMonitorEvent(KHE_PREFER_TIMES_MONITOR m);
}
return the prefer times constraint and event being monitored.
Function
@ID @C {
void KhePreferTimesMonitorDebug(KHE_PREFER_TIMES_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
# @PP
# @C { KheMonitorAttach Check } examines the domains of the meets
# of @C { m }'s event whose durations are of interest to @C { m }'s
# constraint.  If all of these domains are subsets of @C { m }'s
# constraint's domain, then @C { m } may be detached.  A more refined
# check would use the domains of the meets' lea der meets, but
# complications with offsets have ruled that out, at least for now.
# @PP
# A prefer times monitor has provably zero fixed cost when, for each
# meet derived from the event it monitors, either that meet's splits are
# fixed and its duration is not one that the monitor monitors, or its
# domain is fixed to a subset of the set of times defined by the monitor's
# constraint.  @C { KheMeetSplitFix } and @C { KheMeetDomainFix } may
# detach prefer times monitors, and @C { KheMeetSplitUnFix } and
# @C { KheMeetDomainUnFix } may attach them.  There is a small efficiency
# payoff when the meets' assignments change within the domains.
@End @SubSection

@SubSection
    @Title { Spread events monitors }
@Begin
@LP
A spread events monitor has tag @C { KHE_SPREAD_EVENTS_MONITOR_TAG }
and monitors an event group which is one point of application of a
spread events constraint.  It appears in the list of monitors of
all the events in its event group.  Functions
@ID @C {
KHE_SPREAD_EVENTS_CONSTRAINT KheSpreadEventsMonitorConstraint(
  KHE_SPREAD_EVENTS_MONITOR m);
KHE_EVENT_GROUP KheSpreadEventsMonitorEventGroup(
  KHE_SPREAD_EVENTS_MONITOR m);
}
return the spread events constraint and event group being monitored.
There are also
@ID { 0.96 1.0 } @Scale @C {
int KheSpreadEventsMonitorTimeGroupCount(KHE_SPREAD_EVENTS_MONITOR m);
void KheSpreadEventsMonitorTimeGroup(KHE_SPREAD_EVENTS_MONITOR m, int i,
  KHE_TIME_GROUP *time_group, int *minimum, int *maximum, int *incidences);
}
The first returns the number of time groups (as in the corresponding
constraint).  The second returns the @C { i }'th time group and the
minimum and maximum number of meets wanted there (again,
as in the constraint), plus the current number of meets
incident on that time group.  If @C { *incidences } is less than
@C { *minimum } or more than @C { *maximum }, a cost is incurred.
Function
@ID @C {
void KheSpreadEventsMonitorDebug(KHE_SPREAD_EVENTS_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@End @SubSection

@SubSection
    @Title { Link events monitors }
@Begin
@LP
A link events monitor has tag @C { KHE_LINK_EVENTS_MONITOR_TAG }
and monitors an event group which is one point of application of
a link events constraint.  It appears in the list of monitors of
all the events in its event group.  Functions
@ID @C {
KHE_LINK_EVENTS_CONSTRAINT KheLinkEventsMonitorConstraint(
  KHE_LINK_EVENTS_MONITOR m);
KHE_EVENT_GROUP KheLinkEventsMonitorEventGroup(
  KHE_LINK_EVENTS_MONITOR m);
}
return the link events constraint and event group being monitored.
Function
@ID @C {
void KheLinkEventsMonitorDebug(KHE_LINK_EVENTS_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
# @PP
# @C { KheMonitorAttach Check } assumes that assignments of meets not
# lying in nodes will not change for a long time.  For each meet of each
# event monitored by @C { m } it forms a triple, consisting of the
# duration of the meet, its lead er meet as returned by @C { KheMeetLeader }
# (Section {@NumberOf solutions.meets.assignment}), and its offset
# into its lead er meet.  If any triple cannot be built because some
# meet has no lead er meet, then @C { m } should remain attached.
# Otherwise, if for each event @C { e } monitored by @C { m } the set
# of triples formed from the meets derived from @C { e } is the
# same, then @C { m } can be detached.
# @PP
# Detaching link events monitors is arguably the most important
# service provided by @C { KheMonitorAttach Check }.  This is
# because keeping these monitors up to date is slow, despite the
# author's best efforts to optimize.  When the times of a set of
# linked events change together, an attached link events monitor
# receives the changes one by one, forcing it through a tedious
# sequence of cost modifications beginning and ending with 0.
@PP
A link events monitor has provably zero fixed cost when following
to the end the chains of fixed assignments out of the meets of the
events it monitors produces the same result for each event:  the
same offsets and durations within the same final meets.
@C { KheMeetAssignFix } and @C { KheMeetAssignUnFix }
may detach and attach link events monitors.
@PP
Detaching link events monitors is the most important service provided
by fixing.  Keeping these monitors up to date is slow, despite the
author's best efforts to optimize.  When the times of a set of linked
events change together, an attached link events monitor receives the
changes one by one, forcing it through a tedious sequence of cost
changes beginning and ending with 0.
@End @SubSection

@SubSection
    @Title { Order events monitors }
@Begin
@LP
An order events monitor has tag @C { KHE_ORDER_EVENTS_MONITOR_TAG }
and monitors two events which together constitute one point of
application of an order events constraint.  It appears in the
list of monitors of both events.  Functions
@ID @C {
KHE_ORDER_EVENTS_CONSTRAINT KheOrderEventsMonitorConstraint(
  KHE_ORDER_EVENTS_MONITOR m);
KHE_EVENT KheOrderEventsMonitorFirstEvent(KHE_ORDER_EVENTS_MONITOR m);
KHE_EVENT KheOrderEventsMonitorSecondEvent(KHE_ORDER_EVENTS_MONITOR m);
int KheOrderEventsMonitorMinSeparation(KHE_ORDER_EVENTS_MONITOR m);
int KheOrderEventsMonitorMaxSeparation(KHE_ORDER_EVENTS_MONITOR m);
}
return the constraint being monitored and the four attributes of the
monitor:  the two events monitored, and the minimum and maximum separations.
Function
@ID @C {
void KheOrderEventsMonitorDebug(KHE_ORDER_EVENTS_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
# @PP
# @C { KheMonitorAttach Check } assumes that assignments of meets not
# lying in nodes will not change for a long time.  To carry out its
# work on an order events monitor, it checks whether both events
# contain exactly one meet, and if so whether those meets have the
# same lead er meet, as returned by @C { KheMeetLeader }
# (Section {@NumberOf solutions.meets.assignment}), and if so whether
# their separation (the offset into the lead er meet of the second meet,
# minus the duration plus offset into the lead er meet of the first meet)
# is in the legal range.  If so, then @C { m } can be detached,
# otherwise @C { m } should remain attached.
@PP
An order events monitor has provably zero fixed cost when both of its
events are broken into a single meet, following to the end the chains
of fixed assignments out of those two meets leads to the same final
meet, and their separation (the offset into the final meet of the
second meet, minus the duration plus offset into the final meet of
the first meet) is in the legal range.  @C { KheMeetAssignFix } and
@C { KheMeetAssignUnFix } may detach and attach order events monitors.
# Alternatively,
# the final meets may differ if they are both cycle meets; a
# different definition of separation is used then, the obvious one
# based on the index numbers of the times the meets are assigned to.
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Event resource monitors }
    @Tag { monitoring.event_resource_monitors }
@Begin
@LP
An @I { event resource monitor } monitors one or more event resources.
The monitors (attached or unattached) which monitor a given event
resource may be visited by
@ID {0.95 1.0} @Scale -1px @Break @C {
int KheSolnEventResourceMonitorCount(KHE_SOLN soln, KHE_EVENT_RESOURCE er);
KHE_MONITOR KheSolnEventResourceMonitor(KHE_SOLN soln,
  KHE_EVENT_RESOURCE er, int i);
}
The total cost of these monitors measures how well @C { er } is
timetabled.  Functions
@ID -1px @Break @C {
KHE_COST KheSolnEventResourceCost(KHE_SOLN soln, KHE_EVENT_RESOURCE er);
KHE_COST KheSolnEventResourceMonitorCost(KHE_SOLN soln,
  KHE_EVENT_RESOURCE er, KHE_MONITOR_TAG tag);
}
return the total cost of all the monitors monitoring @C { er }, and
the total cost of all monitors monitoring @C { er } of a specific
type, defined by @C { tag }.  @C { KheSolnEventResourceMonitorCost }
returns 0 when @C { tag } does not specify one of the monitor types
in the following subsections.
@PP
Each point of application of an avoid split assignments constraint is a
whole set of event resources, and a monitor of this kind is attached to each
of the event resources in its set.  If @C { KheSolnEventResourceCost(soln, er) }
is summed over all event resources, such a monitor is counted repeatedly,
so the total may exceed the total cost of all event resource monitors.
@PP
Different event resource monitors are affected by sweep times in
different ways.  The details are given below for each event resource type.
@PP
The following subsections list the various kinds of event resource
monitors and the details specific to each of them.  Their types
(@C { KHE_ASSIGN_RESOURCE_MONITOR } and so on) may be obtained by
downcasting from @C { KHE_MONITOR } after checking the type tag.
@BeginSubSections

@SubSection
    @Title { Assign resource monitors }
@Begin
@LP
An assign resource monitor has tag @C { KHE_ASSIGN_RESOURCE_MONITOR_TAG }
and monitors an event resource which is one point of application of
one assign resource constraint.  Functions
@ID -1px @Break @C {
KHE_ASSIGN_RESOURCE_CONSTRAINT KheAssignResourceMonitorConstraint(
  KHE_ASSIGN_RESOURCE_MONITOR m);
KHE_EVENT_RESOURCE KheAssignResourceMonitorEventResource(
  KHE_ASSIGN_RESOURCE_MONITOR m)
}
return the assign resource constraint and event resource being
monitored.  Like assign time monitors, assign resource monitors
are never considered to have provably zero fixed cost.
@PP
Assign resource monitors are affected by sweep times:  an unassigned
monitored task has a cost when it lies within the time sweep, but not
when it lies beyond it.  This is implemented at present by ensuring
that every assign resource monitor @C { m } is detached when it
monitors a task beyond the sweep time, and attached otherwise.  This
rough implementation is correct when there is one sweep time per day,
the time range of @C { m } lies within one day, and @C { m } is
attached initially.
@PP
Function
@ID @C {
void KheAssignResourceMonitorDebug(KHE_ASSIGN_RESOURCE_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@End @SubSection

@SubSection
    @Title { Prefer resources monitors }
    @Tag { monitoring.event_resource_monitors.prefer }
@Begin
@LP
A prefer resources monitor has tag @C { KHE_PREFER_RESOURCES_MONITOR_TAG }
and monitors an event resource which is one point of application of one
prefer resources constraint.  Functions
@ID -1px @Break @C {
KHE_PREFER_RESOURCES_CONSTRAINT KhePreferResourcesMonitorConstraint(
  KHE_PREFER_RESOURCES_MONITOR m);
KHE_EVENT_RESOURCE KhePreferResourcesMonitorEventResource(
  KHE_PREFER_RESOURCES_MONITOR m);
}
return the prefer resources constraint and event resource being
monitored.  Functions
@ID @C {
KHE_RESOURCE_GROUP KhePreferResourcesMonitorDomain(
  KHE_PREFER_RESOURCES_MONITOR m);
KHE_RESOURCE_GROUP KhePreferResourcesMonitorDomainComplement(
  KHE_PREFER_RESOURCES_MONITOR m);
}
return @C { m }'s domain and the complement of its domain in
its resource type.
@PP
As Section {@NumberOf matchings.redundancy} explains, some prefer
resources monitors do not have a corresponding constraint.  For
those monitors, @C { KhePreferResourcesMonitorConstraint } returns
@C { NULL }.  So @C { KhePreferResourcesMonitorDomain } and
@C { KhePreferResourcesMonitorDomainComplement } should be used to
find domains, since calling @C { KhePreferResourcesConstraintDomain }
and @C { KhePreferResourcesMonitorDomainComplement } will not work
when there is no constraint.
@PP
Prefer resources monitors are not affected by sweep times, because tasks
are assumed to be unassigned beyond the sweep time, yielding cost 0.  So,
when given a prefer resources monitor, @C { KheMonitorSetSweepTime }
does nothing and @C { KheMonitorSweepTimeRange } returns @C { false }.
@PP
Function
@ID @C {
void KhePreferResourcesMonitorDebug(KHE_PREFER_RESOURCES_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
# @PP
# For each task monitored by @C { m }, @C { KheMonitorAttach Check } follows
# the chain of assignments leading out of that task to the lead er task.
# These assignments, and the domain of the lead er task, are assumed to be
# unchanging.  If all the lead ers' domains are subsets of the domain of
# @C { m }'s constraint, then no assignments to lead er tasks can violate
# @C { m }, and @C { KheMonitorAttach Check } ensures that @C { m } is
# detached.  Otherwise it ensures that @C { m } is attached.
# @PP
# A prefer resources monitor has provably zero fixed cost when resource
# domains are fixed in the tasks derived from its event resource, to
# subsets of the set of resources of its constraint.
# @C { KheTaskDomainFix } and @C { KheTaskDomainUnFix } may detach and
# attach prefer resources monitors.  There is a small efficiency payoff
# when the tasks' assignments change within the domains.
@End @SubSection

@SubSection
    @Title { Avoid split assignments monitors }
@Begin
@LP
The operations for building avoid split assignments constraints accept
a role and event groups, as required when reading XML.  However, they
also accept a set of event resources, and these are what are actually
used.  Accordingly, one avoid split assignments monitor monitors a
set of event resources, and appears in the list of monitors of each
of those event resources.  Functions
@ID -1.0px @Break @C {
KHE_AVOID_SPLIT_ASSIGNMENTS_CONSTRAINT
  KheAvoidSplitAssignmentsMonitorConstraint(
  KHE_AVOID_SPLIT_ASSIGNMENTS_MONITOR m)
int KheAvoidSplitAssignmentsMonitorEventGroupIndex(
  KHE_AVOID_SPLIT_ASSIGNMENTS_MONITOR m)
}
return the constraint and the index of the set of event resources
being monitored, suitable for passing to functions
@C { KheAvoidSplitAssignmentsConstraintEventResourceCount }
and @C { KheAvoidSplitAssignmentsConstraintEventResource }
(Section {@NumberOf avoid_split_assts}).  There are also
@ID @C {
int KheAvoidSplitAssignmentsMonitorResourceCount(
  KHE_AVOID_SPLIT_ASSIGNMENTS_MONITOR m);
KHE_RESOURCE KheAvoidSplitAssignmentsMonitorResource(
  KHE_AVOID_SPLIT_ASSIGNMENTS_MONITOR m, int i);
int KheAvoidSplitAssignmentsMonitorResourceMultiplicity(
  KHE_AVOID_SPLIT_ASSIGNMENTS_MONITOR m, int i);
}
The first returns the number of distinct resources currently assigned
to tasks monitored by @C { m }.  If @C { m } is a defect this number
will be at least 2.  The second and third return the @C { i }th of
these distinct resources (in an arbitrary order) and the number of
tasks monitored by @C { m } to which that resource is currently
assigned.  The monitor does not record which tasks those are.
@PP
Avoid split assignments monitors are not affected by sweep times, because
tasks are assumed to be unassigned beyond the sweep time, and avoid
split assignments monitors take no notice of unassigned tasks.  So, when
given an avoid split assignments monitor, @C { KheMonitorSetSweepTime }
does nothing and @C { KheMonitorSweepTimeRange } returns @C { false }.
@PP
Function
@ID @C {
void KheAvoidSplitAssignmentsMonitorDebug(
  KHE_AVOID_SPLIT_ASSIGNMENTS_MONITOR m, int verbosity,
  int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
# @PP
# For each task monitored by @C { m }, @C { KheMonitorAssignCheck }
# follows the chain of assignments from the task to its lead er task.
# These chains are assumed to be unchanging.  If they all end at the
# same lead er task, then no assignments can violate @C { m }, and
# @C { KheMonitorAssignCheck } ensures that @C { m } is detached.
# Otherwise it ensures that @C { m } is attached.
@PP
An avoid split assignments monitor has provably zero fixed cost when the
paths of fixed assignments leading out of the tasks it monitors have the
same endpoint.  @C { KheTaskAssignFix } and @C { KheTaskAssignUnFix }
may detach and attach avoid split assignments monitors.  Similarly to
link events monitors, the efficiency payoff is significant.
@End @SubSection

@SubSection
    @Title { Limit resources monitors }
@Begin
@LP
The operations for building limit resources constraints accept
event groups and roles, as needed when reading XML.  However,
what one limit resources monitor actually monitors is a set of
event resources, and it appears in the lists of monitors of
those event resources.  Functions
@ID -1.0px @Break @C {
KHE_LIMIT_RESOURCES_CONSTRAINT KheLimitResourcesMonitorConstraint(
  KHE_LIMIT_RESOURCES_MONITOR m);
int KheLimitResourcesMonitorEventGroupIndex(
  KHE_LIMIT_RESOURCES_MONITOR m);
}
return the constraint, and the index within it of the set of event
resources being monitored, suitable for passing to functions
@C { KheLimitResourcesConstraintEventResourceCount }
and @C { KheLimitResourcesConstraintEventResource }
(Section {@NumberOf constraints.limitresources}).  These allow
the user to visit the monitored event resources, and thence,
using @C { KheEventResourceTaskCount } and
@C { KheEventResourceTask }, the monitored tasks.  There is also
@ID {0.98 1.0} @Scale @C {
void KheLimitResourcesMonitorActiveDuration(KHE_LIMIT_RESOURCES_MONITOR m,
  int *minimum, int *maximum, int *active_durn);
}
It returns @C { m }'s minimum limit (taken from the constraint;
it will be 0 when there is no minimum limit), its maximum limit
(also from the constraint; it will be @C { INT_MAX } when
there is no maximum limit), and the @I { active duration }, which
is the total duration of the tasks derived from the event resources
being monitored which are assigned resources from the constraint.
The deviation is the amount (if any) by which @C { *active_durn }
exceeds @C { *maximum } or falls short of @C { *minimum }.
@PP
Limit resources monitors are affected by sweep times.  As for
assign resources monitors, this is implemented in a rough way
at present by ensuring that every limit resources monitor @C { m }
is detached when it monitors a task beyond the sweep time, and
attached otherwise.
@PP
Function
@ID @C {
void KheLimitResourcesMonitorDebug(KHE_LIMIT_RESOURCES_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Resource monitors }
    @Tag { monitoring.resource_monitors }
@Begin
@LP
A @I { resource monitor } monitors a resource.  The set of monitors
(attached or unattached) which monitor a given resource may be
visited by calling
@ID {0.95 1.0} @Scale @C {
int KheSolnResourceMonitorCount(KHE_SOLN soln, KHE_RESOURCE r);
KHE_MONITOR KheSolnResourceMonitor(KHE_SOLN soln, KHE_RESOURCE r, int i);
}
The order is arbitrary and may be changed by calling
@ID @C {
void KheSolnResourceMonitorSort(KHE_SOLN soln, KHE_RESOURCE r,
  int(*compar)(const void *, const void *));
}
to sort the monitors into increasing order of @C { compar }.
@PP
The total cost of these monitors measures how well @C { r } is
timetabled.  Functions
@ID @C {
KHE_COST KheSolnResourceCost(KHE_SOLN soln, KHE_RESOURCE r);
KHE_COST KheSolnResourceMonitorCost(KHE_SOLN soln, KHE_RESOURCE r,
  KHE_MONITOR_TAG tag);
}
return the total cost of all the monitors monitoring @C { r }, and
the total cost of all monitors monitoring @C { r } of a specific
type, defined by @C { tag }.  @C { KheSolnResourceMonitorCost } returns
0 when @C { tag } does not specify one of the monitor types in the
following subsections.
@PP
Generally speaking, resource monitors are affected by sweep times.
(The exceptions are avoid clashes and avoid unavailable times monitors,
for which the usual assumption that tasks are unassigned beyond the
sweep time implies cost 0.)  The implementations have been done with
care, and almost always yield the best possible lower bound on true cost.
@PP
The following subsections list the kinds of resource monitors
and their features.  Their types (@C { KHE_AVOID_CLASHES_MONITOR }
etc.) may be obtained by
downcasting from @C { KHE_MONITOR } after checking the type tag.
Monitors of type @C { KHE_WORKLOAD_DEMAND_MONITOR }, defined in
Section {@NumberOf matchings.demand}, are also visited by
@C { KheSolnResourceMonitorCount } and @C { KheSolnResourceMonitor }.
However, the timetable monitor for a resource is not visited by these
functions; as explained in Section {@NumberOf monitoring_timetables},
it is retrieved by calling @C { KheResourceTimetableMonitor }.
@BeginSubSections

@SubSection
    @Title { Avoid clashes monitors }
@Begin
@LP
An avoid clashes monitor has tag @C { KHE_AVOID_CLASHES_MONITOR_TAG }
and monitors a resource which is one point of application of one
avoid clashes constraint.  Functions
@ID -1.0px @Break @C {
KHE_AVOID_CLASHES_CONSTRAINT KheAvoidClashesMonitorConstraint(
  KHE_AVOID_CLASHES_MONITOR m);
KHE_RESOURCE KheAvoidClashesMonitorResource(
  KHE_AVOID_CLASHES_MONITOR m);
}
return the avoid clashes constraint and resource being monitored.
Function
@ID @C {
void KheAvoidClashesMonitorDebug(KHE_AVOID_CLASHES_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@PP
An avoid clashes monitor @C { m } may have non-zero
@C { KheMonitorLowerBound(m) }.  Let @M { t } be the total duration
of the events to which @C { m }'s resource is preassigned which either
have preassigned times or are subject to an assign time constraint
of weight greater than @C { m }'s weight.  Then if @M { t } exceeds
the number of times in the cycle, the excess is a lower bound on the
number of defects that @C { m } must have in any reasonable solution
(one in which violations of @C { m } are preferred to violations of
the more expensive assign time constraints).  Converting this number
of defects into a cost using @C { m }'s cost function in the usual
way gives the lower bound.
@End @SubSection

@SubSection
    @Title { Avoid unavailable times monitors }
@Begin
@LP
#An avoid unavailable times monitor has tag
This monitor has tag
@C { KHE_AVOID_UNAVAILABLE_TIMES_MONITOR_TAG } and monitors a resource
which is one point of application of one avoid unavailable times
constraint.  Functions
@ID -1px @Break @C {
KHE_AVOID_UNAVAILABLE_TIMES_CONSTRAINT
  KheAvoidUnavailableTimesMonitorConstraint(
  KHE_AVOID_UNAVAILABLE_TIMES_MONITOR m);
KHE_RESOURCE KheAvoidUnavailableTimesMonitorResource(
  KHE_AVOID_UNAVAILABLE_TIMES_MONITOR m);
}
return the avoid unavailable times constraint and resource being monitored.
Function
@ID @C {
void KheAvoidUnavailableTimesMonitorDebug(
  KHE_AVOID_UNAVAILABLE_TIMES_MONITOR m, int verbosity,
  int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@PP
An avoid unavailable times monitor @C { m } may have non-zero
@C { KheMonitorLowerBound(m) }.  Suppose @C { m }'s resource is
subject to an avoid clashes constraint of weight greater than
@C { m }'s weight.  Let @M { t sub 1 } be the total duration of
the events to which @C { m }'s resource is preassigned which either
have preassigned times or are subject to an assign time constraint
of weight greater than @C { m }'s weight.  Let @M { t sub 2 } be
the number of times to be avoided according to @C { m }.  Then if
@M { t sub 1 + t sub 2 } exceeds the number of times in the cycle,
the excess is a lower bound on the number of defects that @C { m }
must have in any reasonable solution (one in which every meet is
assigned a time, and violations of @C { m } are preferred to violations
of the more expensive assign time and avoid clashes constraints).
Converting this number of defects into a cost using @C { m }'s cost
function in the usual way gives the lower bound.
@End @SubSection

@SubSection
    @Title { Limit idle times monitors }
@Begin
@LP
A limit idle times monitor has tag @C { KHE_LIMIT_IDLE_TIMES_MONITOR_TAG }
and monitors a resource which is one point of application of one limit
idle times constraint.  Functions
@ID -1px @Break @C {
KHE_LIMIT_IDLE_TIMES_CONSTRAINT KheLimitIdleTimesMonitorConstraint(
  KHE_LIMIT_IDLE_TIMES_MONITOR m);
KHE_RESOURCE KheLimitIdleTimesMonitorResource(
  KHE_LIMIT_IDLE_TIMES_MONITOR m);
}
return the limit idle times constraint and resource being monitored, and
@ID @C {
int KheLimitIdleTimesMonitorTimeGroupCount(
  KHE_LIMIT_IDLE_TIMES_MONITOR m);
KHE_TIME_GROUP KheLimitIdleTimesMonitorTimeGroup(
  KHE_LIMIT_IDLE_TIMES_MONITOR m, int i);
}
visit the time groups that @C { m } monitors, that is, the time groups
from the constraint.  There is also
@ID {0.97 1.0} @Scale @C {
KHE_TIME_GROUP KheLimitIdleTimesMonitorTimeGroupState(
  KHE_LIMIT_IDLE_TIMES_MONITOR m, int i, int *busy_count, int *idle_count,
  KHE_TIME extreme_busy_times[2], int *extreme_busy_times_count);
}
which, in addition to returning the @C { i }th time group, also
reports its state, by setting @C { *busy_count } to its
number of busy times, @C { *idle_count } to its number of idle
times, and placing its first and last busy times into
@C { extreme_busy_times[0 .. *extreme_busy_times_count - 1] }.
If there are no busy times, @C { *extreme_busy_times_count } is 0;
if there is one it is 1; otherwise it is 2.
Function
@ID @C {
void KheLimitIdleTimesMonitorDebug(KHE_LIMIT_IDLE_TIMES_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@End @SubSection

@SubSection
    @Title { Cluster busy times monitors }
    @Tag { monitoring.clusterbusy }
@Begin
@LP
A cluster busy times monitor (tag @C { KHE_CLUSTER_BUSY_TIMES_MONITOR_TAG })
monitors a resource and offset making one point of application of
a cluster busy times constraint.  Functions
@ID -1px @Break @C {
KHE_CLUSTER_BUSY_TIMES_CONSTRAINT KheClusterBusyTimesMonitorConstraint(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
KHE_RESOURCE KheClusterBusyTimesMonitorResource(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
}
return the cluster busy times constraint and the resource being
monitored.  Functions
@ID -1px @Break @C {
int KheClusterBusyTimesMonitorHistoryBefore(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
int KheClusterBusyTimesMonitorHistoryAfter(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
int KheClusterBusyTimesMonitorHistory(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
}
return the history before, history after, and history values from
@C { m }'s constraint, or 0 if not present.  In the high school
model, these are always 0.  Function
# , and
# @ID @C {
# int KheClusterBusyTimesMonitorHistoryDeviation(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m);
# }
# returns the deviation from the previous instance, based on these
# history values.  In the high school model, all three values are
# always 0.  Function
@ID @C {
int KheClusterBusyTimesMonitorOffset(KHE_CLUSTER_BUSY_TIMES_MONITOR m);
}
returns the offset being monitored.  In the high school model, and when the
constraint has @C { NULL } for @C { applies_to_tg }, the offset is always
0, otherwise the offset is the difference in index between one useful
time in @C { applies_to_tg } and the first time in @C { applies_to_tg }. 
Functions
@ID @C {
int KheClusterBusyTimesMonitorTimeGroupCount(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
KHE_TIME_GROUP KheClusterBusyTimesMonitorTimeGroup(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m, int i, KHE_POLARITY *po);
}
return the time groups that @C { m } monitors (one for each time group
in the cluster busy times constraint, adjusted using
@C { KheTimeGroupNeighbour } by the offset), and their associated
polarities.
# @PP
# A rough idea of the times monitored by @C { m } is given by function
# @ID @C {
# void KheClusterBusyTimesMonitorRange(KHE_CLUSTER_BUSY_TIMES_MONITOR m,
#   KHE_TIME *first_time, KHE_TIME *last_time);
# }
# It sets @C { *first_time } and @C { *last_time } to the first and
# last times monitored by @C { m }.  In the unlikely event that @C { m }
# monitors no times at all, they will be set to @C { NULL }.  These
# values are calculated the first time that the function is called, and
# cached in @C { m }, so that subsequent calls take almost no time.
@PP
Two functions report the current state of the monitor, as it varies
during the solve.  Function
@ID @C {
void KheClusterBusyTimesMonitorActiveTimeGroupCount(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m, int *active_group_count,
  *open_group_count, int *minimum, int *maximum, bool *allow_zero);
}
sets @C { *active_group_count } to the number of active time groups
(busy positive time groups plus non-busy negative time groups),
@C { *open_group_count } to the number of time groups not known
to be either active or inactive (because @C { history_after } is
non-zero, or because there is a non-trivial sweep time), and
@C { *minimum }, @C { *maximum }, and @C { *allow_zero } to the values
from the constraint.  If @C { m } has non-zero cost, then either
@C { *active_group_count + *open_group_count < *minimum }
or @C { *active_group_count > *maximum }.  Function
@ID @C {
bool KheClusterBusyTimesMonitorTimeGroupIsActive(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m, int i, KHE_TIME_GROUP *tg,
  KHE_POLARITY *po, int *busy_count);
}
returns @C { true } when the time group at index @C { i } is currently
active.  It also sets @C { *tg } and @C { *po } to the time group and
polarity at index @C { i }, and @C { *busy_count } to the number of
busy times in the time group.  It returns @C { true } when @C { *tg }
is active, that is, when
@ID @C {
(*po == KHE_NEGATIVE) == (*busy_count == 0)
}
as the definition of the constraint specifies.
@PP
There may be value in obtaining advance warning that a constraint
is close to being violated.  For that there is function
@ID @C {
int KheClusterBusyTimesMonitorAtMaxLimitCount(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
}
It returns 1 if the monitor is not detecting a violation but the
number of active time groups equals the maximum limit, and 0
otherwise.  It returns an integer rather than a boolean for
consistency with @C { KheLimitActiveIntervalsMonitorAtMaxLimitCount }.
# @PP
# Cluster busy times monitors have their own sweep time functions:
# @ID @C {
# void KheClusterBusyTimesMonitorSetSweepTime(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m, KHE_TIME t);
# bool KheClusterBusyTimesMonitorSweepTimeRange(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m,
#   KHE_TIME *first_time, KHE_TIME *last_time);
# }
# These do what @C { KheMonitorSetSweepTime } and
# @C { KheMonitorSweepTimeRange }
# (Section {@NumberOf monitoring.sweep_times}) do, but for cluster busy
# times monitors.  The monitor understands that time groups with times
# equal to or beyond the sweep time are beyond the scope of the current
# solve.  This does not affect busy time groups, which are considered to
# be active or inactive as usual (depending on their polarity), but it
# does affect non-busy ones, which are considered to be in an @I open
# state, that is, not known to be either active or inactive.  The monitor
# considers an open time group to be active when comparing with a minimum
# limit, and inactive when comparing with a maximum limit.  Either way,
# this makes a violation less likely.
# For the benefit of time sweep algorithms, which may perform better
# if cluster busy times monitors understand that there is no point in
# complaining about problems beyond the point that the time sweep has
# reached, there are functions
# @ID @C {
# void KheClusterBusyTimesMonitorSetSweepIndex(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m, int sweep_index);
# int KheClusterBusyTimesMonitorSweepIndex(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m);
# }
# These functions set and retrieve the monitor's @I { sweep index },
# an integer between 0 and @C { KheClusterBusyTimesMonitorTimeGroupCount }
# inclusive, whose effect is explained below.  If no sweep index has
# been set, @C { KheClusterBusyTimesMonitorSweepIndex(m) } returns
# @C { KheClusterBusyTimesMonitorTimeGroupCount(m) }.  This value
# cuts off nothing, and should be passed when the aim is to remove
# a previously set sweep index.
# #@PP
# #When there is a sweep index, the monitor ignores time groups whose
# #indexes are equal to or larger than the sweep index.  It is just as
# #though they were never added to the monitor's constraint (even
# #@C { KheClusterBusyTimesMonitorTimeGroupCount } changes), except
# #that the number of ignored time groups is added to
# #@C { KheClusterBusyTimesMonitorHistoryAfter(m) }.
# @PP
# In practice it will often be easier to call this function:
# @ID @C {
# void KheClusterBusyTimesMonitorSetSweepTime(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m, KHE_TIME sweep_time);
# }
# It works out the appropriate sweep index for ignoring all time
# groups that contain any time later than @C { sweep_time }, and calls
# @C { KheClusterBusyTimesMonitorSetSweepIndex } with that sweep
# index.  Passing @C { NULL } for @C { sweep_time } removes any
# sweep index.
# @PP
# @C { KheClusterBusyTimesMonitorSetSweepTime } examines @C { m }'s time
# groups from first to last, stopping at the first time group that contains
# a time whose index exceeds the index of @C { sweep_time }.  The index of
# that time group is the sweep index; or if there is no such time group, the
# sweep index is @C { KheClusterBusyTimesMonitorTimeGroupCount(m) }.  The
# function runs much faster than just described when the sweep times are
# increasing, as they usually are.
# @PP
# This procedure may seem dubious, given that there is no requirement for
# the time groups of @C { m }'s constraint to be added in chronological
# order.  However, cluster busy times monitors sort their time groups
# into increasing order of the maximum time index in each group.
# @PP
# @C { KheClusterBusyTimesMonitorSetSweepIndex } returns @C { true }
# when a non-zero number of time groups is being cut off.
# @C { KheClusterBusyTimesMonitorSetSweepTime } does the same.
# For example, passing @C { NULL } for @C { sweep_time } always returns
# value @C { false }.  But other sweep times also return @C { false },
# when they come after the last time in the last time group.
# @PP
# The general idea is that if a solve is attempting to assign times
# only up to a certain point in the cycle, then a sweep index should
# be set to inform the monitor that there is no point in complaining
# about things at or beyond that point.  This improves the value of
# the monitor as an influencer of the solve actually under way.
# @PP
# For the record, however, we need to be specific about the effect
# of a sweep index.  The monitor understands that time groups whose
# indexes are equal to or larger than the sweep index are beyond
# the scope of the current solve.  This does not affect busy time
# groups, which are considered to be active or inactive as usual
# (depending on their polarity), but it does affect non-busy ones,
# which are considered to be in an @I open state, that is, not known to
# be either active or inactive.  The monitor then acts conservatively:
# it considers an open time group to be active when comparing
# with a minimum limit, and inactive when comparing with a maximum
# limit.  Either way, this makes a violation less likely.
# @PP
# There is also
# @ID @C {
# KHE_TIME KheClusterBusyTimesMonitorInitialSweepTime(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
# }
# This returns the smallest time @C { t } such that cutting off at
# @C { t } is not the same as cutting off at index 0, or @C { NULL }
# if there is no such time.
# @PP
# Suppose the aim is to successively cut @C { m } off at @C { t1 },
# @C { t2 }, and so on to @C { tn }, the last time.  Let
# @C { ti = KheClusterBusyTimesMonitorInitialSweepTime(m) },
# and let @C { tj } be the first time such that
# @C { KheClusterBusyTimesMonitorSetSweepTime(m, tj) }
# returns @C { false }.  Then the only calls to set sweeps
# that actually need to be made are
# @ID @C {
# KheClusterBusyTimesMonitorSetSweepIndex(m, 0);
# KheClusterBusyTimesMonitorSetSweepTime(m, ti);
# ...
# KheClusterBusyTimesMonitorSetSweepTime(m, tj);
# }
# Calls between @C { t1 } and @C { ti-1 } change nothing, and calls
# after @C { tj } also change nothing.  If there is no @C { ti },
# then cutting off at index 0 is all that is needed.
@PP
There is a peculiar but apparently unavoidable asymmetry in the handling
of cluster time groups at or after the sweep time:  if they are busy they
have a definite state, either active or inactive, but if they are not busy
they are open.  This can be mitigated by calling
@ID @C {
void KheClusterBusyTimesMonitorSetNotBusyState(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m, int i, bool active);
}
where @C { i } is the index of one of @C { m }'s time groups, call it
@C { tg }.  This informs @C { m } that when @C { tg } is at or after
the sweep time and is not busy, it should be considered either active
or inactive (depending on the @C { active } parameter) rather than
open.  No other cases are affected.  There are no restrictions on
when this function can be called, relative to setting sweep times
or anything else.  It may change the cost of @C { m }.  Function
@ID @C {
void KheClusterBusyTimesMonitorClearNotBusyState(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m, int i);
}
returns @C { tg } to its default state.  (In practice, there is no
reason to call this function, because as the sweep time increases
these effects become irrelevant anyway.)
#@PP
#The frame (Section {@NumberOf extras.frames}) corresponding
#to @C { m } is returned by
#@ID @C { 
#KHE_FRAME KheClusterBusyTimesMonitorFrame(
#  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
#}
#This frame is constructed the first time
#@C { KheClusterBusyTimesMonitorFrame } is called on @C { m }, cached
#in @C { m }, and returned on the first and all subsequent calls.
# @PP
# As an experiment, each cluster busy times monitor contains a
# @I { multiplier }, a non-negative integer whose default value is 1.
# Each monitor's cost (including any history adjustment) is multiplied
# by its multiplier.  By passing a large @C { val }, the user can
# artificially inflate the importance of @C { m }'s constraint.  The
# weight of that constraint is unaffected.
# @PP
# The user can set and retrieve the multiplier by calling
# @ID @C {
# void KheClusterBusyTimesMonitorSetMultiplier(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m, int val);
# int KheClusterBusyTimesMonitorMultiplier(
#   KHE_CLUSTER_BUSY_TIMES_MONITOR m);
# }
# The multiplier can be safely changed at any time.  If the monitor has
# non-zero cost when the multiplier is changed, the solution cost will
# change immediately.
# @PP
# To reset the multiplier to 1, another call to
# @C { KheClusterBusyTimesMonitorSetMultiplier } can be made, or
# @C { KheSolnEnsureOfficialCost } (Section {@NumberOf monitoring.attach})
# can be called; it resets all multipliers to 1.  This ensures that the
# correct solution cost is reported in the end.
@PP
The user can set the monitor's minimum limit:
@ID @C {
int KheClusterBusyTimesMonitorMaximum(KHE_CLUSTER_BUSY_TIMES_MONITOR m);
int KheClusterBusyTimesMonitorMinimum(KHE_CLUSTER_BUSY_TIMES_MONITOR m);
bool KheClusterBusyTimesMonitorSetMinimum(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m, int val);
void KheClusterBusyTimesMonitorResetMinimum(
  KHE_CLUSTER_BUSY_TIMES_MONITOR m);
}
@C { KheClusterBusyTimesMonitorMaximum } returns
@C { m }'s maximum limit.  This is always equal to the maximum
limit of @C { m }'s constraint.
@C { KheClusterBusyTimesMonitorMinimum } returns the current value
of @C { m }'s minimum limit.  Its default value is the minimum
limit stored unchangeably in @C { m }'s constraint.  But
@C { KheClusterBusyTimesMonitorSetMinimum } can be called at
any time to change the monitor's minimum limit.  If the monitor is
attached when this is done, the solution cost may change immediately.
@C { KheClusterBusyTimesMonitorResetMinimum } resets the minimum
limit to the value stored in the constraint.  Alternatively,
@C { KheSolnEnsureOfficialCost } (Section {@NumberOf monitoring.attach})
can be called; it resets the minimums of all monitors to their original
values.
@PP
Finally, function
@ID @C {
void KheClusterBusyTimesMonitorDebug(KHE_CLUSTER_BUSY_TIMES_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@End @SubSection

@SubSection
    @Title { Limit busy times monitors }
    @Tag { monitoring.limitbusy }
@Begin
@LP
A limit busy times monitor (tag @C { KHE_LIMIT_BUSY_TIMES_MONITOR_TAG })
monitors a resource and offset which make up one point of application
of a limit busy times constraint.  Functions
@ID @C {
KHE_LIMIT_BUSY_TIMES_CONSTRAINT KheLimitBusyTimesMonitorConstraint(
  KHE_LIMIT_BUSY_TIMES_MONITOR m);
KHE_RESOURCE KheLimitBusyTimesMonitorResource(
  KHE_LIMIT_BUSY_TIMES_MONITOR m);
int KheLimitBusyTimesMonitorOffset(KHE_LIMIT_BUSY_TIMES_MONITOR m);
}
return the limit busy times constraint and the resource and offset
being monitored.  In the high school model, and when the constraint
has @C { NULL } for @C { applies_to_tg }, the offset is always 0,
otherwise the offset is the difference in index between one useful
time in @C { applies_to_tg } and the first time in @C { applies_to_tg }. 
@PP
The monitored time groups (after applying the offset) are returned by
@ID @C {
int KheLimitBusyTimesMonitorTimeGroupCount(
  KHE_LIMIT_BUSY_TIMES_MONITOR m);
KHE_TIME_GROUP KheLimitBusyTimesMonitorTimeGroup(
  KHE_LIMIT_BUSY_TIMES_MONITOR m, int i, int *busy_count);
}
with @C { *busy_count } set to the number of busy times in the
time group.  The time groups are those of the constraint, adjusted 
using @C { KheTimeGroupNeighbour } by the offset.
# A rough idea of the times monitored by @C { m } is
# given by function
# @ID @C {
# void KheLimitBusyTimesMonitorRange(KHE_LIMIT_BUSY_TIMES_MONITOR m,
#   KHE_TIME *first_time, KHE_TIME *last_time);
# }
# It sets @C { *first_time } and @C { *last_time } to the first and
# last times monitored by @C { m }.  In the unlikely event that @C { m }
# monitors no times at all, they will be set to @C { NULL }.  These
# values are calculated the first time that the function is called, and
# cached in @C { m }, so that subsequent calls take almost no time.
@PP
Functions
@ID @C {
int KheLimitBusyTimesMonitorDefectiveTimeGroupCount(
  KHE_LIMIT_BUSY_TIMES_MONITOR m);
void KheLimitBusyTimesMonitorDefectiveTimeGroup(
  KHE_LIMIT_BUSY_TIMES_MONITOR m, int i, KHE_TIME_GROUP *tg,
  int *busy_count, int *open_count, int *minimum, int *maximum,
  bool *allow_zero);
}
visit the time groups monitored by @C { m } that are currently
defective.  The order in which they appear depends on their
times.  This means that if a time group changes from defective
to non-defective then back to defective, it reappears in its
previous position in the list.  Without this, a traversal of
the list trying to remove each defective time group in turn
would not work properly.
@PP
For each @C { i }, @C { *tg } is set to one defective time
group, @C { *busy_count } is set to the number of times @C { m }'s
resource is busy during @C { *tg }, @C { *open_count } is set to the
number of open times in @C { *tg } (determined by the sweep time),
and @C { *minimum }, @C { *maximum }, and @C { *allow_zero } come
from the constraint.  So either the resource is overloaded during
@C { *tg } and @C { *busy_count > *maximum }, or it is underloaded
during @C { *tg } and @C { *busy_count + *open_count < *minimum }.  Also,
@ID @C {
int KheLimitBusyTimesMonitorDeviation(KHE_LIMIT_BUSY_TIMES_MONITOR m);
}
returns the deviation.
@PP
Limit busy times monitors contain a @C { ceiling } attribute,
set and retrieved by
@ID @C {
void KheLimitBusyTimesMonitorSetCeiling(KHE_LIMIT_BUSY_TIMES_MONITOR m,
  int ceiling);
int KheLimitBusyTimesMonitorCeiling(KHE_LIMIT_BUSY_TIMES_MONITOR m);
}
When @C { busy_count > ceiling }, the usual formula is overridden:
the deviation is 0.  For why this might be useful, consult
Section {@NumberOf general_solvers.matchings.double}.  The default value
of @C { ceiling } is @C { INT_MAX }, which effectively turns it off.
If @C { m } is attached when @C { KheLimitBusyTimesMonitorSetCeiling }
is called, it will be detached and reattached by the call.
# @PP
# Limit busy times monitors have their own sweep time functions:
# @ID @C {
# void KheLimitBusyTimesMonitorSetSweepTime(
#   KHE_LIMIT_BUSY_TIMES_MONITOR m, KHE_TIME t);
# bool KheLimitBusyTimesMonitorSweepTimeRange(
#   KHE_LIMIT_BUSY_TIMES_MONITOR m,
#   KHE_TIME *first_time, KHE_TIME *last_time);
# }
# These do what @C { KheMonitorSetSweepTime } and
# @C { KheMonitorSweepTimeRange }
# (Section {@NumberOf monitoring.sweep_times}) do, but for limit busy
# times monitors.
@PP
Function
@ID @C {
void KheLimitBusyTimesMonitorDebug(KHE_LIMIT_BUSY_TIMES_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@PP
A limit busy times monitor @C { m } may have non-zero
@C { KheMonitorLowerBound(m) }.  Suppose @C { m }'s resource is
subject to an avoid clashes constraint of weight greater than
@C { m }'s weight.  Let @M { t sub 1 } be the total duration of
the events to which @C { m }'s resource is preassigned which either
have preassigned times or are subject to an assign time constraint
of weight greater than @C { m }'s weight.  Let @M { t sub 2 } be the
number of times in the cycle minus the number of times in @C { m }'s
constraint's domain.  Then at least @M { t sub 1 - t sub 2 } of the
times of the events preassigned to @C { m }'s resource must occur in
time groups limited by @C { m }.  If this exceeds the number of time
groups in @C { m }'s constraint times its @C { Maximum }, then the
excess, converted into a cost in the usual way, gives the lower bound.
Monitors are only created for offsets applicable to all times in the
constraint, so this lower bound is the same for all offsets.
@End @SubSection

@SubSection
    @Title { Limit workload monitors }
    @Tag { monitoring_resource_monitors_workload }
@Begin
@LP
A limit workload monitor has tag @C { KHE_LIMIT_WORKLOAD_MONITOR }
and monitors a resource which is one point of application of one
limit workload constraint.  Functions
@ID @C {
KHE_LIMIT_WORKLOAD_CONSTRAINT KheLimitWorkloadMonitorConstraint(
  KHE_LIMIT_WORKLOAD_MONITOR m);
KHE_RESOURCE KheLimitWorkloadMonitorResource(
  KHE_LIMIT_WORKLOAD_MONITOR m);
int KheLimitWorkloadMonitorOffset(KHE_LIMIT_WORKLOAD_MONITOR m);
}
# float KheLimitWorkloadMonitorWorkload(KHE_LIMIT_WORKLOAD_MONITOR m);
return the limit workload constraint and the resource and offset
being monitored.  In the high school model, and when the constraint
has @C { NULL } for @C { applies_to_tg }, the offset is always 0,
otherwise the offset is the difference in index between one useful
time in @C { applies_to_tg } and the first time in @C { applies_to_tg }.
@PP
The monitored time groups (after applying the offset) are returned by
@ID @C {
int KheLimitWorkloadMonitorTimeGroupCount(
  KHE_LIMIT_WORKLOAD_MONITOR m);
KHE_TIME_GROUP KheLimitWorkloadMonitorTimeGroup(
  KHE_LIMIT_WORKLOAD_MONITOR m, int i, float *workload);
}
with @C { *workload } set to the current workload of the @C { i }th
time group.  The time groups are from the constraint, adjusted
using @C { KheTimeGroupNeighbour } by the offset.
# A rough idea of the times monitored by @C { m } is given
# by function
# @ID @C {
# void KheLimitWorkloadMonitorRange(KHE_LIMIT_WORKLOAD_MONITOR m,
#   KHE_TIME *first_time, KHE_TIME *last_time);
# }
# It sets @C { *first_time } and @C { *last_time } to the first and
# last times monitored by @C { m }.  In the unlikely event that @C { m }
# monitors no times at all, they will be set to @C { NULL }.  These
# values are calculated the first time that the function is called, and
# cached in @C { m }, so that subsequent calls take almost no time.
@PP
Functions
@ID @C {
int KheLimitWorkloadMonitorDefectiveTimeGroupCount(
  KHE_LIMIT_WORKLOAD_MONITOR m);
void KheLimitWorkloadMonitorDefectiveTimeGroup(
  KHE_LIMIT_WORKLOAD_MONITOR m, int i, KHE_TIME_GROUP *tg,
  float *workload, int *open_count, int *minimum, int *maximum,
  bool *allow_zero);
}
visit the time groups monitored by @C { m } that are currently
defective.  The order in which they appear depends on their
times.  This means that if a time group changes from defective
to non-defective then back to defective, it reappears in its
previous position in the list.  Without this, a traversal of
the list trying to remove each defective time group in turn
would not work properly.
@PP
For each @C { i }, @C { *tg } is set to one
defective time group, @C { *workload } is set to the workload of
@C { m }'s resource during @C { *tg }, @C { *open_count } is the
number of open times in @C { *tg } (determined by the sweep time), and
@C { *minimum }, @C { *maximum }, and @C { *allow_zero } come from
the constraint.  So either the resource is
underloaded during @C { *tg } and @C { *workload < *minimum }, or it
is overloaded during @C { *tg } and @C { *workload > *maximum }.
If @C { *open_count > 0 }, sweep times are in effect, so the comparison
against @C { *minimum } is adjusted to allow for the possibility that
@C { *open_count } more times could be busy, each with workload
per time up to @C { KheResourceTypeMaxWorkloadPerTime(rt) },
where @C { rt } is the type of @C { m }'s resource:
@ID {0.90 1.0} @Scale @C {
*workload + *open_count * KheResourceTypeMaxWorkloadPerTime(rt) < *minimum 
}
See Section {@NumberOf resource_types} for
@C { KheResourceTypeMaxWorkloadPerTime }.  Also,
@ID @C {
int KheLimitWorkloadMonitorDeviation(KHE_LIMIT_WORKLOAD_MONITOR m);
}
returns the deviation of @C { m }.
@PP
Limit workload monitors contain a @C { ceiling } attribute,
set and retrieved by
@ID @C {
void KheLimitWorkloadMonitorSetCeiling(KHE_LIMIT_WORKLOAD_MONITOR m,
  int ceiling);
int KheLimitWorkloadMonitorCeiling(KHE_LIMIT_WORKLOAD_MONITOR m);
}
When @C { workload > ceiling }, the usual formula is overridden:
the deviation is 0.  For why this might be useful, consult
Section {@NumberOf general_solvers.matchings.double}.  The default value
of @C { ceiling } is @C { INT_MAX }, which effectively turns it off.
If @C { m } is attached when @C { KheLimitWorkloadMonitorSetCeiling }
is called, it will be detached and reattached by the call.
# @PP
# Limit workload monitors have their own sweep time functions:
# @ID @C {
# void KheLimitWorkloadMonitorSetSweepTime(
#   KHE_LIMIT_WORKLOAD_MONITOR m, KHE_TIME t);
# bool KheLimitWorkloadMonitorSweepTimeRange(
#   KHE_LIMIT_WORKLOAD_MONITOR m,
#   KHE_TIME *first_time, KHE_TIME *last_time);
# }
# These do what @C { KheMonitorSetSweepTime } and
# @C { KheMonitorSweepTimeRange }
# (Section {@NumberOf monitoring.sweep_times}) do, but for limit
# workload monitors.
@PP
Function
@ID @C {
void KheLimitWorkloadMonitorDebug(KHE_LIMIT_WORKLOAD_MONITOR m,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@PP
A limit workload monitor @C { m } may have non-zero
@C { KheMonitorLowerBound(m) }.  This is true in all cases, but at
present KHE only calculates a potentially non-zero lower bound when
@C { m } monitors the whole cycle.  In that case, add up the workloads
of the tasks to which @C { m }'s resource is preassigned.  If this
exceeds the maximum of the corresponding limit workload constraint,
converting the excess into a cost using @C { m }'s cost function in
the usual way gives the lower bound.
@End @SubSection

@SubSection
    @Title { Limit active intervals monitors }
    @Tag { monitoring.limitactive }
@Begin
@LP
A limit active intervals monitor has tag
@C { KHE_LIMIT_ACTIVE_INTERVALS_MONITOR_TAG } and monitors a resource
and offset which together make one point of application of one
limit active intervals constraint.  Limit active intervals
constraints occur only in the employee scheduling model, so
limit active intervals monitors also occur only in that
model.  Functions
@ID @C {
KHE_LIMIT_ACTIVE_INTERVALS_CONSTRAINT
  KheLimitActiveIntervalsMonitorConstraint(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
KHE_RESOURCE KheLimitActiveIntervalsMonitorResource(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
}
return the limit active intervals constraint and the resource
being monitored.  Functions
@ID @C {
int KheLimitActiveIntervalsMonitorMinimum(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
int KheLimitActiveIntervalsMonitorMaximum(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
}
return the minimum and maximum limits from the constraint.
@ID @C {
int KheLimitActiveIntervalsMonitorHistoryBefore(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
int KheLimitActiveIntervalsMonitorHistoryAfter(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
int KheLimitActiveIntervalsMonitorHistory(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
}
return the history before, history after, and history values from
@C { m }'s constraint, or 0 if not present.  Function
# The history after value
# changes when a sweep index is set, as explained below.
@ID @C {
int KheLimitActiveIntervalsMonitorOffset(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
}
returns the offset being monitored.  When the constraint has @C { NULL }
for @C { applies_to_tg }, the offset is 0, otherwise it is the
difference in index between one useful time in @C { applies_to_tg }
and the first time in @C { applies_to_tg }.  Functions
@ID @C {
int KheLimitActiveIntervalsMonitorTimeGroupCount(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
KHE_TIME_GROUP KheLimitActiveIntervalsMonitorTimeGroup(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int i, KHE_POLARITY *po);
}
# KHE_TIME_GROUP KheLimitActiveIntervalsMonitorTimeGroupState(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int i, KHE_POLARITY *po,
#   int *busy_count);
return the time groups that @C { m } monitors (one for each time group
in the limit active intervals constraint, adjusted using
@C { KheTimeGroupNeighbour } by the offset), and their associated
polarities.
# A rough idea of the times monitored by @C { m } is given by function
# @ID @C {
# void KheLimitActiveIntervalsMonitorRange(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m,
#   KHE_TIME *first_time, KHE_TIME *last_time);
# }
# It sets @C { *first_time } and @C { *last_time } to the first and
# last times monitored by @C { m }.  In the unlikely event that @C { m }
# monitors no times at all, they will be set to @C { NULL }.  These
# values are calculated the first time that the function is called, and
# cached in @C { m }, so that subsequent calls take almost no time.
@PP
There are also functions which report the state of the monitor
during the solve.  Function
# , and optionally the number of busy times.  When
# but reduced when there is a sweep index (as explained below), and
#@ID @C {
#(*po == KHE_NEGATIVE) == (*busy_count == 0)
#}
#the time group is active.  Function
@ID @C {
bool KheLimitActiveIntervalsMonitorTimeGroupIsActive(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int i, KHE_TIME_GROUP *tg,
  KHE_POLARITY *po, int *busy_count);
}
returns @C { true } when the time group at index @C { i } is currently
active.  It sets @C { *tg } and @C { *po } to the time group and
polarity at index @C { i }, and @C { *busy_count } to the number of
busy times in the time group.  It returns the value of the condition
@C {
(*po == KHE_NEGATIVE) == (*busy_count == 0)
},
as the definition of the constraint specifies.
@PP
For visiting defective active intervals (active intervals whose
length is less than the minimum limit or greater than the maximum
limit from the constraint), functions
@ID {0.98 1.0} @Scale @C {
int KheLimitActiveIntervalsMonitorDefectiveIntervalCount(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
void KheLimitActiveIntervalsMonitorDefectiveInterval(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int i, int *history_before,
  int *first_index, int *last_index, int *history_after, bool *too_long);
}
return the number of defective active intervals and attributes of
the @C { i }th defective active interval:
@IndentedList

@LI { @C { *history_before }.
If the interval includes the first time group, the part of its length from
before there (i.e. @C { KheLimitActiveIntervalsMonitorHistory(m) }),
otherwise 0.
}

@LI { @C { *first_index }.
The index of the first time group in the interval, not including
any history part, so always at least @C { 0 }.
}

@LI { @C { *last_index }.
The index of the last time group in the interval, not including
any history part, so always at most
@C { KheLimitActiveIntervalsMonitorTimeGroupCount(m) - 1 }.
The value could be negative, indicating that the interval lies
entirely within history.
}

@LI { @C { *history_after }.
If the interval includes the last time group, the part of its
length from after the last time group.  This must be 0 when
the the interval violates a maximum limit.
}

@LI { @C { *too_long }.
Since this is a defective interval, its length must either be too
long or too short.  This value is @C { true } if it is too long,
and @C { false } if it is too short.
}

@EndList
The value compared with the limits is
@ID @C { *history_before + (*last_index - *first_index + 1) + *history_after }
See Jeff Kingston's paper on history for the rationale for this.
All these definitions hold good (although their consequences are
not quite obvious) when there is a sweep time.
@PP
In rare cases, @C { KheLimitActiveIntervalsMonitorDefectiveInterval }
sets @C { *last_index } to @C { -1 }.  This indicates that there
is a defective interval lying entirely within the history range.
A solver can do nothing about this; it must check this condition
and do nothing when it occurs.
@PP
@C { KheLimitActiveIntervalsMonitorDefectiveInterval } visits the
defective intervals in increasing order of @C { *first_index }.  This
ensures that if, between calls to this function, the solution is
changed, then changed back again to its previous state, a partially
completed traversal of defective intervals using this function is
not invalidated.
# first indexes.  To visit them in that order, call
# @ID @C {
# void KheLimitActiveIntervalsMonitorSortDefectiveIntervals(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
# }
# before visiting them.
@PP
There may be value in obtaining advance warning that a constraint
is close to being violated.  For that there is function
@ID @C {
int KheLimitActiveIntervalsMonitorAtMaxLimitCount(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
}
It returns the number of active intervals which do not violate
any limits, but whose length equals the maximum limit.  It has
been considered most efficient to not maintain this value
incrementally; instead, the list of non-violating intervals
is scanned when this function is called.
# @PP
# Limit active intervals monitors have their own sweep time functions:
# @ID @C {
# void KheLimitActiveIntervalsMonitorSetSweepTime(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, KHE_TIME t);
# bool KheLimitActiveIntervalsMonitorSweepTimeRange(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, KHE_TIME *first_time,
#   KHE_TIME *last_time);
# }
# These do what @C { KheMonitorSetSweepTime } and
# @C { KheMonitorSweepTimeRange }
# (Section {@NumberOf monitoring.sweep_times}) do, but for limit
# workload monitors.  The precise effect is as described for cluster
# busy times monitors.
# @PP
# For the benefit of time sweep algorithms, which may perform better
# if active intervals monitors understand that there is no point in
# complaining about problems beyond the point that the time sweep has
# reached, there are functions
# @ID @C {
# bool KheLimitActiveIntervalsMonitorSetSweepIndex(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int sweep_index);
# int KheLimitActiveIntervalsMonitorSweepIndex(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
# }
# These functions set and retrieve the monitor's @I { sweep index }, an integer
# between 0 and @C { KheLimitActiveIntervalsMonitorTimeGroupCount(m) }
# inclusive, whose effect is explained below.  If no sweep
# index has been set, @C { KheLimitActiveIntervalsMonitorSweepIndex(m) }
# returns @C { KheLimitActiveIntervalsMonitorTimeGroupCount(m) }.  This
# value cuts off nothing, and should be passed when the aim is to remove
# a previously set sweep index.
# @PP
# In practice it will often be easier to call this function:
# @ID @C {
# bool KheLimitActiveIntervalsMonitorSetSweepTime(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, KHE_TIME sweep_time);
# }
# It works out the appropriate sweep index for ignoring all time
# groups that contain any time later than @C { sweep_time }, and calls
# @C { KheLimitActiveIntervalsMonitorSetSweepIndex } with that sweep
# index.  Passing @C { NULL } for @C { sweep_time } removes any
# sweep index.
# # If @C { m } is attached, it is
# # detached before setting the sweep index and reattached afterwards.
# @PP
# @C { KheLimitActiveIntervalsMonitorSetSweepTime } examines @C { m }'s
# time groups from first to last, stopping at the first time group that
# contains a time whose index exceeds the index of @C { sweep_time }.
# The index of that time group is the sweep index; or if there is no
# such time group, the sweep index is
# @C { KheLimitActiveIntervalsMonitorTimeGroupCount(m) }.  The
# function runs much faster than just described
# when the sweep times are increasing, as they usually are.
# @PP
# @C { KheLimitActiveIntervalsMonitorSetSweepIndex } returns @C { true }
# when a non-zero number of time groups is being cut off.
# @C { KheLimitActiveIntervalsMonitorSetSweepTime } does the same.
# For example, passing @C { NULL } for @C { sweep_time } always returns
# value @C { false }.  But other sweep times also return @C { false },
# when they come after the last time in the last time group.
# @PP
# The general idea is that if a solve is attempting to assign times
# only up to a certain point in the cycle, then a sweep index should
# be set to inform the monitor that there is no point in complaining
# about things at or beyond that point.  This improves the value of
# the monitor as an influencer of the solve actually under way.
# @PP
# For the record, however, we need to be specific about the effect
# of a sweep index.  It influences its monitor in two ways.  First,
# and most simply, active intervals that begin at or after the sweep
# index do not attract a cost, no matter how short or long they are.
# Active intervals that begin before the sweep index and extend
# beyond it are not truncated, however, except where the second
# effect (which we are about to explain) changes the state of some
# of their time groups.
# @PP
# Second, and more subtly, the monitor understands that time groups
# whose indexes are equal to or larger than the sweep index are
# beyond the scope of the current solve.  This does not affect busy
# time groups, which are considered to be active or inactive as usual
# (depending on their polarity), but it does affect non-busy ones,
# which are considered to be in an @I open state, that is, not known to
# be either active or inactive.  The monitor then acts conservatively:
# it considers an open time group to be active when comparing with a
# minimum limit, and inactive when comparing with a maximum limit.
# Either way, this makes a violation less likely.
# @PP
# There is also
# @ID @C {
# KHE_TIME KheLimitActiveIntervalsMonitorInitialSweepTime(
#   KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
# }
# This returns the smallest time @C { t } such that cutting off at
# @C { t } is not the same as cutting off at index 0, or @C { NULL }
# if there is no such time.
# @PP
# Suppose the aim is to successively cut @C { m } off at @C { t1 },
# @C { t2 }, and so on to @C { tn }, the last time.  Let
# @C { ti = KheLimitActiveIntervalsMonitorInitialSweepTime(m) },
# and let @C { tj } be the first time such that
# @C { KheLimitActiveIntervalsMonitorSetSweepTime(m, tj) }
# returns @C { false }.  Then the only calls to set sweeps
# that actually need to be made are
# @ID @C {
# KheLimitActiveIntervalsMonitorSetSweepIndex(m, 0);
# KheLimitActiveIntervalsMonitorSetSweepTime(m, ti);
# ...
# KheLimitActiveIntervalsMonitorSetSweepTime(m, tj);
# }
# Calls between @C { t1 } and @C { ti-1 } change nothing, and calls
# after @C { tj } also change nothing.  If there is no @C { ti },
# then cutting off at index 0 is all that is needed.
#@PP
#The frame (Section {@NumberOf extras.frames}) corresponding
#to @C { m } is returned by
#@ID @C { 
#KHE_FRAME KheLimitActiveIntervalsMonitorFrame(
#  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
#}
#This frame is constructed the first time
#@C { KheLimitActiveIntervalsMonitorFrame } is called on @C { m },
#cached in @C { m }, and returned on the first and all subsequent calls.
@PP
There is a peculiar but apparently unavoidable asymmetry in the handling
of time groups at or after the sweep index:  if they are busy they have
a definite state, either active or inactive, but if they are not busy
they are open.  This can be mitigated by calling
@ID @C {
void KheLimitActiveIntervalsMonitorSetNotBusyState(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int i, bool active);
}
where @C { i } is the index of one of @C { m }'s time groups, call it
@C { tg }.  This informs @C { m } that when @C { tg } is at or after
the sweep index and is not busy, it should be considered either active
or inactive (depending on the @C { active } parameter) rather than
open.  No other cases are affected.  There are no restrictions on
when this function can be called, relative to setting the sweep
index or anything else.  It may change the cost of @C { m }.  Function
@ID @C {
void KheLimitActiveIntervalsMonitorClearNotBusyState(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int i);
}
returns @C { tg } to its default state.  (In practice, there is no
reason to call this function, because as the sweep index increases
these effects become irrelevant anyway.)
@PP
For example, suppose that some resource @C { r } has requested that a
certain time group @C { tg } be kept free.  Suppose that @C { r } is
subject to a limit active intervals monitor @C { m }, whose @C { i }th
time group is a subset of @C { tg }.  Then we can expect that time
group to be free, and hence active if it is negative and inactive
if it is positive.  This expectation can be conveyed to @C { m }
by calling @C { KheLimitActiveIntervalsMonitorSetNotBusyState }.
This can make a significant difference to time sweep solvers
when @C { m } has a non-trivial minimum limit (2 or more), by
penalizing them for starting a new sequence of busy days just
before a resource is due for some free time.
@PP
To support @I { tilting the plateau }
(Section {@NumberOf resource_structural.adjust.tilting}),
KHE offers functions
@ID @C {
void KheLimitActiveIntervalsMonitorSetTilt(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
void KheLimitActiveIntervalsMonitorClearTilt(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m);
bool KheLimitActiveIntervalsMonitorTilt(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m)
}
The tilt is a Boolean flag stored in @C { m } which changes the
costs of defective intervals slightly when set.
@C { KheLimitActiveIntervalsMonitorSetTilt } sets the flag
to @C { true }, or does nothing if it is already @C { true }.
@C { KheLimitActiveIntervalsMonitorClearTilt } sets the flag
to @C { false }, or does nothing if it is already @C { false }.
@C { KheLimitActiveIntervalsMonitorTilt } returns the current value
of the flag.  For why tilting is useful, and how the costs change,
consult Section {@NumberOf resource_structural.adjust.tilting}.
@PP
If @C { m } is attached when the flag's value is changed, it will
be detached before the change and reattached afterwards.  The
cost after reattaching may differ from the cost before detaching.
@PP
Finally, function
@ID @C {
void KheLimitActiveIntervalsMonitorDebug(
  KHE_LIMIT_ACTIVE_INTERVALS_MONITOR m, int verbosity,
  int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Timetable monitors }
    @Tag { monitoring_timetables }
@Begin
@LP
A @I { timetable } is a record of what is going on at each time.
As part of monitoring cost, KHE monitors the timetable of each
event and each resource.
@BeginSubSections

@SubSection
    @Title { Event timetable monitors }
    @Tag { monitoring_timetables_event }
@Begin
@LP
Function
@ID @C {
KHE_EVENT_TIMETABLE_MONITOR KheEventTimetableMonitor(KHE_SOLN soln,
  KHE_EVENT e);
}
returns the event timetable monitor of event @C { e }.  Type
@C { KHE_EVENT_TIMETABLE_MONITOR } is a subtype of @C { KHE_MONITOR }
with tag @C { KHE_EVENT_TIMETABLE_MONITOR_TAG }.
@PP
An event timetable monitor always has cost 0.  When it is attached, a
particular set of meets is known to it at any moment:  the set of meets
derived from @C { e } that are assigned a time.  The monitor offers
these operations, which report which meets are running at each time:
@ID @C {
int KheEventTimetableMonitorTimeMeetCount(
  KHE_EVENT_TIMETABLE_MONITOR etm, KHE_TIME time);
KHE_MEET KheEventTimetableMonitorTimeMeet(
  KHE_EVENT_TIMETABLE_MONITOR etm, KHE_TIME time, int i);
}
@C { KheEventTimetableMonitorTimeMeetCount } returns the number of
meets running at @C { time }, and @C { KheEventTimetableMonitorTimeMeet }
returns the @C { i }th of these meets.  Closely related is
@ID @C {
bool KheEventTimetableMonitorTimeAvailable(
  KHE_EVENT_TIMETABLE_MONITOR etm, KHE_MEET meet, KHE_TIME time);
}
which returns @C { true } if moving @C { meet } within @C { etm },
or adding it to @C { etm }, so that its starting time is @C { time },
would neither place @C { meet } partly off the end of the timetable
nor cause clashes.
@PP
An event timetable monitor offers no operations which report its set of
meets directly.  For that, call functions @C { KheEventMeetCount } and
@C { KheEventMeet } from Section {@NumberOf solutions.top.traversal} to
obtain the meets derived from a particular event; the timetabled meets
are those with an assigned time.
@PP
As usual, event timetable monitors are created by @C { KheSolnMake }
and exist for as long as the solution does.  There is one for each
event.  Link events monitors (but not spread events monitors) depend
on event timetable monitors.
@PP
Unlike most monitors, event timetable monitors are not attached initially.
The event timetable monitor returned by @C { KheEventTimetableMonitor }
may be unattached and so not up to date (it will be empty in that case).
When a monitor is attached, any unattached timetable monitor(s) it
depends on are also attached.  When the last monitor that depends on
some event timetable monitor is detached, that event timetable monitor
is detached.  Thus, unless the user chooses to attach an event timetable
monitor explicitly, it will be attached only as needed by other monitors.
Detaching an event timetable monitor does nothing unless no attached
monitors depend on it.  In practice, when using an event timetable
monitor @C { etm }, it is best to call
@ID @C {
if( !KheMonitorAttachedToSoln((KHE_MONITOR) etm) )
  KheMonitorAttachToSoln((KHE_MONITOR) etm);
}
beforehand, and
@ID @C {
KheMonitorDetachFromSoln((KHE_MONITOR) etm);
}
afterwards, unless @C { etm } must be attached, because some
monitor that depends on it is attached.
@PP
Although it would make sense to treat an event timetable monitor as a
group monitor (Section {@NumberOf monitoring.group}), that option
is not offered.  The user who wants all the problems associated
with a given event to be channelled through a single monitor must
create a group monitor, separate from the event timetable monitor,
and add the appropriate monitors to it in the usual way.
@PP
Event timetable monitors may be debugged by calling
@C { KheEventTimetableMonitorDebug } (defined below) as usual.  And
@ID {0.98 1.0} @Scale @C {
void KheEventTimetableMonitorPrintTimetable(
  KHE_EVENT_TIMETABLE_MONITOR etm, int cell_width, int indent, FILE *fp);
}
prints a conventional tabular timetable, using @C { Days } and
possibly @C { Weeks } time groups from the instance to determine
its shape.  Parameter @C { cell_width } is the width of each cell,
in characters.
@PP
The user may create an event timetable monitor by calling
@ID @C {
KHE_EVENT_TIMETABLE_MONITOR KheEventTimetableMonitorMake(KHE_SOLN soln,
  KHE_EVENT_GROUP eg);
}
The result monitors the meets of @C { soln } derived from the events
of @C { eg }, and thus offers a way to keep track of which events of
@C { eg } are running at each time, something which is not otherwise
available in KHE.  It can be attached and detached at will in the
usual way.  Initially, it is detached, so in practice its creation
would always be followed by a call to @C { KheMonitorAttachToSoln }.
@PP
To delete an event timetable monitor made in this way, call
@ID @C {
KheEventTimetableMonitorDelete(KHE_EVENT_TIMETABLE_MONITOR etm);
}
This function begins by detaching @C { etm } if it is attached.
Function
@ID @C {
void KheEventTimetableMonitorDebug(KHE_EVENT_TIMETABLE_MONITOR etm,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
@End @SubSection

@SubSection
    @Title { Resource timetable monitors }
    @Tag { monitoring_timetables_resource }
@Begin
@LP
Function
@ID @C {
KHE_RESOURCE_TIMETABLE_MONITOR KheResourceTimetableMonitor(
  KHE_SOLN soln, KHE_RESOURCE r);
}
returns the resource timetable monitor of resource @C { r }.  Type
@C { KHE_RESOURCE_TIMETABLE_MONITOR } is a subtype of @C { KHE_MONITOR }
with tag @C { KHE_RESOURCE_TIMETABLE_MONITOR_TAG }.  Functions
@ID @C {
KHE_SOLN KheResourceTimetableMonitorSoln(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm);
KHE_RESOURCE KheResourceTimetableMonitorResource(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm);
}
return @C { rtm }'s solution and resource attributes.
@PP
A resource timetable monitor always has cost 0.  When it is attached, a
particular set of tasks is known to it at any moment:  those assigned
the resource (either directly, or indirectly via other tasks) whose
enclosing meet is assigned a time (either directly, or indirectly via
other meets).  The monitor offers these operations, which report which
tasks are running at each time:
@ID @C {
int KheResourceTimetableMonitorTimeTaskCount(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME time);
KHE_TASK KheResourceTimetableMonitorTimeTask(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME time, int i);
}
@C { KheResourceTimetableMonitorTimeTaskCount } returns the number of
tasks running at @C { time }; @C { KheResourceTimetableMonitorTimeTask }
returns the @C { i }th of these tasks.
@PP
Several functions work out whether @C { rtm }'s resource is free,
or available.  Function
# Other functions are offered which may be more convenient in some
# cases.  Function
# @ID @C {
# int KheResourceTimetableM onitorBusyTimes(
#   KHE_RESOURCE_TIMETABLE_MONITOR rtm);
# }
# returns the number of busy times in @C { rtm }.  This quantity is
# kept up to date as the timetable changes, so retrieving it costs
# almost nothing.  Next,
@ID @C {
bool KheResourceTimetableMonitorTimeAvailable(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_MEET meet, KHE_TIME time);
}
returns @C { true } if moving @C { meet } within @C { rtm }, or
adding it to @C { rtm }, so that its starting time is @C { time },
would neither place @C { meet } partly off the end of the timetable
nor cause clashes.
# And
# @ID @C {
# bool KheResourceTimetableMonitorTimeGroupAvailable(
#   KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME_GROUP tg,
#   bool nocost_off, bool check_avoid_unavailable_times_monitors);
# }
# returns @C { true } when the resource monitored by @C { rtm } is
# free at all of the times of @C { tg }.
# @PP
# Ordinarily, @C { KheResourceTimetableMonitorTimeGroupAvailable }
# considers tasks for which @C { KheTaskNeedsAssignment } returns
# @C { false } to be free time, given that they can be unassigned
# at no cost.  But if @C { nocost_off } is true, they are considered
# to be not free time.
# @PP
# If @C { check_avoid_unavailable_times_monitors } is @C { true },
# then as well as checking for tasks,
# @C { KheResourceTimetableMonitorTimeGroupAvailable }
# checks for avoid unavailable times monitors monitoring the times
# of @C { tg }.  If it finds any, it returns @C { false }, not because
# the resource is busy during @C { tg }, but because it is unavailable.
# @PP
# Function
# @ID @C {
# bool KheResourceTimetableMonitorTaskAvailableInFrame(
#   KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TASK task, KHE_FRAME frame,
#   KHE_TASK ignore_task);
# }
# is similar but more elaborate.  For each time that @C { task } and its
# descendants is running, it finds the time group containing that time in
# @C { frame }.  It returns @C { true } when all of those time groups are
# available.  If @C { ignore_task } is non-@C { NULL }, it ignores any
# task whose proper root is @C { ignore_task }.  This is useful, for
# example, when checking whether a swap of the assignments of @C { task }
# and @C { ignore_task } would create no cases of two tasks running in
# the same time group of @C { frame }.
@PP
Function
@ID @C {
int KheResourceTimetableMonitorBusyTimesForTimeGroup(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME_GROUP tg);
}
returns the number of times during @C { tg } when @C { rtm }'s
resource is busy attending one or more tasks.
@PP
Here are three functions for determining whether a resource is free
at certain times:
@ID @C {
bool KheResourceTimetableMonitorFreeForTime(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME t,
  KHE_FRAME frame, KHE_TASK ignore_task, bool ignore_nocost_tasks);
bool KheResourceTimetableMonitorFreeForTimeGroup(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME_GROUP tg,
  KHE_FRAME frame, KHE_TASK ignore_task, bool ignore_nocost_tasks);
bool KheResourceTimetableMonitorFreeForTask(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TASK task,
  KHE_FRAME frame, KHE_TASK ignore_task, bool ignore_nocost_tasks);
}
All three functions return @C { true } when @C { rtm }'s resource is free
(that is, not assigned to any task) at a certain set of times @M { T }.
For @C { KheResourceTimetableMonitorFreeForTime }, @M { T } is the set
of times containing just @C { t }.
For @C { KheResourceTimetableMonitorFreeForTimeGroup }, @M { T } is the set
of times of @C { tg }.  For @C { KheResourceTimetableMonitorFreeForTask },
@M { T } is the set of times that @C { task } is running, including any
tasks assigned to @C { task }, directly or indirectly.
@PP
For all three functions, if @C { frame != NULL } then the test is
extended to include every time in every time group of @C { frame }
that contains at least one time from @M { T }.  This is useful when
@C { rtm }'s resource can be assigned to at most one task per day.
@PP
For all three functions, if @C { ignore_task != NULL }, then that
task is ignored if it is present in the timetable.  This is
useful when investigating whether a task swap is feasible.
@PP
For all three functions, if @C { ignore_nocost_tasks } is @C { true },
then every task @C { t } for which @C { KheTaskNeedsAssignment(t) }
returns @C { false } is ignored.  This is useful for deciding whether
the resource would be free if it was unassigned from these tasks,
something that incurs no cost.
@PP
Here are three similar functions that determine whether a resource
is available (that is, not subject to an avoid unavailable times
constraint) at certain times:
@ID @C {
bool KheResourceTimetableMonitorAvailableForTime(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME t);
bool KheResourceTimetableMonitorAvailableForTimeGroup(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME_GROUP tg);
bool KheResourceTimetableMonitorAvailableForTask(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TASK task);
}
The same times @M { T } are used, but here the test is for whether
there is an avoid unavailable times constraint at any of the times.
This is why the other parameters are omitted.  For example, there
is no @C { frame } parameter because unavailable times are not
influenced by days like busy times are.
@PP
Next we have
@ID {0.98 1.0} @Scale @C {
void KheResourceTimetableMonitorAddProperRootTasksInTimeGroup(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME_GROUP tg,
  bool include_preassigned, KHE_TASK_SET ts);
}
This adds to existing task set @C { ts } the proper root tasks of the
tasks of @C { rtm } that overlap with time group @C { tg }.  Here
@C { tg } may be @C { NULL }, in which case the time group containing
every time of the cycle is used.  It adds the tasks in the order that
it discovers them, as it proceeds through @C { tg } in chronological
order; so the tasks will appear in @C { ts } in chronological order,
except for tasks that lie partly within @C { tg } and partly outside
it.  The function does not add tasks that are already present.  If
@C { include_preassigned } is @C { true }, preassigned tasks are
included, otherwise they aren't.  Omitting them makes sense when the
tasks will be reassigned.
@PP
Two similar functions are
@ID @C {
void KheResourceTimetableMonitorAddProperRootTasksInTimeRange(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, int first_time_index,
  int last_time_index, bool include_preassigned, KHE_TASK_SET ts);
void KheResourceTimetableMonitorAddProperRootTasksInInterval(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_FRAME frame,
  int first_frame_index, int last_frame_index,
  bool include_preassigned, KHE_TASK_SET ts);
}
These add to @C { ts } the proper root tasks running between the
times with indexes @C { first_time_index } and @C { last_time_index }
inclusive, and the proper root tasks running between the first time
of the time group of @C { frame } with index @C { first_frame_index }
and the last time of the time group of @C { frame } with index
@C { last_frame_index }.  Here @C { first_frame_index } is increased
to 0 if it is less than 0, and @C { last_frame_index } is decreased
to the index of the last time group of @C { frame } if it exceeds
that number.
# @ID @C {
# KHE_BUSY_TYPE KheResourceTimetableMonitorTaskBusyType(
#   KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TASK task,
#   KHE_FRAME days_frame, KHE_TASK_SET r_ts, bool ignore_nocost,
#   bool certain);
# KHE_BUSY_TYPE KheResourceTimetableMonitorTaskSetBusyType(
#   KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TASK_SET task_set,
#   KHE_FRAME days_frame, KHE_TASK_SET r_ts, bool ignore_nocost,
#   bool certain);
# }
# add to existing task set @C { r_ts } the proper roots of the tasks of
# @C { rtm } that are running on the same days as @C { task } or the
# tasks of @C { task_set }, including descendant tasks, using
# @C { days_frame } to determine what the days are.  They do not
# add tasks to @C { r_ts } that are already present.  Both functions
# return a value of type
# @ID @C {
# typedef enum {
#   KHE_BUSY_NONE = 0,
#   KHE_BUSY_SOME = 1,
#   KHE_BUSY_ALL = 2
# } KHE_BUSY_TYPE;
# }
# saying whether @C { rtm } is busy on no day that @C { task } or
# @C { task_set } is running, or one some but not all days, or on all
# days.  If @C { ignore_nocost }, the calculation of this return value
# considers tasks @C { t } for which
# @C { KheTaskNonAssignmentHasCost(t, certain) }
# returns @C { false } to be the same as free time.  However such
# tasks are still added to @C { r_ts }.
#Omitting them makes sense when the tasks will be reassigned.  And
#@ID @C {
#bool KheResourceTimetableMonitorTaskBusy(
#  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TASK task,
#  KHE_FRAME days_frame, KHE_TASK_SET ts);
#bool KheResourceTimetableMonitorTaskSetBusy(
#  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TASK_SET task_set,
#  KHE_FRAME days_frame, KHE_TASK_SET ts);
#}
#add to existing task set @C { ts } the proper roots of the tasks of
#@C { rtm } that are running on the same days as @C { task } or the
#tasks of @C { task_set }, including descendant tasks, using
#@C { days_frame } to determine what the days are.  They do not
#add tasks to @C { ts } that are already present.  Both functions
#return @C { true } if @C { rtm } is busy on every day that @C { task }
#or @C { task_set } is running.  (So if @C { rtm } is busy on some days
#but not others, @C { false } is returned and at least one task is added
#to @C { ts }.)
@PP
One can also get direct access to the times where the resource has clashes:
@ID @C {
int KheResourceTimetableMonitorClashingTimeCount(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm);
KHE_TIME KheResourceTimetableMonitorClashingTime(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, int i);
}
These work in the usual way, visiting each clashing time in turn.
The times are kept in increasing time index order, which is handy
when repairing clashes, because it means that removing a clash then
reinstating it does not change the order that the times appear.
@PP
A resource timetable monitor offers no operations which report its set of
tasks directly.  For that, one can use @C { KheResourceAssignedTaskCount }
and @C { KheResourceAssignedTask } from
Section {@NumberOf solutions.tasks.asst} to obtain all the tasks
assigned the resource; the timetabled ones are just those whose
enclosing meet has an assigned time.
# @PP
# The condition @C { KheResourceTimetableMonitorTimeTaskCount(rtm, time) >= 2 }
# is true at each time when @C { rtm } has a clash.  To find out quickly
# which times these are, use
# @ID @C {
# int KheResourceTimetableMonitorClashingTimeCount(
#   KHE_RESOURCE_TIMETABLE_MONITOR rtm);
# KHE_TIME KheResourceTimetableMonitorClashingTime(
#   KHE_RESOURCE_TIMETABLE_MONITOR rtm, int i);
# }
# They return all times such that @C { rtm } has a clash at that time,
# not in chronological order.
@PP
As usual, resource timetable monitors are created by @C { KheSolnMake }
and exist for as long as the solution does.  There is one for each
resource.  All resource monitors (except possibly limit workload
monitors) depend on resource timetable monitors.
@PP
Unlike most monitors, resource timetable monitors are not attached
initially.  The resource timetable monitor returned by
@C { KheResourceTimetableMonitor } may be unattached and so not up to
date (it will be empty in that case).  When a monitor is attached,
any unattached timetable monitor(s) it depends on are also attached.
When the last monitor that depends on some resource timetable monitor
is detached, that resource timetable monitor is detached.  Thus, unless
the user chooses to attach a resource timetable monitor explicitly, it
will be attached only as needed by other monitors.  Detaching a resource
timetable monitor does nothing unless no attached monitors depend on it.
So when using a resource timetable monitor @C { rtm }, it is best to call
@ID @C {
if( !KheMonitorAttachedToSoln((KHE_MONITOR) rtm) )
  KheMonitorAttachToSoln((KHE_MONITOR) rtm);
}
beforehand, and
@ID @C {
KheMonitorDetachFromSoln((KHE_MONITOR) rtm);
}
afterwards, unless @C { rtm } must be attached, because some
monitor that depends on it is attached.
@PP
Although it would make sense to treat a resource timetable monitor as
a group monitor (Section {@NumberOf monitoring.group}), that option
is not offered.  The user who wants all the problems associated
with a given resource to be channelled through a single monitor
must create a group monitor, separate from the resource timetable
monitor, and add the appropriate monitors to it in the usual way.
@PP
Here are two functions created to support the needs of particular
solvers.  First,
@ID @C {
int KheResourceTimetableMonitorAtMaxLimitCount(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME t);
}
returns the sum, over all cluster busy times and limit active
intervals monitors that monitor @C { rtm }'s resource at time
@C { t }, of the values returned by those monitors' @C { AtMaxLimitCount }
functions.  It is an efficient way to find out, during time sweep
resource assignment, whether assignments at time @C { t } have
brought any of these monitors to their maximum limits.  Second,
@ID @C {
void KheResourceTimetableMonitorAddRange(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, int first_time_index,
  int last_time_index, bool include_avoid_unavailable_times,
  KHE_GROUP_MONITOR gm);
}
adds to @C { gm } all cluster and limit busy times monitors @C { m }
such that @C { m } monitors @C { rtm }, @C { m }'s constraint applies
to at least half of the resources of @C { rtm }'s resource's type,
and @C { m }'s range (as given by @C { KheClusterBusyTimesMonitorRange }
and @C { KheLimitBusyTimesMonitorRange }) lies between the times indexed
by @C { first_time_index } and @C { last_time_index } inclusive.
If parameter @C { include_avoid_unavailable_times } is @C { true },
add in @C { rtm }'s avoid unavailable times monitors as well.  Any
monitor that is already a child of @C { gm } is not added again.
@PP
A similar function is
@ID @C {
void KheResourceTimetableMonitorAddInterval(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_FRAME frame,
  int first_frame_index, int last_frame_index,
  bool include_avoid_unavailable_times, KHE_GROUP_MONITOR gm);
}
This calls @C { KheResourceTimetableMonitorAddRange }, passing it
the index of the first time in the time group of @C { frame } with
index @C { first_frame_index }, and the index of the last time in
the time group of @C { frame } with index @C { last_frame_index }.
If @C { first_frame_index < 0 } it is increased to 0.  If
@C { last_frame_index } is too large it is decreased to the index
of @C { frame }'s last time group.
@PP
All resource timetable monitors are created automatically when the
solution is created.  The KHE user is offered nothing equivalent
to @C { KheEventTimetableMonitorMake }.
@PP
Function
@ID @C {
void KheResourceTimetableMonitorDebug(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, int verbosity,
  int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
There is also
@ID @C {
void KheResourceTimetableMonitorSetDebug(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_TIME_GROUP tg, bool val);
}
If @C { val } is @C { true }, this marks the times of @C { tg } for
debugging.  Whenever @C { rtm }'s timetable changes at any of these
times, a one-line debug print is produced on @C { stderr } giving
the resource, the time, and a brief indication of the change.  This
is useful for working out why a resource is busy (or not) during a
given time group.  If @C { val } is @C { false } this debugging is
turned off at the times of @C { tg }.
@PP
Finally, there is
@ID {0.95 1.0} @Scale @C {
void KheResourceTimetableMonitorPrintTimetable(
  KHE_RESOURCE_TIMETABLE_MONITOR rtm, KHE_FRAME days_frame,
  int cell_width, int indent, FILE *fp);
}
which prints a tabular timetable, using @C { Days } and possibly
@C { Weeks } time groups from the instance to determine its shape.
If @C { days_frame != NULL } there is one table cell per day, otherwise
there is one cell per time.  Parameter @C { cell_width } is the width
of each cell, in characters.
@End @SubSection

@EndSubSections
@End @Section

#@Section
#    @Title { Time group monitors }
#    @Tag { monitoring_timegroup }
#@Begin
#@LP
#A @I { time group } monitor is a monitor associated with one
#timetable monitor.  It monitors what is happening at the times
#of its time group within the timetable; specifically, it keeps
#track of how many of the times of the time group are busy in
#that timetable (occupied by at least one meet).  It also keeps
#track of how many idle times the time group contains, but only
#if there is a limit idle times monitor in the vicinity that needs
#to know.
#@PP
#Time group monitors are created and attached by KHE as required,
#and it is best not to meddle with that.  However, there is no
#problem with retrieving information from them:
#@ID @C {
#KHE_TIMETABLE_MONITOR KheTimeGroupMonitorTimetableMonitor(
#  KHE_TIME_GROUP_MONITOR m);
#KHE_TIME_GROUP KheTimeGroupMonitorTimeGroup(KHE_TIME_GROUP_MONITOR m);
#int KheTimeGroupMonitorBusyCount(KHE_TIME_GROUP_MONITOR m);
#}
#These return @C { m }'s associated timetable monitor, the time group
#that @C { m } monitors, and the number of busy times in that time group.
#@PP
#When a limit idle times monitor is attached which monitors
#@C { tgm }'s time group within @C { tgm }'s timetable monitor,
#two other functions related to idle times calculations may be
#called:
#@ID @C {
#int KheTimeGroupMonitorIdleCount(KHE_TIME_GROUP_MONITOR m);
#void KheTimeGroupMonitorFirstAndLastBusyTimes(
#  KHE_TIME_GROUP_MONITOR tgm, KHE_TIME times[2], int *count);
#}
#The first returns the number of idle times.  The second places
#the first and last busy times into @C { times }, and sets
#@C { *count } to the number of times it placed there.  If
#there are no busy times, @C { *count } is 0; if there is one
#busy time, @C { *count } is 1; else @C { *count } is 2.  This
#specification does not refer to idle times, but nevertheless the
#function will abort if there is no limit idle times monitor nearby.
#@End @Section

@Section
    @Title { Group monitors }
    @Tag { monitoring.group }
@Begin
@LP
Sometimes the cost of a @I single monitor is needed:  for example, when
reporting problems to the user.  And the total cost of @I all monitors
is always needed, since that is the cost of the solution.
@PP
Sometimes something in between these two extremes is needed:  the
cost of a set of related monitors.  To support this, the monitors
of a solution are organized into a directed acyclic graph, or
@I { dag } for short, of arbitrary depth.  Each monitor reports
its cost to its parent monitors.  The dag is often a tree, in
which case the picture looks like this:
@CD -1px @Break @Diag margin { 0.2c } {
||0.5rt RR:: @Box 2c @Wide 0.9c @High @I Soln
//0.6c
||0.5rt GMA:: @Box 2c @Wide 0.9c @High @I { Group @LLP monitor }
&4c     GMB:: @Box 2c @Wide 0.9c @High @I { Group @LLP monitor }
//0.6c
||0.5rt NGA:: @Box 2c @Wide 0.9c @High @I { Non-group monitor }
&2c     NGB:: @Box 2c @Wide 0.9c @High @I { Non-group monitor }
&2c     ...
&2c     NGC:: @Box 2c @Wide 0.9c @High @I { Non-group monitor }
//0.6c
||0.5rt SOLN:: @Box 14c @Wide 0.4c @High @I { Solution }
//
@Arrow from { GMA } to { RR }
@Arrow from { GMB } to { RR }
@Arrow from { NGA } to { GMA }
@Arrow from { NGB } to { GMA }
@Arrow from { NGC } to { GMB }
@Arrow from { SOLN@NW ++ { 0.5c 0 } } to { NGA }
@Arrow from { SOLN@NW ++ { 1.5c 0 } } to { NGA }
@Arrow from { SOLN@NW ++ { 2.5c 0 } } to { NGA }
@Arrow from { SOLN@NW ++ { 5.0c 0 } } to { NGB }
@Arrow from { SOLN@NW ++ { 6.0c 0 } } to { NGB }
@Arrow from { SOLN@NW ++ { 7.0c 0 } } to { NGB }
@Arrow from { SOLN@NE -- { 0.5c 0 } } to { NGC }
@Arrow from { SOLN@NE -- { 1.5c 0 } } to { NGC }
@Arrow from { SOLN@NE -- { 2.5c 0 } } to { NGC }
}
The leaves are the @I { non-group monitors }, the various monitors
described previously which monitor the solution directly.  The
internal nodes are called @I { group monitors }, because they
monitor a set of monitors (their children).  The cost of a group
monitor is the sum of the costs of its children.
@PP
The solution object itself is a group monitor (initially, the
only one).  It supports all the group monitor operations, plus
the many other operations described earlier.
@PP
Group monitors have type @C { KHE_GROUP_MONITOR }, a concrete subtype
of @C { KHE_MONITOR }, like @C { KHE_ASSIGN_TIME_MONITOR } etc.
@C { KHE_GROUP_MONITOR } is a supertype of @C { KHE_SOLN }, so upcast
@ID @C { (KHE_GROUP_MONITOR) soln }
is safe, although often unnecessary, since many operations on
type @C { KHE_GROUP_MONITOR } have @C { KHE_SOLN } versions.
For example, since @C { KHE_GROUP_MONITOR } is itself a subtype
of @C { KHE_MONITOR }, the total cost of all monitors could be
found by calling
@ID @C { KheMonitorCost((KHE_MONITOR) soln) }
but of course the equivalent @C { KHE_SOLN } version, @C { KheSolnCost },
is easier to use.
@PP
When the solution changes at some point, the change is reported to
the non-group monitors that monitor that point.  Each updates its
cost and reports any change to its parents, which update their
cost and report to their parents, and so on until there are no
parents.  The dag usually has a single root, the solution object
itself, but it does not have to be that way, because the links
that join non-group and group monitors to their parent monitors
can be added and deleted at will.
@BeginSubSections

@SubSection
    @Title { Basic operations on group monitors }
    @Tag { monitoring.group.basic }
@Begin
@LP
Unlike other types of monitors, group monitors other than the
solution object can be freely created and deleted.  Function
@ID @C {
KHE_GROUP_MONITOR KheGroupMonitorMake(KHE_SOLN soln, int sub_tag,
  char *sub_tag_label);
}
creates a new group monitor with no parents and no children.  It
is passed the solution as a parameter, and it remembers it, but
it is not made a child of it.  Functions
@ID @C {
int KheGroupMonitorSubTag(KHE_GROUP_MONITOR gm);
char *KheGroupMonitorSubTagLabel(KHE_GROUP_MONITOR gm);
}
return the @C { sub_tag } and @C { sub_tag_label } attributes of
@C { gm }.  These are used to distinguish kinds of group
monitors.   If @C { sub_tag_label } is non-@C { NULL }, it is
printed when debugging.  The values of these attributes in
solution objects are @C { -1 } and @C { "Soln" }.  The term
`sub-tag' is used because group monitors already have a tag
attribute, whose value is @C { KHE_GROUP_MONITOR_TAG }.
@PP
A group monitor other than the solution object may be deleted by calling
@ID @C {
void KheGroupMonitorDelete(KHE_GROUP_MONITOR gm);
}
Its children will no longer have it as a parent, and its parents will
no longer have it as a child.  For each parent of @C { gm }, the hole
in the parent's list of child monitors is plugged by moving the last
child monitor to @C { gm }'s position.  For each child of @C { gm },
the hole in the child's list of parent monitors is plugged by moving
the last parent monitor to @C { gm }'s position.
@PP
Every group monitor can have any number of child monitors, and
every monitor (group or non-group) can have any number of parent
monitors.  Even the solution object can have parents, allowing
monitoring of the total cost of a set of solutions.  The operations
for adding children to a group monitor and removing them are
@ID { 0.95 1.0 } @Scale @C {
void KheGroupMonitorAddChildMonitor(KHE_GROUP_MONITOR gm, KHE_MONITOR m);
void KheGroupMonitorDeleteChildMonitor(KHE_GROUP_MONITOR gm, KHE_MONITOR m);
}
Here @C { m } could be a non-group monitor or a group monitor.
@C { KheGroupMonitorAddChildMonitor } makes @C { m } a child of
@C { gm }, and @C { gm } a parent of @C { m }.  It aborts if this
would create a cycle in the dag (only possible when @C { m }
is a group monitor).  @C { KheGroupMonitorDeleteChildMonitor }
removes @C { m } from @C { gm }, leaving @C { m } with one less
parent and @C { gm } with one less child.  The resulting holes
are plugged as described above for deleting group monitors.  It
aborts if @C { m } is not a child of @C { gm }.  There is also
@ID {0.98 1.0} @Scale @C {
bool KheGroupMonitorHasChildMonitor(KHE_GROUP_MONITOR gm, KHE_MONITOR m);
}
which returns @C { true } when @C { m } is a child of @C { gm }.
It is useful when @C { m } may already be a child of @C { gm }:
@ID @C {
if( !KheGroupMonitorHasChildMonitor(gm, m) )
  KheGroupMonitorAddChildMonitor(gm, m);
}
No-one is checking that one monitor does not become the child of
another twice over; and if it does, its cost will be counted twice
in the cost of its parent.
@PP
For group monitor @C { m }, @C { KheMonitorLowerBound(m) } sums
the lower bounds of @C { m }'s children.  It may increase when
a descendant is added, and decrease when a descendant is removed.
@PP
Initially, all non-group monitors are made children of the
solution object, and all of them except demand monitors are
attached to the solution, so that @C { KheSolnCost } is the
total cost of all non-demand monitors, which is indeed the
cost of the solution.  Care is needed when grouping not to
inadvertently disconnect monitors from the solution, since
then their costs will not be counted, or to connect them via
multiple paths, since then their costs will be counted
multiple times.  It is usually best to make a new group monitor
a child of the solution immediately:
@ID @C {
gm = KheGroupMonitorMake(soln, sub_tag, sub_tag_label);
KheGroupMonitorAddChildMonitor((KHE_GROUP_MONITOR) soln,
  (KHE_MONITOR) gm);
}
And when deleting a group monitor, the best option may be
helper function
@ID @C {
void KheGroupMonitorBypassAndDelete(KHE_GROUP_MONITOR gm);
}
It calls @C { KheGroupMonitorDelete }, but first it makes @C { gm }'s
children into children of @C { gm }'s parents, if any, thus keeping
them linked in.  There is also
@ID @C {
void KheSolnBypassAndDeleteAllGroupMonitors(KHE_SOLN soln);
}
which applies @C { KheGroupMonitorBypassAndDelete } to every
group monitor of @C { soln }.
@PP
Functions
@ID @C {
int KheGroupMonitorChildMonitorCount(KHE_GROUP_MONITOR gm);
KHE_MONITOR KheGroupMonitorChildMonitor(KHE_GROUP_MONITOR gm, int i);
}
visit the child monitors of group monitor @C { gm } in the
usual way.  If @C { gm } is the solution object, these
versions of the functions allow the user to avoid the upcast:
@ID @C {
int KheSolnChildMonitorCount(KHE_SOLN soln);
KHE_MONITOR KheSolnChildMonitor(KHE_SOLN soln, int i);
}
Functions
@ID @C {
int KheMonitorParentMonitorCount(KHE_MONITOR m);
KHE_GROUP_MONITOR KheMonitorParentMonitor(KHE_MONITOR m, int i);
}
visit the parent monitors of @C { m }.  There is also
@ID @C {
bool KheMonitorDescendant(KHE_MONITOR m1, KHE_MONITOR m2);
}
which returns @C { true } if @C { m1 } is a descendant of @C { m2 },
including when the two are equal, and
@ID @C {
void KheMonitorParentMonitorsSort(KHE_MONITOR m);
}
which sorts the parent monitors of @C { m } so that traversal using
@C { KheMonitorParentMonitorCount } and @C { KheMonitorParentMonitor }
visits them in order of increasing solution index.  And
@ID @C {
void KheGroupMonitorDebug(KHE_GROUP_MONITOR gm,
  int verbosity, int indent, FILE *fp);
}
is like @C { KheMonitorDebug }, only specific to this type of monitor.
When C { verbosity } is 2 or more, it prints the child monitors and
checks that their total cost is equal to the group monitor's cost,
aborting if not.
@PP
A group monitor has the usual attach and detach operations, but they do
nothing substantial; in particular, they do not change its cost.  They
just mark the monitor as attached or detached.  Perhaps they should
attach and detach it from its children, but they don't.
@End @SubSection

@SubSection
    @Title { Defects }
    @Tag { monitoring.group.defects }
@Begin
@LP
Informally, a defect is a specific problem with a solution.
In KHE, the word has a formal meaning as well:  a @I defect
is a monitor whose cost is non-zero.
@PP
It can be helpful to target defects directly, rather than wasting
time changing parts of the solution where there are no defects.
This is especially the case near the end of the solve process, when
there may be thousands of monitors but only a handful of defects.
To support this, KHE offers fast access to those child monitors of
a group monitor which are defects:
@ID @C {
int KheGroupMonitorDefectCount(KHE_GROUP_MONITOR gm);
KHE_MONITOR KheGroupMonitorDefect(KHE_GROUP_MONITOR gm, int i);
}
When a monitor's cost changes from zero to non-zero, the monitor is
added to its parents' defect lists; and when its cost changes from
non-zero to zero it is removed.  This takes a negligible amount of time.
# @PP
# The defects could appear in any order.  Function
# @ID @C {
# void KheGroupMonitorDefectSort(KHE_GROUP_MONITOR gm, bool diversify);
# }
# sorts the defects by decreasing cost, allowing the worst defects
# to be targeted first.  The order is @I not kept up to date as the
# solution changes and defects are added and removed.  If @C { diversify }
# is @C { true }, ties in cost are broken differently depending on the
# monitor's solution's diversifier.
# @PP
When the group monitor is the solution there are convenience
versions:
@ID @C {
int KheSolnDefectCount(KHE_SOLN soln);
KHE_MONITOR KheSolnDefect(KHE_SOLN soln, int i);
}
# void KheSolnDefectSort(KHE_SOLN soln);
# void KheSolnDefectDiversifySort(KHE_SOLN soln);
There is also
@ID @C {
void KheGroupMonitorDefectDebug(KHE_GROUP_MONITOR gm,
  int verbosity, int indent, FILE *fp);
}
which is like @C { KheGroupMonitorDebug } applied to @C { gm }, except
that it prints only defective children, and
@ID @C {
void KheGroupMonitorDefectTypeDebug(KHE_GROUP_MONITOR gm,
  KHE_MONITOR_TAG tag, int verbosity, int indent, FILE *fp);
}
which is like @C { KheGroupMonitorDefectDebug } except that it
prints only children of type @C { tag }.
@PP
If a solution is changed and then changed back again to its original
state, its cost returns to its original value, but there are two ways
in which its defects can be different.  First, they may appear in a
different order.  Second, although the number of defects which are
demand monitors (Chapter {@NumberOf matchings}) must return to its
original value, the demand monitors that make up that number may
change.  This is because there are many maximum matchings in general,
and KHE does not guarantee to find any particular one of them.
@PP
In practice, one wants to traverse a list of defects and try to
repair them.  Quite commonly, an attempt to repair a defect will
remove it temporarily and then reinstate it if the repair was not
successful.  This will cause the defect to be shifted to the end
of the defect list.  A simple traversal of the defects from first
to last will visit some defects more than once, and others not
at all.  To handle this problem, it is necessary to make a copy
of the defects and traverse the copy.  Although every defect
will have non-zero cost at the time it is copied, as the list
is traversed, after the solution changes or if the list includes
demand monitors, one cannot assume that every monitor on the copy
list will have non-zero cost.
# KHE offers functions
# @ID @C {
# void KheGroupMonitorCopyDefects(KHE_GROUP_MONITOR gm);
# int KheGroupMonitorDefectCopyCount(KHE_GROUP_MONITOR gm);
# KHE_MONITOR KheGroupMonitorDefectCopy(KHE_GROUP_MONITOR gm, int i);
# }
# plus convenience versions of them for solutions:
# @ID @C {
# void KheSolnCopyDefects(KHE_SOLN soln);
# int KheSolnDefectCopyCount(KHE_SOLN soln);
# KHE_MONITOR KheSolnDefectCopy(KHE_SOLN soln, int i);
# }
# The first function makes a private copy of the list of defects (it
# does not copy the monitors, just the list), and the second and third
# traverse this copied list.  This list does not change until the next
# call to @C { KheGroupMonitorCopyDefects(gm) }, so the problems with
# traversing a changing list are removed.  On the other hand, after the
# solution changes or if the list includes demand monitors, one cannot
# assume that every monitor on the copy list will have non-zero cost.
# @PP
# When a solution is copied, @C { KheGroupMonitorDefectCopyCount } will
# be 0 for every group monitor of the copy, whatever it was in the
# original.  It is not safe to copy a defect copy list, since it could
# contain group monitors which have been deleted since it was used.
@PP
To find the total cost of all monitors of a given type in
the descendants of @C { gm }, call
@ID @C {
KHE_COST KheGroupMonitorCostByType(KHE_GROUP_MONITOR gm,
  KHE_MONITOR_TAG tag, int *defect_count);
}
It returns the number of defects, in @C { *defect_count }, as well
as the cost.  It traverses the whole sub-dag of monitors of @C { gm }
(actually, just the defects), so it is slow:  it is intended for
reporting, not for solving.  It returns @C { 0 } when @C { tag }
is @C { KHE_GROUP_MONITOR_TAG }, because it attributes cost to
the monitors that originally generated it.  Version
@ID @C {
KHE_COST KheSolnCostByType(KHE_SOLN soln, KHE_MONITOR_TAG tag,
  int *defect_count);
}
may be called when the group monitor is the solution object.
The values returned by these functions are displayed in a
convenient tabular form by functions
@ID @C {
void KheGroupMonitorCostByTypeDebug(KHE_GROUP_MONITOR gm,
  int verbosity, int indent, FILE *fp);
void KheSolnCostByTypeDebug(KHE_SOLN soln,
  int verbosity, int indent, FILE *fp);
}
which print one line for each kind of monitor under
@C { gm } or @C { soln } for which there are defects.
@End @SubSection

@SubSection
    @Title { Tracing }
    @Tag { monitoring.group.tracing }
@Begin
@LP
Sometimes a solver needs to know which monitors have experienced
a change in cost recently.  Ejection chain solvers, for example,
need this information, and @I { monitor tracing } provides it.
@PP
Tracing involves objects of type @C { KHE_TRACE }.  To create one, call
@ID @C {
KHE_TRACE KheTraceMake(KHE_GROUP_MONITOR gm);
}
where @C { gm } is the group monitor to be traced.  The solution may
be traced by upcasting it:
@ID @C {
t = KheTraceMake((KHE_GROUP_MONITOR) soln);
}
The group monitor that a trace object is for can be found by calling
@ID @C {
KHE_GROUP_MONITOR KheTraceGroupMonitor(KHE_TRACE t);
}
To delete a trace object, call
@ID @C {
void KheTraceDelete(KHE_TRACE t);
}
This will call @C { KheTraceEnd(t) } below if needed.  KHE keeps a
free list of trace objects in the solution object, so many trace
objects can be created and deleted at virtually no cost.
@PP
Actual tracing is initiated and ended by calling
@ID @C {
void KheTraceBegin(KHE_TRACE t);
void KheTraceEnd(KHE_TRACE t);
}
These must be called in matching pairs.  @C { KheTraceBegin } removes
any information left over from any preceding trace, and attaches
@C { t } to its group monitor so that it can record what happens.
@C { KheTraceEnd } detaches @C { t } from its group monitor.
Different trace objects may be attached and detached quite
independently of each other, even when they have the same group monitor.
@PP
After the trace ends, the following functions may be called:
@ID @C {
KHE_COST KheTraceInitCost(KHE_TRACE t);
int KheTraceMonitorCount(KHE_TRACE t);
KHE_MONITOR KheTraceMonitor(KHE_TRACE t, int i);
KHE_COST KheTraceMonitorInitCost(KHE_TRACE t, int i);
}
@C { KheTraceInitCost } returns the initial cost of @C { t }'s group
monitor (at the time the trace began); @C { KheTraceMonitorCount }
returns the number of child monitors of @C { t }'s group monitor
whose cost changed during the trace; @C { KheTraceMonitor } returns
the @C { i }th of these child monitors; and
@C { KheTraceMonitorInitCost(t, i) } returns the initial cost of
@C { KheTraceMonitor(t, i) }.  Also,
@ID @C {
KHE_COST KheTraceMonitorCostIncrease(KHE_TRACE t, int i);
}
returns
@C { KheMonitorCost(KheTraceMonitor(t, i)) - KheTraceMonitorInitCost(t, i) }.
It will be negative when the monitor's cost decreased.
@PP
The list of child monitors whose cost has changed never contains the
same monitor @C { m } twice, no matter how many times @C { m }'s cost
changes during the trace.  This is desirable, but it means that when
@C { m }'s cost changes, this list has to be searched to see if
@C { m } is already present.  So it is best to use tracing on group
monitors that group only a small number of monitors; or if a large
group monitor like the solution object is traced, to trace it for
only small sequences of operations that are not likely to change
the cost of a large number of monitors.
@PP
These functions may be called during a trace as well as after
it, returning values as though the trace had just ended.  While it
is not an error to call @C { KheGroupMonitorAddChildMonitor } or
@C { KheGroupMonitorDeleteChildMonitor } while tracing the group
monitor concerned, it is not recommended.  A solution cannot be
copied while one of its group monitors is being traced.
@PP
For the convenience of ejection chain algorithms, function
@ID @C {
void KheTraceReduceByCostIncrease(KHE_TRACE t, int max_num);
}
sorts the monitors by decreasing @C { KheTraceMonitorCostIncrease },
removes all monitors whose cost increase is zero or negative, then
keeps removing monitors from the end until at most @C { max_num }
remain.  These may be accessed with @C { KheTraceMonitorCount },
@C { KheTraceMonitor }, and @C { KheTraceMonitorInitCost } as usual.
The other monitors are gone and cannot be got back.
@PP
Finally, function
@ID @C {
void KheTraceDebug(KHE_TRACE t, int verbosity, int indent, FILE *fp);
}
prints @C { t } onto @C { fp } with the given verbosity and indent,
showing monitors whose cost changed.
@End @SubSection

@EndSubSections
@End @Section

@EndSections
@End @Chapter
