@Chapter
    @Title { NRC Instances and Solutions }
    @Tag { instances }
@Begin
An @I instance is a particular case of the nurse rostering problem,
for a particular ward and a particular period of time.  A @I { solution }
is a solution to a particular instance, saying which workers to assign
to which shifts.  This chapter describes the @C { NRC_INSTANCE } and
@C { NRC_SOLN } data types, which represents instances and solutions
as defined by the NRC model.
@BeginSections

@Section
    @Title { Overview }
    @Tag { instances.intro }
@Begin
@LP
NRC instances contain days, shifts, workers, and constraints (unlike
KHE instances, which contain times, resources, events, and constraints).
These data types are strongly interconnected, so we begin by giving
informal definitions of most of them, as an overview.
@PP
@C { NRC_INSTANCE } represents one @I instance of the nurse rostering
problem:  one case of it, for a particular hospital ward and a particular
interval of time.
@PP
@C { NRC_DAY } represents one @I { day }:  not a generic day like
`Friday', but a particular day like `Friday 18 November 2016',
although its calendar date need not be known to the instance.
@PP
@C { NRC_DAY_SET } represents one @I { day-set }, which is a set
(actually a sequence) of days.  An example of a day-set is the
@I { cycle }, containing all the days of the instance.
@PP
@C { NRC_DAY_SET_SET } represents one @I { day-set set }:  a set
(again, actually a sequence) of day-sets.  An example of a day-set
set is the one containing one day-set for each day of the week.
Its first day-set contains all the Sundays, its second contains
all the Mondays, and so on.
@PP
@C { NRC_SHIFT_TYPE } represents a @I { shift type }:  a generic
shift like the day shift or night shift.
@PP
@C { NRC_SHIFT_TYPE_SET } represents a @I { shift-type set }:  a set
of shift types.
@PP
@C { NRC_SHIFT } represents a @I { shift }, which is a particular
shift such as the night shift on 18 November 2016.  Each shift
is characterised by a day plus a shift type.
@PP
@C { NRC_SHIFT_SET } represents a @I { shift-set }:  a set of
shifts.  For example, the shifts whose day is 18 November 2016 form
a shift-set, as do the shifts whose shift type is the night shift.
@PP
@C { NRC_SHIFT_SET_SET } represents a @I { shift-set set }, which
is a set of shift-sets.
@PP
@C { NRC_WORKER } represents one @I { worker }, NRC's term for
a nurse or employee.
@PP
@C { NRC_WORKER_SET } represents one @I { worker-set }:  a set
of workers.  The leading examples of worker-sets are the sets
of workers that share a particular contract, and the sets of
workers that share a particular skill.  Indeed, contracts and
skills are represented in NRC by worker-sets.
@PP
@C { NRC_WORKER_SET_SET } represents one @I { worker-set set }:
a set of worker-sets.  For example, the set of all contracts
is a worker-set set.
@PP
@C { NRC_WORKER_SET_TREE } is a tree of worker-sets, where
children are subsets of their parents, and siblings are
disjoint.  It is used when analysing overlapping cover
requirements.
@PP
@C { NRC_DEMAND } represents one @I { demand }, describing a
demand for one worker made by a shift, including the penalty
for when a worker is not assigned, and the default penalty
to apply when a worker without the appropriate skill is assigned.
One shift may have any number of demands.
@PP
@C { NRC_DEMAND_SET } represents one @I { demand-set }, a set
of demands.  One can add a demand-set to a shift, which is the
same as adding each of its demands separately, only more convenient.
# @PP
# @C { NRC_COVER } represents one @I { cover }, describing a
# demand for workers made by a shift, including minimum, optimum,
# and maximum numbers of workers and their skills.  One shift may
# have many covers, meaning that it demands all of them.
# @PP
# @C { NRC_COVER_SET } represents one @I { cover-set }, a set
# of covers.  When a shift has a cover-set, it is the same as
# having each of its covers separately.
@PP
@C { NRC_POLARITY } is used by patterns and constraints to say
that what counts about a shift-set is whether a worker is busy
for at least one of its shifts, or free for all of them.
@PP
@C { NRC_PATTERN } represents a @I { pattern }:  a sequence of
shift-sets, each with a polarity.  A pattern may be used to define
a worker constraint which, for example, applies a penalty when the
pattern appears within a worker's timetable.
@PP
@C { NRC_CONSTRAINT } represents one @I { worker constraint }:
a rule about what a worker may do, which if broken in some
solution adds a penalty to that solution's cost.
# @C { NRC_LIMIT } and @C { NRC_LIMIT_TYPE } is used by constraints
# to say whether the constraint applies a minimum or maximum limit,
# and give its numerical value.
@PP
@C { NRC_SOLN } represents one @I { solution }:  a collection of
assignments to the demands of the shifts of one instance.
@End @Section

@Section
    @Title { Debug functions }
    @Tag { instances.debug }
@Begin
@LP
Many of NRC's entities have functions included to help with debugging.
These functions all work in the same way.  Their interface has this form:
@ID @C {
void NrcEntityDebug(NRC_ENTITY e, int indent, FILE *fp);
}
where @C { NRC_ENTITY } stands for an NRC type like @C { NRC_SHIFT },
@C { NRC_WORKER }, and so on.  This produces a debug print of @C { e }
onto file @C { fp }, which must be open for writing 8-bit characters.
@PP
If @C { indent >= 0 }, the print will be indented @C { indent }
spaces and occupy one or more complete lines (that is, it will end
with a newline).  One debug function often calls another, in which
case it adds 2 to the indent, producing a neatly formatted result.
@PP
If @C { indent < 0 }, the print will not be indented and will
contain no newlines.  It will usually be abbreviated, perhaps
by printing just the object's name rather than its contents.
@End @Section

@Section
    @Title { Instance objects }
    @Tag { instances.instances }
@Begin
@LP
This section describes instance objects:  how to create them, and
how to visit their components.  (Whenever NRC makes an object that
is part of an instance, that object is not only created and
returned to the user, it is also added to the instance.  So one
can visit every object via functions on the instance.)  Operations
for creating components appear in later sections.
@BeginSubSections

@SubSection
    @Title { Creation, metadata, and archives }
    @Tag { instances.instances.creating }
@Begin
@LP
To make a new, empty instance, start by calling
@ID {0.96 1.0} @Scale @C {
NRC_INSTANCE NrcInstanceMakeBegin(char *id, char *worker_word,
  HA_ARENA_SET as);
}
Parameter @C { id } is an identifier identifying the instance,
returned by
@ID @C {
char *NrcInstanceId(NRC_INSTANCE ins);
}
Parameter @C { worker_word } is the name to give to the single XESTT
resource type.  Good choices are @C { "Worker" }, @C { "Nurse" },
@C { "Employee" }, and so on.  This value is also used when NRC
decides to assign its own names to the workers
(Section {@NumberOf instances.workers}).  Parameter @C { as } may be
@C { NULL }, or it may be an arena set, as for @C { NrcArchiveMake };
indeed, it would almost certainly be the same arena set.
@PP
After adding all the elements of the instance, but before
adding any of its solutions, call
@ID @C {
void NrcInstanceMakeEnd(NRC_INSTANCE ins);
}
NRC will abort if this is omitted.
@PP
Functions
@ID @C {
HA_ARENA NrcInstanceArenaBegin(NRC_INSTANCE ins);
void NrcInstanceArenaEnd(NRC_INSTANCE ins, HA_ARENA a);
}
provide a convenient interface for obtaining and releasing a memory
arena, recycled through the arena set passed to @C { NrcInstanceMake }.
Consult the KHE User's Guide for more information about memory arenas,
arena sets, and memory management generally.
@PP
NRC needs to know what penalty is wanted when a worker is
assigned twice to the same shift.  The default value is
@ID @C { NrcPenalty(true, 1, NRC_COST_FUNCTION_LINEAR, ins) }
which, as Section {@NumberOf instances.constraints.penalties}
explains, makes avoiding clashes a hard constraint with weight 1.
@FootNote
{
When a constraint which limits a worker to a most one shift per
day is added, what it actually does is limit the number of times
during that day when the worker may be busy to one.  A worker who
is assigned twice to the same shift is still only busy for one
time, so NRC must generate a separate constraint, called an avoid
clashes constraint, which prevents this.  It does this without
being asked, using this penalty for the constraint's penalty.
}
If this is not correct for some reason, it can be changed,
and the value retrieved, by
@ID @C {
void NrcInstanceSetAvoidClashesPenalty(NRC_INSTANCE ins, NRC_PENALTY p);
NRC_PENALTY NrcInstanceAvoidClashesPenalty(NRC_INSTANCE ins);
}
There is also
@ID @C {
NRC_PENALTY NrcInstanceZeroPenalty(NRC_INSTANCE ins);
}
which is a convenient way to obtain a penalty with weight 0.
@PP
Instance metadata may be set and retrieved by calling
@ID @C {
void NrcInstanceSetMetaData(NRC_INSTANCE ins, char *name,
  char *contributor, char *date, char *country, char *description,
  char *remarks);
void NrcInstanceMetaData(NRC_INSTANCE ins, char **name,
  char **contributor, char **date, char **country, char **description,
  char **remarks);
}
where @C { remarks }, being optional, may be @C { NULL }.
@PP
For the convenience of functions that reorganize archives, an instance
may lie in any number of archives.  To add an instance to an archive and
delete it from an archive, call functions @C { NrcArchiveAddInstance } and
@C { NrcArchiveDeleteInstance } from Section {@NumberOf archives.archives}.
To visit the archives containing a given instance, call
@ID @C {
int NrcInstanceArchiveCount(NRC_INSTANCE ins);
NRC_ARCHIVE NrcInstanceArchive(NRC_INSTANCE ins, int i);
}
in the usual way.
@End @SubSection

@SubSection
    @Title { Day names, days, day-sets, and day-set sets }
    @Tag { instances.instances.days }
@Begin
@LP
By default, the seven days of the week have their usual English
names.  To change this, call
@ID @C {
void NrcInstanceSetDayNames(NRC_INSTANCE ins, char *short_names,
  char *long_names);
}
The first parameter contains the short names of the seven days, separated
by colons, and beginning with the name of Sunday (which is how the Unix
@C { mktime } function does it).  The second parameter is the same except
that it contains long names.  For example, the call
@ID @C {
NrcInstanceSetDayNames(ins, "Sun:Mon:Tue:Wed:Thu:Fri:Sat",
  "Sunday:Monday:Tuesday:Wednesday:Thursday:Friday:Saturday");
}
does not need to be made, because it sets the day names to
their default values.
@PP
Do not try to use @C { NrcInstanceResetDayNames } to begin the cycle on a
day of the week other than Sunday.  Setting parameter @C { first_day_index }
of @C { NrcCycleMake } (Section {@NumberOf instances.days}) to a value
other than 0 is the right way to do that.
@PP
To retrieve the day names, use
@ID @C {
int NrcInstanceDayNameCount(NRC_INSTANCE ins);
char *NrcInstanceShortDayName(NRC_INSTANCE ins, int i);
char *NrcInstanceLongDayName(NRC_INSTANCE ins, int i);
}
The first day name (the one for Sunday) has index 0, the second
(for Monday) has index 1, and so on.  @C { NrcInstanceDayNameCount }
always returns 7.
@PP
The day objects created make up a day-set called the @I { cycle }.
For visiting them, see Section {@NumberOf instances.instances.cycle}
below.  To visit all the day-sets created within an instance, including
the cycle, use
@ID @C {
int NrcInstanceDaySetCount(NRC_INSTANCE ins);
NRC_DAY_SET NrcInstanceDaySet(NRC_INSTANCE ins, int i);
}
The day-sets are numbered from 0, so the code for visiting them all is
@ID @C {
for( i = 0;  i < NrcInstanceDaySetCount(ins);  i++ )
{
  ds = NrcInstanceDaySet(ins, i);
  ... visit ds ...
}
}
This is a standard arrangement throughout NRC.  Similarly, call
@ID @C {
int NrcInstanceDaySetSetCount(NRC_INSTANCE ins);
NRC_DAY_SET_SET NrcInstanceDaySetSet(NRC_INSTANCE ins, int i);
}
to visit all the day-set sets created within @C { ins }.
@End @SubSection

@SubSection
    @Title { The cycle and the days of the week }
    @Tag { instances.instances.cycle }
@Begin
@LP
The @I cycle (the sequence of all the days of the instance) is a
day-set stored in the instance.  Once a cycle has been added, by
calling @C { NrcCycleMake } or @C { NrcCalendarCycleMake }
(Section {@NumberOf instances.days.days}), the following operations
become available.  To retrieve the entire cycle as a day-set, call
@ID @C {
NRC_DAY_SET NrcInstanceCycle(NRC_INSTANCE ins);
}
To visit the days in chronological order, call
@ID @C {
int NrcInstanceCycleDayCount(NRC_INSTANCE ins);
NRC_DAY NrcInstanceCycleDay(NRC_INSTANCE ins, int i);
}
@C { NrcInstanceCycleDayCount } returns the number of days, and
@C { NrcInstanceCycleDay } returns the @C { i }'th day.  As usual
in NRC, counting starts from 0, so the code to visit each day is
@ID @C {
for( i = 0;  i < NrcInstanceCycleDayCount(ins);  i++ )
{
  day = NrcInstanceCycleDay(ins, i);
  ... visit day ...
}
}
There is also
@ID @C {
bool NrcInstanceCycleRetrieveDay(NRC_INSTANCE ins, char *ymd,
  NRC_DAY *d);
}
which retrieves a day from the cycle by its calendar date.  If
the cycle contains a day whose year-month-day name is @C { ymd },
this function sets @C { *d } to one such day and returns @C { true };
if not, it sets  @C { *d } to @C { NULL } and returns @C { false }.
The date string must contain three non-negative integers separated
by hyphens; a copy, normalized to a four-digit year and two-digit
month and day, is used when retrieving.
@PP
At the same time a cycle is added to an instance, day-sets
representing the 7 days of the week are also added.  These are
stored in a day-set set, and may be retrieved in that form by
@ID @C {
NRC_DAY_SET_SET NrcInstanceDaysOfWeek(NRC_INSTANCE ins);
}
They may also be visited individually by calling
@ID @C {
int NrcInstanceDaysOfWeekDaySetCount(NRC_INSTANCE ins);
NRC_DAY_SET NrcInstanceDaysOfWeekDaySet(NRC_INSTANCE ins, int i);
}
@C { NrcInstanceDaysOfWeekDaySetCount } returns the number
of day-sets representing days of the week (always 7), and
@C { NrcInstanceDaysOfWeekDaySet } returns the @C { i }'th
of these day-sets, counting from 0 as usual.  There is also
@ID @C {
bool NrcInstanceDaysOfWeekRetrieveDaySet(NRC_INSTANCE ins,
  char *long_name, NRC_DAY_SET *ds);
}
which retrieves one of these day sets by long name.  Irrespective of
how the cycle was created, the first of these day-sets holds the
Sunday days, the second holds the Monday days, and so on.
@End @SubSection

@SubSection
    @Title { Shift types and shift-type sets }
    @Tag { instances.instances.shift_types }
@Begin
@LP
Functions for creating and querying shift types and shift-type sets
are given in Section {@NumberOf instances.shift_types}.  To retrieve
all the shift types of the instance as a shift-type set, call
@ID @C {
NRC_SHIFT_TYPE_SET NrcInstanceAllShiftTypes(NRC_INSTANCE ins);
}
To visit the shift types of an instance one by one, call
@ID @C {
int NrcInstanceShiftTypeCount(NRC_INSTANCE ins);
NRC_SHIFT_TYPE NrcInstanceShiftType(NRC_INSTANCE ins, int i);
}
counting from 0 in the usual way.  To retrieve a shift type by name, call
@ID @C {
bool NrcInstanceRetrieveShiftType(NRC_INSTANCE ins, char *name,
  NRC_SHIFT_TYPE *st);
}
As usual, if there is a shift type with the given name, this sets
@C { *st } to that shift type and returns @C { true }, otherwise
it sets @C { *st } to @C { NULL } and returns @C { false }.  Function
@ID @C {
bool NrcInstanceRetrieveShiftTypeByLabel(NRC_INSTANCE ins, char *label,
  NRC_SHIFT_TYPE *st);
}
is the same, except that it searches for a shift type with a
non-@C { NULL } label equal to @C { label }.
@PP
To visit the shift-type sets of an instance, call
@ID @C {
int NrcInstanceShiftTypeSetCount(NRC_INSTANCE ins);
NRC_SHIFT_TYPE_SET NrcInstanceShiftTypeSet(NRC_INSTANCE ins, int i);
}
in the usual way.  If a shift-type set has a non-@C { NULL } name,
it may be retrieved by calling
@ID @C {
bool NrcInstanceRetrieveShiftTypeSet(NRC_INSTANCE ins, char *name,
  NRC_SHIFT_TYPE_SET *sts);
}
in the usual way.
@End @SubSection

@SubSection
    @Title { Shifts, shift-sets, and shift-set sets }
    @Tag { instances.instances.shifts }
@Begin
@LP
The shifts of an instance are stored in the instance as a shift-set.  To
retrieve this shift-set call
@ID @C {
NRC_SHIFT_SET NrcInstanceAllShifts(NRC_INSTANCE ins);
}
To visit the shifts one by one, call
@ID @C {
int NrcInstanceShiftCount(NRC_INSTANCE ins);
NRC_SHIFT NrcInstanceShift(NRC_INSTANCE ins, int i);
}
as usual.  (In many cases, however, a better way to visit each shift is
to visit each day, and then visit each shift on that day.)  Also,
functions
@ID @C {
NRC_SHIFT_SET NrcInstanceDailyStartingShiftSet(NRC_INSTANCE ins);
NRC_SHIFT_SET NrcInstanceWeeklyStartingShiftSet(NRC_INSTANCE ins);
}
return the set of shifts which are first in each day, and first in
each week.  These are useful values for the @C { starting_ss }
parameter of @C { NrcConstraintMake }
(Section {@NumberOf instances.constraints.worker_constraints}).  To
visit all shift-sets, call
@ID @C {
int NrcInstanceShiftSetCount(NRC_INSTANCE ins);
NRC_SHIFT_SET NrcInstanceShiftSet(NRC_INSTANCE ins, int i);
}
and to visit all shift-set sets, call
@ID @C {
int NrcInstanceShiftSetSetCount(NRC_INSTANCE ins);
NRC_SHIFT_SET_SET NrcInstanceShiftSetSet(NRC_INSTANCE ins, int i);
}
in the usual way.  There are also
@ID @C {
NRC_SHIFT_SET_SET NrcInstanceDaysShiftSetSet(NRC_INSTANCE ins);
}
which returns a shift-set set containing one shift-set for each
day of the cycle, holding the shifts of that day, and
@ID @C {
NRC_SHIFT_SET_SET NrcInstanceShiftsShiftSetSet(NRC_INSTANCE ins);
}
which returns a shift-set set containing one shift-set for each
shift, holding that shift.
@End @SubSection

@SubSection
    @Title { Workers, worker-sets, and worker-set sets }
    @Tag { instances.instances.workers }
@Begin
@LP
Functions for creating and querying workers, worker-sets, and
worker-set sets are given in Section {@NumberOf instances.workers}.
The workers of an instance are held in a worker-set in the instance
called the @I { staffing }.  It may be retrieved by calling
@ID @C {
NRC_WORKER_SET NrcInstanceStaffing(NRC_INSTANCE ins);
}
For convenience, its elements may be visited directly by
@ID @C {
int NrcInstanceStaffingWorkerCount(NRC_INSTANCE ins);
NRC_WORKER NrcInstanceStaffingWorker(NRC_INSTANCE ins, int i);
}
There is also
@ID @C {
bool NrcInstanceStaffingRetrieveWorker(NRC_INSTANCE ins,
  char *name, NRC_WORKER *w);
}
which retrieves a worker with the given name from the staffing, setting
@C { *w } to that worker and returning @C { true } if successful, and
setting @C { *w } to @C { NULL } and returning @C { false } otherwise.
@PP
It can be convenient sometimes to have access to an empty worker set:
@ID @C {
NRC_WORKER_SET NrcInstanceEmptyWorkerSet(NRC_INSTANCE ins);
}
Adding a worker to the result of this function will cause strange errors.
@PP
To visit all the worker-sets of an instance (including the staffing), call
@ID @C {
int NrcInstanceWorkerSetCount(NRC_INSTANCE ins);
NRC_WORKER_SET NrcInstanceWorkerSet(NRC_INSTANCE ins, int i);
}
in the usual way.  There is also
@ID @C {
bool NrcInstanceRetrieveWorkerSet(NRC_INSTANCE ins, char *name,
  NRC_WORKER_SET *ws);
}
which retrieves a worker-set with the given name from the instance,
setting @C { *ws } to that worker-set and returning @C { true } if
successful, and setting @C { *ws } to @C { NULL } and returning
@C { false } otherwise.
@PP
To visit all the worker-set sets of an instance,
call
@ID @C {
int NrcInstanceWorkerSetSetCount(NRC_INSTANCE ins);
NRC_WORKER_SET_SET NrcInstanceWorkerSetSet(NRC_INSTANCE ins, int i);
}
in the usual way.
@End @SubSection

@SubSection
    @Title { Contracts and skills }
    @Tag { instances.instances.contracts }
@Begin
@LP
Several nurse rostering models offer @I { contracts }, which are
sets of constraints.  A worker can be made subject to a contract,
which means that the contract's constraints apply to that worker.
At least one model allows a worker to be subject to more than one
contract.
@PP
In NRC, a worker-set is used to model each contract.  Its name is
the name of the contract, perhaps with @C { "Contract-" } prepended,
and its members are the workers subject to the contract.  The
contract's constraints are not stored in the worker-set.  Instead,
each constraint has a worker-set attribute saying which workers it
applies to.  When there are contracts, this would be the worker-set
for the contract that the constraint lies within.  When there are no
contracts, it would be something else---the set of all workers
returned by @C { NrcInstanceStaffing } above, perhaps, or
@C { NrcWorkerSingletonWorkerSet(w) }, the worker-set containing
just worker @C { w }.
@PP
Each NRC instance holds a worker-set set called the @I { contracts },
intended to hold the set of all contracts, although what it actually
holds is up to the user.  This worker-set set is not consulted when
generating an instance; it is there only for the convenience of the
user.  (Exception:  for documentation, a KHE resource group is
generated for each contract, even if it is not used.)
@PP
To add a contract to the contracts, call
@ID @C {
void NrcInstanceContractsAddContract(NRC_INSTANCE ins,
  NRC_WORKER_SET contract_ws);
}
To retrieve the contracts as a worker-set set, call
@ID @C {
NRC_WORKER_SET_SET NrcInstanceContracts(NRC_INSTANCE ins);
}
To visit the contracts one by one, call
@ID @C {
int NrcInstanceContractsContractCount(NRC_INSTANCE ins);
NRC_WORKER_SET NrcInstanceContractsContract(NRC_INSTANCE ins, int i);
}
To retrieve a contract by name, call
@ID @C {
bool NrcInstanceContractsRetrieveContract(NRC_INSTANCE ins,
  char *name, NRC_WORKER_SET *contract_ws);
}
If the contracts contain a contract with the given name, this
sets @C { *contract_ws } to a contract with that name and
returns @C { true }, otherwise it sets @C { *contract_ws }
to @C { NULL } and returns @C { false }.
@PP
It is acceptable to define the contract at one time and add
workers to it later.  Indeed, this is what usually happens,
given that contracts are defined at one point in the source
file and workers declare their adherence to a contract at
another.
@PP
Most nurse rostering models offer @I { skills }.  A skill is some
capability that a worker has, such as being a senior nurse, or a
CPR expert.  A worker may have any number of skills.  A demand
for a worker may require that a worker with a particular skill be
assigned.  If a worker without that skill is assigned, there is
a penalty, which may vary depending on which worker is assigned.
@PP
Again, in NRC a worker-set is used to model each skill.  Its name
is the name of the skill, and its elements are the workers who have
that skill.  Each demand has an optional worker-set attribute
specifying the skill that workers satisfying that demand should have.
@PP
Each NRC instance holds a worker-set set called the @I { skills },
intended to hold the set of all skills, although what it actually
holds is up to the user.  This worker-set set is not consulted
when generating an instance; it is there only for the convenience
of the user.  (Exception:  for documentation, a KHE resource group
is generated for each skill, even if it is not used.)
@PP
Operations entirely analogous to those for the contracts
are offered for the skills:
@ID @C {
void NrcInstanceSkillsAddSkill(NRC_INSTANCE ins,
  NRC_WORKER_SET skill_ws);
NRC_WORKER_SET_SET NrcInstanceSkills(NRC_INSTANCE ins);
int NrcInstanceSkillsSkillCount(NRC_INSTANCE ins);
NRC_WORKER_SET NrcInstanceSkillsSkill(NRC_INSTANCE ins, int i);
bool NrcInstanceSkillsRetrieveSkill(NRC_INSTANCE ins,
  char *name, NRC_WORKER_SET *skill_ws);
}
The contracts and skills may well be the only worker-sets the user
needs.  There is nothing to prevent a worker from lying within two
or more contracts, or two or more skills.  Indeed, this is quite
normal, at least for skills.
@End @SubSection

@SubSection
    @Title { Demands, demand-sets, patterns, and constraints }
    # @Title { Covers, cover-sets, patterns, and constraints }
    @Tag { instances.instances.constraints }
@Begin
@LP
Functions for creating and querying demands, demand-sets, patterns, pattern
sets, and constraints are given in Section {@NumberOf instances.constraints}.
All these objects are stored in the instance.  Demands may be visited by
@ID @C {
int NrcInstanceDemandCount(NRC_INSTANCE ins);
NRC_DEMAND NrcInstanceDemand(NRC_INSTANCE ins, int i);
}
and demand-sets may be visited by
@ID @C {
int NrcInstanceDemandSetCount(NRC_INSTANCE ins);
NRC_DEMAND_SET NrcInstanceDemandSet(NRC_INSTANCE ins, int i);
}
in the usual way.  Patterns may be visited by
# Functions for creating and querying covers, cover-sets, patterns, and
# constraints are given in Section {@NumberOf instances.constraints}.
# All these objects are stored in the instance.  Covers may be visited by
# @ID @C {
# int NrcInstanceCoverCount(NRC_INSTANCE ins);
# NRC_COVER NrcInstanceCover(NRC_INSTANCE ins, int i);
# }
# and cover-sets may be visited by
# @ID @C {
# int NrcInstanceCoverSetCount(NRC_INSTANCE ins);
# NRC_COVER_SET NrcInstanceSetCover(NRC_INSTANCE ins, int i);
# }
# in the usual way.  Patterns may be visited by
@ID @C {
int NrcInstancePatternCount(NRC_INSTANCE ins);
NRC_PATTERN NrcInstancePattern(NRC_INSTANCE ins, int i);
}
in the usual way, and patterns with a non-@C { NULL } name may be
retrieved by calling
@ID @C {
bool NrcInstanceRetrievePattern(NRC_INSTANCE ins, char *name,
  NRC_PATTERN *p);
}
The stored patterns are not used privately by NRC; in particular, they
do not become unwanted unless they are added to worker constraints.
Pattern sets are may be visited by
@ID @C {
int NrcInstancePatternSetCount(NRC_INSTANCE ins);
NRC_PATTERN_SET NrcInstancePatternSet(NRC_INSTANCE ins, int i);
}
Pattern sets have no names so there is no retrieve operation.
@PP
Demand constraints and worker constraints are stored in the instance,
and may be visited by
@ID @C {
int NrcInstanceDemandConstraintCount(NRC_INSTANCE ins);
NRC_DEMAND_CONSTRAINT NrcInstanceDemandConstraint(NRC_INSTANCE ins,
  int i);
}
and 
@ID @C {
int NrcInstanceConstraintCount(NRC_INSTANCE ins);
NRC_CONSTRAINT NrcInstanceConstraint(NRC_INSTANCE ins, int i);
}
in the usual way.
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Days }
    @Tag { instances.days }
@Begin
@LP
In informal discourse, a day could be a specific day, such as 23
July 2016, or it could be a day of the week, such as Friday.  In
NRC and this documentation, the term @I { day } always refers to
a specific day, represented by an object of type @C { NRC_DAY }.
@BeginSubSections

@SubSection
    @Title { The cycle and the days of the week }
    @Tag { instances.days.cycle }
@Begin
@LP
There is no NRC function for creating one day.  Instead, there
is a function for creating the @I { cycle }, the set of all
days of an instance:
@ID @C {
void NrcCycleMake(NRC_INSTANCE ins, int day_count, int first_day_index);
}
@C { NrcCycleMake } adds to @C { ins } a cycle of @C { day_count } days.
Parameter @C { first_day_index } says which day of the week the first
day is on:  0 means that the first day is a Sunday, 1 means that the
first day is a Monday, and so on.
@PP
Although the days created by @C { NrcCycleMake } are specific
days, they are not associated with calendar dates.  To get days
with calendar dates, call @C { NrcCalendarCycleMake } instead:
@ID @C {
bool NrcCalendarCycleMake(NRC_INSTANCE ins,
  char *start_ymd, char *end_ymd, char **err_str);
}
@C { NrcCalendarCycleMake } creates a cycle with first day
@C { start_ymd } and last day @C { end_ymd }, where the two strings
are given in @C { YYYY-MM-DD } format.  (Actually, the format is
just three non-negative integers separated by hyphens; but the
dates actually stored are normalized to the format shown.)  The Unix
@C { mktime } function is used to find out which day of the week
@C { start_ymd } is on, and other important facts such as the number
of days in each month.  The two days are arbitrary except that there
must be at least one day in the cycle.  Value @C { true } is returned
if successful; otherwise @C { false } is returned and @C { err_str }
is set to an error message explaining what went wrong.  This will be
some problem with @C { start_ymd } or @C { end_ymd }, such as being
formatted wrongly or specifying a non-existent date.
@PP
@C { NrcCycleMake } and @C { NrcCalendarCycleMake } may only be
called after the last call to @C { NrcShiftTypeMake }
(Section {@NumberOf instances.shifts.shift_types}).  A call to
@C { NrcShiftTypeMake } after the cycle is made will cause NRConv
to exit with an error message.
@End @SubSection

@SubSection
    @Title { Days }
    @Tag { instances.days.days }
@Begin
@LP
A @I { day } in NRC is an object of type @C { NRC_DAY } representing
a specific day, such as Monday 21 November 2016, although the calendar
date of the day need not be known.
@PP
There is no function for creating an individual day.  Instead, functions
@C { NrcCycleMake } and @C { NrcCalendarCycleMake }
(Section {@NumberOf instances.days.cycle}) are called, to make all the days
at once.  The days created by these functions can be accessed using
functions @C { NrcInstanceCycleDayCount } and @C { NrcInstanceCycleDay }
(Section {@NumberOf instances.instances.cycle}).
@PP
The basic attributes of a day may be found by calling
@ID @C {
NRC_INSTANCE NrcDayInstance(NRC_DAY d);
char *NrcDayYMD(NRC_DAY d);
char *NrcDayShortName(NRC_DAY d);
char *NrcDayLongName(NRC_DAY d);
}
@C { NrcDayInstance } returns the enclosing instance.  @C { NrcDayYMD }
returns the date of day @C { d } in @C { YYYY-MM-DD } format if the day
was created by @C { NrcCalendarCycleMake }, or @C { "-" } otherwise.
@C { NrcDayShortName } and @C { NrcDayLongName } return the name of the
day in either short and long form, consisting of a week number followed
by a short or long day name as defined by @C { NrcInstanceSetDayNames }
(Section {@NumberOf instances.instances.days}).  For example, @C { 1Mon }
is the short name of the day which represents the Monday of the first
week of the cycle.
@PP
Several functions return integer indexes defining the position
of the day in the cycle:
@ID @C {
int NrcDayIndexInCycle(NRC_DAY d);
int NrcDayWeekInCycle(NRC_DAY d);
int NrcDayIndexInWeek(NRC_DAY d);
}
@C { NrcDayIndexInCycle } returns the index of @C { d } in the cycle:
@C { 0 } for the first day, 1 for the second, and so on.
@C { NrcDayWeekInCycle } returns the number of the week that @C { d }
lies in.  The first 7 days of the cycle have week number 1, the second
7 days have week number 2, and so on, irrespective of the day of the week
the cycle begins on.  @C { NrcDayIndexInWeek } returns the index of
@C { d }'s day of the week:  0 for Sunday, 1 for Monday, and so on
(which is how the Unix @C { mktime } function does it).  NRC does
not have an @C { NRC_WEEK } data type.
@PP
Functions
@ID @C {
NRC_DAY NrcDayPrev(NRC_DAY d);
NRC_DAY NrcDayNext(NRC_DAY d);
}
return the day preceding @C { d } in the cycle, or @C { NULL } when
@C { d } is the first day, and the day following @C { d } in the
cycle, or @C { NULL } when @C { d } is the last day.
@PP
A surprisingly useful function is
@ID @C {
NRC_DAY_SET NrcDayDayOfWeek(NRC_DAY d);
}
which returns @C { d }'s day of the week.  NRC does not have a data type
for day of the week.  Instead, a day of the week is represented by an
@C { NRC_DAY_SET } object holding a set of days---all the days that
fall on the same day of the week.  The day set objects returned by
@C { NrcDayDayOfWeek } are created by @C { NrcCycleMake } and
@C { NrcCalendarCycleMake } while they are creating the days; the
user does not need to create them.  Another function that returns
a day-set is
@ID @C {
NRC_DAY_SET NrcDaySingletonDaySet(NRC_DAY d);
}
The result is a a day-set containing just @C { d }.
@PP
Function
@ID @C {
NRC_SHIFT_SET NrcDayShiftSet(NRC_DAY d);
}
returns a shift-set containing the shifts of @C { d }.  There is one of
these for each shift type, in the order that the shift types were added
to the instance.  For convenience,
@ID @C {
int NrcDayShiftCount(NRC_DAY d);
NRC_SHIFT NrcDayShift(NRC_DAY d, int i);
}
can be used to visit this shift-set's shifts directly.  Function
@ID @C {
NRC_SHIFT NrcDayShiftFromShiftType(NRC_DAY d, NRC_SHIFT_TYPE st);
}
returns the shift with day @C { d } and type @C { st }, i.e.
@C { NrcDayShift(d, NrcShiftTypeIndex(st)) }, and
@ID @C {
NRC_SHIFT_SET NrcDayShiftSetFromShiftTypeSet(NRC_DAY d,
  NRC_SHIFT_TYPE_SET sts);
}
does this for each element of @C { sts }, producing a shift-set.
There is also
@ID @C {
NRC_SHIFT_SET_SET NrcDayShiftSetSet(NRC_DAY d);
}
which returns a shift-set set containing one shift-set for each
shift on day @C { d }, namely the singleton shift-set holding that
shift.
@PP
To produce a debug print of day @C { d }, call
@ID @C {
void NrcDayDebug(NRC_DAY d, int indent, FILE *fp);
}
This works as explained in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Day-sets }
    @Tag { instances.days.day_sets }
@Begin
@LP
A @I { day-set } is a set (more precisely, a sequence) of days.
Although any days can make up a day-set, the most likely
combinations are adjacent days (for example, the days of a
weekend) and days that share the same day of the week
(for example, the set of all Mondays in the cycle).
@PP
@C { NrcCycleMake } and @C { NrcCalendarCycleMake }
make day-sets:  one holding the cycle as a whole, and one for each
of the seven days of the week (the day-set of all Mondays, the
day-set of all Tuesdays, and so on).  Day-sets can also be created
by the user, by calling
@ID @C {
NRC_DAY_SET NrcDaySetMake(NRC_INSTANCE ins, char *short_name,
  char *long_name);
void NrcDaySetAddDay(NRC_DAY_SET ds, NRC_DAY d);
}
in the usual way.  Both names must be non-@C { NULL }.  Functions
@ID @C {
NRC_INSTANCE NrcDaySetInstance(NRC_DAY_SET ds);
char *NrcDaySetShortName(NRC_DAY_SET ds);
char *NrcDaySetLongName(NRC_DAY_SET ds);
}
return the attributes of day-set @C { ds }, functions
@ID @C {
int NrcDaySetDayCount(NRC_DAY_SET ds);
NRC_DAY NrcDaySetDay(NRC_DAY_SET ds, int i);
}
visit the days in the order they were inserted,
@ID @C {
bool NrcDaySetContainsDay(NRC_DAY_SET ds, NRC_DAY d);
}
returns @C { true } when @C { ds } contains @C { d }, and
@ID @C {
bool NrcDaySetRetrieveDay(NRC_DAY_SET ds, char *ymd, NRC_DAY *d);
}
retrieves a day from @C { ds } by its @C { ymd } value.  The
date string must contain three non-negative integers separated
by hyphens; a copy, normalized to a four-digit year and two-digit
month and day, is used when retrieving.
Function
@ID @C {
bool NrcDaySetsOverlap(NRC_DAY_SET ds1, NRC_DAY_SET ds2);
}
returns @C { true } when @C { ds1 } and @C { ds2 } have a non-empty
intersection.  And
@ID @C {
NRC_DAY_SET NrcDaySetDifference(NRC_DAY_SET ds1, NRC_DAY_SET ds2);
}
returns a new day-set containing the days of @C { ds1 } that
are not in @C { ds2 }.
@PP
Function
@ID @C {
NRC_SHIFT_SET NrcDaySetShiftSet(NRC_DAY_SET ds);
}
returns a shift-set containing all the shifts on all the days
of @C { ds }, while
@ID @C {
NRC_SHIFT_SET NrcDaySetStartingShiftSet(NRC_DAY_SET ds);
}
returns a shift-set containing the first shift on each day of
@C { ds }.  This helps when constructing suitable values for the
@C { starting_ss } parameter of @C { NrcConstraintMake }
(Section {@NumberOf instances.constraints.worker_constraints}).
If any of the shift-sets of the days of @C { ds } is empty,
@C { NrcDaySetStartingShiftSet } aborts.  Also,
@ID @C {
NRC_SHIFT_SET_SET NrcDaySetShiftSetSet(NRC_DAY_SET ds);
}
returns a shift-set set containing one shift-set for each day of
@C { ds }, holding that day's shifts.  And
@ID @C {
NRC_SHIFT_SET NrcDaySetShiftSetFromShiftTypeSet(NRC_DAY_SET ds,
  NRC_SHIFT_TYPE_SET sts);
}
returns a shift-set containing all shifts whose day
is in @C { ds } and whose shift type is in @C { sts }.
@PP
Function
@ID @C {
void NrcDaySetDebug(NRC_DAY_SET ds, int indent, FILE *fp);
}
produces a debug print of @C { ds } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Day-set sets }
    @Tag { instances.days.day_set_sets }
@Begin
@LP
A @I { day-set set } is a set (more precisely, a sequence) of
day-sets.  For example, @C { 1Sat } is a day, @C { {1Sat, 1Sun} }
is a day-set representing one weekend, and
@ID @C { {{1Sat, 1Sun}, {2Sat, 2Sun}, {3Sat, 3Sun}, {4Sat, 4Sun}} }
is a day-set set representing (possibly) the set of all weekends
in the cycle.
@PP
To create a day-set set and add day-sets to it, the functions are
@ID @C {
NRC_DAY_SET_SET NrcDaySetSetMake(NRC_INSTANCE ins, char *short_name,
  char *long_name);
void NrcDaySetSetAddDaySet(NRC_DAY_SET_SET dss, NRC_DAY_SET ds);
}
Functions
@ID @C {
NRC_INSTANCE NrcDaySetSetInstance(NRC_DAY_SET_SET dss);
char *NrcDaySetSetShortName(NRC_DAY_SET_SET dss);
char *NrcDaySetSetLongName(NRC_DAY_SET_SET dss);
}
return the attributes of a day-set set, and
@ID @C {
int NrcDaySetSetDaySetCount(NRC_DAY_SET_SET dss);
NRC_DAY_SET NrcDaySetSetDaySet(NRC_DAY_SET_SET dss, int i);
bool NrcDaySetSetRetrieveDaySet(NRC_DAY_SET_SET dss,
  char *long_name, NRC_DAY_SET *ds);
}
are used to visit the day-sets of a day-set set in the order
they were inserted, and to retrieve a day-set from a day-set
set by long name.  And
@ID @C {
void NrcDaySetSetDebug(NRC_DAY_SET_SET dss, int indent, FILE *fp);
}
produces a debug print of @C { dss } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Time intervals }
    @Tag { instances.time_intervals }
@Begin
@LP
A @I { time interval } is an interval of time, consisting of a
start time and an end time, measured in seconds since midnight.
These are not absolute intervals like `10am to 11am on 7 April
2007', but rather generic ones, like `10am to 11am'.
@PP
As is common in nurse rostering, an end time may be smaller
than a start time, meaning that the interval spans midnight.
Strictly speaking, then, what is representable is a time
interval that starts at any time of day and ends less than
24 hours later, on the same day or the following day.
@PP
Before considering operations on time intervals proper, here are two
more basic functions.  The first converts a string in @C { HH:MM:SS }
or @C { HH:MM } format into an integer number of seconds:
@ID @C {
bool NrcHMSToSecs(char *hms, int *res);
}
It returns @C { true } and sets @C { *res } to the number of seconds
if successful, and returns @C { false } and sets @C { *res } to @C { -1 }
if not successful (because @C { hms } has a format problem).  The
second function,
@ID @C {
char *NrcSecsToHMS(int secs, HA_ARENA a);
}
converts an integer number of seconds to a string in @C { HH:MM:SS }
format stored in arena @C { a }.
@PP
To create a time interval, call
@ID @C {
NRC_TIME_INTERVAL NrcTimeIntervalMake(int start_secs, int end_secs,
  NRC_INSTANCE ins);
}
The new object will be stored in the arena of @C { ins } and deleted
when the instance is deleted.  There are @C { 24 * 60 * 60 } seconds
in a day, so @C { start_secs } and @C { end_secs } must satisfy
@ID @C {
0 <= start_secs < 24 * 60 * 60
0 < end_secs <= 24 * 60 * 60
}
Disallowing @C { start_secs == 24 * 60 * 60 } and @C { end_secs == 0 }
ensures that there is only one way to represent any non-empty interval,
including intervals that start or end at midnight.
@PP
Function
@ID @C {
bool NrcTimeIntervalMakeFromHMS(char *start_hms, char *end_hms,
  NRC_TIME_INTERVAL *res, NRC_INSTANCE ins);
}
converts @C { start_hms } and @C { end_hms } using @C { NrcHMSToSecs }
above, and makes a time interval from them, returning @C { true } and
setting @C { *res } to it if successful, and returning @C { false }
and setting @C { *res } to @C { NULL } if unsuccessful, because
@C { start_hms } or @C { end_hms } has a format problem or is out of
range.  As occurs in instances, @C { end_hms } may be @C { 00:00:00 },
which is taken to mean @C { 24:00:00 }.
@PP
The two basic queries are
@ID @C {
int NrcTimeIntervalStartSecs(NRC_TIME_INTERVAL ti);
int NrcTimeIntervalEndSecs(NRC_TIME_INTERVAL ti);
}
There are also set operations on time intervals:
@ID {0.95 1.0} @Scale @C {
bool NrcTimeIntervalEqual(NRC_TIME_INTERVAL ti1, NRC_TIME_INTERVAL ti2);
bool NrcTimeIntervalDisjoint(NRC_TIME_INTERVAL ti1, NRC_TIME_INTERVAL ti2);
bool NrcTimeIntervalSubset(NRC_TIME_INTERVAL ti1, NRC_TIME_INTERVAL ti2);
}
These return @C { true } when @C { ti1 } and @C { ti2 } are equal, or
disjoint, or when @C { ti1 } is a subset of @C { ti2 }.  These operations
consider intervals to be @I { open }, that is, to not include their
endpoints.  So when one interval's end time equals another's start
time, the two intervals are disjoint.  They also understand what it
means when @C { end_secs < start_secs }, and act accordingly.  Function
@ID @C {
NRC_SHIFT_SET NrcTimeIntervalShiftSet(NRC_TIME_INTERVAL ti, NRC_DAY d);
}
returns a shift-set containing those shifts which have time intervals
which intersect with (are not disjoint with) time interval @C { ti }
on day @C { d }.  The shifts of the result do not necessarily all
come from day @C { d }; some may come from the previous day if they
span midnight and there is a previous day, while others may come from
the next day if @C { ti } spans midnight and there is a next day.
Finally,
@ID @C {
char *NrcTimeIntervalShow(NRC_TIME_INTERVAL ti, HA_ARENA a);
}
returns a string, stored in arena @C { a }, representing time
interval @C { ti }.
@End @Section

@Section
    @Title { Shift types }
    @Tag { instances.shift_types }
@Begin
@LP
In informal discourse, a shift could be a specific shift, such as
the night shift on 23 July 2016, or it could be a generic shift,
such as the night shift.  In NRC, a generic shift is called a
@I { shift type }, and a specific shift is called a @I { shift }.
There is one shift of each shift type on each day.
@BeginSubSections

@SubSection
    @Title { Shift types }
    @Tag { instances.shifts.shift_types }
@Begin
@LP
A @I { shift type } is a generic shift, such as `the day shift'
or `the night shift'.  To make one, call
@ID @C {
NRC_SHIFT_TYPE NrcShiftTypeMake(NRC_INSTANCE ins, char *name,
  int workload);
}
This creates a new shift type object with the given name and workload,
adds it to @C { ins }, and returns it.  The workload is a value in
arbitrary units (for example, in minutes), describing how much work
a shift of this type is.  It is only needed when there are worker
constraints that limit total workload.  When it is not needed,
@C { NRC_NO_WORKLOAD } (a synonym for @C { 1 }) should be passed.
@PP
Some shift types have a label as well as a name.  Function
@ID @C {
void NrcShiftTypeUseLabelInEventName(NRC_SHIFT_TYPE st, char *label);
}
adds a label to @C { st } and ensures that it is used in event names.
@PP
To retrieve the attributes of a shift type, call
@ID @C {
NRC_INSTANCE NrcShiftTypeInstance(NRC_SHIFT_TYPE st);
char *NrcShiftTypeName(NRC_SHIFT_TYPE st);
char *NrcShiftTypeLabel(NRC_SHIFT_TYPE st);
int NrcShiftTypeWorkload(NRC_SHIFT_TYPE st);
int NrcShiftTypeIndex(NRC_SHIFT_TYPE st);
}
@C { NrcShiftTypeLabel } returns @C { NULL }
if @C { NrcShiftTypeUseLabelInEventName } has not been called on
@C { st }.  @C { NrcShiftTypeIndex } returns @C { st }'s index in the
instance (0 for the first shift type added, 1 for the second, and so on).
There is also
@ID @C {
NRC_SHIFT_TYPE_SET NrcShiftTypeSingletonShiftTypeSet(NRC_SHIFT_TYPE st);
}
which returns a shift-type set containing just @C { st }.
@PP
Two functions give access to the shifts of type @C { st }:
@ID @C {
NRC_SHIFT_SET NrcShiftTypeShiftSet(NRC_SHIFT_TYPE st);
NRC_SHIFT_SET_SET NrcShiftTypeShiftSetSet(NRC_SHIFT_TYPE st);
}
@C { NrcShiftTypeShiftSet } returns a shift-set containing all shifts
which have @C { st } for their shift type, in increasing day order.
@C { NrcShiftTypeShiftSetSet } is similar, except that each shift
lies in its own singleton shift set.
@PP
There is no @C { NrcShiftTypeDebug } function, because a shift
type is essentially just its name.  Use @C { NrcShiftTypeName }
instead.
@PP
There is one shift for each shift type on each day.  Shift types must
be added before days.  Later, when days are added, by @C { NrcCycleMake }
or @C { NrcCalendarCycleMake } (Section {@NumberOf instances.days}),
one shift of each type is added to each day.
@PP
#There is at least one instance (@C { COI-QMC-1 }) containing a
#special shift type such that assigning that shift means the same
#as not assigning a shift at all:  it means the resource is free.
#This is not a desirable way to do things, so NRC offers
#@ID @C {
#void NrcShiftTypeSetMeansTimeOff(NRC_SHIFT_TYPE st, bool val);
#bool NrcShiftTypeMeansTimeOff(NRC_SHIFT_TYPE st);
#}
#to set and retrieve a `means time off' attribute in @C { st }.
#Its default value is @C { false }.  Setting it to @C { true }
#informs NRC that this shift type really means time off.  Then the
#converted instance will not contain times or shifts corresponding
#to this shift type, but the conversion will still be exact.
#@PP
#In principle, the conversion of instances containing `means time
#off' shift types should abort in certain cases.  For example, when
#the instance contains constraints that place limits on the number
#of time-off shifts, clearly these cannot be converted when the
#distinction between assigning a time off shift and not assigning
#a shift at all is lost.  But these cases are not all handled
#correctly at present, because, owing to lack of interest, the
#author has only implemented the minimum required to convert
#instance @C { COI-QMC-1 } correctly.
#@PP
A shift type may optionally contain a time interval.  It is not used
by NRC, but it may be useful to the user.  The operations for setting
and retrieving it are
@ID {0.96 1.0} @Scale @C {
void NrcShiftTypeAddTimeInterval(NRC_SHIFT_TYPE st, NRC_TIME_INTERVAL ti);
NRC_TIME_INTERVAL NrcShiftTypeTimeInterval(NRC_SHIFT_TYPE st);
}
@C { NrcShiftTypeTimeInterval } returns @C { NULL } when @C { st }'s
time interval has not been set.
# @PP
# Shift types may optionally contain start and end times.  These
# are stored as integer numbers of seconds since midnight, so
# we first provide functions that convert between these integer
# seconds and seconds represented by strings in @C { HH:MM:SS }
# format.  Function
# @ID @C {
# bool NrcHMSToSecs(char *hms, int *res);
# }
# converts string @C { hms } in @C { HH:MM:SS } (or @C { HH:MM })
# format to seconds, returning @C { true } and setting @C { *res }
# to the number of seconds if successful, and returning @C { false }
# if not successful (because @C { hms } has a format problem).  Conversely,
# @ID @C {
# char *NrcSecsToHMS(int secs);
# }
# converts an integer number of seconds to a string in @C { HH:MM:SS }
# format stored in heap memory.
# @PP
# To add start and end times to a shift type, call
# @ID @C {
# void NrcShiftTypeAddStartAndEndTimes(NRC_SHIFT_TYPE st,
#   int start_secs, int end_secs);
# }
# Here @C { start_secs > end_secs } is permitted and means that the
# interval spans midnight.  To retrieve these values, call
# @ID @C {
# int NrcShiftTypeStartSecs(NRC_SHIFT_TYPE st);
# int NrcShiftTypeEndSecs(NRC_SHIFT_TYPE st);
# }
# These will return @C { -1 } when start and end times have not been
# added.  There is also
# @ID @C {
# bool NrcShiftTypeIntersects(NRC_SHIFT_TYPE st,
#   int start_secs, int end_secs);
# }
# which returns @C { true } when the time interval during which
# @C { st } is running (excluding its endpoints) has a non-empty
# intersection with the time interval delimited by @C { start_secs }
# and @C { end_secs } (again excluding the endpoints).  As usual,
# @C { start_secs > end_secs } is permitted and means that the
# interval spans midnight.
@PP
The author hesitated over whether to include shift types, since a
shift-set with the name of the shift type does most of what a shift
type does.  However, to construct that shift-set one needs some way to
identify what is common to its shifts---a name, presumably; but then
that is the name of a shift type, not of a shift.  More importantly,
with shift types available, NRC can make the individual shifts itself,
and guarantee a uniform structure of one shift of each type on each
day.  This uniformity matters, for example, when implementing patterns.
If some of these shifts do not need to be covered on some days (for
example, if the early shift does not need to be staffed on Sundays),
one can just add no demands to those shifts.
@End @SubSection

@SubSection
    @Title { Shift-type sets }
    @Tag { instances.shifts.shift_type_sets }
@Begin
@LP
A @I { shift-type set } is a set of shift types.  It is created
in the usual way:
@ID {0.95 1.0} @Scale @C {
NRC_SHIFT_TYPE_SET NrcShiftTypeSetMake(NRC_INSTANCE ins, char *name);
void NrcShiftTypeSetAddShiftType(NRC_SHIFT_TYPE_SET sts, NRC_SHIFT_TYPE st);
}
The name is optional (may be @C { NULL }).  Its attributes are returned by
@ID @C {
NRC_INSTANCE NrcShiftTypeSetInstance(NRC_SHIFT_TYPE_SET sts);
char *NrcShiftTypeSetName(NRC_SHIFT_TYPE_SET sts);
}
and its shift types are visited by
@ID @C {
int NrcShiftTypeSetShiftTypeCount(NRC_SHIFT_TYPE_SET sts);
NRC_SHIFT_TYPE NrcShiftTypeSetShiftType(NRC_SHIFT_TYPE_SET sts, int i);
}
There are also
@ID @C {
bool NrcShiftTypeSetContainsShiftType(NRC_SHIFT_TYPE_SET sts,
  NRC_SHIFT_TYPE st);
}
which returns @C { true } when @C { sts } contains @C { st },
@ID @C {
bool NrcShiftTypeSetEqual(NRC_SHIFT_TYPE_SET sts1,
  NRC_SHIFT_TYPE_SET sts2);
}
which returns @C { true } when @C { sts1 } and @C { sts2 } contain the
same shift types, and
@ID @C {
bool NrcShiftTypeSetDisjoint(NRC_SHIFT_TYPE_SET sts1,
  NRC_SHIFT_TYPE_SET sts2);
}
which returns @C { true } when they are disjoint.  Finally,
@ID @C {
NRC_SHIFT_TYPE_SET NrcShiftTypeSetMerge(NRC_SHIFT_TYPE_SET sts1,
  NRC_SHIFT_TYPE_SET sts2);
}
returns a new shift-type set containing the set union of @C { sts1 }
and @C { sts2 }.  Shift-type sets are mainly used when constructing
patterns (Section {@NumberOf instances.constraints.patterns}).
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Shifts }
    @Tag { instances.shifts }
@Begin
# NRC, the term @I shift refers to a specific shift, defined by a name
# and a day.  If a shift type is needed, # (in patterns, for example),
# it may be represented by the set of all shifts with a particular name.
# In informal discourse, a shift could be a specific shift, such as
# the night shift on 23 July 2016, or it could be a generic shift,
# such as the night shift.  In NRC and this documentation, a
# generic shift is called a @I { shift type }; the term @I shift
# refers to a specific shift, defined by a shift type and a day.
# @PP
# It is fair to ask whether shift types are needed:  why not just
# have shifts?  The answer is that if there is no logical connection
# between two night shifts, say, on different days, then the concept
# of a @I pattern of shifts (Section {@NumberOf instances.patterns})
# makes no sense.  This connection is made by shift types.
@BeginSubSections

@SubSection
    @Title { Shifts }
    @Tag { instances.shifts.shifts }
@Begin
@LP
There are no functions for creating individual shifts.  Instead,
NRC automatically creates one shift, of type @C { NRC_SHIFT },
for each shift type on each day.  These shifts can be accessed as
elements of the shift-sets returned by @C { NrcShiftTypeShiftSet }
and @C { NrcDayShiftSet }, or using @C { NrcInstanceShiftCount }
and @C { NrcInstanceShift }.
@PP
To retrieve the basic attributes of a shift, call
@ID @C {
NRC_INSTANCE NrcShiftInstance(NRC_SHIFT s);
NRC_DAY NrcShiftDay(NRC_SHIFT s);
NRC_SHIFT_TYPE NrcShiftType(NRC_SHIFT s);
}
The shift's index in the list of all shifts held by the instance is
@ID @C {
int NrcShiftIndex(NRC_SHIFT s);
}
This is equal to the shift's day's index multiplied by the
number of shift types, plus the shift's shift type's index.
In other words, as indexes increase we run through the shifts
of the first day in shift type order, then the shifts of the
second day, and so on.
@PP
Function
@ID @C {
char *NrcShiftName(NRC_SHIFT s);
}
returns the name that @C { s } will have in the converted instance,
based on the day and shift type.
@PP
There is also
@ID @C {
NRC_SHIFT_SET NrcShiftSingletonShiftSet(NRC_SHIFT s);
}
which returns a shift-set containing just @C { s }.
@PP
A shift has an optional workload, measured in arbitrary units, for
example minutes:
@ID @C {
int NrcShiftWorkload(NRC_SHIFT s);
}
The workload of a shift is the workload of its
shift type, and this cannot be changed.
# To set the workload of a shift and retrieve it, call
# @ID @C {
# void NrcShiftSetWorkload(NRC_SHIFT s, int workload);
# int NrcShiftWorkload(NRC_SHIFT s);
# }
@PP
To add a demand (Section {@NumberOf instances.constraints.demands})
to a shift, specifying that a worker, optionally with a certain skill,
needs to be assigned to that shift, call
@ID @C {
void NrcShiftAddDemand(NRC_SHIFT s, NRC_DEMAND d);
}
Any number of demands may be added in this way; their total number
is the total number of workers demanded by the shift.  There are
also the convenience functions
@ID {0.96 1.0} @Scale @C {
void NrcShiftAddDemandMulti(NRC_SHIFT s, NRC_DEMAND d, int multiplicity);
void NrcShiftAddDemandSet(NRC_SHIFT s, NRC_DEMAND_SET ds);
}
@C { NrcShiftAddDemandMulti } adds @C { d } to @C { s }
@C { multiplicity } times, while @C { NrcShiftAddDemandSet } adds
the demands of @C { ds } individually to @C { s }.  The fact that
these demands arrived in a group is not remembered.  To visit the
demands of shift @C { s }, call
@ID @C {
int NrcShiftDemandCount(NRC_SHIFT s);
NRC_DEMAND NrcShiftDemand(NRC_SHIFT s, int i);
}
as usual.  Demands are immutable objects and
may be shared by several shifts, and added to the same shift several
times, when several workers with the same characteristics are wanted.
In fact, behind the scenes NRC forces you to share demands:  the
demand object returned by @C { NrcDemandMake } is only new when
there is no existing demand with the same attributes.  This helps
to reduce the size of the generated XESTT file, as it turns out.
@PP
Workers can be preassigned to shifts by calling
@ID @C {
void NrcShiftAddPreassignment(NRC_SHIFT s, NRC_WORKER w);
}
To visit these preassignments, call
@ID @C {
int NrcShiftPreassignmentCount(NRC_SHIFT s);
NRC_WORKER NrcShiftPreassignment(NRC_SHIFT s, int i);
}
as usual.  This works in simple cases, but be warned that the
implementation is rough and ready.  At present there is no way to
indicate that the preassigned worker should fill a particular role or
satisfy the demand for a particular skill.  And if the preassignments
cannot all be included in the XESTT event which is the result of
converting the shift, NRC aborts with an error message.
# @PP
# To add a cover (Section {@NumberOf instances.constraints.covers})
# to a shift, specifying that a certain number of workers with a
# certain skill need to be assigned to that shift, call
# @ID @C {
# void NrcShiftAddCover(NRC_SHIFT s, NRC_COVER c);
# }
# Any number of covers may be added in this way, and visited by
# @ID @C {
# int NrcShiftCoverCount(NRC_SHIFT s);
# NRC_COVER NrcShiftCover(NRC_SHIFT s, int i);
# }
# as usual.  Entire cover-sets may be added by calling
# @ID @C {
# void NrcShiftAddCoverSet(NRC_SHIFT s, NRC_COVER cs);
# }
# and visited by
# @ID @C {
# int NrcShiftCoverSetCount(NRC_SHIFT s);
# NRC_COVER_SET NrcShiftCoverSet(NRC_SHIFT s, int i);
# }
# The workers requested by a shift are all of the workers in all of
# the shift's covers and cover-sets, independently of each other.
# Covers and cover-sets may be shared by several shifts, and indeed
# it is advantageous to share them, because it reduces the size of
# the generated file.
@PP
Function
@ID @C {
void NrcShiftDebug(NRC_SHIFT s, int indent, FILE *fp);
}
produces a debug print of @C { s } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Shift-sets }
    @Tag { instances.shifts.shift_sets }
@Begin
@LP
A shift-set is a set of shifts.  To make a shift-set, use
@ID @C {
NRC_SHIFT_SET NrcShiftSetMake(NRC_INSTANCE ins, char *name);
void NrcShiftSetAddShift(NRC_SHIFT_SET ss, NRC_SHIFT s);
}
as usual; or to add the shifts of another shift-set @C { ss2 }
to shift-set @C { ss } all at once, call
@ID @C {
void NrcShiftSetAddShiftSet(NRC_SHIFT_SET ss, NRC_SHIFT_SET ss2);
}
To retrieve the attributes, call
@ID @C {
NRC_INSTANCE NrcShiftSetInstance(NRC_SHIFT_SET ss);
char *NrcShiftSetName(NRC_SHIFT_SET ss);
int NrcShiftSetShiftCount(NRC_SHIFT_SET ss);
NRC_SHIFT NrcShiftSetShift(NRC_SHIFT_SET ss, int i);
}
There is also
@ID @C {
bool NrcShiftSetContainsShift(NRC_SHIFT_SET ss, NRC_SHIFT s);
}
which returns @C { true } when @C { ss } contains @C { s }.
@PP
Function
@ID @C {
bool NrcShiftSetUniform(NRC_SHIFT_SET ss, int *offset);
}
returns @C { true } when @C { ss } is uniform:  when successive shifts
are the same distance apart.  A shift set containing the shifts of one
day is uniform, but so is a shift set containing the first shift on
each day.  If the shift set is uniform, @C { *offset } is set to the
gap between successive shifts.
@PP
A different kind of uniformity is tested by
@ID {0.95 1.0} @Scale @C {
bool NrcShiftSetsUniform(NRC_SHIFT_SET ss1, NRC_SHIFT_SET ss2, int *offset);
}
Here @C { ss1 } and @C { ss2 } do not have to be uniform in
the previous sense.  Instead, @C { ss2 } has to be equal to
@C { ss1 } except shifted by @C { *offset }.  Finally,
@ID @C {
bool NrcShiftSetsEqual(NRC_SHIFT_SET ss1, NRC_SHIFT_SET ss2);
}
is a conventional equality test, equivalent to uniformity with
an offset of 0.
@PP
The shifts of a shift-set may be arbitrary, but often they will be all
the shifts of a particular day, or all the shifts with a particular shift
type.  These shift-sets are constructed automatically by NRC, and are
obtained by calling @C { NrcDayShiftSet } and @C { NrcShiftTypeShiftSet }.
@PP
Function
@ID @C {
void NrcShiftSetDebug(NRC_SHIFT_SET ss, int indent, FILE *fp);
}
produces a debug print of @C { ss } onto @C { fp } with the given indent,
as described in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Shift-set sets }
    @Tag { instances.shifts.shift_set_sets }
@Begin
@LP
A shift-set set is a set of shift-sets.  To make a shift-set set,
call
@ID @C {
NRC_SHIFT_SET_SET NrcShiftSetSetMake(char *name);
void NrcShiftSetSetAddShiftSet(NRC_SHIFT_SET_SET sss, NRC_SHIFT_SET ss);
}
To retrieve the name and the shift-sets, call
@ID @C {
char *NrcShiftSetSetName(NRC_SHIFT_SET_SET sss);
int NrcShiftSetSetShiftSetCount(NRC_SHIFT_SET_SET sss);
NRC_SHIFT_SET NrcShiftSetSetShiftSet(NRC_SHIFT_SET_SET sss, int i);
}
in the usual way.
@PP
Function
@ID @C {
NRC_SHIFT_SET NrcShiftSetSetStartingShiftSet(NRC_SHIFT_SET_SET sss);
}
returns a shift-set containing the first shift from each shift-set
of @C { sss }.  This helps when constructing values for the
@C { starting_ss } parameter of @C { NrcConstraintMake }
(Section {@NumberOf instances.constraints.worker_constraints}).
If any of the shift-sets of @C { sss } is empty,
@C { NrcShiftSetSetStartingShiftSet } aborts.
Function
@ID @C {
void NrcShiftSetSetDebug(NRC_SHIFT_SET_SET sss, int indent, FILE *fp);
}
produces a debug print of @C { sss } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Workers }
    @Tag { instances.workers }
@Begin
@LP
A @I worker is one person capable of filling shifts.  The term
`worker' has been preferred to `nurse' because it is more general,
and to `employee' because it is shorter.
@BeginSubSections

@SubSection
    @Title { Workers }
    @Tag { instances.workers.workers }
@Begin
@LP
To create a worker with a given name, call
@ID @C {
NRC_WORKER NrcWorkerMake(NRC_INSTANCE ins, char *name);
}
The new object is added to @C { ins } and returned.  The basic
attributes may be retrieved by
@ID @C {
NRC_INSTANCE NrcWorkerInstance(NRC_WORKER w);
char *NrcWorkerName(NRC_WORKER w);
}
as usual.  There is also
@ID @C {
char *NrcWorkerConvertedName(NRC_WORKER w);
}
This returns the name that will be used to identify @C { w } in
the converted instances and solutions.  This could be just
@C { NrcWorkerName(w) }, but it could also be the value of the
@C { worker_word } parameter of @C { NrcInstanceMake } followed
by a number, if NRC decides that @C { NrcWorkerName(w) } is not
suitable as it stands (if it begins with a digit, or is very long).
@PP
The author would have preferred to omit this function.  But sometimes
one wants to create an entity with the name of worker @C { w } as
part of its name, and then @C { NrcWorkerConvertedName(w) } is best,
not @C { NrcWorkerName(w) }, since NRC does not convert the names of
other entities.
@PP
Function
@ID @C {
int NrcWorkerIndex(NRC_WORKER w);
}
which returns the index of @C { w } in the instance (the number
of previously created workers), and
@ID @C {
NRC_WORKER_SET NrcWorkerSingletonWorkerSet(NRC_WORKER w);
}
which returns a worker-set (Section {@NumberOf instances.workers.worker_sets})
containing just @C { w }.
# @PP
# In some models, when a worker without the appropriate skill is assigned to
# a shift, the penalty (Section {@NumberOf instances.constraints.penalties})
# varies with the worker.  In those cases, call function
# @ID @C {
# void NrcWorkerAddSkillPenalty(NRC_WORKER w, NRC_PENALTY p);
# }
# to add this penalty to worker @C { w }.  This may be done at most once
# per worker.  Function
# @ID @C {
# NRC_PENALTY NrcWorkerSkillPenalty(NRC_WORKER w);
# }
# returns this penalty, or @C { NULL } if @C { NrcWorkerAddSkillPenalty }
# has not been called for @C { w }.
@PP
To say that a worker wants a particular shift, shift-set, or day off, call
@ID {0.95 1.0} @Scale @C {
extern void NrcWorkerAddShiftOff(NRC_WORKER w, NRC_SHIFT s, NRC_PENALTY p);
extern void NrcWorkerAddShiftSetOff(NRC_WORKER w, NRC_SHIFT_SET ss,
  NRC_PENALTY p);
extern void NrcWorkerAddDayOff(NRC_WORKER w, NRC_DAY d, NRC_PENALTY p);
}
Requesting a shift-set or day off means requesting that no shift of
that shift-set or day be assigned.  The @C { p } parameters give the
penalty for failing to satisfy the request.  These penalties may
differ from one request to another, even for the same worker.
Similarly, to say that a worker wants a particular shift, shift-set, or
day on, call
@ID {0.95 1.0} @Scale @C {
void NrcWorkerAddShiftOn(NRC_WORKER w, NRC_SHIFT s, NRC_PENALTY p);
void NrcWorkerAddShiftSetOn(NRC_WORKER w, NRC_SHIFT_SET ss, NRC_PENALTY p);
void NrcWorkerAddDayOn(NRC_WORKER w, NRC_DAY d, NRC_PENALTY p);
}
Requesting a shift-set or day on means requesting that some shift of that
shift-set or day be assigned, without caring which.  By calling
@C { NrcShiftAddPreassignment } (Section {@NumberOf instances.shifts.shifts}),
a resource may also be preassigned to a shift---essentially an
unbreakable shift-on request.  Also,
@ID @C {
void NrcWorkerAddStartDay(NRC_WORKER w, NRC_DAY d, NRC_PENALTY p);
void NrcWorkerAddEndDay(NRC_WORKER w, NRC_DAY d, NRC_PENALTY p);
}
say that @C { w } is only available starting at day @C { d }, or ending
at day @C { d }.  The given penalties apply to every assignment before
the start day or after the end day.
@PP
# NRC divides history into @I { short-term history }, concerned with what
# the worker did in the days immediately before the current instance begins,
# and @I { long-term history }, concerned with what the worker did
# over preceding weeks or months.
# so for short-term history NRC offers something more general:
# @ID @C {
# void NrcWorkerAddHistoryPattern(NRC_WORKER w, NRC_PATTERN p);
# bool NrcWorkerRetrieveHistoryPattern(NRC_WORKER w, NRC_PATTERN *p);
# }
# The pattern (Section {@NumberOf instances.constraints.patterns})
# represents what the worker did for @M { K } days, where @M { K }
# is the length of the pattern, immediately before the current instance
# begins.  An exact timetable can be represented, by pattern elements
# with one member each; or something less specific can be represented,
# by more flexible pattern elements.
# @PP
# Long-term history amounts to a set of totals.  The leading model has
# two:  the total number of shifts, and the total number of weekends,
# worked in previous weeks.  NRC offers functions
# In the author's opinion, the
# right way to include history, at least recent history, is to give the
# timetable of the worker for the week, or several weeks, preceding the
# current instance.  This does not cause efficiency problems when an
# incremental solve platform is used (one which evaluates constraints
# only when something directly relevant changes, as in KHE).  However,
# the leading model that includes history does not do it this way, and
# in any case it may not suit longer-term history.
Some models include @I { history }:  information about what a worker
did before the current instance began.  NRC offers these two functions
for handling a worker's history:
@ID @C {
void NrcWorkerAddHistory(NRC_WORKER w, char *name, int value);
bool NrcWorkerRetrieveHistory(NRC_WORKER w, char *name, int *value);
}
@C { NrcWorkerAddHistory } associates @C { value } with @C { name }
within @C { w }, and @C { NrcWorkerRetrieveHistory } sets @C { *value }
to the value associated with @C { name } within @C { w }, or returns
@C { false } if there is no value associated with @C { name }.  For
example,
@ID @C {
NrcWorkerAddHistory(w, "WeekendsWorked", 10);
}
says that @C { w } has worked 10 weekends before the current
instance begins.
@PP
NRC does not understand what the names mean or use history itself; it
simply stores it so that the user can retrieve it later when generating
constraints (Section {@NumberOf instances.constraints.history}).
@PP
Although only integer values may be stored, it is easy to get
around this.  For example, the leading model which includes
history mainly uses integers, but it does include one shift type.
This may be stored as the index of the shift type in the instance.
# instead, other functions which generate constraints can be
# passed the same name, informing NRC that those constraints
# need to take that history total into account.
# @PP
# Workers have some other, optional attributes, needed to support
# various properties of existing source models.  These include
# penalties for assignment without the required skill, a history of
# recent assignments from before the start of the current instance,
# and time-off and time-on requests.  These are described as they arise.
@PP
Function
@ID @C {
void NrcWorkerDebug(NRC_WORKER w, int indent, FILE *fp);
}
produces a debug print of @C { w } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Worker-sets }
    @Tag { instances.workers.worker_sets }
@Begin
@LP
A worker-set is a set of workers.  To create a new, empty
worker-set, call
@ID @C {
NRC_WORKER_SET NrcWorkerSetMake(NRC_INSTANCE ins, char *name);
}
where @C { name } is a unique name for the worker-set (it may
not be @C { NULL }).  To retrieve these two attributes, call
@ID @C {
NRC_INSTANCE NrcWorkerSetInstance(NRC_WORKER_SET ws);
char *NrcWorkerSetName(NRC_WORKER_SET ws);
}
To add a worker to a worker-set, call
@ID @C {
void NrcWorkerSetAddWorker(NRC_WORKER_SET ws, NRC_WORKER w);
}
A worker-set may contain any number of workers, and a worker
may lie in any number of worker-sets.  There is also
@ID @C {
void NrcWorkerSetAddWorkerSet(NRC_WORKER_SET ws1, NRC_WORKER_SET ws2);
}
which adds the workers of @C { ws2 } to @C { ws1 }.
@PP
To visit the workers of a worker-set, call
@ID @C {
int NrcWorkerSetWorkerCount(NRC_WORKER_SET ws);
NRC_WORKER NrcWorkerSetWorker(NRC_WORKER_SET ws, int i);
}
with the first worker having index 0 as usual.  However, the
workers are not stored in the order they are added; they are
stored in order of increasing @C { NrcWorkerIndex }.  This is
done to facilitate comparisons between worker sets to see whether
they have the same workers.  There is also
@ID @C {
bool NrcWorkerSetContainsWorker(NRC_WORKER_SET ws, NRC_WORKER w);
}
This returns @C { true } when @C { ws } contains @C { w }.  And there
is also
@ID @C {
bool NrcWorkerSetRetrieveWorker(NRC_WORKER_SET ws, char *name,
  NRC_WORKER *w);
}
If @C { ws } contains a worker with the given name, it sets @C { *w }
to one such worker and returns @C { true }.  Otherwise it sets
@C { *w } to @C { NULL } and returns @C { false }.
@PP
There is nothing to prevent the same worker from being added
twice.  Function
@ID @C {
bool NrcWorkerSetHasNoDuplicates(NRC_WORKER_SET ws);
}
returns @C { true } when this has not occurred in @C { ws }.
@PP
Functions
@ID @C {
bool NrcWorkerSetEqual(NRC_WORKER_SET ws1, NRC_WORKER_SET ws2);
bool NrcWorkerSetDisjoint(NRC_WORKER_SET ws1, NRC_WORKER_SET ws2);
bool NrcWorkerSetSubset(NRC_WORKER_SET ws1, NRC_WORKER_SET ws2);
}
return @C { true } when @C { ws1 }'s set of workers is equal to
@C { ws2 }'s (the name, and the order in which the workers were
added, may differ), when @C { ws1 } and @C { ws2 } have no workers
in common, and when every worker in @C { ws1 } is also in @C { ws2 }.
@PP
In principle, NRC should offer the usual set operations on worker
sets.  At present, only one is implemented:
@ID @C {
NRC_WORKER_SET NrcWorkerSetComplement(NRC_WORKER_SET ws);
}
It returns a worker set containing the workers not in @C { ws }.
Care is needed because this function uses a particular convention
for naming these worker sets, which is to add a `@C { ! }' at the
start of the name of the uncomplemented set (the `complement name').
Here are the details.
@PP
If @C { ws } contains all workers, the result is
@C { NrcInstanceEmptyWorkerSet(ins) }.  And if @C { ws }
is empty, then the result is @C { NrcInstanceStaffing(ins) }.  In
these cases names do not matter.
@PP
If the name of @C { ws } does not begin with `@C { ! }', then
@C { NrcWorkerSetComplement } tries to retrieve a worker set
with the complement name from the instance.  If it succeeds,
it assumes that this is the complement and returns it.  If
it fails, it builds the complement worker-set worker by worker
and adds it, with the complement name, to the instance.
@PP
If the name of @C { ws } begins with `@C { ! }', then
@C { NrcWorkerSetComplement } tries to retrieve a worker set
with the same name minus the `@C { ! }' from the instance.
If it fails, it aborts.  Otherwise it assumes that this
is the complement and returns it.
@PP
Function
@ID @C {
void NrcWorkerSetDebug(NRC_WORKER_SET ws, int indent, FILE *fp);
}
produces a debug print of @C { ws } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@PP
NRC will abort if an attempt is made to create two worker-sets
with the same name.  Most worker-sets represent skills and
contracts (Section {@NumberOf instances.instances.workers}),
and name clashes are easily avoided there.  The result of
@C { NrcWorkerSingletonWorkerSet(w) } is created the first
time it is called for; its name is @C { w }'s name.  NRC
also creates its own worker-sets, one with name @C { "RG:All" }
holding all workers, and others to do with penalizing the assignment
of workers to shifts they are not qualified for.  These last have
obscure names that do not clash with each other and are unlikely
to clash with others.  In short, you can forget about worker-set
name clashes until you get one.
@PP
Worker-sets have a useful property:  they can be used (passed to
worker constraints, for example) before workers are added to them.
This applies to all worker-sets:  the staffing worker-set (holding
all workers), contract and skill worker-sets, whatever.  As long
as the workers are added eventually, before @C { NrcArchiveWrite },
everything works; but see Section {@NumberOf source.comp2} for a caveat.
@End @SubSection

@SubSection
    @Title { Worker-set sets }
    @Tag { instances.workers.worker_set_sets }
@Begin
@LP
A @I { worker-set set } is a set of worker-sets.  To define
one, call functions
@ID {0.95 1.0} @Scale @C {
NRC_WORKER_SET_SET NrcWorkerSetSetMake(NRC_INSTANCE ins);
NRC_INSTANCE NrcWorkerSetSetInstance(NRC_WORKER_SET_SET wss);
void NrcWorkerSetSetAddWorkerSet(NRC_WORKER_SET_SET wss, NRC_WORKER_SET ws);
}
in the usual way.  To visit the elements of a worker-set set, call functions
@ID @C {
int NrcWorkerSetSetWorkerSetCount(NRC_WORKER_SET_SET wss);
NRC_WORKER_SET NrcWorkerSetSetWorkerSet(NRC_WORKER_SET_SET wss, int i);
}
The first element has index 0 as usual.  There is also
@ID @C {
bool NrcWorkerSetSetRetrieveWorkerSet(NRC_WORKER_SET_SET wss,
  char *name, NRC_WORKER_SET *ws);
}
If @C { wss } contains a worker-set with the given name, this function
sets @C { *ws } to that worker-set and returns @C { true }.  Otherwise
it sets @C { *ws } to @C { NULL } and returns @C { false }.  Function
@ID @C {
void NrcWorkerSetSetDebug(NRC_WORKER_SET_SET wss, int indent, FILE *fp);
}
produces a debug print of @C { wss } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Worker-set trees }
    @Tag { instances.workers.worker_set_trees }
@Begin
@LP
A @I { worker-set tree } is a tree whose nodes are sets of worker-sets
from a common instance @C { ins }, subject to the following conditions:
@BulletList

@LI {
The worker-sets that share any given node contain the same
workers;
}

@LI {
The root of the tree contains @C { NrcInstanceStaffing(ins) },
the set of all workers;
}

@LI {
The worker-sets of a node are subsets of the worker-sets of its
parent, if any;
}

@LI {
The worker-sets of sibling nodes are disjoint.
}

@EndList
This structure turns out to be useful when disentangling cover
requirements for overlapping skills, although the preferred
approach at present is to leave them entangled and use limit
resources constraints.  To create a worker-set tree, call
@ID @C {
NRC_WORKER_SET_TREE NrcWorkerSetTreeMake(NRC_INSTANCE ins);
}
The result has one node, containing one worker-set:
@C { NrcInstanceStaffing(ins) }.  To add a worker-set to a tree, call
@ID @C {
bool NrcWorkerSetTreeAddWorkerSet(NRC_WORKER_SET_TREE wst,
  NRC_WORKER_SET ws, NRC_WORKER_SET *incompatible_ws);
}
This will search @C { wst } for the unique appropriate place to
insert @C { ws }, returning @C { true } and inserting @C { ws }
there if that place exists, and returning @C { false } and not
inserting @C { ws } otherwise.  In the latter case, @C {
*incompatible_ws } is set to an incompatible worker-set, one
which prevents insertion of @C { ws } because @C { ws } and
@C { *incompatible_ws } are not disjoint, and nor is either
a subset of the other.
#@PP
#To free a worker-set tree, call
#@ID @C {
#void NrcWorkerSetTreeFree(NRC_WORKER_SET_TREE wst);
#}
#This does not free the worker-sets, just the tree nodes.
@PP
To visit the worker-sets stored in the root of worker-set tree
@C { wst }, call
@ID @C {
int NrcWorkerSetTreeRootWorkerSetCount(NRC_WORKER_SET_TREE wst);
NRC_WORKER_SET NrcWorkerSetTreeRootWorkerSet(NRC_WORKER_SET_TREE wst,
  int i);
}
as usual.  To visit the children of @C { wst }, call
@ID @C {
int NrcWorkerSetTreeChildCount(NRC_WORKER_SET_TREE wst);
NRC_WORKER_SET_TREE NrcWorkerSetTreeChild(NRC_WORKER_SET_TREE wst,
  int i);
}
in the usual way.  The tree lies in its instance's arena and will
be freed when its instance is freed.  Finally,
@ID {0.95 1.0} @Scale @C {
void NrcWorkerSetTreeDebug(NRC_WORKER_SET_TREE wst, int indent, FILE *fp);
}
produces a debug print of @C { wst } onto @C { fp } with the given indent.
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Constraints }
    @Tag { instances.constraints }
@Begin
@LP
A @I { constraint } is a rule which constrains a solution.  If the rule
is violated by some solution, a cost is added to the solution's cost.
The cost of a solution is the total cost of all constraint violations.
@PP
A constraint may be @I { hard }, meaning that any cost is added to a
total called the @I { hard cost }, or @I { soft }, meaning that it
is added to a total called the @I { soft cost }.  So the cost of a
solution is actually this pair of values.  A solution with non-zero
hard cost is often considered infeasible.
@PP
In nurse rostering there are  two kinds of constraints:
@I { demand constraints } (often called @I { cover constraints }),
which specify the numbers and skills of workers needed by shifts,
and @I { worker constraints }, which give rules that the timetables
of individual workers must follow:  a limit on the number of shifts
worked, no morning shift on the day after a night shift, and so on.
Both kinds are described in this section, although in the NRC model
they are not closely related.
@BeginSubSections

@SubSection
    @Title { Penalties and costs }
    @Tag { instances.constraints.penalties }
@Begin
@LP
The cost of a violation of a constraint is a function of two
things:  the @I { degree of violation } of the constraint,
also called the @I { deviation }, and the @I { penalty }
associated with the constraint.
@PP
Most constraints are not simply violated or not; rather, they are
violated to some degree.  For example, if some constraint requires
worker @C { Smith } to work at most 18 shifts, the degree of violation
is the amount by which the number of shifts @C { Smith } works exceeds
18, or 0 if it does not.  The degree of violation is always a
non-negative integer.
@PP
The @I { penalty } is a triple of values:  @C { hard }, a Boolean
value which is @C { true } when the constraint is hard, and
@C { false } when it is soft (in NRC, every constraint can be
hard or soft); @C { weight }, a non-negative integer; and
@C { cost_fn }, a value of type
@ID @C {
typedef enum {
  NRC_COST_FUNCTION_STEP,
  NRC_COST_FUNCTION_LINEAR,
  NRC_COST_FUNCTION_QUADRATIC
} NRC_COST_FUNCTION;
}
Let the degree of violation (a non-negative number) be @M { x }.
When @M { x = 0 }, the cost is @M { 0 }.  When @M { x > 0 }, the cost
depends on the cost function.  When @C { cost_fn } is
@C { NRC_COST_FUNCTION_STEP } it is @M { w }, the penalty weight.
When @C { cost_fn } is @C { NRC_COST_FUNCTION_LINEAR } (the usual
value) the cost is @M { wx }.  When @C { cost_fn } is
@C { NRC_COST_FUNCTION_QUADRATIC } the cost is @M { w x sup 2 }.  This
cost is added to the total hard cost or soft cost, depending on whether
@C { hard } is @C { true } or @C { false }.
@PP
A penalty is represented by a non-@C { NULL } value of type
@C { NRC_PENALTY }.  It would ordinarily be created by a function called
@C { NrcPenaltyMake }, but a briefer name has been chosen in this case:
@ID @C {
NRC_PENALTY NrcPenalty(bool hard, int weight,
  NRC_COST_FUNCTION cost_fn, NRC_INSTANCE ins);
}
A negative @C { weight } causes @C { NrcPenalty } to abort, while if
@C { weight > 1000 }, it is silently reduced to @C { 1000 } (the largest
legal XESTT weight).  Also, if @C { weight == 0 }, @C { hard } is silently
set to @C { false } and @C { cost_fn } to @C { NRC_COST_FUNCTION_LINEAR }.
To create a penalty with weight zero, it may be easier to call
@C { NrcInstanceZeroPenalty }
(Section {@NumberOf instances.instances.creating}) than to make
a fresh one using @C { NrcPenalty }.
@PP
The attributes of a penalty may be retrieved by calls to
@ID @C {
bool NrcPenaltyHard(NRC_PENALTY p);
int NrcPenaltyWeight(NRC_PENALTY p);
NRC_COST_FUNCTION NrcPenaltyCostFn(NRC_PENALTY p);
}
as usual.  There is also
@ID @C {
bool NrcPenaltyEqual(NRC_PENALTY p1, NRC_PENALTY p2);
}
which returns @C { true } when @C { p1 } and @C { p2 } have equal
attributes, and
@ID @C {
bool NrcPenaltyLessThan(NRC_PENALTY p1, NRC_PENALTY p2);
}
which returns @C { true } when @C { p1 } is less than @C { p2 }.
@C { NrcPenaltyLessThan } is somewhat complicated.  It aborts if
@C { p1 } and @C { p2 } have different cost functions.  It returns
@C { true } when their hardnesses differ and @C { p1 }'s is soft,
and when their hardnesses are equal and @C { p1 }'s weight is less
than @C { p2 }'s.
@PP
The sum of two penalties is returned by
@ID @C {
NRC_PENALTY NrcPenaltyAdd(NRC_PENALTY p1, NRC_PENALTY p2,
  NRC_INSTANCE ins);
}
If either @C { p1 } or @C { p2 } has weight 0, @C { NrcPenaltyAdd }
returns the other.  Otherwise, if one of @C { p1 } and @C { p2 } is
hard and the other is soft, then @C { NrcPenaltyAdd } returns the hard
one.  This is arguably not exact, but the inexactness does not matter.
Otherwise, if the cost functions differ, @C { NrcPenaltyAdd }
aborts.  Otherwise, the result is a new penalty object, stored
in @C { ins }'s arena, whose hardness and cost function are
those of @C { p1 } and @C { p2 }, and whose weight is the sum
of the weights of @C { p1 } and @C { p2 }, reduced as usual to
1000 if necessary.
@PP
To help with debugging, functions
@ID @C {
char *NrcCostFnShow(NRC_COST_FUNCTION cost_fn);
char *NrcPenaltyShow(NRC_PENALTY p);
}
display a cost function or penalty as a string, for example
@C { "step" } and @C { "h10q" }.  @C { NrcPenaltyShow } begins
with @C { "h" } or @C { "s" }, follows with the weight, and
ends with @C { "s" }, @C { "q" }, or nothing, the latter meaning
@C { NRC_COST_FUNCTION_LINEAR }.
@End @SubSection

@SubSection
    @Title { Bounds }
    @Tag { instances.constraints.bounds }
@Begin
@LP
A @I { bound } is a set of integer minimum or maximum limits,
together with penalties which are to be applied when the value
of some quantity (not specified by the bound itself) falls short
of a minimum limit or exceeds a maximum limit.  Together, these
define a function which maps each non-negative value of the
quantity to a non-negative cost.
@PP
For several good reasons, bounds are not as general as they could
be.  For example, they do not implement arbitrary piecewise linear
functions.  Instead, they focus on things needed in practice.  To
create a bound which initially limits nothing (defining the zero
function), call
@ID @C {
NRC_BOUND NrcBoundMake(NRC_INSTANCE ins);
}
The instance may be retrieved by
@ID @C {
NRC_INSTANCE NrcBoundInstance(NRC_BOUND b);
}
To add a minimum, maximum, or preferred limit to a bound, call
@ID @C {
bool NrcBoundAddMin(NRC_BOUND b, int min_value, bool allow_zero,
  NRC_PENALTY below_min_penalty);
bool NrcBoundAddMax(NRC_BOUND b, int max_value,
  NRC_PENALTY above_max_penalty);
bool NrcBoundAddPreferred(NRC_BOUND b, int preferred_value,
  NRC_PENALTY below_preferred_penalty,
  NRC_PENALTY above_preferred_penalty);
}
Each of these functions can be called at most once on a given
bound @C { b }.  Each returns @C { true } when the limit is
consistent with all other limits previously added to @C { b }.
@PP
@C { NrcBoundAddMin } says that if the value @C { x } of the quantity
being limited is below @C { min_value }, then penalty
@C { below_min_penalty } applies to @C { min_value - x }.
When @C { allow_zero } is @C { true }, if @C { x } is 0,
then, as a special case, no penalty applies.
@PP
@C { NrcBoundAddMax } says that if the value @C { x } of the quantity
being limited is above @C { max_value }, then penalty
@C { above_max_penalty } applies to @C { x - max_value }.
@PP
@C { NrcBoundAddPreferred } says that if the value @C { x }
is below @C { preferred_value }, then penalty
@C { below_preferred_penalty } applies to @C { preferred_value - x },
while if it is above @C { preferred_value }, then
@C { above_preferred_penalty } applies to @C { x - preferred_value }.
@PP
When there is both a minimum value and a maximum value, @C { false }
is returned if the maximum value is less than the minimum value.
@PP
When there is both a minimum and a preferred value, @C { false }
is returned if the preferred value is smaller than the minimum value.
The preferred penalty applies from the preferred value exclusive
down to the minimum value inclusive.  This interval is empty when
the preferred value equals the minimum value.  Below the minimum
value, only the minimum penalty applies.
@PP
When there is both a maximum and a preferred value, @C { false }
is returned if the preferred value is larger than the maximum value.
The preferred penalty applies from the preferred value exclusive
up to the maximum value inclusive.  This interval is empty when
the preferred value equals the maximum value.  Above the maximum
value, only the maximum penalty applies.
@PP
A preferred limit is not just a minimum limit plus a maximum
limit; it applies with lower priority than a minimum or maximum
limit, as can be seen when its value is equal to a minimum or
maximum limit.  This is one of the good reasons why the bound
type is not more general.
@PP
There is one last rule.  When there is both a preferred limit and
a maximum limit, both penalties must be linear, and the weight of
the maximum penalty must be substantially larger than the weight
of the preferred penalty (for how much larger, see below.)  As
usual, @C { false } is returned when these conditions do not
hold.  A corresponding rule applies when there is both a preferred
limit and a minimum limit.
@PP
This rule is made because, above the maximum limit, both constraints
will be violated in XESTT, whereas in a bound, only the maximum
penalty applies.  (This is to agree with the Curtois original
instances.)  Accordingly, the weight of the maximum penalty must
be reduced by the weight of the preferred penalty, and a constant
adjustment must be added, using a constraint with a step cost
function.  The Appendix to this section has the details.
@PP
For convenience, there are also functions that make a bound
object and add one limit to it:
@ID @C {
NRC_BOUND NrcBoundMakeMin(int min_value, bool allow_zero,
  NRC_PENALTY below_min_penalty, NRC_INSTANCE ins);
NRC_BOUND NrcBoundMakeMax(int max_value,
  NRC_PENALTY above_max_penalty, NRC_INSTANCE ins);
NRC_BOUND NrcBoundMakePreferred(int preferred_value,
  NRC_PENALTY below_preferred_penalty,
  NRC_PENALTY above_preferred_penalty, NRC_INSTANCE ins);
}
The first limit cannot be inconsistent, so these functions
do not need to return a Boolean result.  Further limits may
be added as usual.  And functions
@ID @C {
bool NrcBoundMin(NRC_BOUND b, int *min_value, bool *allow_zero,
  NRC_PENALTY *below_min_penalty);
bool NrcBoundMax(NRC_BOUND b, int *max_value,
  NRC_PENALTY *above_max_penalty);
bool NrcBoundPreferred(NRC_BOUND b, int *preferred_value,
  NRC_PENALTY *below_preferred_penalty,
  NRC_PENALTY *above_preferred_penalty);
}
return @C { true } when a minimum, maximum, or preferred limit has
been added to @C { b }, setting the other parameters to its
attributes if so.  Finally, to display a bound for debugging there is
@ID @C {
char *NrcBoundShow(NRC_BOUND b);
}
The result is stored in static memory and will be overwritten by
the next call to @C { NrcBoundShow }.
@PP
@B { Appendix. }  Here is what needs to be done when there is both
a preferred limit and a maximum limit.  We assume that both penalties
are linear, and that either both are hard or both are soft.  The
desired penalty function is
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { f(x) ^= 0 } }
    B { @Math { x <= x sub 1 } }
@Rowa
    A { @Math { ^= w sub 1 (x - x sub 1 ) } }
    B { @Math { x sub 1 < x <= x sub 2 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 2 (x - x sub 2 ) } }
    B { @Math { x sub 2 < x } }
}
where @M { x sub 1 } is the preferred limit, @M { w sub 1 } is the
penalty weight for exceeding @M { x sub 1 }, @M { x sub 2 } is the
maximum limit, @M { w sub 2 } is the penalty weight for exceeding
@M { x sub 2 }, and @M { x }, @M { x sub 1 }, and @M { x sub 2 }
are integers.
@PP
We can't just use the obvious two constraints, because the cost
will be @M { w sub 1 (x - x sub 1 ) + w sub 2 (x - x sub 2 ) }
for @M { x sub 2 < x }, not @M { w sub 2 (x - x sub 2 ) }.  Our first
attempt at a fix is to reduce @M { w sub 2 } by @M { w sub 1 }
to compensate, giving
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { g sub 1 (x) ^= 0 } }
    B { @Math { x <= x sub 1 } }
@Rowa
    A { @Math { ^= w sub 1 (x - x sub 1 ) } }
    B { @Math { x sub 1 < x <= x sub 2 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 1 (x - x sub 1 ) +
                   ( w sub 2 - w sub 1 ) (x - x sub 2 ) } }
    B { @Math { x sub 2 < x } }
}
This is implementable with two constraints.  The first two parts
are correct, but the third is
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { w sub 1 (x ^- x sub 1 ) + ( w sub 2 - w sub 1 ) (x - x sub 2 )
        ^=  w sub 1 x - w sub 1 x sub 1 + w sub 2 ( x - x sub 2 )
- w sub 1 x + w sub 1 x sub 2 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 2 ( x - x sub 2 ) + w sub 1 ( x sub 2 - x sub 1 ) } }
}
which differs from the needed @M { w sub 2 ( x - x sub 2 ) } by
the constant value @M { w sub 1 ( x sub 2 - x sub 1 ) }.
@PP
A constant can be compensated for using a constraint with a step cost
function; but @M { w sub 1 ( x sub 2 - x sub 1 ) } is positive, so the
weight would need to be negative, which is not allowed.  To fix this
problem, we start the second constraint from @M { x sub 2 + 1 } rather
than @M { x sub 2 }:
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { g sub 2 (x) ^= 0 } }
    B { @Math { x <= x sub 1 } }
@Rowa
    A { @Math { ^= w sub 1 (x - x sub 1 ) } }
    B { @Math { x sub 1 < x <= x sub 2 + 1 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 1 (x - x sub 1 ) +
                   ( w sub 2 - w sub 1 ) (x - ( x sub 2 + 1 ) ) } }
    B { @Math { x sub 2 + 1 < x } }
}
Now the third part is
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { w sub 1 (x ^- x sub 1 ) +
	( w sub 2 - w sub 1 ) (x - ( x sub 2 + 1 ) )
        ^=  w sub 1 x - w sub 1 x sub 1 + w sub 2 x -
w sub 2 x sub 2 - w sub 2 - w sub 1 x + w sub 1 x sub 2 + w sub 1 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 2 ( x - x sub 2 ) +
	  w sub 1 ( x sub 2 - x sub 1 + 1 ) - w sub 2 } }
}
which gives a negative constant as desired, provided @M { w sub 2 }
is sufficiently large.  This leads to
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { g sub 3 (x) ^= 0 } }
    B { @Math { x <= x sub 1 } }
@Rowa
    A { @Math { ^= w sub 1 (x - x sub 1 ) } }
    B { @Math { x sub 1 < x <= x sub 2 + 1 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 1 (x - x sub 1 ) +
( w sub 2 - w sub 1 ) (x - ( x sub 2 + 1 ) ) +
( w sub 2 - w sub 1 ( x sub 2 - x sub 1 + 1 ) ) } }
    B { @Math { x sub 2 + 1 < x } }
}
However, there is now a problem at @M { x = x sub 2 + 1 }:  we have
@M { f( x sub 2 + 1 ) = w sub 2 ( x sub 2 + 1 - x sub 2 ) = w sub 2 },
whereas @M { g sub 3 ( x sub 2 + 1 ) }
@M { = w sub 1 ( x sub 2 + 1 - x sub 1 ) }.  But this can be fixed
by including @M { x sub 2 + 1 } in the step, giving
@ID @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { g sub 4 (x) ^= 0 } }
    B { @Math { x <= x sub 1 } }
@Rowa
    A { @Math { ^= w sub 1 (x - x sub 1 ) } }
    B { @Math { x sub 1 < x <= x sub 2 } }
@Rowa
    A { @Math { ^= w sub 1 (x - x sub 1 ) +
        ( w sub 2 - w sub 1 ( x sub 2 - x sub 1 + 1 ) ) } }
    B { @Math { x sub 2 < x <= x sub 2 + 1 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 1 (x - x sub 1 ) +
        ( w sub 2 - w sub 1 ( x sub 2 - x sub 1 + 1 ) ) +
        ( w sub 2 - w sub 1 ) (x - ( x sub 2 + 1 ) ) } }
    B { @Math { x sub 2 + 1 < x } }
}
This is implementable by three constraints:
a linear constraint with maximum limit @M { x sub 1 } and weight
@M { w sub 1 }; a step constraint with maximum limit @M { x sub 2 }
and weight @M { w sub 2 - w sub 1 ( x sub 2 - x sub 1 + 1) }; and
a linear constraint with maximum limit @M { x sub 2 + 1 } and weight
@M { w sub 2 - w sub 1 }.
@PP
As a final check, we verify that @M { g sub 4 (x) = f(x) }.  For
@M { x <= x sub 1 }, both functions are 0.  For
@M { x sub 1 < x <= x sub 2 }, both functions are
@M { w sub 1 (x - x sub 1 ) }.  For @M { x sub 2 < x <= x sub 2 + 1 },
that is, for @M { x = x sub 2 + 1 }, we have
@M { f(x) = f( x sub 2 + 1 ) = w sub 2 ( x sub 2 + 1 - x sub 2 ) = w sub 2 },
while @M { g sub 4 (x) = w sub 1 ( x sub 2 + 1 - x sub 1 ) +
        ( w sub 2 - w sub 1 ( x sub 2 - x sub 1 + 1 ) ) = w sub 2 }.
Finally, for @M { x sub 2 + 1 < x }, we have
@M { f(x) = w sub 2 ( x - x sub 2 ) }, while
@BAD
@DP
@RIAD @Math { g sub 4 (x) ^= w sub 1 (x - x sub 1 ) +
        ( w sub 2 - w sub 1 ( x sub 2 - x sub 1 + 1 ) ) +
        ( w sub 2 - w sub 1 ) (x - ( x sub 2 + 1 ) ) }
@DP
@RIAD @Math { ^= w sub 1 x - w sub 1 x sub 1 + w sub 2 -
  w sub 1 x sub 2 + w sub 1 x sub 1 - w sub 1 +
  w sub 2 ( x - x sub 2 ) - w sub 2 - w sub 1 x + w sub 1 x sub 2 + w
  sub 1 }
@DP
@RIAD @Math { ^= w sub 2 ( x - x sub 2 ) }
@DP
@EAD
So there we are.
@PP
There are a few obvious special cases.  When @M { x sub 1 = x sub 2 },
replacing @M { x sub 1 } by @M { x sub 2 } in @M { f(x) } gives
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { f(x) ^= 0 } }
    B { @Math { x <= x sub 2 } }
@Rowa
    A { @Math { ^= w sub 1 (x - x sub 2 ) } }
    B { @Math { x sub 2 < x <= x sub 2 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 2 (x - x sub 2 ) } }
    B { @Math { x sub 2 < x } }
}
The second case is empty, so this reduces to a single constraint; the
preferred limit can be ignored.  This is true for all penalty functions.
When the weight given above for the step constraint is negative,
that constraint cannot be implemented and this conversion fails.
When it is 0 the step constraint can be omitted as usual.
@PP
Essentially the same analysis applies when there is both a minimum
limit and a preferred limit.  Assume for now that @C { allow_zero }
is not requested.  The desired penalty function is
@ID @OneRow @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { f(x) ^= 0 } }
    B { @Math { x >= x sub 1 } }
@Rowa
    A { @Math { ^= w sub 1 ( x sub 1 - x ) } }
    B { @Math { x sub 1 > x >= x sub 2 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 2 ( x sub 2 - x ) } }
    B { @Math { x sub 2 > x } }
}
where @M { x sub 1 } is the preferred limit, @M { w sub 1 } is the
penalty weight for falling short of @M { x sub 1 }, @M { x sub 2 }
is the minimum limit, @M { w sub 2 } is the penalty weight for
falling short of @M { x sub 2 }, and @M { x }, @M { x sub 1 }, and
@M { x sub 2 } are integers.  Function
@ID @Tbl
   aformat { @Cell indent { align } A | @Cell | @Cell B }
   mv { 0.7vx }
{
@Rowa
    ma { 0i }
    A { @Math { h sub 4 (x) ^= 0 } }
    B { @Math { x >= x sub 1 } }
@Rowa
    A { @Math { ^= w sub 1 ( x sub 1 - x ) } }
    B { @Math { x sub 1 > x >= x sub 2 } }
@Rowa
    A { @Math { ^= w sub 1 ( x sub 1 - x ) +
        ( w sub 2 - w sub 1 ( x sub 1 - x sub 2 + 1 ) ) } }
    B { @Math { x sub 2 > x >= x sub 2 - 1 } }
@Rowa
    mb { 0i }
    A { @Math { ^= w sub 1 ( x sub 1 - x ) +
        ( w sub 2 - w sub 1 ( x sub 1 - x sub 2 + 1 ) ) +
        ( w sub 2 - w sub 1 ) ( ( x sub 2 - 1 ) - x ) } }
    B { @Math { x sub 2 - 1 > x } }
}
does the trick.  It is implementable by three constraints:
a linear constraint with minimum limit @M { x sub 1 } and weight
@M { w sub 1 }; a step constraint with minimum limit @M { x sub 2 }
and weight @M { w sub 2 - w sub 1 ( x sub 1 - x sub 2 + 1) }; and
a linear constraint with minimum limit @M { x sub 2 - 1 } and weight
@M { w sub 2 - w sub 1 }.
@PP
Constraints with 0 limits are dropped before applying this
formula.  Even then, @M { x sub 2 - 1 = 0 } is possible,
in which case the third constraint does nothing and is omitted.
@PP
It does not matter whether or not the preferred limit requests
@C { allow_zero }, because it is overridden by the minimum limit.
If the minimum limit requests @C { allow_zero }, that is easily
handled by requesting @C { allow_zero } in each generated constraint.
@PP
A different approach to the general problem of multiple limits
would be to extend XESTT to allow cost functions which are
arbitrary piecewise step, linear and quadratic functions.
However, that would substantially increase the complexity of XESTT
for the sake of an uncommon case which adds very little, considered
from the point of view of the institution being modelled.
@PP
In instance file @F { Musa.ros }, lines 306 and 453 form a
case where there is a minimum value and a preferred value, with
@M { x sub 1 = 3 }, @M { w sub 1 = 5 }, @M { x sub 2 = 1 }, and
@M { w sub 2  = 7 }.  This fails the formula given above, but it
is somewhat illogical, because it gives values @M { f(3) = 0 },
@M { f(2) = 5 }, @M { f(1) = 10 }, and @M { f(0) = 7 }.  Rather
than reject the instance, NRConv chooses to ignore the minimum
limit (with a warning message) and carry on.  @F { Musa.ros }
contains 14 essentially identical instances of this problem.
@End @SubSection

@SubSection
    @Title { Demands }
    @Tag { instances.constraints.demands }
@Begin
@LP
A @I { demand } is an object of type @C { NRC_DEMAND }, defining
a request for one worker to be assigned to an unspecified shift,
and the penalties to apply when the assignment is defective.
@PP
In this section, the term @I { worker assignment } will denote the
assignment, or non-assignment, of a worker to fulfill the request
represented by a demand object.  If there are @M { W } workers, there
are @M { W + 1 } distinct worker assignments:  one for each worker,
and one representing non-assignment.  A demand object represents
a function that associates a penalty with each worker assignment.  
@PP
Adding a demand to a shift is done separately, by @C { NrcShiftAddDemand }
(Section {@NumberOf instances.shifts.shifts}).  One demand may be
added any number of times to one shift, or several shifts.  Demand
objects are immutable after creation, so doing it this way is safe.
It helps the implementation to reduce the length of the generated
file.  The penalties apply independently to each occurrence of the
demand object.  To apply penalties across sets of demands, use
demand constraints (Section {@NumberOf instances.constraints.cover}).
@PP
Some models specify an optimum number of workers but no maximum.
For them, one must decide on some maximum (twice the optimum,
perhaps), and add that many demands.  This is because XESTT requires
each event to contain a definite fixed number of event resources.
# @PP
# The pure way to define a demand object would be by a sequence of
# calls, each associating a penalty with one worker assignment.
# But that is not convenient in practice.  One practical issue is
# that we want to use a record of the sequence of calls as the basis
# of a name for the demand, and one call per worker assignment is
# too many.  Instead, @I { penalizer functions } ares used to
# associate penalties with multiple workers, in ways needed by
# the various nurse rostering models.
@PP
Creation of a demand object begins with a call to
@ID @C {
NRC_DEMAND NrcDemandMakeBegin(NRC_INSTANCE ins);
}
Initially, every worker assignment has a penalty with weight 0; no
distinction is made between this and having no penalty at all.
Then comes a sequence of calls to @I { penalizer functions } which
associate penalties with worker assignments; we'll return to them in
a moment.  After they are done, creation is ended, including marking
@C { d } as immutable, by a compulsory call to
@ID @C {
void NrcDemandMakeEnd(NRC_DEMAND d);
}
Any subsequent calls to @C { d }'s penalizer functions, or to
@C { NrcDemandMakeEnd }, will abort.
@PP
# Behind the scenes, NRC builds equivalence classes of demand objects.
# (This is important for minimizing the length of the generated XESTT
# file.)  When @C { NrcDemandMakeEnd(d) } is called,
# it searches a table of demand objects held in the instance for an
# existing demand object which has already been marked immutable by
# a call to @C { NrcDemandMakeEnd } and which represents the same
# function from worker assignments to penalties as @C { d }.  If found,
# it adds a pointer to this other object to @C { d }, and ensures that
# all subsequent calls on @C { d } are delegated to this other object,
# except that further calls on @C { NrcDemandMakeEnd(d) } do nothing.
# The effect of all this is that the user does not have to be aware
# that this equivalencing process is going on.
# @PP
We turn now to the penalizer functions.  There are three of them:
@ID @C {
void NrcDemandPenalizeNonAssignment(NRC_DEMAND d,
  NRC_PENALTY_TYPE ptype, NRC_PENALTY p);
void NrcDemandPenalizeWorkerSet(NRC_DEMAND d, NRC_WORKER_SET ws,
  NRC_PENALTY_TYPE ptype, NRC_PENALTY p);
void NrcDemandPenalizeNotWorkerSet(NRC_DEMAND d, NRC_WORKER_SET ws,
  NRC_PENALTY_TYPE ptype, NRC_PENALTY p);
}
# They all associate @C { p } with worker assignments.
@C { NrcDemandPenalizeNonAssignment } associates
@C { p } with non-assignment, so that @C { p } is incurred if
no assignment is made to the demand.
@C { NrcDemandPenalizeWorkerSet } associates
@C { p } with each worker assignment of a worker from @C { ws },
so that @C { p } is incurred if an assignment of a worker from
@C { ws } is made to the demand.
@C { NrcDemandPenalizeNotWorkerSet } associates
@C { p } with each worker assignment of a worker not from @C { ws }
(but not with non-assignment), so that @C { p } is incurred if an
assignment of a worker not from @C { ws } is made to the demand.
As usual, worker sets whose workers
will be added later may be passed to these functions.
@PP
In all three functions, parameter @C { ptype } has type
@ID @C {
typedef enum {
  NRC_PENALTY_REPLACE,
  NRC_PENALTY_ADD,
  NRC_PENALTY_UNIQUE
} NRC_PENALTY_TYPE;
}
and says how to combine the new penalty with the existing penalty for each
affected worker assignment.  If @C { ptype } is @C { NRC_PENALTY_REPLACE },
the new penalty replaces the existing one; if @C { ptype } is
@C { NRC_PENALTY_ADD }, the new and existing penalties are added using
@C { NrcPenaltyAdd } (Section {@NumberOf instances.constraints.penalties});
and if @C { ptype } is @C { NRC_PENALTY_UNIQUE }, the existing penalty
must have weight 0 (otherwise the program aborts) and is replaced.
@C { NRC_PENALTY_UNIQUE } does not mean that the new penalty cannot
be replaced later.
# @PP
# Care is needed when adding two penalties, given that a penalty
# has three attributes:  a cost function, a hardness, and a weight.
# The cost function does not matter in a demand, because the degree
# of violation is at most 1.  For definiteness its value must
# be @C { NRC_COST_FUNCTION_LINEAR }.  When adding two penalties,
# one of which is hard and the other soft, the result is the hard
# penalty, which is fine in practice, if arguably inexact in theory.
# If the hardnesses are the same then the result has that hardness,
# and its weight is the sum of the weights.
@PP
For example, suppose that the penalty for non-assignment is @C { p },
and the penalty for assigning a worker from outside worker set @C { ws1 }
is @C { p1 }.  Then the appropriate calls are
@ID @C {
NrcDemandPenalizeNonAssignment(d, NRC_PENALTY_UNIQUE, p);
NrcDemandPenalizeNotWorkerSet(d, ws1, NRC_PENALTY_UNIQUE, p1);
}
Or suppose we prefer that the demand not be assigned at all.  The
call is
@ID @C {
NrcDemandPenalizeWorkerSet(d, NrcInstanceStaffing(ins),
  NRC_PENALTY_UNIQUE, p);
}
This says that any assignment of an actual worker attracts penalty @C { p }.
@PP
The First International Nurse Rostering Competition associates a penalty
with each contract.  This is to be applied whenever any nurse subject
to that contract is unpreferred.  Suppose there are two contracts, one
for nurses @C { ws1 } with penalty @C { p1 }, the other for nurses
@C { ws2 } with penalty @C { p2 }.  Then if the preferred worker set
for some demand is @C { ws }, the appropriate calls are
@ID @C {
NrcDemandPenalizeNonAssignment(d, NRC_PENALTY_UNIQUE, hard_p);
NrcDemandPenalizeWorkerSet(d, ws1, NRC_PENALTY_UNIQUE, p1);
NrcDemandPenalizeWorkerSet(d, ws2, NRC_PENALTY_UNIQUE, p2);
NrcDemandPenalizeWorkerSet(d, ws, NRC_PENALTY_REPLACE, p0);
}
This first installs penalty @C { hard_p } for non-assignment
(in INRC1 this is a hard cost of 1).  It then adds a penalty for
each worker in each contract, after which all worker assignments
should have a penalty.  But then it replaces the penalties for
the preferred workers by @C { p0 }, a zero penalty.
@PP
Calling @C { NrcDemandPenalizeWorkerSet } with an empty worker set
does nothing (unless workers are added to the worker set later).
Calling @C { NrcDemandPenalizeNotWorkerSet } with a worker set
containing every worker also does nothing.
@PP
Calling @C { NrcDemandPenalizeWorkerSet } with a worker set containing
every worker is the same as calling @C { NrcDemandPenalizeNotWorkerSet }
with an empty worker set:  both penalize the assignment of any worker.
When this is wanted, it is best to pass the sets provided by NRC:
@C { NrcInstanceStaffing(ins) } and @C { NrcInstanceEmptyWorkerSet(ins) }
from Section {@NumberOf instances.instances.workers}.  Doing that will
make the generated XESTT file easier to read.
@PP
Behind the scenes, a unique name is created for each demand, and used
in the generated XESTT file as part of the names of roles and event
groups.  The name is based on the calls made when constructing the
demand.  For example,
@ID @F "NA=h1+NW0=s100"
is the name of a demand in which non-assignment has hard cost 1
(@F { NA=h1 }) and assigning a worker not from worker set @F "0"
has soft cost 100 (@F { NW0=s100 }).
# The retrieval of an existing
# demand object with the desired penalties is done by name.
# If there are too many calls,
# then the name is replaced by something short and uninformative.
This name is returned by
@ID @C {
char *NrcDemandName(NRC_DEMAND d);
}
but this only works after @C { NrcDemandMakeEnd(d) } has been called.
@PP
The instance that a demand is for may be retrieved by
@ID @C {
NRC_INSTANCE NrcDemandInstance(NRC_DEMAND d);
}
Its penalizers may be retrieved by
@ID @C {
int NrcDemandPenalizerCount(NRC_DEMAND d);
void NrcDemandPenalizer(NRC_DEMAND d, int i, NRC_PENALIZER_TYPE *pt,
  NRC_WORKER_SET *ws, NRC_PENALTY_TYPE *ptype, NRC_PENALTY *p);
}
where @C { NRC_PENALIZER_TYPE } is
@ID @C {
typedef enum {
  NRC_PENALIZER_NON_ASSIGNMENT,
  NRC_PENALIZER_WORKER_SET,
  NRC_PENALIZER_NOT_WORKER_SET
} NRC_PENALIZER_TYPE;
}
Its members correspond to the three functions given above.
@C { NrcDemandPenalizer } sets @C { *ws } to @C { NULL } when
@C { *pt } is @C { NRC_PENALIZER_NON_ASSIGNMENT }.
@PP
As we know, @C { d } holds one penalty for each worker, and one
for non-assignment.  Function
@ID @C {
NRC_PENALTY NrcDemandWorkerPenalty(NRC_DEMAND d, NRC_WORKER w);
}
returns the penalty associated with worker @C { w }, or
@C { NrcInstanceZeroPenalty } if no penalty has been associated with
@C { w }.  Passing @C { NULL } for @C { w } returns the penalty for
non-assignment.  It may only be called after @C { NrcDemandMakeEnd(d) }
has been called and before conversion to XESTT.
@PP
Finally, function
@ID {0.98 1.0} @Scale @C {
void NrcDemandDebug(NRC_DEMAND d, int multiplicity, int indent, FILE *fp);
}
produces a debug print of @C { d } onto @C { fp } with the given
indent, as explained in Section {@NumberOf instances.debug}.  As
a convenience to some callers, if @C { multiplicity } is at least 2
it is included in the print.
#@DP
#@I { Becoming obsolete below here }  A demand is created by a call to
#@ID @C {
#NRC_DEMAND NrcDemandMake(NRC_INSTANCE ins,
#  NRC_PENALTY not_assigned_penalty, NRC_PENALTY assigned_penalty,
#  NRC_WORKER_SET preferred_ws, NRC_PENALTY not_preferred_penalty);
#}
#This returns an existing object with these attributes if there is one,
#otherwise it returns a new one.  Returning an existing object is quite
#safe, because demand objects are immutable, and doing it this way
#helps the implementation to optimize the length of the generated file.
#@PP
#In a solution, penalty @C { not_assigned_penalty } is incurred if a
#worker is not assigned to satisfy this demand.  Penalty
#@C { assigned_penalty } is incurred if a worker @I is assigned to
#satisfy this demand.  If a worker not in @C { preferred_ws } is assigned
#(but not if no worker is assigned), penalty @C { not_preferred_penalty }
#is incurred.
#@PP
#Penalties with weight 0 may be passed to @C { NrcDemandMake }.  The
#penalty for assigning an unpreferred worker may vary from one worker
#to another, so @C { not_preferred_penalty } is a default value, used
#when some worker not in @C { preferred_ws } is assigned, but
#@C { NrcWorkerAddSkillPenalty } (Section {@NumberOf instances.workers})
#has not been called to associate a penalty with that worker.  Passing
#@C { NULL } for @C { preferred_ws } is the way to omit this constraint,
#not passing @C { NULL } for @C { not_preferred_penalty }.
#@PP
#Adding a demand to a shift is a separate step, done by
#@C { NrcShiftAddDemand } (Section {@NumberOf instances.shifts.shifts}).
#The same demand object may be added any number of times to one shift,
#or to several shifts.
#@PP
#Some models specify an optimum number of workers but no maximum.  For
#these it is necessary to fix on some maximum (twice the optimum,
#perhaps), and pass that many demands, some, perhaps, with assignment
#penalties.  This necessity arises because the XESTT model requires
#that each event contain a definite fixed number of event resources.
#@PP
#The attributes of a demand object may be retrieved by calling
#@ID @C {
#NRC_INSTANCE NrcDemandInstance(NRC_DEMAND d);
#NRC_PENALTY NrcDemandNotAssignedPenalty(NRC_DEMAND d);
#NRC_PENALTY NrcDemandAssignedPenalty(NRC_DEMAND d);
#NRC_WORKER_SET NrcDemandPreferredWorkerSet(NRC_DEMAND d);
#NRC_PENALTY NrcDemandNotPreferredPenalty(NRC_DEMAND d);
#}
# The number of workers is given by @C { opt_min }, @C { opt_max },
# and @C { upper_lim }.  These must satisfy
# @ID @C { 0 <= opt_min <= opt_max <= upper_lim }
# If less than @C { opt_min } workers are assigned to satisfy
# this cover, then there is a penalty with hardness @C { under_req d }
# and cost @C { under_wei ght } multiplied by the amount by which
# the number of workers falls short of @C { opt_min }.  If between
# @C { opt_min } and @C { opt_max } (inclusive) workers are assigned,
# then there is no penalty.  If more than @C { opt_max } workers are
# assigned, then the penalty has hardness @C { under_req d } and cost
# @C { under_weig ht } multiplied by the amount by which the number of
# workers exceeds @C { opt_max }.
# @PP
# There cannot be more than @C { upper_lim } workers assigned,
# because the XESTT instance generated by NRC does not permit it.
# But @C { upper_lim } cannot be set to a very large number, like
# @C { INT_MAX }, because the size of the XESTT instance increases
# linearly with @C { upper_lim } (@C { upper_lim } event resources
# are generated for each shift containing the cover).  In cases
# where there is no fixed upper limit, the conversion has to invent
# one, for example @C { 2 * opt_max }.
# @PP
# When @C { opt_min == 0 }, @C { under_req d } and @C { under_wei ght }
# are ignored; their values do not matter.  When @C { opt_min > 0 },
# this is taken to mean that there should be a penalty for under-filling,
# so @C { under_wei ght } must be non-zero.  Similarly,
# when @C { opt_max == upper_lim }, @C { over_req d } and @C { over_wei ght }
# are ignored; their values do not matter.  When @C { opt_min < upper_lim },
# this is taken to mean that there should be a penalty for over-filling,
# so @C { over_wei ght } must be non-zero.
# @PP
# A cover can also penalize workers without appropriate skills.  To
# do this, set @C { skill_ws } to the desired skill, and
# @C { skill_penalty_req d } and @C { skill_penalty_wei ght } to the
# penalty for each worker not in @C { skill_ws } assigned to satisfy
# the cover.  To not do this, set @C { skill_ws } to @C { NULL }.
@End @SubSection

@SubSection
    @Title { Demand-sets }
    @Tag { instances.constraints.demand_sets }
@Begin
@LP
Demand-sets are sets of demands, defined in the usual way:
@ID @C {
NRC_DEMAND_SET NrcDemandSetMake(NRC_INSTANCE ins);
void NrcDemandSetAddDemand(NRC_DEMAND_SET ds, NRC_DEMAND d);
}
There is also the trivial helper function
@ID @C {
void NrcDemandSetAddDemandMulti(NRC_DEMAND_SET ds, NRC_DEMAND d,
  int multiplicity);
}
which calls @C { NrcDemandSetAddDemand(ds, d) } @C { multiplicity }
times.  It is quite normal for one demand object to be added to a
demand set multiple times, this way or otherwise; it just means
that that many identical demands are being made.
@PP
Demand-sets make it easy to build up the total requirements for
one shift into a single object.
#For example, here is the author's
#original code for constructing a suitable demand-set for shifts in
#the Second International Nurse Rostering Competition:
#@ID @C {
#p1 = NrcPenalty(true, 1, NRC_COST_FUNCTION_LINEAR, ins);
#p2 = NrcPenalty(false, 30, NRC_COST_FUNCTION_LINEAR, ins);
#p3 = NrcPenalty(false, 0, NRC_COST_FUNCTION_LINEAR, ins);
#dms = NrcDemandSetMake(ii->ins);
#dm = NrcDemandMake(ii->ins, p1, p3, ws, p1);
#NrcDemandSetAddDemandMulti(dms, dm, min_cover);
#dm = NrcDemandMake(ii->ins, p2, p3, ws, p1);
#NrcDemandSetAddDemandMulti(dms, dm, opt_cover - min_cover);
#dm = NrcDemandMake(ii->ins, p3, p3, ws, p1);
#NrcDemandSetAddDemandMulti(dms, dm, opt_cover);
#}
#The demand-set contains @C { min_cover } demands for which
#non-assignment incurs a hard penalty, @C { opt_cover - min_cover }
#demands for which non-assignment incurs a soft penalty, and
#@C { opt_cover } demands for which non-assignment incurs no
#penalty.  All demands include a hard penalty for assigning
#a worker without the required skill.
#@PP
#In the example just given, the minimum and optimum cover are reminiscent
#of a bound (Section {@NumberOf instances.constraints.bounds}) with
# minimum and preferred limits.  This function develops this idea:
There might be a minimum, preferred, and maximum number of workers
required, similarly to what is represented by a bound.  This function
develops this idea:
@ID @C {
NRC_DEMAND_SET NrcDemandSetMakeFromBound(NRC_INSTANCE ins,
  NRC_BOUND b, int count, NRC_WORKER_SET preferred_ws,
  NRC_PENALTY not_preferred_penalty);
}
It returns a new demand-set containing @C { count } demands.  It
would be too tedious to describe all the cases, but suppose the
bound contains a @C { min_value }, @C { preferred_value }, and
@C { max_value }.  Then the first @C { min_value } demands penalize
non-assignment by the penalty for being below @C { min_value };
the next @C { preferred_value - min_value } demands also penalize
non-assignment, but by the penalty for being below
@C { preferred_value }; the next @C { max_value - preferred_value }
demands penalize assignment of a worker, by the penalty for being
above @C { preferred_value }; and the last @C { count - max_value }
demands also penalize assignment of a worker, but by the penalty for
being above @C { max_value }.  In addition, if @C { preferred_ws } is
non-@C { NULL }, all the demands penalize the assignment of a
worker not in @C { preferred_ws } by @C { not_preferred_penalty }.
The penalties must all be linear, and all @C { allow_zero }
attributes must be @C { false }.
# @C { preferred_ws } (if non-@C { NULL }), with penalty
# @C { not_preferred_penalty } if a worker not .  Each
# @C { not_assigned_penalty } and @C { assigned_penalty } attribute
# is either one of the penalties in the bound or else is zero (has
# weight 0).  It would be too tedious to describe all the cases.  But,
# as an example, suppose that minimum,
# preferred, and maximum values are present in the bound.  Then the
# first @C { min_value } demands have @C { below_min_penalty } for
# @C { not_assigned_penalty } and zero for @C { assigned_penalty };
# the next @C { preferred_value - min_value } demands have
# @C { below_preferred_penalty } for @C { not_assigned_penalty } and
# zero for @C { assigned_penalty }; the next
# @C { max_value - preferred_value } demands have zero
# for @C { not_assigned_penalty } and @C { above_preferred_penalty }
# for @C { assigned_penalty }; and the last @C { count - max_value }
# demands have zero for @C { not_assigned_penalty } and
# @C { above_max_penalty } for @C { assigned_penalty }.  All these
# penalties must be linear, and any @C { allow_zero } attribute must
# be @C { false }.
@PP
For example, the following handles the Second International Nurse
Rostering Competition, whose shifts have a hard minimum cover and
a soft optimum (preferred) cover:
@ID @C {
p1 = NrcPenalty(true, 1, NRC_COST_FUNCTION_LINEAR, ins);
p2 = NrcPenalty(false, 30, NRC_COST_FUNCTION_LINEAR, ins);
p3 = NrcPenalty(false, 0, NRC_COST_FUNCTION_LINEAR, ins);
b = NrcBoundMakeMin(min_cover, false, p1);
NrcBoundAddPreferred(b, opt_cover, p2, p3);
dms = NrcDemandSetMakeFromBound(ins, b, opt_cover * 2, ws, p1);
}
This is much easier and clearer than adding the demands individually.  To
add a maximum cover, for example, just add a maximum value to the bound.
@PP
The instance that a demand-set is for is returned by
@ID @C {
NRC_INSTANCE NrcDemandSetInstance(NRC_DEMAND_SET ds);
}
To visit the demands of a demand-set, in the order they were added, call
@ID @C {
int NrcDemandSetDemandCount(NRC_DEMAND_SET ds);
NRC_DEMAND NrcDemandSetDemand(NRC_DEMAND_SET ds, int i);
}
The same demand may be returned multiple times; there is no
memory in the demand-set of how its demands were added.  Function
@ID @C {
void NrcDemandSetDebug(NRC_DEMAND_SET ds, int indent, FILE *fp);
}
produces a debug print of @C { ds } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Demand constraints }
    @Tag { instances.constraints.cover }
@Begin
@LP
The usual way to specify the workers required by shifts is to add
demands to the shifts, as just explained.  However, some constraints
(notably in the Curtois original instances) apply to the whole set of
workers that attend some shift, or even to the set of workers that
attend a set of shifts (when the constraint is on the workers that
attend during some time period).  In some cases these constraints can
be decomposed into constraints on individual demands, but not always.
@PP
For these awkward cases an alternative approach is offered.
First, specify a maximum number of workers that may be assigned
to each shift, using unconstrained demands like this:
@ID @C {
NrcInstanceDemandBegin(ins);
dm = NrcInstanceDemandEnd(ins);
dms = NrcDemandSetMake(ins);
NrcDemandSetAddDemandMulti(dms, dm, total_cover);
NrcShiftAddDemandSet(s, dms);
}
or equivalently like this:
@ID @C {
dms = NrcDemandSetMakeFromBound(ins, NrcBoundMake(ins), total_cover,
  NULL, NULL);
NrcShiftAddDemandSet(s, dms);
}
This ensures that shift @C { s } can be assigned up to @C { total_cover }
workers, without any constraint on how many assignments there should
be, or on the assigned workers' skills.  Second, call
@ID @C {
NRC_DEMAND_CONSTRAINT NrcDemandConstraintMake(NRC_BOUND b,
  NRC_SHIFT_SET ss, NRC_WORKER_SET ws, char *name);
}
# NRC_DEMAND_CONSTRAINT NrcDemandConstraintMake(NRC_SHIFT_SET ss,
#   NRC_WORKER_SET ws, char *name);
This adds a constraint to @C { ss }'s instance which limits
the total number of demands from an arbitrary set of shifts
that may be assigned workers from a given set.  Functions
@ID @C {
NRC_BOUND NrcDemandConstraintBound(NRC_DEMAND_CONSTRAINT dc);
NRC_SHIFT_SET NrcDemandConstraintShiftSet(NRC_DEMAND_CONSTRAINT dc);
NRC_WORKER_SET NrcDemandConstraintWorkerSet(NRC_DEMAND_CONSTRAINT dc);
char *NrcDemandConstraintName(NRC_DEMAND_CONSTRAINT dc);
}
retrieve the four attributes of demand constraint @C { dc }.
@PP
Parameter @C { b } is a bound object
(Section {@NumberOf instances.constraints.bounds}) which specifies
any combination of minimum, maximum, or preferred limits on the
number of assignments.  It may be a freshly created object with
no limits when passed to @C { NrcDemandConstraintMake }; the
limits may be added to it later.
@PP
Parameter @C { ss } is the set of shifts whose assignments are being
constrained.  For example, if the constraint is on a single shift
@C { s }, then @C { ss } would be @C { NrcShiftSingletonShiftSet(s) }.
@PP
Parameter @C { ws } is the set of workers.  The constraint is only
interested in assignments of these workers; assignments of other
workers do not influence it.  If the constraint is on the total
number of assignments irrespective of skill, then @C { ws } would
be @C { NrcInstanceStaffing(ins) }.
@PP
Parameter @C { name } does not influence the meaning of the
constraint; rather, it helps to identify the constraint in
evaluation prints.  It does not have to be unique.  It should
indicate what is being constrained but not the actual limits,
because NRC adds that information to the name.
#@ID @C {
#bool NrcDemandConstraintAddMin(NRC_DEMAND_CONSTRAINT dc,
#  int min_number, NRC_PENALTY below_min_penalty);
#bool NrcDemandConstraintAddMax(NRC_DEMAND_CONSTRAINT dc,
#  int max_number, NRC_PENALTY above_max_penalty);
#bool NrcDemandConstraintAddPreferred(NRC_DEMAND_CONSTRAINT dc,
#  int pref_number, NRC_PENALTY below_pref_penalty,
#  NRC_PENALTY above_pref_penalty);
#}
#in any order.  @C { NrcDemandConstraintAddMin } specifies that the
#minimum number of assignments of workers from @C { ws } to the demands
#of the shifts of @C { ss } is @C { min_number }, and that for each
#unassigned demand below that number the penalty is @C { below_min_penalty }.
#Similarly, @C { NrcDemandConstraintAddMax } specifies the maximum number
#of assignments and the penalty for every assignment above it.
#@C { NrcDemandConstraintAddPreferred } specifies a preferred number,
#and gives the penalty for every assignment below that number (but not
#below @C { min_number }, if present) and above that number (but not
#above @C { max_number }, if present).
#@PP
#Some checks are carried out by the three @C { Add } functions, and
#@C { false } is returned and @C { dc } is left unchanged if any fail.
#The two obvious checks are that each @C { Add } function is
#called at most once on a given @C { dc }, and that
#@C { min_number <= pref_number <= max_number },
#where the values are present.  Less obviously, these checks are also made:
#@ID {0.95 1.0} @Scale @C {
#NrcPenaltyHard(below_pref_penalty) == NrcPenaltyHard(below_min_penalty)
#NrcPenaltyWeight(below_min_penalty) >= NrcPenaltyWeight(below_pref_penalty)
#NrcPenaltyHard(above_pref_penalty) == NrcPenaltyHard(above_max_penalty)
#NrcPenaltyWeight(above_max_penalty) >= NrcPenaltyWeight(above_pref_penalty)
#}
#where the values are present.  The reason is that when there is a
#preferred number, the weight for being below the minimum is set to
#@ID {0.95 1.0} @Scale @C {
#NrcPenaltyWeight(below_min_penalty) - NrcPenaltyWeight(below_pref_penalty)
#}
#in the XESTT constraint, to cancel out the double counting arising
#from also being below the preferred number; and a similar adjustment
#is made to the weight for being above the maximum.
#bool NrcDemandConstraintMin(NRC_DEMAND_CONSTRAINT dc,
#  int *min_number, NRC_PENALTY *below_min_penalty);
#bool NrcDemandConstraintMax(NRC_DEMAND_CONSTRAINT dc,
#  int *max_number, NRC_PENALTY *above_max_penalty);
#bool NrcDemandConstraintPreferred(NRC_DEMAND_CONSTRAINT dc,
#  int *pref_number, NRC_PENALTY *below_pref_penalty,
#  NRC_PENALTY *above_pref_penalty);
#The last three return @C { true } when their corresponding @C { Add }
#functions have been called.
@PP
There is also the usual debug function,
@ID @C {
void NrcDemandConstraintDebug(NRC_DEMAND_CONSTRAINT dc,
  int indent, FILE *fp);
}
which produces a debug print of @C { dc } onto @C { fp } with the
given indent.
@PP
NRC demand constraints are converted to XESTT limit resources
constraints, or in some cases to assign resource and prefer
resources constraints, which are preferable because they constrain
each event resource independently---a fact which can have practical
consequences, for example for time sweep assignment algorithms.
For the details, consult Section {@NumberOf impl.demand}.
# @PP
# For each shift, assign resource and prefer resources constraints
# are used when the demand constraints that apply to the shift
# apply to it alone, their worker-sets are the entire staffing,
# and their bounds are mergeable.  Two bounds are mergeable when
# one is a minimum limit and the other is a maximum limit.  Also,
# as a concession to Curtois original instance @F { COI-BCDT-Sep },
# cases where there are two minimum limits and two maximum limits are
# considered mergeable when the lower minimum and the higher maximum
# limits are hard, and the higher minimum and lower maximum limits are
# soft and equal.  Their common value goes into the merged bound as a
# preferred value.  This is slightly inexact in that violating both
# minimum or both maximum limits will be treated like violating just
# the hard one, but the inexactness is evidently negligible.
# @PP
# The description just given took effect in June 2019.  Before then,
# assign resource and prefer resources constraints were used only
# for shifts with a single demand constraint.  The change was made
# to improve the conversion of @F { COI-BCDT-Sep }, but it has
# affected several @F { COI } instances.
@End @SubSection

@SubSection
    @Title { Patterns }
    @Tag { instances.constraints.patterns }
@Begin
@LP
@I { Patterns } are used in several nurse rostering models to say
that some sequences of shift types---a morning shift following a
night shift, for example---should be forbidden, or penalized.
@PP
Given that a worker takes at most one shift per day, the choices on
each day are one of its shifts or nothing.  Denote the shift types by
@C { 1 }, @C { 2 }, and @C { 3 }, and denote the absence of a shift
(a free day) by @C { 0 }.  Using regular expression notation, an
arbitrary subset of these choices is represented by enclosing them
in brackets.  For example, @C { [02] } means `a shift of type 2 or
nothing.' In source models, a @I { pattern } is a sequence of these
@I { terms }, representing the choices on consecutive days.  For
example, @C { [3][1] } means `an early shift following a night shift'.
@PP
A pattern @I { matches } a worker's timetable at any day where the
worker has a sequence of shifts or days off, each of which matches
the corresponding term of the pattern.  For example, if a worker's
timetable contains a shift of type @C { 3 } on day @C { 1Wed } and
a shift of type @C { 1 } on day @C { 1Thu }, then pattern @C { [3][12] }
matches that timetable at @C { 1Wed }.
@PP
The empty term @C { [] } is allowed, but it never matches, which
makes it useless in practice.  On the other hand, @C { [0123] } says
that we don't care what happens on that day, which can be useful.
@PP
NRC supports patterns.  A pattern is created by
@ID @C {
NRC_PATTERN NrcPatternMake(NRC_INSTANCE ins, char *name);
}
where @C { name } is optional (may be @C { NULL }).  To retrieve the
attributes, call
@ID @C {
NRC_INSTANCE NrcPatternInstance(NRC_PATTERN p);
char *NrcPatternName(NRC_PATTERN p);
}
To add a term to a pattern, call
@ID {0.98 1.0} @Scale @C {
void NrcPatternAddTerm(NRC_PATTERN p, NRC_SHIFT_TYPE_SET sts,
  NRC_POLARITY po);
}
As shown, a term consists of a shift-type set and a @I { polarity }, of type
@ID @C {
typedef enum {
  NRC_NEGATIVE,
  NRC_POSITIVE
} NRC_POLARITY;
}
These attributes will be explained shortly.  To visit the terms of a
pattern, call
@ID @C {
int NrcPatternTermCount(NRC_PATTERN p);
void NrcPatternTerm(NRC_PATTERN p, int i, NRC_SHIFT_TYPE_SET *sts,
  NRC_POLARITY *po);
}
in the usual way.  There is also
@ID @C {
bool NrcPatternIsUniform(NRC_PATTERN p);
}
which returns @C { true } when @C { p } is @I { uniform }:  when
all its terms contain equal shift-type sets and equal polarities.
Unwanted patterns can be implemented more efficiently when they
are uniform.
@PP
Type @C { NRC_POLARITY } has just one operation:
@ID @C {
NRC_POLARITY NrcPolarityNegate(NRC_POLARITY po);
}
which returns negative for positive and positive for negative.
@PP
A term @C { t } matches the timetable of worker @C { w } on
day @C { d } if either @C { t }'s polarity is @C { NRC_POSITIVE }
and @C { w } works a shift on day @C { d } whose type is one of
the types of @C { t }'s shift-type set, or else @C { t }'s polarity
is @C { NRC_NEGATIVE } and @C { w } does not work a shift on day
@C { d } whose type is one of the types of @C { t }'s shift-type
set.  This second case includes not working at all.  A pattern
matches @C { w }'s timetable on day @C { d } if its first term
matches on day @C { d }, its second term matches on the day
after @C { d }, and so on.
# @PP
# NRC patterns contain shifts, not shift types, and so they match
# at a single point in the cycle, not at any point along the cycle.
# When defining a pattern, shift-sets should be included which match
# at the first possible position.  This initial pattern can then be
# repeated along the cycle by adding it to a worker constraint
# (Section {@NumberOf instances.constraints.worker_constraints})
# whose @C { starting_ss } parameter is non-@C { NULL }.
# @PP
# For example, suppose @C { [123][0] } is unwanted on weekends.  Make
# a pattern with two terms, the first a positive shift-set holding
# the shifts of the first Saturday of the cycle, the second a negative
# shift-set holding the shifts of the first Sunday of the cycle.  Add
# this pattern to a worker constraint whose @C { starting_ss } parameter
# is the value returned by @C { NrcInstanceWeeklyStartingShiftSet },
# which specifies that it is to apply every week.
@PP
A term which does not contain @C { 0 } is represented by a shift-type
set containing its shift types, with polarity @C { NRC_POSITIVE }.
A term which contains @C { 0 } is represented by a shift-type set
containing the complement of the term's non-@C { 0 } shift types,
with polarity @C { NRC_NEGATIVE }.  The reader can easily verify
that this does what is wanted.  In particular, the don't-care term
@C { [0123] } is represented by an empty shift-type set with negative
polarity.  This term always matches.
@PP
Creating a pattern does not make it unwanted:  it has to be added to
a worker constraint, using function @C { NrcConstraintAddPattern }
(Section {@NumberOf instances.constraints.worker_constraints}).  The
constraint holds information about the cost of violations, and
which days the pattern is allowed to match with.
@PP
All patterns are stored in the instance, and are accessible by
@C { NrcInstancePatternCount }, @C { NrcInstancePattern }, and
@C { NrcInstanceRetrievePattern }
(Section {@NumberOf instances.instances.constraints}).
Function
@ID @C {
void NrcPatternDebug(NRC_PATTERN p, int indent, FILE *fp);
}
produces a debug print of @C { p } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@End @SubSection

@SubSection
    @Title { Pattern sets }
    @Tag { instances.constraints.pattern.sets }
@Begin
@LP
A @I { pattern set } is a set of patterns.  To make an initially
empty pattern set, call
@ID @C {
NRC_PATTERN_SET NrcPatternSetMake(NRC_INSTANCE ins);
}
Functions
@ID @C {
NRC_INSTANCE NrcPatternSetInstance(NRC_PATTERN_SET ps);
int NrcPatternSetIndexInInstance(NRC_PATTERN_SET ps);
}
return the pattern set's instance, and its index in the instance.
@PP
To add a pattern to a pattern set, call
@ID @C {
void NrcPatternSetAddPattern(NRC_PATTERN_SET ps, NRC_PATTERN p);
}
This may be done any number of times.  To visit the patterns
of a pattern set, call
@ID @C {
int NrcPatternSetPatternCount(NRC_PATTERN_SET ps);
NRC_PATTERN NrcPatternSetPattern(NRC_PATTERN_SET ps, int i);
}
in the usual way.
@PP
The function that makes pattern sets non-trivial is
@ID @C {
NRC_PATTERN_SET NrcPatternSetReduce(NRC_PATTERN_SET ps);
}
This returns a new pattern set whose patterns match at the same
points as @C { ps }'s patterns do, but usually using fewer
patterns.  To see the use for this, consider this excerpt from
one of the recent Curtois and Qu instances:
@ID @F @Verbatim {
a4,720,a1|a2|a3|a4|d1|d2|d3|d4|d5
d1,480,a1|a2|a3
d2,480,a1|a2|a3
d3,600,a1|a2|a3|a4
d4,720,a1|a2|a3|a4|d1|d2|d3|d4|d5
}
Ignoring the workload limits, this gives for each shift type
(not all are shown here) a list of other shift types that may not
follow it, so it defines a set of patterns.  The reduced set is
@ID @F @Verbatim {
a4|d4,720,a1|a2|a3|a4|d1|d2|d3|d4|d5
d1|d2,480,a1|a2|a3
d3,600,a1|a2|a3|a4
}
These patterns match at the same points as the originals, but
there are fewer of them, leading to smaller generated instances.
The function merges pairs of patterns with the same length and
equal elements and polarities except at one place, where the
elements must be disjoint and the polarities must be equal.  
@PP
Instead of building then reducing, it may be simpler to reduce
while building, by calling
@ID @C {
void NrcPatternSetMergePattern(NRC_PATTERN_SET ps, NRC_PATTERN p);
}
It is like @C { NrcPatternSetAddPattern } except that it first
tries to merge @C { p } into an existing pattern of @C { ps },
only adding it as a separate pattern as a last resort.  Finally,
@ID @C {
void NrcPatternSetDebug(NRC_PATTERN_SET ps, int indent, FILE *fp);
}
produces a debug print of @C { ps } in the usual way.
@End @SubSection

@SubSection
    @Title { Worker constraints }
    @Tag { instances.constraints.worker_constraints }
@Begin
@LP
A @I { worker constraint } is a constraint on the timetables of
individual workers.  Worker constraints all seem to have a similar
form:  they contain a set of shift-sets, and for each worker they
determine whether the worker is busy or free during each shift-set,
calculate totals of busy and free shift-sets, and assign a penalty
proportional to the amount by which the totals fall short of a given
minimum limit or exceed a given maximum limit.  There are variations:
when there is a non-zero minimum limit, in some cases a total of 0
is nevertheless not penalized; sometimes the total workload (measured
in minutes, say) is limited rather than the number of shifts; some
constraints are repeated along the cycle (every weekend, for example);
some apply to sequences of consecutive shift-sets, others are just
concerned with totals, not with ordering; and so on.  Nevertheless
NRC offers a single interface for all worker constraints.
@PP
A shift is @I { busy } for a worker when the worker works that
shift.  A shift is @I { free } for a worker when it is not busy
for the worker.  A shift-set is busy for a worker when at least
one of its shifts is busy for the worker.  A shift-set is free
for a worker when it is not busy for the worker.
@PP
When a shift-set is added to a constraint, a polarity
(Section {@NumberOf instances.constraints.patterns}) is added
with it, saying whether the shift-set is to be treated
@I { positively } or @I { negatively }.  Informally, we say that a
shift-set is @I { positive } when its associated polarity is
positive, and @I { negative } otherwise.  However, it is the
usage of the shift-set within the constraint which is positive or
negative, not the shift-set itself.
@PP
When a constraint is applied to a particular worker, a shift-set
within it is @I active when it is positive and busy for the worker,
or negative and free for the worker.  Otherwise it is @I { inactive }.
The constraint calculates the total number of active shift-sets, and
compares it with the limits.  If all shift-sets are positive, this
constrains busy shift-sets; if all are negative, it constrains
free shift-sets.  Mixtures of positive and negative are legal,
and useful for implementing unwanted patterns.
@PP
To create a worker constraint, initially with no shift-sets, call
@ID @C {
NRC_CONSTRAINT NrcConstraintMake(NRC_INSTANCE ins, char *name,
  NRC_WORKER_SET ws, NRC_CONSTRAINT_TYPE type, NRC_BOUND bound,
  NRC_SHIFT_SET starting_ss);
}
#NRC_CONSTRAINT NrcConstraintMake(NRC_INSTANCE ins, char *name,
#  NRC_WORKER_SET ws, NRC_PENALTY penalty, NRC_LIMIT_TYPE limit_type,
#  int limit, NRC_SHIFT_SET starting_ss);
This returns a new constraint and also adds it to @C { ins }.  The
type should really be called @C { NRC_WORKER_CONSTRAINT }, but
@C { NRC_CONSTRAINT } is shorter.  To retrieve the attributes, call
@ID @C {
NRC_INSTANCE NrcConstraintInstance(NRC_CONSTRAINT c);
char *NrcConstraintName(NRC_CONSTRAINT c);
NRC_WORKER_SET NrcConstraintWorkerSet(NRC_CONSTRAINT c);
NRC_CONSTRAINT_TYPE NrcConstraintType(NRC_CONSTRAINT c);
NRC_BOUND NrcConstraintBound(NRC_CONSTRAINT c);
NRC_SHIFT_SET NrcConstraintStartingShiftSet(NRC_CONSTRAINT c);
}
# int NrcConstraintLimit(NRC_CONSTRAINT c);
# NRC_LIMIT_TYPE NrcConstraintLimitType(NRC_CONSTRAINT c);
# NRC_PENALTY NrcConstraintPenalty(NRC_CONSTRAINT c);
Parameter @C { name } is the name given to XESTT constraints derived
from this constraint.  A good choice here is an informal source model
description, expressed positively, that is, as what is wanted rather
than what is to be avoided:  @C { "At most 4 busy weekends" } and so
on.  Names mainly appear as entries in tables of defects, where there
are other entries giving the details, so a short, informal phrase is
best.  There is no need for names to be distinct.  NRC will ensure that
the XESTT constraints it generates have distinct Ids, which is a
different thing.
@PP
Parameter @C { ws } says which workers the constraint applies to.
For example, @C { ws } could hold the workers who share a contract
containing this constraint.  If the constraint is for a single worker
@C { w }, then @C { ws } is @C { NrcWorkerSingletonWorkerSet(w) }
(Section {@NumberOf instances.workers.workers}).  Worker constraints
which are equal apart from @C { ws } are merged by @C { NrcArchiveWrite }
into a single XESTT constraint.
@PP
Parameter @C { type } determines what is constrained, and has type
@ID @C {
typedef enum {
  NRC_CONSTRAINT_ACTIVE,
  NRC_CONSTRAINT_CONSECUTIVE,
  NRC_CONSTRAINT_WORKLOAD
} NRC_CONSTRAINT_TYPE;
}
@C { NRC_CONSTRAINT_ACTIVE } means that the constraint is on
the number of active shift-sets; @C { NRC_CONSTRAINT_CONSECUTIVE }
means that the constraint is on the number of consecutive active
shift-sets;
@FootNote {
The author learned of this approach to constraining consecutive
subsequences from Gerhard Post.
}
and @C { NRC_CONSTRAINT_WORKLOAD } means that the constraint is
on the total workload of the shifts of one shift-set.
@PP
Parameter @C { bound } says whether the constraint is a minimum
limit, a minimum limit in which zero is allowed, or a maximum
limit, or a combination, and includes penalties for when the
limit is violated (Section {@NumberOf instances.constraints.bounds }).
#Parameter @C { penalty } defines the penalty associated with the
#constraint, as in Section {@NumberOf instances.constraints.penalties}.
#@PP
#Parameter @C { limit }, of type @C { NRC_LIMIT }, defines the type
#and value of the limit whose violation is to be penalized.  For
#example, it might specify a minimum limit of 3, so that the degree
#of violation is the amount by which the number of active shift-sets
#falls short of 3, or a maximum limit of 4, so that the degree of
#violation is the amount by which the number of active shift-sets
#exceeds 4.  Full details appear below
#(Section {@NumberOf instances.constraints.examples}).
@PP
Lastly, @C { starting_ss } repeats the constraint along the
cycle.  If it is @C { NULL }, the constraint is applied only once.
If it is non-@C { NULL }, the distance from its first shift to
each of its other shifts defines a distance along the cycle to
repeat the constraint.  For example, if @C { starting_ss } holds
the first shift of each day, the constraint repeats on every day.
# @PP
# Building @C { starting_ss } shift by shift would be unusual.
@C { NrcInstanceDailyStartingShiftSet } and
@C { NrcInstanceWeeklyStartingShiftSet }
(Section {@NumberOf instances.instances.shifts}),
@C { NrcDaySetStartingShiftSet }
(Section {@NumberOf instances.days.day_sets}),
and
@C { NrcShiftSetSetStartingShiftSet }
(Section {@NumberOf instances.shifts.shift_set_sets})
return most of the starting shift-sets needed in practice.
@PP
When @C { starting_ss } is used, the shift-sets added to the constraint
must define only the earliest occurrence of the constraint.  Some of
@C { starting_ss }'s shifts may place the constraint at points of the
cycle where some parts of it go off the end.  Such shifts are legal
but are ignored.
@PP
One may use @C { starting_ss } with the consecutive limit types, to get
constraints such as a limit on the number of consecutive days worked
within each four-week interval.  But these never seem to occur in
source models, perhaps because they are very artificial at the boundaries.
@PP
After creating the constraint, add shift-sets to it by calling
@ID @C {
void NrcConstraintAddShiftSet(NRC_CONSTRAINT c,
  NRC_SHIFT_SET ss, NRC_POLARITY po);
void NrcConstraintAddShiftSetSet(NRC_CONSTRAINT c,
  NRC_SHIFT_SET_SET sss, NRC_POLARITY po);
}
any number of times, arbitrarily intermixed.  This adds the
shift-sets, each accompanied by a polarity, either one at a
time or many at once.  There is also
@ID {0.98 1.0} @Scale @C {
void NrcConstraintAddPattern(NRC_CONSTRAINT c, NRC_PATTERN p, NRC_DAY d);
}
A pattern is a sequence of shift-type sets with polarities, and
@C { NrcConstraintAddPattern } simply makes the corresponding
sequence of calls to @C { NrcConstraintAddShiftSet }, converting
each shift type set @C { sts } into a shift set, by calling
@C { NrcDayShiftSetFromShiftTypeSet(d, sts) } for the shift
type set of the first term, and similarly using successive
days for successive terms.
@PP
To visit the shift-sets and polarities added to a constraint
@C { c }, call
@ID @C {
int NrcConstraintShiftSetCount(NRC_CONSTRAINT c);
void NrcConstraintShiftSet(NRC_CONSTRAINT c, int i,
  NRC_SHIFT_SET *ss, NRC_POLARITY *po);
}
as usual.  The constraint does not remember whether the shift-sets
and polarities were added individually, or using shift-set sets, or
using patterns.
@PP
One common form of constraint, the unwanted pattern, is already
implemented:
@ID @C {
NRC_CONSTRAINT NrcUnwantedPatternConstraintMake(NRC_INSTANCE ins,
  char *name, NRC_WORKER_SET ws, NRC_PENALTY penalty, NRC_PATTERN p,
  NRC_DAY_SET starting_ds);
}
The first three parameters and the return value are as for
@C { NrcConstraintMake }.  Parameter @C { penalty } is the
penalty to apply when the pattern is violated.  The last two
parameters give the unwanted pattern and the set of days on
which it may begin (pass @C { NrcInstanceCycle(ins) } if it
may begin on any day).  Here @C { p } must contain at least
one term, and @C { starting_ds } must contain at least one day.
@PP
Function
@ID @C {
void NrcConstraintDebug(NRC_CONSTRAINT c, int indent, FILE *fp);
}
produces a debug print of @C { c } onto @C { fp }, as explained
in Section {@NumberOf instances.debug}.
@PP
Behind the scenes, NRConv implements an important optimization
called @I { condensing }, which converts sets of constraints
of type @C { NRC_CONSTRAINT_ACTIVE } into constraints of type
@C { NRC_CONSTRAINT_CONSECUTIVE } when the shift-sets are
uniform (when they repeat regularly along the cycle).  When
source files implement minimum and maximum limits on
the number of busy days using patterns, condensing changes
them back into constraints which limit the numbers directly.
The implementation has been done with care and produces an
exact result whenever it is applied.  The new constraints
have the old names with @C { " (condensed)" } appended.
@End @SubSection

#@SubSection
#    @Title { Limits }
#    @Tag { instances.constraints.limits }
#@Begin
#@LP
#In the previous section, worker constraints were defined, but
#how the limits on the number of active shift-sets are defined was
#deferred to this section.
#@PP
#Each worker constraint contains one @I { limit }, which is either
#a @I { minimum limit }, saying that at least some number of
#active shift-sets is wanted, a @I { maximum limit }, saying
#that at most some number of active shift-sets is wanted, or a
#@I { double limit }, giving both a minimum and a maximum.
#@PP
#A limit is represented by an object of type @C { NRC_LIMIT },
#created by calling either of
#@ID @C {
#NRC_LIMIT NrcLimit(NRC_LIMIT_TYPE type, int limit);
#NRC_LIMIT NrcLimit2(NRC_LIMIT_TYPE type, int min_limit, int max_limit);
#}
#Every limit object contains three attributes, corresponding to the
#three parameters of @C { NrcLimit2 }.  These three attributes may
#be retrieved by calling
#@ID @C {
#NRC_LIMIT_TYPE NrcLimitType(NRC_LIMIT limit);
#int NrcLimitMinLimit(NRC_LIMIT limit);
#int NrcLimitMaxLimit(NRC_LIMIT limit);
#}
#@C { NrcLimit } sets both limits to @C { limit }.  If the type is not
#a double limit, only one will be used.
#@PP
#The @C { type } attribute has type @C { NRC_LIMIT_TYPE }, which is
#@ID @C {
#typedef enum {
#  NRC_LIMIT_MIN,
#  NRC_LIMIT_MIN_OR_ZERO,
#  NRC_LIMIT_MAX,
#  NRC_LIMIT_MIN_CONSECUTIVE,
#  NRC_LIMIT_MAX_CONSECUTIVE,
#  NRC_LIMIT_MIN_WORKLOAD,
#  NRC_LIMIT_MAX_WORKLOAD,
#  NRC_LIMIT_MIN_AND_MAX,
#  NRC_LIMIT_MIN_OR_ZERO_AND_MAX,
#  NRC_LIMIT_MIN_AND_MAX_CONSECUTIVE,
#  NRC_LIMIT_MIN_AND_MAX_WORKLOAD
#} NRC_LIMIT_TYPE;
#}
#and specifies various minimum (@C { MIN }), maximum (@C { MAX })
#and double (@C {MIN_AND_MAX}) limits.
#@PP
#@C { NRC_LIMIT_MIN } means that the limit is a minimum limit on
#the number of active shift-sets:  the degree of violation of the
#enclosing constraint is the amount by which that number falls short
#of the limit's @C { min_limit } attribute.  The limit's @C { max_limit }
#attribute is not used.
#@PP
#@C { NRC_LIMIT_MIN_OR_ZERO } is like @C { NRC_LIMIT_MIN } except
#that, as a special case, there is no violation when the number is 0.
#@PP
#@C { NRC_LIMIT_MAX } means that the limit is a maximum limit on
#the number of active shift-sets:  the degree of violation of the
#enclosing constraint is the amount by which that number exceeds
#the limit's @C { max_limit } attribute.  The limit's @C { min_limit }
#attribute is not used.
#@PP
#@C { NRC_LIMIT_MIN_CONSECUTIVE } and @C { NRC_LIMIT_MAX_CONSECUTIVE }
#cause the enclosing constraint's shift-sets to be taken consecutively.
#The limit applies, not to the total number of active shift-sets, but to
#the length of each maximal non-empty subsequence of active shift-sets.
#@FootNote {
#The author learned of this approach to constraining consecutive
#subsequences from Gerhard Post.
#}
#&2s The penalty is the sum over all maximal non-empty subsequences of
#active shift-sets @M { I } of the cost associated with the amount by
#which the length of @M { I } exceeds the limit, or falls short of it.
#@PP
#@C { NRC_LIMIT_MIN_WORKLOAD } and @C { NRC_LIMIT_MAX_WORKLOAD } are
#like @C { NRC_LIMIT_MIN } and @C { NRC_LIMIT_MAX }, except that the
#limit applies to the total workload of the worker's busy shifts,
#instead of their number.
## In these cases it is an error to call
## @C { NrcConstraintAddShiftSet } and the similar functions defined
## below, because the constraint always applies to all shifts.
#@PP
#There is no @C { NRC_LIMIT_MIN_OR_ZERO_CONSECUTVE } limit type
#because a non-empty subsequence cannot have length zero.  There
#are no @C { NRC_LIMIT_MIN_WORKLOAD_CONSECUTIVE } and
#@C { NRC_LIMIT_MAX_WORKLOAD_CONSECUTIVE } limit types because,
#although they would arguably make sense, they are not needed
#in practice and are not supported.
#@PP
#The last four limit types are double limits, combining one
#minimum limit with one maximum limit.  They use both the
#@C { min_limit } and the @C { max_limit } attributes.  One
#constraint with a double limit has identical effect to two
#constraints with the corresponding single limits.
#@PP
#For debugging, functions
#@ID @C {
#char *NrcLimitTypeShow(NRC_LIMIT_TYPE limit_type);
#char *NrcLimitShow(NRC_LIMIT limit);
#}
#return a string representation of a limit type (@C { "min" },
#@C { "max_consecutive" }, and so on) and a string representation
#of a limit (@C { "min 3" }, @C { "max_consecutive 4" }, and so on).
#The result of @C { NrcLimitShow } lies in static memory and will
#be overwritten by the next call to @C { NrcLimitShow }.
#@End @SubSection

@SubSection
    @Title { Examples of worker constraints }
    @Tag { instances.constraints.examples }
@Begin
@LP
@I { this section is out of date, it needs a makeover }
@LP
This section presents some examples of worker constraints.  Many
more may be found in the source code.  For reference, here is the
interface of @C { NrcConstraintMake } from
Section {@NumberOf instances.constraints.worker_constraints}:
@ID @C {
NRC_CONSTRAINT NrcConstraintMake(NRC_INSTANCE ins, char *name,
  NRC_WORKER_SET ws, NRC_CONSTRAINT_TYPE type, NRC_BOUND bound,
  NRC_SHIFT_SET starting_ss);
}
Let @C { ins } be an NRC instance.  To say that all staff should
work at most one shift per day:
@ID @C {
c = NrcConstraintMake(ins, "Single assignment per day",
  NrcInstanceStaffing(ins), p, NRC_LIMIT_MAX, 1,
  NrcInstanceDailyStartingShiftSet(ins));
NrcConstraintAddShiftSetSet(c,
  NrcDayShiftSetSet(NrcInstanceCycleDay(ins, 0), NRC_POSITIVE);
}
Looking along the arguments of @C { NrcConstraintMake }, @C { c }
applies to all workers, has penalty @C { p }, maximum limit 1
(not consecutive), and repeats each day.  The second statement
defines the first point where it applies:  to the shifts of the
first day of the cycle.  The shift-set set ensures that each
shift is added in its own shift-set, so that the usual limit
on the number of busy shift-sets becomes a limit on the number
of busy shifts.  It would be wrong to pass in a single shift-set
containing all the shifts of the day, but NRConv works out that
this is a simple case and generates a limit busy times constraint
rather than a cluster busy times constraint.
@PP
To impose a maximum workload limit of 28 shifts:
@ID @C {
c = NrcConstraintMake(ins, "At most 28 shifts",
  NrcInstanceStaffing(ins), p, NRC_LIMIT_MAX, 28, NULL);
NrcConstraintAddShiftSetSet(c, NrcInstanceShiftsShiftSetSet(ins),
  NRC_POSITIVE);
}
Here @C { c } applies to all workers, has penalty @C { p },
is not consecutive, and does not repeat.  The second statement
adds each shift, again in its own shift-set.
@PP
Making a pattern @C { p } unwanted is very easy:
@ID @C {
c = NrcConstraintMake(ins, "Unwanted pattern", NrcInstanceStaffing(ins),
  p, NRC_LIMIT_MAX, NrcPatternTermCount(p) - 1,
  NrcInstanceDailyStartingShiftSet(ins));
NrcConstraintAddPattern(c, p, NrcInstanceCycleDay(ins, 0));
}
The constraint applies to all workers, has penalty @C { p }, has a
maximum limit of one less than the pattern length (not consecutive),
and starts afresh each day.  The last line adds shift-sets defining
the first occurrence of the pattern, beginning on the first day of
the cycle.
@PP
NRConv offers @C { NrcUnwantedPatternConstraintMake }, its own
implementation of unwanted patterns, documented near the end of
Section {@NumberOf instances.constraints.worker_constraints}.
It is rather more complex than the code above, mainly because,
if the pattern is uniform (has the same shift-set and the same
polarity at every term) and may begin on any day, it optimizes
by generating a limit active intervals constraint rather than a
cluster busy times constraint which repeats on each day:
@ID @C {
NRC_CONSTRAINT NrcUnwantedPatternConstraintMake(NRC_INSTANCE ins,
  char *name, NRC_WORKER_SET ws, NRC_PENALTY penalty, NRC_PATTERN p,
  NRC_DAY_SET starting_ds)
{
  NRC_CONSTRAINT res;  NRC_SHIFT_TYPE_SET sts;  NRC_POLARITY po;  int i;
  NRC_DAY d;  NRC_SHIFT_SET ss;

  MAssert(NrcPatternTermCount(p) > 0,
    "NrcUnwantedPatternConstraintMake:  empty pattern");
  MAssert(NrcDaySetDayCount(starting_ds) > 0,
    "NrcUnwantedPatternConstraintMake:  empty starting_ds");
  if( NrcDaySetDayCount(starting_ds) == NrcInstanceCycleDayCount(ins)
      && NrcPatternIsUniform(p) )
  {
    /* uniform pattern, single limit active intervals constraint */
    res = NrcConstraintMake(ins, name, ws, penalty,
      NRC_LIMIT_MAX_CONSECUTIVE, NrcPatternTermCount(p)-1, NULL);
    NrcPatternTerm(p, 0, &sts, &po);
    for( i = 0;  i < NrcInstanceCycleDayCount(ins);  i++ )
    {
      d = NrcInstanceCycleDay(ins, i);
      ss = NrcDayShiftSetFromShiftTypeSet(d, sts);
      NrcConstraintAddShiftSet(res, ss, po);
    }
  }
  else
  {
    /* non-uniform pattern, repeating cluster busy times constraint */
    res = NrcConstraintMake(ins, name, ws, penalty, NRC_LIMIT_MAX,
      NrcPatternTermCount(p)-1, NrcDaySetStartingShiftSet(starting_ds));
    NrcConstraintAddPattern(res, p, NrcDaySetDay(starting_ds, 0));
  }
  return res;
}
}
This function could be written by an NRC user; it does not use any
behind-the-scenes features.
@PP
Constraints involving weekends need to know when the weekends are.
One way to express this is as a day-set set, each day-set of which
contains the days of one weekend, in chronological order.  Such a
day-set set can be built using NRC's functions for building day-sets
and day-set sets, following whatever rule the format uses to define
weekends, and shared by all constraints concerning weekends.  Assuming
that @C { weekends_dss } is such a day-set set, the following code
places a maximum limit of 3 on the number of consecutive weekends
that worker @C { w } can work:
@ID {0.98 1.0} @Scale @C {
NRC_CONSTRAINT c;  int i;  NRC_DAY_SET ds;
c = NrcConstraintMake(ins, "At most 3 consecutive weekends",
  NrcWorkerSingletonWorkerSet(w), p, NRC_LIMIT_MAX_CONSECUTIVE, 3, NULL);
for( i = 0;  i < NrcDaySetSetDaySetCount(weekends_dss);  i++ )
{
  ds = NrcDaySetSetDaySet(weekends_dss, i);
  NrcConstraintAddShiftSet(c, NrcDaySetShiftSet(ds), NRC_POSITIVE);
}
}
The constraint applies to @C { w } only, has penalty @C { p },
has maximum limit 3, and is consecutive.  There is one shift-set
for each weekend, containing the shifts of that weekend.
@End @SubSection

@SubSection
    @Title { Adding history to worker constraints }
    @Tag { instances.constraints.history }
@Begin
@LP
Some constraints need to be influenced by the history of the
workers whose timetables they constrain.  This can be done by
first calling
@ID @C {
void NrcConstraintAddHistory(NRC_CONSTRAINT c, int history_before,
  int history_after);
}
once, then
@ID @C {
void NrcConstraintAddHistoryWorker(NRC_CONSTRAINT c, NRC_WORKER w,
  int value);
}
at most once for each worker @C { w } in @C { c }'s worker-set.
The @C { history_before }, @C { history_after }, and @C { value }
values are the @M { a sub i }, @M { c sub i }, and @M { x sub i }
values from Jeff Kingston's paper on history.
# Their effect is complicated and depends on @C { consecutive }.
# Here @C { value } must be non-negative.  It makes the constraint
# behave (for @C { w } only) as though it contained @C { value }
# shift-sets immediately preceding the existing ones, all active.  If
# @C { consecutive } is @C { false }, this is similar to reducing the
# limit by @C { value }, the difference being that it works even when
# that would make the limit negative (which is not otherwise allowed),
# and that the XESTT it generates is more concise.  If @C { consecutive }
# is @C { true }, this is similar to reducing the limit for the first
# active sub-sequence if it starts with the first shift-set, something
# that is hard to model without @C { NrcConstraintAddHistory }.
# @PP
# A worker @C { w } in @C { c }'s worker-set for which no call to
# @C { NrcConstraintAddHistory } is made is treated as though there
# was a call @C { NrcConstraintAddHistory(c, w, 0) }.
@PP
Functions @C { NrcWorkerAddHistory } and @C { NrcWorkerRetrieveHistory }
from Section {@NumberOf instances.workers.workers} make it easy to
store history values in workers.  However, they do not automatically
pass these values on to constraints.  Code like this is needed for that:
@ID @C {
c = NrcConstraintMake(..., ws, ...);
NrcConstraintAddHistory(c, ...);
for( i = 0;  i < NrcWorkerSetWorkerCount(ws);  i++ )
{
  w = NrcWorkerSetWorker(ws, i);
  if( NrcWorkerRetrieveHistory(w, "WeekendsWorked", &v) && v > 0 )
    NrcConstraintAddHistoryWorker(c, w, v);
}
}
Accordingly, NRC offers helper function
@ID @C {
void NrcConstraintAddHistoryAllWorkers(NRC_CONSTRAINT c,
  int history_before, int history_after, char *name);
}
whose body is the call to @C { NrcConstraintAddHistory } plus
the loop, with @C { name } for @C { "WeekendsWorked" } and
@C { NrcConstraintWorkerSet(c) } for @C { ws }.  Most cases
are best handled by @C { NrcConstraintAddHistoryAllWorkers },
but when its simple approach is not sufficient,
one can fall back on @C { NrcConstraintAddHistory } and
@C { NrcConstraintAddHistoryWorker }.
@PP
History may not be added to a constraint with a starting shift-set.
It is just too hard to assign a reasonable meaning to it.
#This section presents NRC's functions for adding constraints to
#instances.  Nurse rostering has many similar constraints, and
#there have been many attempts to classify them.  This section
#contains another attempt, loosely based on working backwards
#from what NRC produces.
#@BeginSubSections
#
#@SubSection
#    @Title { Limiting the number of consecutive busy or free days }
#@Begin
#@LP
#The author has struggled to classify constraints that limit the
#number of consecutive busy or free days, and so we begin with a
#discussion of them.
#@PP
## To begin with, there is the question of whether some requirement
## is one large constraint or several small ones.  If each worker
## wants to either work both days of each weekend or neither, is
## that one constraint, or one per worker, or one per weekend, or
## one per weekend and worker?
## @PP
## There are reasons for favouring large constraints:  they usually
## reflect the user's thinking, they tend to produce less verbose
## instance files, and monitoring one large constraint may be more
## efficient than monitoring several small ones.  However, the real
## issue is rather different, and concerns constraints which limit
## the number of consecutive busy or free days.  The distinction
## between small and large is challenged by these constraints.  On
## the one hand,
#Sequences of too few or too many consecutive busy or free days can
#appear anywhere in the cycle and be of any length.  This suggests that
#one large constraint spanning the whole cycle is appropriate for them.
#On the other hand, they are often implemented (in integer programming
#models, for example) using many small overlapping time windows.
#@PP
#Time windows have two main advantages.  First, they are familiar from
#other constraints, notably unwanted pattern constraints, for which
#they are perfectly appropriate.  Second, for each window the
#implementation is simple, involving keeping track of which days are
#busy and which are free, and comparing a total with the limits.
#Tracking maximal subsequences of busy or free days over the cycle
#is harder, and may need complex data structures, such as splay
#trees, if the potential for increased efficiency in having fewer
#constraints to update is to be realized.
## to ensure efficient incremental evaluation for longer cycles.
#@PP
#But time windows also have disadvantages.  First, there is an
#undesirable artificiality about implementing limits on the number of
#consecutive busy or free days with them.  A clear symptom of this is
#the care needed to ensure that the correct costs are attributed to
#violating sequences.  Second, the number of time windows for minimum
#limits seems excessive:  one for every value below the limit starting
#on every day.  In the whole-cycle approach, each day appears just once
#in the constraint; in the time window approach, if the minimum limit
#is @M { m }, each day not near the end of the cycle appears in about
#@M { m sup 2 "/" 2 } windows.
#@PP
#Some light is shed on this problem by the limit idle times constraint
#from XHSTT.  An idle time (with respect to some fixed sequence of
#times, such as the times of one day) is a time in the sequence when
#a resource is not busy, but is busy earlier in the sequence and
#later.  Here a large constraint covering the whole fixed sequence
#is inevitable, because smaller time windows simply do not work.  It
#may be, then, that the existence of time window implementations of
#constraints that limit the number of consecutive busy or free days
#is a coincidence, and not a worthy basis of an implementation.
#Limit idle times constraints are also a reminder of the
#heterogeneity of timetabling constraints.  There is no inherent
#virture in trying to fit them all to one template.
#@PP
#NRC may be said to finesse this problem.  There are clear advantages
#for users in offering large constraints in the intermediate model,
#including limits on the number of consecutive busy and free days,
#and this NRC does.  Whether XESTT supports these large constraints
#directly, or requires NRC to expand them into sets of small constraints,
#then becomes a separate issue.
#@End @SubSection
#
#@SubSection
#    @Title { A classification }
#@Begin
#@LP
#In this section we present our classification in general terms.
#Later sections give the specifics of the NRC implementation.
#@PP
#Classifications often use the term `sequencing constraint' for
#constraints which prevent certain sequences of shifts in a timetable.
#This term is acceptable informally, but it is problematic for
#classification, because it has no clear boundary.  For example, a
#familiar constraint places a limit on the number of weekends worked
#during each four-week period.  One would not call this a sequencing
#constraint.  But it is similar to limiting the number of days worked
#during each four-day period, and if the limit is 3, then that is the
#same as imposing a maximum limit of 3 consecutive working days, a
#sequencing constraint.  So our classification will not use this term.
#@PP
#The first attribute of our classification says whether a minimum or
#maximum limit is imposed, and may have value @C { Min },
#@C { MinOrZero }, @C { Max }, or @C { Unwanted }.  @C { MinOrZero }
#means that either the minimum limit must be reached, or that zero
#is acceptable.  For example, to say that a worker should either
#work both days on a weekend or neither, a @C { MinOrZero } limit
#is needed with minimum limit 2.  @C { Unwanted } just means
#`maximum of zero'.  It is a convenient form of expression in some
#cases, such as in @C { UnwantedDays }.
## @PP
## Implementing minimum limits can be more complex than implementing
## maximum ones, requiring a set of constraints, each of which rules
## out one of the values below the minimum.  This phenomenon also
## appears in integer programming formulations.  What follows is based
## on maximum limits; the extra complexity of implementing minimum
## limits is treated as unimportant from the classification point of view.
#@PP
#The second attribute specifies whether the limit applies to busy
#shift-sets (shift-sets containing at least one busy shift for the
#worker) or free shift-sets (shift-sets containing no busy shifts for
#the worker).  Accordingly, its value may be @C { Busy } or @C { Free },
#except that, when the shift-sets make patterns, some may have to be
#busy and others free, for which we use the value @C { Matching }.
#@PP
#The third attribute identifies the kinds of shift-sets that appear
#in the constraint.  For example, they could be shifts, or days, or
#weekends, and so @C { Shifts }, @C { Days }, and @C { Weekends }
#are suitable values, among others.
## But there are also
## cases where what is wanted here is more complicated.  For
## example, in patterns some time groups have to be free, others
## have to be busy, and so on.  So a third value, @C { Pattern },
## is allowed, which specifies that these details are to be found
## in the constraint's parameters.
#@PP
#The fourth and last attribute of our classification concerns how a
#constraint is localized within the cycle.  Its values are @C { Global },
#for when there is one large time window covering the whole cycle,
#@C { Windowed } when there is a small time window repeated along the
#cycle, @C { Local } when there is a small time window not repeated
#along the cycle, and @C { Consecutive } when maximal sequences of
#consecutive busy or free shift-sets define the localization.
#@PP
#A few words are needed about @C { Windowed }.  In a hospital, one
#week is like another, and one day is like another except for Saturday
#and Sunday.  Thus, when a constraint applies to some local area, such
#as a weekend, it is usually repeated on every such local area, and
#this is what is offered by @C { Windowed }.  But how often it repeats
#can vary.  A pattern extends over several days but repeats every day.
#A limit on the number of weekends worked in four weeks extends over
#four weeks, but could repeat every week or every four weeks.  We
#leave these details to the constraint's parameters, and just use
#@C { Windowed } to indicate the general form of the localization.
#@PP
#All this leads to constraint names like @C { MaxBusyDaysGlobal },
#@C { MinFreeWeekendsWindowed }, @C { MinBusyDaysConsecutive },
#@C { UnwantedBusyDaysLocal }, and so on.  Here is a comparison
#with the constraint names used in the First International Nurse
#Rostering Competition:
#@CD @Tbl
#   bformat { @Cell ml { 0i } @I A | @Cell mr { 0i } @I B }
#   aformat { @Cell ml { 0i } @F A | @Cell mr { 0i } @F B }
#   mv { 0.5vx }
#{
#@Rowb
#   A { Name in competition }
#   B { Our name }
#   rb { yes }
#@Rowa
#   A { SingleAssignmentPerDay }
#   B { MaxBusyShiftsWindowed }
#@Rowa
#   A { MaxNumAssignments }
#   B { MaxBusyDaysGlobal }
#@Rowa
#   A { MinNumAssignments }
#   B { MinBusyDaysGlobal }
#@Rowa
#   A { MaxConsecutiveWorkingDays }
#   B { MaxBusyDaysConsecutive }
#@Rowa
#   A { MinConsecutiveWorkingDays }
#   B { MinBusyDaysConsecutive }
#@Rowa
#   A { MaxConsecutiveFreeDays }
#   B { MaxFreeDaysConsecutive }
#@Rowa
#   A { MinConsecutiveFreeDays }
#   B { MinFreeDaysConsecutive }
#@Rowa
#   A { MaxConsecutiveWorkingWeekends }
#   B { MaxBusyWeekendsConsecutive }
#@Rowa
#   A { MinConsecutiveWorkingWeekends }
#   B { MinBusyWeekendsConsecutive }
#@Rowa
#   A { MaxWorkingWeekendsInFourWeeks }
#   B { MaxBusyWeekendsWindowed }
#@Rowa
#   A { CompleteWeekends }
#   B { MinOrZeroBusyDaysWindowed }
#@Rowa
#   A { IdenticalShiftTypesDuringWeekend }
#   B { MinOrZeroBusyShiftsWindowed }
#@Rowa
#   A { NoNightShiftBeforeFreeWeekend }
#   B { MaxMatchingDaysWindowed }
#@Rowa
#   A { AlternativeSkillCategory }
#   B { (affects cover constraint) }
#@Rowa
#   A { DayOff }
#   B { UnwantedBusyDaysLocal }
#@Rowa
#   A { ShiftOff }
#   B { UnwantedBusyShiftsLocal }
#@Rowa
#   A { UnwantedPatterns }
#   B { MaxMatchingDaysWindowed }
#   rb { yes }
#}
#Our names are not intended to fully describe constraints in all cases.
#Parameters containing limits, shift-sets, patterns, and so on must be
#added to complete the specifications.
#@End @SubSection
@End @SubSection

@EndSubSections
@End @Section

@Section
    @Title { Solutions }
    @Tag { instances.solns }
@Begin
@LP
This section describes solutions.  A solution is a collection of
assignments to the demands of the shifts of one instance.  It is
a very simple thing, making this a very short section.
@PP
To create a new solution for a given instance, call
@ID @C {
NRC_SOLN NrcSolnMake(NRC_INSTANCE ins, HA_ARENA_SET as);
}
where @C { as } is as for @C { NrcInstanceMake }.
To retrieve the instance, call
@ID @C {
NRC_INSTANCE NrcSolnInstance(NRC_SOLN soln);
}
A solution contains an optional description, giving its
provenance.  To set and retrieve it, call
@ID @C {
void NrcSolnSetDescription(NRC_SOLN soln, char *description);
char *NrcSolnDescription(NRC_SOLN soln);
}
@C { NrcSolnDescription } returns @C { NULL } when there
is no description.
@PP
A solution also contains an optional running time, giving the
time in seconds that it took to find.  To set this value and
retrieve it, call
@ID @C {
void NrcSolnSetRunningTime(NRC_SOLN soln, float running_time);
float NrcSolnRunningTime(NRC_SOLN soln);
}
@C { NrcSolnRunningTime } returns @C { -1.0 } when no running
time has been passed, meaning `absent'.
@PP
A newly created solution does not lie in any archives.  To add it to
an archive, the user must first ensure that that archive has a
solution group, by calling @C { NrcSolnGroupMake }
(Section {@NumberOf archives.soln_groups}).  Then the solution may be
added to the solution group, by calling @C { NrcSolnGroupAddSoln }.
@PP
Internally, a solution is just a collection of assignments of
workers to the demands of shifts.  Each demand accepts at most
one assignment.  To add an assignment, call
@ID @C {
void NrcSolnAddAssignment(NRC_SOLN soln, NRC_SHIFT s, int i,
  NRC_WORKER w);
}
This assigns @C { w } to demand @C { i } of @C { s }, where
@C { 0 <= i < NrcShiftDemandCount(s) }.  The assignment is in
@C { soln }, not in the instance; the instance does not change.
@C { NrcSolnAddAssignment } aborts if an attempt is made to
assign a second worker to the same demand.
@PP
To inspect an existing assignment, call
@ID @C {
NRC_WORKER NrcSolnAssignment(NRC_SOLN soln, NRC_SHIFT s, int i);
}
This returns @C { NULL } when no assignment has been made.  Unassigned
demands are acceptable within solutions, although they usually incur a
penalty, depending on the demand's penalties.
@End @Section

@EndSections
@End @Chapter
