|
|
Vishnu User's Guide
I. Introduction
I.1 What is Vishnu?
Vishnu is a reconfigurable, web-based, optimizing scheduling system. It
performs scheduling in the sense that it assigns tasks to resources at
particular times. It is reconfigurable in that it is capable of being configured
purely by data specifications and not by recoding to handle a wide range
of different scheduling problems with different scheduling semantics. It
is optimizing insofar as it allows the specification of a criterion for
evaluating how good a legal schedule is and will try to find a schedule
that is as good as possible (in many cases actually finding an optimal
or near optimal schedule). It is web-based since the GUI runs completely
from a browser and since all interactions with the central database are
via a web server. The graphical interface allows the user to define
Vishnu problems using the point-and-click interface afforded by today's
web browsers.
So, if you have a scheduling problem that you've been trying to solve
better, Vishnu may be the solution for you. You can tailor the type
of data that will be optimized and specify in detail how that data should
be used in forming a meaningful schedule, what dependencies that may exist
between elements of the schedule, and how to determine the goodness of
a given schedule. You can also tailor the details of the search algorithm
to allow for a detailed, fine-grained search if the best possible schedule
is needed irregardless of real-time, or to allow for a quick and dirty
search that will find the best solution it can as quickly as possible.
It is all in your hands - you provide both the problem-specific data and
the problem-specific logic to guide the search. Vishnu provides the
framework you need to enter that knowledge and a proven back-engine that
will chug away for you.
I.2 Vishnu Technology
Vishnu delivers its capabilities through the use of a web server front-end
and a genetic algorithm back-end. To use Vishnu, and for this tutorial,
you do not need to know details of what genetic algorithms are and how
they work. But, a brief introduction is provided <here> if you
wish to familiarize yourself with some of the basics. The web-server
front-end has a visual interface (see vishnu.bbn.com/vishnu/vishnu.php
) that allows a user to manually specify a scheduling problem and submit
it for optimization. The web-server can also be used seamlessly as
a service to a domain-dependent scheduling application. That application
may submit problems directly to the web-site, initiate the optimization
and extract the resulting solutions. All without the user ever looking
at the web-site. To properly design such an application, the <Vishnu
API> and the <Vishnu XML problem format> must be understood. The
API is currently in Java, but instructions on how to access the web-server
directly are provided <here>. User of ALP may use the Couggar-Vishnu
Bridge to quickly design an interface to Vishnu for their problems.
I.3 What is a Scheduling Problem in Vishnu?
The goal of Vishnu is to solve a given scheduling problem by finding the
best possible way of assigning tasks to resources
over time. The assigning of a task to a resource basically involves "reserving"
that resource for the particular task for a particular contiguous time
interval. In a basic Vishnu problem, a single task may reserve only
a single resource (for a single time interval) and a single resource may
be reserved by multiple tasks over time. The total picture: multiple
tasks assigned to multiple resources at various time intervals, with no
overlapping and with no unassigned tasks. We'll call this a schedule.
Given a set of tasks and resources, there are a variety of possible
schedules since tasks may be assigned to different resources in different
orders at different times. In the most general case, Vishnu will
assume that all tasks are fully independent and that they may be assigned
to any resource in any order at any time, so long as they are given a sufficient
time interval on the resource that they are finally assigned to.
This is very simplistic, and in most interesting problems there are a variety
of dependencies that may exist among the tasks and between the tasks and
resources. For example, a task may require that certain other
particular tasks, regardless of which resources they are assigned to, be
complete before it can start. This notion of a pre-requisite
is
one of several dependencies among tasks supported by Vishnu. As another
example, a task may require that it be assigned to a subset of the resources
since it is not capable of being performed on certain resources.
This notion of capability is one of several dependencies
between tasks and resources supported by Vishnu. Problems may also
have constraints placed upon the tasks and resources. For example,
a particular resource (e.g., a computer) may not be available at all times
due to known issues (e.g., goes down for backup every day from 1:00 am
to 2:00 am). This notion of unavailability is one of
several constraints supported by Vishnu.
Defining a scheduling problem in Vishnu requires a complete specification
of all tasks, all resources, all dependencies among tasks and between tasks
and resources, and all constraints on tasks and resources. Together,
these define what constitutes a valid schedule. Finally,
defining a scheduling problem in Vishnu also requires an explicit specification
of a function that measures of how good a particular, valid schedule is.
Without this optimization criterion, Vishnu is unable to
compare schedules and search for the best possible one.
The idea is simple: Let Vishnu know what defines a legal schedule,
and how to compare different schedules, and Vishnu will search for the
best schedule it can find.
I.4 What Kinds of Problems can be Solved by Vishnu?
Vishnu is capable of solving any problem which involves the allocation
of instances of a single type of task to instances
of a single type of resource for contiguous intervals of time. Given
a particular real-world problem, the user of Vishnu must conceptualize
that problem in terms of allocating a set of similar tasks to a set of
similar resources. This modelling step may require some initial effort
since it may require a slight change in the normal way of viewing that
scheduling problem in its domain. One must also be very clear about
what constraints are to be used to define a legal schedule. Vishnu
has been designed to allow a variety of dependencies and constraints to
be specified, and future work will extend these capabilities even further.
Finally, for Vishnu to be capable of performing an optimization, the user
must quantify the criteria that are to be used to determine how good a
particular schedule is. This is another step that may require a change
in mind-set since the original problem may have been optimized manually
used vague criteria or rough rules-of-thumb. Once the problem can
be modelled as above, it remains to enter the appropriate data and logic
into Vishnu.
Scheduling Problem: Job-Shop Scheduling
Many classic scheduling problems have a natural formulation that is easily
specified in and solved by Vishnu. For example, consider the classic
Muth-Thompson NxM job-shop scheduling research problem (JSS). There are
M machines and N manufacturing jobs to be completed. Each job consists
of a chain of M steps. Each step of a job is assigned to a different
specified machine and requires the exclusive use of that machine for a
given duration. No two steps of a job are assigned to the same machine.
There is a specified order in which the steps for a certain job must be
performed, with one step unable to start until the previous step has ended.
The criterion to minimize is the makespan, which is defined as the
end time of the last step completed.
Can JSS be solved by Vishnu? Recall the two basic modelling steps
that are required:
a. Represent the problem in terms of one type of task and one type of
resource.
-
Here we have multiple machines and multiple jobs, each with multiple steps.
Which should be a task and which should be a resource? The obvious
answer is that the steps of a job should be the "tasks" and the machines
should be the "resources". The idea is that a job step "reserves"
the machine, and that multiple steps (of different jobs) wish to do this.
-
But, we have several dependencies that must be included, namely that the
steps of each jobs must be processed in a specific order. This type of
dependency (requiring one or more tasks to be the pre-requisite of another
task) is supported in Vishnu, so we are set - each successive step of a
given job can be assigned the previous step as a pre-requisite. Between
jobs there are no dependencies.
b. Develop clear criteria for evaluating how good a particular solution
is.
We wish to minimize the final completion time of the last step on the
schedule. This requires a simple lookup of the latest completion
time of all scheduled tasks.
|
Scheduling Problem? : Travelling Salesperson Problem
Many other problems, such as general optimization problems, may
not at first glance seem like something that can be solved by Vishnu.
These problems may require a shift or two in mind-set to specify and solve
them in Vishnu. For example, consider the popular Travelling Salesperson
Problem (TSP). There is a salesperson that needs to start at a given
city, travel to a set of other cities, visiting each city exactly once,
and then return to the starting city. The distance from any city
to any other city is known. The objective of TSP is to minimize the
total distance travelled.
Can TSP be solved by Vishnu? Recall the two basic modelling steps
that are required:
a. Represent the problem in terms of one type of task and one type of
resource.
-
Here we have multiple cities and a single salesperson. Which should
be a task and which should be a resource? If we considered the salesperson
to be the "task" and the cities to be "resources", then a Vishnu scheduling
problem would involve scheduling the salesperson to a single city and we
would be done. Not what we are looking for. If we consider
the cities to be the "tasks" and the salesperson to be the "resource",
then a Vishnu scheduling problem would involve scheduling all the cities
in various orders to the saleperson. This sounds better. The
idea is that a city "reserves" the salesperson, and that multiple cities
wish to do this.
-
But, what about the idea in Vishnu of allocating based upon "time"?
TSP involves the use of distance, not time. Can we model TSP in Vishnu?
Yes. It simply requires us to assume that each unit of distance takes
a unit of time. Drawing the equality between time and distance reflects
a change in "mind-set" as mentioned earlier. So, we define a resource
allocation as: a given city will reserve a salesperson for an amount of
time equal to the distance between that city and the previous one in the
schedule. This type of dependency (making the time interval of one
element of a schedule dependent upon the previous element) is supported
by Vishnu, so we are set.
-
And, we have one final dependency that we must include: the final city
must be the same as the start city. This requires a bit of finesse
in our thinking. Since it is impossible to schedule the same task
twice in a given schedule in Vishnu, we must represent the starting city
as two separate tasks - first and last. To ensure that
first
is the initial element of the schedule and last is the final element,
we must include appropriate dependencies into the problem. For example,
we can require that first must occur before every other task and
we can require that every other task must occur before last.
This type of dependency (requiring one or more tasks to be the pre-requisite
of another task) is supported in Vishnu, so we are set.
b. Develop clear criteria for evaluating how good a particular solution
is.
We wish to minimize total distance travelled. Given our equality
of time with distance, we thus wish to minimize the total time used.
The best schedule will have the lowest end-to-end time for the usage of
the salesperson.
|
The remainder of this tutorial will describe the details of defining,
creating, and executing a scheduling problem in Vishnu. The above
two problems will be revisited occasionally to illustrate the finer specification
details.
II. Defining a Vishnu Scheduling Problem
II.1 Overview: How is a Problem Specified
in Vishnu?
Now that we have a basic understanding of what a Vishnu scheduling
problem involves, it will be helpful to more concretely detail the specifics
of a Vishnu problem (and how they are manipulated using the Vishnu on-screen
interface).
Recall that the basic Vishnu problem is solved by legitimately and optimally
assigning tasks to resources. In Vishnu, we specify only one task
type and one resource type per problem. This
is analogous to specifying a user-defined data type in a high-level programming
language like C. Once a task type (resource type) has been defined,
we may create task instances (resource instances)
that store the data corresponding to the tasks (resources) of the problem.
When defining a task type or resource type, we specify for each a number
of data fields. Each field may be given an arbitrary name and the
information stored in the fields is given one of several formats (e.g.,
string,
list and number), as will be detailed later.
The task type (resource type) must contain a minimum of one field, and
must have a field which stores a unique value that is used to distinguish
task instances (resource instances) from each other. This field is
known as the KEY field.
For example, in the traveling salesperson problem we attempt to find
the optimal path for a salesperson (a resource) to take through a number
of cities (each city being a task that needs to be accomplished).
Note that in this problem there is only one type of task, a City,
but that there are multiple instances of that task. When defining
the task type for this problem, as a bare minimum we would want to include
a field such as name to store the name of the city as a string and
a field such as distances to store the distances from all the other
cities to the current one as a list. Information in a list
is indexed much in the same way as an array. So, our task type would
also require a field such as index to store a unique index number
for that city to correspond to the entries in the distances lists of other
cities. We make the index field the KEY field of the task
type since it contains unique values. Following our design of the
TSP problem in the previous section, we would also include a field such
as preceding_cities
in the task type. The value of preceding_cities
would store as a list all the cities that the salesperson must visit before
the current one.
But, we now arrive at a fundamental design issue in Vishnu. The
information present in the fields of the tasks and resources is simply
that: information. We may add any arbitrary number of fields with
arbitrary names to a given task type or resource type and store a variety
of actual data in the corresponding fields of the task and resource instances,
but this does not explain to Vishnu how to treat such information.
The user needs to define logic rules that use the data in
the various fields to define the dependencies, constraints and optimization
criteria that constitute a complete scheduling problem in Vishnu.
In particular, Vishnu allows the user to define 17 different logic rules
using a Vishnu-specific functional language (detailed later). Each
logic rule represents a function that is used by the optimization system
in a fixed manner. Each logic rule has a default function, which
the user may override with a new user-defined function. For example,
Vishnu contains a logic rule called Prerequisites which,
when executed for a given task, returns a list containing the KEY value
of all other tasks that must occur before that task. By default,
it returns the empty list. In our TSP example, we have made the specification
of that rule easy since it merely has to perform a lookup on the task's
preceding_cities
field. The syntax of this specification is described later.
Travelling Salesperson Problem:
City
(task type) |
Salesperson
(resource type) |
| Field
Name |
Field
Type |
| name |
string |
| index (KEY) |
number |
| distances |
list |
| preceding_cities |
list |
|
| Field
Name |
Field
Type |
| name (KEY) |
string |
|
Sample Cities:
Consider TSP with 3 cities: Washington, D.C.; Boston, MA; and New York,
NY. If our salesperson lives in Washington, we would want that to
be our starting and final city. Based upon the design above and in
the earlier section, we would create the following task instances to define
our problem.
Washington_first
(task instance)
|
Boston
(task instance)
|
New York
(task instance)
|
Washington_last
(task instance)
|
|
Field Name
|
Field Value
|
| name |
Washington D.C. |
| index |
1 |
| distances |
0, 440, 225, 0 |
| preceding_cities |
|
|
|
Field Name
|
Field Value
|
| name |
Boston |
| index |
2 |
| distances |
440, 0, 217, 440 |
| preceding_cities |
1 |
|
|
Field Name
|
Field Value
|
| name |
New York |
| index |
3 |
| distances |
225, 217, 0, 225 |
| preceding_cities |
1 |
|
|
Field Name
|
Field Value
|
| name |
Washington D.C. |
| index |
4 |
| distances |
0, 440, 225, 0 |
| preceding_cities |
1, 2, 3 |
|
Logic Rules (incomplete):
Prerequisites: task.preceding_cities |
In some problems, it is necessary or convenient to store information
in variables that are not directly associated with the tasks or resources.
These may be thought of as "global" variables. Vishnu includes the
capability of defining an arbitrary number of global types
and creating an arbitrary number of instances of each. A field of
a task type, resource type or other global type may be a reference to a
global instance or may be a instance of the global type itself. As
a fun example, we could create a global type called TV_show which
stores the name, producer, network, and actors
of
a given television show. We could create several global instances
of TV_show (e.g., Friends, Star Trek, Ally McBeal). At the
global level, we now have data that may be referenced by our cities.
We could add a field called
most_watched_show to the task type,
and then enter a specific show in each city (task instance). Two
or more cities could share the same show. Of course, this information
has no bearing on the TSP problem, but it illustrates how global instances
may be referenced.
Creating a scheduling problem in Vishnu requires the following
steps (not necessarily in order):
-
Defining a task type
-
Defining a resource type
-
Defining global type(s)
-
Defining a set of logic rules
-
Creating task instances
-
Creating resource instances
-
Creating global instances
|
In the following sections, we will describe what is involved in each
of these steps. As we go, we will describe both the design issues
involved as well as the practical steps that are required in manipulating
the user interface.
II.2 Vishnu Data Types
II.2.1 Predefined Types
Vishnu provides a variety of predefined atomic types and
predefined
object types that may be used when creating the user-defined data
types (i.e., task types, resource types and global types). The predefined
types in Vishnu are:
-
predefined atomic types:
-
string - A string is any combination of standard characters.
It may not contain the following five characters: " < > &
,
-
number - A number can be an integer or a floating point number.
-
boolean - A boolean has value either "true" or "false".
-
datetime - A datetime is formatted as "YYYY-MM-DD HH:MM:SS".
-
list - A list is a set of values of another type of unspecified
length. All the elements in a particular list should be of the same type.
The data type of the elements can be any predefined type other than a list
or it may be a user-defined type. If you need a list of lists, either use
a matrix (see below) or define an object type to contain the inner lists.
-
predefined object types:
-
interval - An interval represents an interval of time and contains
the fields:
-
start - A datetime specifying the start time of the interval
-
end - A datetime specifying the end time of the interval
-
label1 - A string that can be null (but is usually used for resource
unavailabilities, as discussed below)
-
label2 - A string that can be null
-
xy_coord - An xy_coord represents a point in x-y coordinates and
contains the fields:
-
x - A number specifying the x coordinate
-
y - A number specifying the y coordinate
-
latlong - A latlong represents a point on the earth's surface and
contains the fields:
-
latitude - A number between -90 and 90 specifying the latitude
-
longitude - A number between -180 and 180 specifying the longitude
-
matrix - A matrix is a two-dimensional array of numbers and contains
the fields:
-
numrows - A number specifying the number of rows
-
numcols - A number specifying the number of columns
-
values - A list of numbers of length numrows * numcols to fill in
the array by rows
II.2.2 User-Defined Types
Vishnu requires that the user define a task type and a resource type, and
provides the capability to define an arbitrary number of global types.
In creating each of these user-defined types, the following syntax rules
apply:
-
All user-defined types must have unique names.
-
Any name may be given to a user-defined type, so long as:
-
it starts with an alphabetic character
-
all characters in the name are either alphabetic, numeric, or '_'
-
Note, specifically, that type names may not have spaces in them
-
A task (resource) type must contain a minimum of 1 data field, which will
contain aKEY value that will uniquely identify all task (resource) instances.
-
The name of the KEY field may differ from the name of the task (resource)
type itself.
-
The type of the KEY field is always a string.
-
A global type does not contain a KEY field. Instead, the name of
each instance is used to uniquely identify that instance. A global
type may thus have 0 or more fields.
-
Fields in a user-defined type (including the KEY field) may be given any
name, so long as:
-
it is different from all other field names in that user-defined type
-
it starts with an alphabetic character
-
all characters in the name are either alphabetic, numeric, or '_'
-
Note, specifically, that field names may not have spaces in them
-
Each field is assigned a specific data type. When assigning a type
to a field, the following options are available:
-
a predefined atomic type (string, number, datetime, boolean)
-
a pointer to an instance of a predefined object type (interval, latlong,
xy_coord, matrix)
-
an encapsulated predefined object type
-
a pointer to an instance of a global type
-
an encapsulated global type
-
a list containing elements of a specific predefined type or global type.
A pointer to a global type (or global pointer) allows an
instance (A) of one object type to refer to an instance (B) of another
object type. This reference is made by entering the name of the target
instance (i.e., B) in the appropriate field of the referring instance (i.e.,
A).
An encapsulated global type allows a data field to become
a complex data field with multiple sub-fields. We can thus distinguish
between "top-level" fields of an object and "lower-level" fields.
Note that neither a task type nor a resource type may be assigned to a
field in any user-defined type (i.e., not in a global type, task type,
nor resource type). Also note that within user-defined global types,
circular encapsulations are possible in the current implementation, but
will eventually cause an error. So, the user must be careful to avoid
these. (In later versions, circular dependencies will be avoided
automatically.)
II.2.3 User-Defined Instances
Once types have been defined, instances of those types must created to
store the appropriate information for the problem. When creating
instances, the following syntax rules apply:
-
All task instances must have a unique KEY value.
-
All resource instances must have a unique KEY value.
-
These are permitted to be the same as the KEY values of task instances.
-
Global instances may be instances of a predefined object type or of a user-defined
global type.
-
All global instances, regardless of type, must have unique names.
-
For example, if there are five instances of global type A, three
instances of global type B, and two instances of latlong, then all ten
instances must have different names.
-
These names are permitted to be the same as the KEY values of task or resource
instances.
-
The name of any task, resource or global instance may be any arbitrary
string
-
e.g., spaces, punctutation, etc are permitted.
-
Note the difference: the name of the type has a strict format, but the
name of an instance is just a string
-
If a user-defined object contains a field that is a global pointer, then
the user should fill in the name of a global instance of the appropriate
type.
-
Note that Vishnu does not currently verify this information for you, so
please ensure that the instance is created and of the appropriate type.
(Later versions will perform automatic verification).
-
If a user-defined object contains a field that is an encapsulated type,
then the user will be prompted to enter the appropriate information for
the lower-level fields.
-
Lower-level fields are indicated through the use of an accessor.
Say a field in the object type "City" is named "statistics" and has an
encapsulated global type of "City_Stats". Say "City_Stats" has three
fields: "founding_date", "location" and "population". When
creating an instance of "City", you would be prompted to enter a value
for "statistics.founding_date", "statistics.location" and "statistics.population".
When the fields within the encapsulated object are themselves encapsulated
objects, those lower-levels will be indicated through a chain of accessors.
This syntax should look very familiar to programmers of object-oriented
languages.
We illustrate this syntax by expanding upon our earlier TSP example.
| Travelling Salesperson Problem:
We add two global types to our earlier example: TV_Show
and City_Stats. We also add two new fields to our task type.
The 'most_watched_show' field is a global pointer to a TV_Show instance.
The 'statistics' field is an encapsulated object of type City_Stats.
City
(task type) |
Salesperson
(resource type) |
TV_Show
(global type)
|
City_Stats
(global type)
|
| Field
Name |
Field
Type |
| name |
string |
| index (KEY) |
number |
| distances |
list |
| preceding_cities |
list |
| most_watched_show |
global ptr to TV_Show |
| statistics |
City_Stats |
|
| Field
Name |
Field
Type |
| name (KEY) |
string |
|
| Field
Name |
Field
Type |
| name |
string |
| networks |
list of string |
|
| Field
Name |
Field
Type |
| founding_date |
datetime |
| location |
latlong |
| population |
number |
|
Sample Cities:
A set of task instances, resource instances, and global instances
are provided. Note that the global instance 'Friends' is pointed
to by several task instances.
Washington_first
(task instance)
|
Boston
(task instance)
|
New York
(task instance)
|
Washington_last
(task instance)
|
|
Field Name
|
Field Value
|
| name |
Washington D.C. |
| index |
1 |
| distances |
0, 440, 225, 0 |
| preceding_cities |
|
| most_watched_show |
Friends |
| statistics.founding_date |
1790-01-01 00:00:00 |
| statistics.location |
39N 77W |
| statistics.population |
572059 |
|
|
Field Name
|
Field Value
|
| name |
Boston |
| index |
2 |
| distances |
440, 0, 217, 440 |
| preceding_cities |
1 |
| most_watched_show |
Friends |
| statistics.founding_date |
1630-01-01 00:00:00 |
| statistics.location |
42N 71W |
| statistics.population |
589141 |
|
|
Field Name
|
Field Value
|
| name |
New York |
| index |
3 |
| distances |
225, 217, 0, 225 |
| preceding_cities |
1 |
| most_watched_show |
Star Trek |
| statistics.founding_date |
1664-01-01 00:00:00 |
| statistics.location |
41N 73W |
| statistics.population |
8008278 |
|
|
Field Name
|
Field Value
|
| name |
Washington D.C. |
| index |
4 |
| distances |
0, 440, 225, 0 |
| preceding_cities |
1, 2, 3 |
| most_watched_show |
Friends |
| statistics.founding_date |
1790-01-01 00:00:00 |
| statistics.location |
39N 77W |
| statistics.population |
572059 |
|
Fred
(resource instance)
|
Friends
(global instance)
|
Star Trek
(global instance)
|
Ally McBeal
(global instance)
|
|
Field Name
|
Field Value
|
| name |
Fred Smith |
|
|
Field Name
|
Field Value
|
| name |
Friends |
| networks |
nbc |
|
|
Field Name
|
Field Value
|
| name |
Star Trek: Next Generation |
| networks |
abc, nbc, fox |
|
|
Field Name
|
Field Value
|
| name |
Ally McBeal |
| networks |
fox |
|
Logic Rules (incomplete):
Prerequisites: task.preceding_cities |
II.2.4 Keyword Variables
As we will see later, a logic rule requires access to certain information
about the Vishnu problem in order to perform meaningful computation.
To accomodate this, Vishnu has certain keyword variables
that are predefined. Not all keyword variables are available to all
logic rules. (Note: currently there is no restriction that avoids
an instance having the same name as a keyword variable. unknown effects
and potential logical errors in rule design may occur, especially in novices
- who may feel compelled to explicitly define such variables)
Keyword variables available to all logic rules:
-
tasks - a list of all task instances
-
resources - a list of all resource instances
-
start_time - the start of the scheduling window as a datetime object
-
end_time - the end of the scheduling window as a datetime object
Keyword variables available to only certain logic rules. The descriptions
may be slightly cryptic at this point, but will be elaborated upon later.
-
task - the task instance that is currently being considered for
insertion into the schedule
-
resource - the resource instance that is currently being analysed
-
prerequisites - a list of all task instances that have been computed
to be the prerequisites of task
-
previous - the task instance that occurs before task, assuming
a tentative insertion
-
next - the task instances that occurs immediately after task,
assuming a tentative insertion
-
duration - the task duration (for certain rules, this is available since it is computed by the underlying interpreter before the rule is executed)
-
assigned_so_far - all resources to which a task has been assigned so far (primarily for multitasking)
-
task1,task2 - used by Groupable rule to refer to two generic tasks (i.e., to compare them to see if they can be in the same group)
Note, these could have been defined as functions in the Vishnu specification
language described in the next section, but are provided as keywords for
ease of use when designing logic rules.
II.3 Vishnu Specification Language
Underlying the specification of logic rules in Vishnu is a simple functional
language reminiscent of LISP called the Vishnu specification language,
which includes predefined functions and operators.
II.3.1 Basic Functions
The Vishnu specification language includes a variety of basic predefined
functions that may be used when designing logic rules to manipulate data.
That data will be from the task instances, resource instances, and global
instances and may be of predefined or user-defined type.
The basic functions in the Vishnu specification language are described
in the table below. Each function has a unique name (e.g.,
'mod') as indicated in column 1. The function accepts specific parameter
types (e.g., 2 parameters: a 'number 'and a 'number'), and returns a specific
type (e.g., a 'number'). This is indicated in the second column
(e.g., '(number, number) => number' ). In the specifying the parameter
and return types, 'type' refers to an arbitrary data type (predefined
or user-defined) and '?' refers to an arbitary extra number of like elements.
A verbal description of each function is provided in the third column.
For ease of interpretation, the functions in the table have been grouped
roughly according to their main purpose. Most functions are fairly
straightforward. The iteration functions require a bit more careful
attention in order to understand exactly what they are computing.
| Function |
Data
Types |
Description |
| Variable Binding Functions |
|
|
| withvar |
(String,
type1, type2)
| The result of evaluating the second parameter is bound to the variable name provided by the first parameter. In computing the third parameter, the variable name may be used directly to refer to its value. (e.g., withvar("foo",5*3,foo+foo*foo)). Provides important efficiency properties (especially if the middle argument is complex and must be used multiple times in the third argument).
|
| Boolean Functions |
|
|
| if |
(boolean,
type,
<type>) => type |
If the first
argument is true, returns the second argument; otherwise, the third argument
(or null) |
| and |
(boolean,
<boolean>, ?) => boolean |
Logical
and of arguments |
| or |
(boolean,
<boolean>, ?) => boolean |
Logical
or of arguments |
| not |
(boolean)
=> boolean |
Logical
not of argument |
| hasvalue |
(type)
=> boolean |
Returns
true if the argument is not null |
| Math Functions |
|
|
| mod |
(number,
number) => number |
Remainder
when dividing the first argument by the second argument |
| abs |
(number)
=> number |
Absolute
value of a number |
| max |
(number,
<number>, ?) => number or
(datetime, <datetime>, ?) => datetime |
Maximum
value of arguments |
| min |
(number,
<number>, ?) => number or
(datetime, <datetime>, ?) => datetime |
Minimum
value of arguments |
| Creation Functions |
|
|
| string |
(type)
=> string |
Convert
any object into a string |
| latlong |
(number,
number) => latlong |
Return a
latlong object with latitude and longitude set to the first and second
arguments respectively |
| xy_coord |
(number,
number) => xy_coord |
Return a
xy_coord object with x and y set to the first and second arguments respectively |
| interval |
(datetime,
datetime, <string>, <string>) => interval |
Return an
interval object with start and end times set to the first and second arguments
and label1 and label2 set to the third and fourth arguments |
| list |
(<type>,
<type>,
?) => list |
Makes a
list out of all the arguments |
| append |
(string,
string) => string or
(list, list) => list |
Appends
two strings/lists into a longer string/list |
| Access Functions |
|
|
| dist |
(latlong,
latlong) => number or
(xy_coord, xy_coord) => number |
Returns
the distance (in nautical miles if using latlong's) between the two arguments. (Note, to convert from nautical miles to miles, must multiply by conversion factor 1.1507795) |
| entry |
(list, number)
=> type |
Returns
the ith element (starting from 1) of the list, where i is the
second argument |
| matentry |
(matrix,
number, number) => type |
Returns
the i-jth element (starting from 1) of the matrix, where i and
j are the second and third arguments |
| length |
(list) =>
number |
Returns
the length of a list |
| find |
(list, string,
boolean) => type |
Returns
the first element in the list such that when the variable named by the
second argument is set to this element the boolean expression given by
the third argument is true |
| position |
(list, type)
=> number |
Returns
the first position in the list (with the first element being 1) of the
given element |
| contains |
(list, type)
=> boolean |
Returns
true if the given list contains the given object.
|
| Iteration Functions |
|
|
| loop |
(number,
string,
type) => list |
Iterates,
setting the variable named by the second argument equal to all integers
between 1 and the first argument inclusive, accumulating the third argument
into a list |
| mapover |
(list, string,
type)
=> list |
Iterates
over each element of the first argument, setting the variable given by
the second argument to it, accumulating the value of the third argument
into a new list |
| sumover |
(list, string,
number) => number |
Iterates
over each element of the first argument, setting the variable given by
the second argument to it, summing the values of the third argument |
| maxover |
(list, string,
number) => number |
Iterates
over each element of the first argument, setting the variable given by
the second argument to it, maximizing over the values of the third argument |
| minover |
(list, string,
number) => number |
Iterates
over each element of the first argument, setting the variable given by
the second argument to it, minimizing over the values of the third argument |
| andover |
(list, string,
boolean) => boolean |
Iterates
over each element of the first argument, setting the variable given by
the second argument to it, doing a logical and of the values of the third
argument |
| orover |
(list, string,
boolean) => boolean |
Iterates
over each element of the first argument, setting the variable given by
the second argument to it, doing a logical or of the values of the third
argument |
Table 1. Basic Functions
II.3.2 Task Functions
The Vishnu specification language includes a number of predefined functions
that are used to access and manipulate task instances. Each of these
functions accepts parameters that are known to be task instances (i.e.,
passing predefined atomic/object data, global instances or resource instances
will cause an error).
Task functions are used primarily to extract assignation data
that is associated with a task instance. In addition to the user-defined
fields of a task type, each task instance contains several "hidden" fields
that may be accessed only through these functions. These hidden fields
contain information about how that task has been assigned to a resource
by the underlying Vishnu scheduler.
Note an obvious conclusion: in order to use these functions to access
a task, that task must have already been scheduled. These functions
are typically used in one of two ways when defining logic rules:
(1) Given a certain interim state of the schedule, we can use information
about the tasks already scheduled to add a new task to the schedule; (2)
Given a complete (or partial) schedule, we may use the information about
how the tasks were scheduled to evaluate how good that (partial) schedule
is.
| Function |
Data
Types |
Description |
| findtask |
(list, string)
=> task |
Return the
task in a list whose key is equal to the second argument |
| taskstarttime |
(task) =>
datetime |
Returns
the assigned start time of a task, or null if not yet assigned |
| taskendtime |
(task) =>
datetime |
Returns
the assigned end time of a task, or null if not yet assigned |
| tasksetuptime |
(task) =>
datetime |
Returns
the assigned time for the start of the setup period of a task, or null
if not yet assigned |
| taskwrapuptime |
(task) =>
datetime |
Returns
the assigned time for the end of the setup period of a task, or null if
not yet assigned |
| resourcefor |
(task) =>
resource |
Returns
the resource assigned to a task, or null if not yet assigned |
| formersetuptime |
(task) =>
datetime |
Returns
the setup time for a task after a temprary assignment. Ideal for use in computation of differences in setup time of the "next" task after a given task during computation of delta criterion. Returns null if the task does not exist or is not yet assigned |
| formerwrapuptime |
(task) =>
datetime |
Returns
the wrapup time for a task after a temporary assignment. Ideal for use in computation of differences in
wrapup time of the "next" task after a given task during computation of delta criterion. Returns null if
the task does not exist or is not yet assigned |
| taskstoredcontrib |
(task, number) =>
number |
Returns
the #th (#=second parameter) capacity value that has been stored for the given task in its current assignment. Generally use #=0 unless capacity is a vector. Returns null if the task does not exist, or if the task has not yet been assigned (or if # is out-of-bounds). |
| capacitycontrib |
(task, number) =>
number |
Similar to taskstoredcontrib, but recomputes the capacity contribution value using the CapacityContribution rule. If second parameter is not given, returns the first element of the capacity vector (i.e., same as number = 0).
Returns null if the task does not exist, or if the task has not yet
been assigned. (May cause error is second parameter is out-of-bounds.) |
| taskprevioustask |
(task) =>
task |
Returns the task that is assigned immediately before the given task on the same resource, or null if no such task or if given task is null or unassigned. |
| nexttask |
(resource, datetime) =>
task |
Returns the next task that is assigned to the given resource after the given datetime (i.e., starttime is strictly greater than given time). Returns null if no such resource or if no task has been assigned after the given time. |
| currenttask |
(resource, datetime) =>
task |
Returns the current task that is assigned
to the given resource at the given datetime (i.e., the task-starttime <= datetime <= task-endtime)
Returns null if no such resource or if no task has been assigned at the given time. |
Table 2. Task Functions
II.3.3 Resource Functions
The Vishnu specification language includes a number of predefined functions
that are used to access and manipulate resource instances. Each of
these functions accepts parameters that are known to be resource instances
(i.e., passing predefined atomic/object data, global instances or task
instances will cause an error).
Similar to task functions, resource functions are used primarily to
extract assignation data that is associated with a resource
instance. Most of these functions perform a computation based upon
how tasks are currently scheduled on that particular resource. These
functions are typically used when evaluating how good a complete or partial
schedule is.
| Function |
Data
Types |
Description |
| findresource |
(list, string)
=> resource |
Return the
resource in a list whose key is equal to the second argument |
| tasksfor |
(resource)
=> list |
Returns
the list of tasks assigned to this resource |
| numtasks |
(resource)
=> number |
Returns
the number of tasks assigned to this resource, or null if the resource does not exist |
| complete |
(resource)
=> datetime |
Returns
the time when a resource has finished all its assignments |
| busytime |
(resource,
<datetime>, <datetime>) => number |
Returns
the number of seconds that a resource has spent performing tasks in the
time interval between the second and third arguments (or for all time) |
| preptime |
(resource)
=> number |
Returns
the number of seconds that a resource has spent doing setup and wrapup |
| previousdelta |
(resource)
=> number |
Returns
the sum of all delta evaluations for all the tasks already assigned to
a resource |
| lasttask |
(resource)
=> task |
Returns
the last task currently assigned to the given resource, or null if the resource is null or if no task has been assigned to the resource
|
| firsttask |
(resource)
=> task |
Returns
the first task currently assigned to the given resource, or null if the resource is null or if no task has been assigned to the resource
|
| isavailable |
(resource, datetime, datetime)
=> boolean |
Returns
true if the given resource if available between the two given datetimes. Assumes that the first datetime is less than or equal to the second. inclusive of start, exclusive of end. If datetimes are null, assigns min.max possible value, as appropriate. Returns null if the given resource is null.
|
Table 3. Resource Functions
II.3.2b Misc Functions
| Function
td>
| Data
Types |
Description
b> |
| tasknamed |
(String) =>
task |
Returns
the task that has the given String as its name (i.e., key). Returns null if no such task exists. |
| resourcesfor |
(task) =>
list |
Returns
the list of resources to which this task is assigned, or null if not yet assigned |
| midnight |
(datetime) =>
datetime |
Returns
the datetime representing midnight on the same day (earlier) as the given datetime. Daylight savings is preserved. |
| addclock |
(datetime, number) =>
datetime |
Returns
the datetime resulting from adding the given number of seconds to the given datetime. However, Daylight Savings is "preserved" -- if the second parameter is 86400, which normally represents "24 hours" and
it crosses a time zone boundary, then the value returned is adjusted accordingly.
Thus, 8am + 24 hours = 8 am (not 7 or 9 due to daylight savings start/end). Returns null if either parameter is null. |
| dayname |
(datetime) =>
String |
Returns
the name of the day associated with the given datetime (e.g., "Monday", "Tuesday", etc)
|
| midnight |
(datetime) =>
datetime |
Returns
the datetime representing midnight on the same day (earlier) as the given datetime. Daylight savings is preserved. |
| get |
|
|
| globget |
|
|
| groupfor |
|
|
| committedresource |
|
|
| commitmentlevel |
|
|
| committedtime |
|
|
| varintervals |
|
|
| fixedintervals |
|
|
| threshold |
|
|
| vishnutime |
|
|
| vishnulocaltime |
|
|
| todate |
|
|
| toduration |
|
|
| argminover |
|
|
| argmaxover |
|
|
Table 3b. Misc Functions
II.3.4 Operators
In addition to the predefined functions above, the Vishnu specification
language includes a set of arithmetic and comparison operators.
Arithmetic operators are (+, -, *, /), which add / subtract / multiply
/ divide two numbers.
-
addition (+) can also add a datetime and a number (of seconds) to get a
new datetime
-
subtraction (-) can take the difference of two datetimes to get a
number (of seconds) or the difference of a datetime and a number to get
a datetime. For example, taskstarttime(task) - start_time will give the
number of seconds after the start of the scheduling window that task has
been scheduled.
Comparison operators are (=, !=, <, <=, >, >=), which compare two
values of the same type and return a boolean.
-
In the case of <, <=, >, and >=, the two values must be either two
numbers or two datetimes. For example, resource.location.x < 10 will
return true if the value of the referenced field is less than 10 and false
otherwise.
II.4 Vishnu Constraints and Logic Rules
II.4.1 Expressions
Now that we have a basic understanding of the data types and specification
language available in Vishnu, we have the necessary tools to finish the
design of a Vishnu problem. At the heart of the reconfigurability
of the Vishnu scheduler is the ability of the user to specify the behavior
of the scheduler. There are a variety of different types of problem constraints
that can be specified. A few of these constraints are simply multiple
choice among a set of options. However, most of these constraints
are specified as a logic rule. Vishnu allows the user to define 17
different logic rules. Each logic rule is a single expression.
Expressions involve the following types of components:
-
Constants - There are three types of constants: numeric, string,
and boolean. An example of each of these are 21.3, "hello world", and true.
Note that all string constants are quoted to distinguish them from variables.
-
Variables - There are three ways that variables are defined.
-
First, there are some variables that are predefined. These always include
tasks
(a list of all tasks), resources (a list of all resources),
start_time
(the start of the scheduling window), and end_time (the end of the
scheduling window or, if that is not set, the "end of time"). Additionally,
there can be predefined variables specific to each constraint. In the tables
below that describes the constraints, we list the associated predefined
variables for each constraint.
-
A second way to define variables is using global data. The name associated
with a global instance is the variable name that references that instance.
Note that it is therefore important to ensure that the variable names do
not conflict with the keyword variables. (Current implementation permits
such naming conflicts, but future versions will not allow them)
-
A third way to defined variables is using iteration functions such as loop,
mapover, sumover, and maxover. These functions take as an argument a string
which becomes the variable name that allows access to the iterated value
(e.g., the current list entry for this iteration). Again, it is important
to avoid naming conflicts with keyword variables. (Future versions
will not permit this)
-
Accessors - Accessors provide the means to access the fields of
an object. To access a top-level field, use a '.' followed by the field
name. For example, task.id will access the id field of the variable task.
When the fields within an object are themselves objects, chaining together
accessors will access lower-level fields. For example, resource.location.x
will access the x field of the location field of the variable resource.
Global pointers act just like other fields in terms of chaining of accessors.
-
Operators - There is a set of arithmetic operators (+, -, *, /)
that add / subtract / multiply / divide two numbers. Addition can also
add a datetime and a number (of seconds) to get a new datetime, while subtraction
can take the difference of two datetimes to get a number (of seconds) or
the difference of a datetime and a number to get a datetime. For example,
taskstarttime(task) - start_time will give the number of seconds after
the start of the scheduling window that task has been scheduled.
-
There is another set of comparison operators (=, !=, <, <=, >, >=)
that compare two values of the same type and return a boolean. In the case
of <, <=, >, and >=, the two values must be either two numbers or
two datetimes. For example, resource.location.x < 10 will return true
if the value of the referenced field is less than 10 and false otherwise.
-
Functions - There is a (growing) set of functions that can be used
in expressions. A function has the form fcn_name (arg1, ..., argn). The
arguments to a function are themselves expressions that are evaluated as
part of the process of evaluating the function. An example of an expression
involving functions is if (task.use_resource, resourcefor (task), resource).
Some sample expressions are:
-
abs (task.location.x) * (mod (task.location.y, 5) + 2)
-
if (resource.name = "machine 1", "the one", resource.name)
-
mapover (tasks, "task1", task1.prerequisites)
Thus, a logic rule could be an expression that is: a constant value; an
access to (a data field of) a keyword variable; an access to a data field
of a global instance; or a compound expression that uses functions and
operators to produce a single result. Each of the 17 possible logic
rules represents a value that is used by the Vishnu optimization system
in a fixed manner. Each logic rule has a default expression, which
the user may override by defining a new expression. Default values
for each logic rule are given so that a user does not need to specify an
expression for all logic rules. In the following sections, all the
logic rules are explained. To properly understand their place in
the Vishnu system, some of the underlying algorithms used in Vishnu are
described at a high level.
II.4.2 Genetic Algorithm
Vishnu is an reconfigurable scheduler that is based upon a genetic algorithm
search component and a greedy scheduling component. The logic rules
of Vishnu allow the user to modify certain behaviours of both components.
Basic knowledge of genetic algorithms and greedy algorithms is assumed
in the following discussion.
The genetic algorithm component uses an order-based chromosome. Each
chromosome is a list of all the tasks that need to be scheduled
in
a particular order. The initial population generator creates
random orderings of the tasks. The mutation operator picks some of the
elements of the parent's list (that in general are not contiguous) and
shuffles their order to create the child. The crossover operator picks
some of the elements of the first parent's list and puts them in the order
they are in the second parent. To evaluate each chromosome,
it is passed to a decoder that uses the greedy scheduler to translate
each ordering of tasks into a schedule. Finally, the fitness of the
schedule is evaluated and it is inserted into the population accordingly.
(Note that the fact that the decoder itself does a simple optimization
means that the genetic algorithm does not have to work as hard. Even if
the genetic algorithm generates just a single individual, this individual
will generally always be a much-better-than-average schedule and can potentially
even be optimal if there is little or no contention for resources. This
is important to keep in mind when choosing genetic algorithm parameters.)
The key constraint upon the genetic algorithm is that only certain orderings
of the task are valid. The validity of a given task
ordering is determined by the logic rule Prerequisites.
For each possible task instance, this rule specifies a list of all other
task instances (by name) that must occur before it. By default, Prerequisites
returns the empty set. The population generator and all genetic operators
will always obey the constraints given in this rule. Note that it
is possible to specify a circular constraint, in which case an error will
occur when the initial population is created (since no valid ordering is
possible). Future versions may include some logical debugging that
will avoid this in simple cases.
Once a chromosome has been passed to the greedy scheduler and decoded
into a schedule, the fitness of that chromosome is determined by the logic
rule Optimization
Criterion. For a given complete schedule, this rule returns
a single number reflecting the fitness of that schedule. By default,
Optimization
Criterion returns a constant of 0. The chromosome is inserted
into the population based upon this fitness value and the value of the
constraint Optimization Direction. This constraint
is either "minimize" or "maximize" and is not an expression. By default,
the value is "minimize".
Table 1 lists the genetic algorithm constraints along with what data
type the expression needs to return, what variables other than tasks,
resources,
start_time
and end_time are defined in its context, what is the default value,
and a short description of the purpose of the constraint.
| Constraint |
Type |
Variables |
Default
Value |
Description |
| Optimization
Criterion |
number |
|
0 |
Numerical
value indicating how good the current schedule is |
| Optimization
Direction |
multiple
choice |
N/A |
minimize |
Must
be either minimize or maximize |
| Prerequisites |
list
of strings |
task |
empty
list |
Names
of all the tasks that must be scheduled before scheduling task |
Table 4. Genetic Algorithm Constraints
II.4.3 Greedy Scheduler
The majority of the logic rules pertain to the behaviour of the greedy
scheduler. The greedy scheduler iterates performing the following
procedure until all tasks are scheduled (or deemed unscheduled).
-
Take the first element in the list that is not yet scheduled (or marked
unscheduled) and for which all of the tasks in its lists of prerequisites
are already scheduled.
-
For each resource eligible to performing this task, find the nearest
possible available time interval of sufficient length and
temporarily assign the task to that resource at that interval.
-
Evaluate how good each assignment is
-
Keep the assignment to that resource that is the best (i.e., perform a
greedy selection of resource).
The greedy scheduler uses several logic rules to clarify exactly what is
meant by each of the highlighted actions above.
-
Resource Eligibility:
-
A resource may be considered inelgible since it may not be capable of
executing the task in question.
-
The Capability logic
rule determines whether a resource can perform a particular task.
In step 2, the scheduler computes this logic rule for the task in question
to determine all the capable resources.
-
A resource may also be considered ineligible since it may not have enough
capacity
to handle the task in question.
-
A fixed number of resource supplies are considered to exist.
-
The Capacity Threshold
logic rule specifies the initial quantity (or capacity) of every supply
that is available on a particular resource. Each resource may have
a different capacity for each supply. For each new individual, each
resource starts with the amount of each supply indicated by Capacity
Threshold.
-
The Capacity
Contribution logic rule specifies how much of each supply a particular
task will require. This may be dependent upon the resource
that the task is assigned to, and may be dependent upon a specific temporary assignment of that task.
-
Every time a task is assigned to a schedule, the capacity of remaining
supplies are reduced by the amounts consumed by that task.
-
Together, these two logic rules ensure that the capacity thresholds are
not exceeded over the history of the resource.
-
By default, resources have no supplies and tasks require no supplies.
-
Nearest Time:
-
The Best Time logic rule determines
a "starting point" from which the scheduler tries to find a large enough
time interval for performing a specific task. By default, the overall
start_time
is used. The scheduler will actually search in both directions from
the best-time for the nearest sufficient interval. To restrict the
time search to only times after the best-time, explicit constraints
must be provided through other logic rules below.
-
Available Time:
-
The Task Unavailability
logic rule determines which periods of time to block off in terms of not
allowing the given task to be scheduled during those times. It returns
a list of time intervals, which by default is empty. This rule is
called every time a task is chosen in step 1 of the greedy scheduler.
It is computed based upon the partially completed schedule so far.
Thus, the value for a particular task may potentially vary from chromosome
to chromosome.
-
Another way of viewing this logic rule is that it includes the "semantics"
for the effect of the pre-requisites. (Note, other unavailabilities
may be included as well). So, if we specify that Task A is a pre-requisite
to Task B, then in Task Unavailability, we must indicate what timing
constraint we mean to have imposed. For example, we could enforce
that Task A cannot start until Task B finishes. Or, we may simply
enforce that Task A may not start until after Task B has started.
We may force a rest period between the completion of B and the commencement
of A, and so on. Note: Vishnu doesn't help you out here.
It is up to you to include the correct semantics for the pre-requisites.
-
(to verify with Dave) If no task-unavailable-times constraints based
upon pre-requisites are included, then the "pre-requisite" effectively
becomes a priority on the placement of the tasks (first-come/ best-served).
i.e., Task B would tend to be placed nearer to the best-time than Task
A would be.
-
The Resource
Unavailability logic rule determines when a given resource cannot
be scheduled for a task. It returns a list of time intervals, which
by default is empty. This rule is called exactly once - at the beginning
of the genetic algorithm. The constraints thus do not vary from chromosome
to chromosome.
-
Together, these two rules provide a specification of when a task may execute
upon a resource.
-
Sufficiently Long Time Interval
-
By default, every task has a duration that is independent of all
other tasks and independent of the resource it is assigned to. However,
three logic rules allow the user to introduce certain dependencies.
-
When the current task is being assigned to a resource, it is assumed to
have a setup duration, a core duration, and a wrapup duration.
-
The Core Duration
logic rule determines how much time the current task takes. This
may be dependent upon the resource to which the task is temporarily assigned.
By default the core duration is 0.
-
The Setup Duration
logic rule determines how much time the task (A) must spend in setting
up. This may be dependent upon the resource as well as upon the task
(B) that was scheduled before A. The rule may use the keyword variable
previous
to access B. By default, the setup duration is 0.
-
The Wrapup Duration
logic rule determines how much time the task (A) must spend in wrapping
up. This may be dependent upon the resource as well as upon the task
(B) that was scheduled afterA. The rule may use the keyword variable
next
to
access B. By default, the wrapup duration is 0.
-
How the greedy scheduler decides an interval is sufficiently long for task
A.
-
Starting at best-time, find the next non-zero, available interval after
best-time.
-
For that interval, temporarily assign A to that interval. Generally,
A will be slotted in between two tasks previous and next.
-
Compute the effect of A upon the wrapup duration of previous and
upon the setup duration of next. Compute the setup and wrapup
durations of A itself (given previous and next).
-
If A can still fit in between previous and next, we have
found a valid interval.
-
If A does not fit, return to step a and continue until a valid interval
is found
-
Repeat, searching for a valid interval before best-time.
-
Return the valid interval that is closest to best-time.
-
Goodness of Temporary Assignments
-
The Delta Criterion logic
rule is used by the greedy scheduler to evaluate the partial schedules
that arise from assigning the task to each eligible resource. The
rule should return the effect that a particular assignation has upon the
overall fitness of the schedule. The best Delta Criterion
of all assignations (lowest if Optimization Direction is "minimizing",
highest if Optimization Direction is "maximizing") is selected as
the greedy choice. Ideally, the sum of all the delta criterions of
all the greedy choices that were made should equal the result of the Optimization
Criterion logic rule.
| Dependencies between Setup Duration / Core Duration / Wrapup Duration:
The dependencies between durations of tasks next to each other in the
schedule may be illustrated conceptually as follows: Let us say that
we are assigning drives (tasks) to busses (resources). Let us consider
3 drivers (tasks): Bob, George, and Anne. Let us simplify things
with only a single bus. Now, let us pretend that George and Bob like
to play practical jokes on each other, but that Anne is very proper and
doesn't stand for any of that nonsense.
Let us define task setup as involving: Finding where the bus is parked
and starting it up.
Let us define task wrapup as involving: Parking the bus and stopping
it.
The bus is supposed to always be parked in the same spot near the school,
and Anne won't tolerate otherwise. But, George and Bob like to park
the bus as far away as possible - but only if they know the next driver
won't be Anne. Parking close takes time C, and parking far away takes
time F. Finding the bus when close takes 0 time, but finding it when
far takes X time.
Driving the bus route always takes D time, for simplicity.
The bus always starts and end in its correct spot.
Now, if we schedule the drivers in the following order: G, B,
A, we know that the following will happen:
before Bob:
G = 0 + D + C
A = 0 + D + C
After inserting Bob:
G = 0 + D + F
B = X + D + C
A = 0 + D + C
But if we schedule drivers in the order A, B, G
Before Bob:
A = 0 + D + C
G = 0 + D + C
After inserting Bob:
A = 0 + D + C
B = 0 + D + F
G = X + D + C
Note that the placement of B in the middle of A and G has a different
effect on everyone's timings as compared to placement in the middle of
G and A.
|
Other Logic Rules:
-
The Multitasking
constraint determines how resources handle multiple tasks at once.
-
A value of none implies that
a resource handles only one task at a time.
-
A value of grouped implies
that a resource can handle multiple tasks at once only if they start and
end at the same times.
-
A value of ungrouped implies
that a resource can handle multiple tasks without the need to coordinate
the start and end times.
-
A value of ignoring time
implies that no time-based calculation will occur. This means the problem
will be of the knapsack variety, like the Generalized Assignment
Problem.
-
The Capacity Contribution
and Capacity
Threshold
constraints apply differently depending on whether or not
there is multitasking.
-
When there is multitasking, the capacity constraints ensure that none of
the different types of capacities are exceeded at any given time.
-
When there is no multitasking, these constraints ensure that the capacities
are not exceeded over the history of the resource.
-
The Groupable constraint
applies only for grouped multitasking and determines when two tasks can
be performed by a single resource at the same time. Groupability is assumed
to be defined to be both
-
reflexive (if task1 is groupable with task2 then task2 is groupable with
task1) and
-
transitive (it task1 is groupable with task2 and task2 is groupable with
task3, then task1 is groupable with task3); any non-transitive aspects
of groupability can generally instead be handled using multiple capacities.
-
Linked/Link Time Difference
| Constraint |
Type |
Variables |
Default
Value |
Description |
| Delta
Criterion |
number |
task,
resource |
0 |
Incremental
contribution to optimization criterion introduced by having resource perform
task |
| Best
Time |
datetime |
task,
resource, duration |
start_time |
Optimal
time for the task to begin |
| Capability |
boolean |
task,
resource |
true |
Whether
resource has the required skills to perform task |
| Task
Duration |
number |
task,
resource |
0 |
How
many seconds it takes resource to perform task |
| Setup
Duration |
number |
task,
previous, resource |
0 |
How
many seconds it takes resource to prepare to perform task if it last performed
previous |
| Wrapup
Duration |
number |
task,
next, resource |
0 |
How
many seconds it takes resource to clean up after doing task if it will
be performing next |
| Task
Unavailability |
list
of intervals |
task,
resource, prerequisites, duration |
empty
list |
All
intervals of time when task cannot be scheduled (label1 and label2 fields
ignored) |
| Resource
Unavailability |
list
of intervals |
resource |
empty
list |
All
intervals of time when resource is busy (label1 and label2 can be used
for text and color) |
| Capacity
Contribution |
number
or
list of numbers |
task |
0 |
How
much task contributes towards filling each type of capacity |
| Capacity
Threshold |
number
or
list of numbers |
resource |
0 |
How
much capacity of each type that resource has |
| Multitasking |
multiple
choice |
N/A |
none |
Ability
of resources to perform more than one task at a time (must be none
, ungrouped , grouped
, or ignoring_time ) |
| Groupable |
boolean |
task1,
task2 |
true |
Whether
task1 and task2 can be done as part of the same group (should be reflexive
and transitive) |
| Linked |
boolean |
task1,
task2 |
false |
Whether
the start time of task2 is linked to the start time of task1 |
| Link
Time Difference |
number |
task1,
task2 |
0 |
Number
of seconds that the start time of task2 must follow the start time
of task1 |
Table 5. Scheduling Constraints
| Constraint |
Type |
Variables |
Default
Value |
Description |
| Task
Text |
string
or
number or boolean |
task |
"" |
Text to
put in box for task on the schedule graphic |
| Activity
Text |
string
or
number or boolean |
interval |
"" |
Text to
put in box for the activity associated with interval on the schedule graphic |
| Grouped
Tasks Text |
string
or
number or boolean |
tasks
(overloaded) |
"" |
Text to
put in box on the schedule graphic for the given group of tasks performed
simultaneously |
| Task
Color (one for each possible color) |
boolean |
task |
false |
Whether
task should be displayed in the given color on the schedule graphic |
| Activity
Color (one for each possible color) |
boolean |
interval |
false |
Whether
activity of interval should be displayed in the given color on the schedule
graphic |
| Grouped
Tasks Color (one for each possible color) |
boolean |
tasks
(overloaded) |
false |
Whether
the set of grouped tasks should be displayed in the given color on the
schedule graphic |
| Setup
Display |
multiple
choice |
N/A |
left |
Must be
left (left diagonal striping), right (right diagonal striping), line (single
dotted line), or color (use color specs) |
| Wrapup
Display |
multiple
choice |
N/A |
right |
Must be
left (left diagonal striping), right (right diagonal striping), line (single
dotted line), or color (use color specs) |
Table 6. Graphical Display Constraints
II.4.4 Logical Debugging
There are two mechanisms in place to ensure that expressions are robust
under evaluation. The first is type checking, which is performed by the
expression compiler. All the components of a expression are checked to
validate that they are returning the right type for their context, including
making sure that the entire expression returns the correct type for its
constraint. (The correct type associated with a particular constraint is
given in Table 1.)
The second mechanism is handling of undefined values encountered during
runtime execution. It is sometimes possible for a function to have no valid
value to return. For example, taskstarttime has no valid value to return
if the task that is its argument has not been assigned yet and therefore
does not have a start time. In this case, the function returns the value
null. All functions, operators and accessors are capable of handling a
null value by passing along null as a result. If the user wants to explicitly
handle a null condition, there is a function hasvalue that tests whether
a particular value is null.
Appendix A: Vishnu Interface Tutorial
See Interface Tutorial
Appendix B: Vishnu Architecture and API
Vishnu has essentially a client-server architecture. The server
consists of a relational database (MySQL) and a web server (Apache) with
PHP modules that provide dynamic content for the serviced URLs. There are
three types of clients: browsers for display and user interaction, automated
schedulers for generating optimized schedules, and (optionally) application
drivers that potentially provide the data and read back the generated schedules.
The database is capable of holding an arbitrary number of problems (within
disk space limitations), with the provision that each problem must have
a different name. There is one database instance for every problem, each
named vishnu_prob_[probname]. The database for each problem contains all
the data formats (see
Section 3), data (see
Section
3), scheduling specifications (see
Section
4), automated scheduler specification (see Section
5) and the results from the automated scheduler (see Section
5).
There is one additional database instance called vishnu_central that
serves as a central point. It contains a list of all the problems and a
list of all requests for the automated scheduler to run.
All interactions of the clients with the database are via the web server.
The client sends data to a URL, and the web server processes the request,
making the appropriate database interactions and returns data to the client.
For the URLs used by browser clients, the data returned is HTML data and
other data (such as images) that the browser can display. For the URLs
used by the automated schedulers and application clients, the data is in
XML format. The data sent to the URLs is in the form of typical URL arguments.
Any complex data is in XML format within the URL arguments.
There can potentially be more than one automated scheduler. They can
either be on the same machine as the database or on a different machine
because all communication is via URLs. Each automated scheduler queries
the database at regular intervals to see if there are any new problems.
When there is a new problem, the scheduler needs to query the database
for the problem contents, solve the problem (i.e., create a new schedule),
and then write the schedule to the database.
There are six different URLs that the scheduler needs to access. These
are:
-
currentrequest.php - This URL allows the scheduler to query whether
there is a new problem to solve and what it is.
-
ackrequest.php - This URL allows the scheduler to specify an integer
between 0 and 100 (inclusive) telling how far along it is on solving the
problem. The scheduler is required to change this to a value between 0
and 100 (exclusive) when it is starting to work on the problem and 100
when it has finished. Currently, the scheduler changes the status to 1
when it starts work and 100 when it is finished but does not provide intermediate
values.
-
data.php - This URL queries for the metadata and data for a particular
problem.
-
specs.php - This URL queries for the scheduling specifications.
-
gaparms.php - This URL queries for the genetic algorithm parameters.
-
postassignments.php - This URL allows the scheduler to write the
schedule into the database.
Expression (or Formula) Compiler
The purpose of the expression compiler is to allow users to enter the scheduling
specifications in "expression" format (see see Section
4) and have them automatically translated into the XML format that
can be easily parsed into the database. The expression compiler is a separate
Java process that queries the database at regular intervals to see if there
are any new expressions to compile. (There can potentially be more than
one expression compiler process, but in practice this should not be necessary.)
If so, it reads the expression for the oldest request, validates that the
expression is correct syntactically, translates the expression into XML,
and writes back the XML.
There are two different URLs that the expression compiler needs to access:
-
compilerrequest.php - This URL queries the database for any outstanding
requests for expression compilation, and if one exists, returns the expression
plus all the context data required to perform the compilation.
-
postcompilerresult.php - This URL allows the expression compiler
to write back the XML text or else an error message for what went wrong.
GUI/Browser Clients
The client side of the GUI is just a standard web browser. The server
side of the GUI is PHP code that reads from the database and dynamically
serves up HTML to the browser. Using the GUI, a user can load a problem
or data for a problem from a file, request the scheduler to run, check
the scheduler's status, and view the data from a problem and the associated
schedule in a variety of forms.
We do not list all the URLs that the GUI uses, as these are too numerous
and easily deduced from the PHP code. We leave until see Section
6 a more detailed explanation of what the GUI actually does.
Application Clients
An alternative to the browser-based approach to loading a problem and requesting
the creation of a schedule for the problem is for an executing application
to do this. The procedure is that the application should first write a
new problem or update the data for an existing problem, then kickoff the
scheduler, then periodically read the status until the scheduler has completed,
and finally read back the schedule that has been created.
The URLs used are:
-
postproblem.php - This URL allows the client to create or modify
a problem. The single argument is data, which should contain XML data of
the format specified in Appendix B.
-
postdata.php - This URL allows the client to add, modify, or delete
object data for an existing problem. The two arguments are problem and
data, where problem specifies the problem name and data contains XML data
of the format specified in Appendix B.
-
postkickoff.php - This URL allows the client to request the scheduler
to run on the data for a problem. The two arguments are problem and username.
-
readstatus.php - This URL allows the client to tell whether the
scheduler is done generating the scheduler. The single argument is problem.
The text sent back will have the form percent_complete=[value], where value
will be 100 when the scheduler is finished.
assignments.php - This URL allows the client to read the assignments
that the automated scheduler made. The single argument is problem. The
text sent back will be XML assignment data in the format
Appendix B: Tailoring the Genetic Algorithm Parameters
The scheduler stops running when any of the following four quantities
exceed their specified limit: (1) the elapsed time for the run, (2) the
total number of individuals evaluated, (3) the number of consecutive evaluations
without an improvement to the best individual, and (4) the number of duplicate
individuals generated.
When the scheduler stops running, it writes the following information
back to the database: (1) the set of all assignments of tasks to resources,
including the times (setup start, task start, task end, and wrapup end)
and the color and text to be displayed and (2) the set of non-task activities
for each resource, including times, color and text.
The following table provides the parameters that can be varied to control
the genetic algorithm performance:
| Parameter
Name |
Description |
| Population
Size |
Number of
individuals in the population at any one time; they are generated randomly
for the initial population and then gradually replaced by their descendants;
make this larger in order to run the genetic algorithm longer and find
a better solution |
| Parent Scalar |
This parameter
controls the fitness pressure; the kth best individual in the
population is this times less likely than the (k-1)st to be
selected as a parent; this should always be less than 1; making this closer
to 1 decreases the pressure and allows the genetic algorithm to search
longer before converging on a single solution; a good choice for this parameter
is given by the formula 1 - (10 / population_size) |
| Maximum Evaluations |
Limit on
the number of individuals that the genetic algorithm can generate before
being forced to stop |
| Maximum Time |
Limit on
the number of seconds that the genetic algorithm can execute before being
forced to stop |
| Maximum Top
Dog Age |
Limit on
the number of consecutive individuals that the genetic algorithm can generate
without generating one better than the current best individual before being
forced to stop |
| Crossover
Probability |
Probability
of choosing crossover as the genetic operator used to generate the next
child (should sum to 1 with the mutation probability); a good value for
this is 0.5 |
| Mutation
Probability |
Probability
of choosing mutation as the genetic operator used to generate the next
child (should sum to 1 with the crossover probability); a good value for
this is 0.5 |
| Maximum Fraction
Mutated |
The mutation
operator will randomly choose some fraction of the chromosome to mutate,
and this paramater sets the upper limit on this fraction; a good value
for this is 1.0 |
| Report Interval |
How often
(in seconds) the genetic algorithm reports its percent complete status
to the web server (0 means not until the end) |
Appendix C: Cougaar-Vishnu Bridge
Cougaar is an architecture
for construction of large-scale, distributed multiagent systems. Vishnu
provides a way to easily integrate one or more Vishnu schedulers into a
multiagent system based on Cougaar.
This section uses Cougaar terminology
and concepts extensively, so interested readers should first familiarize
themselves with these first before attempting to read this section.
The Cougaar-Vishnu Bridge is used to connect a Cougaar
plugin to the Vishnu Scheduling System. The bridge is instantiated in the
usual plugin flavors: expander, allocator, and aggregator. Typically an
allocator would be used for a one-to-one scheduling problem (multitasking
= none/ignoring_time) and an aggregator for a many-to-one problem (multitasking
= grouped/ungrouped). (Sometimes a task-to-resource assignment needs to
be made in an expander and that assignment recorded in prepositions on
the new subtask of the expansion. Such an assignment might be a piece of
necessary information for a downstream plugin.)
The Bridge interfaces between a Cougaar
plugin and Vishnu by mapping Cougaar
tasks and assets to Vishnu tasks and resources. LDM objects are translated
into Vishnu objects so they can be manipulated by the Vishnu scheduler.
The scheduler creates Vishnu assignments, and these are used to create
plan elements.
When a bridge plugin receives a task for the first time, it sends its
problem definition to Vishnu. The problem definition is composed of the
object format of the tasks and resources, the scheduling specs, the GA
parameters, the object format of any other data that is neither task nor
resource, and that other data itself.
The associated files are, by default, the name of the cluster, with
a suffix identifying the type of file. For instance, a cluster named Sample
with a bridge plugin might have the following files:
| File |
Description |
Required |
| Sample.vsh.xml |
Scheduling specifications for the problem |
Yes |
| Sample.ga.xml |
GA parameters for the problem |
Yes |
| Sample.env.xml |
Vishnu parameters
(possibly including vishnu_parameters.env.xml and vishnu_server.xml) |
Usual, but not required |
| vishnu_parameters.env.xml |
Typical parameters governing Vishnu behavior |
Usual |
| vishnu_server.env.xml |
Information defining possible web servers, when in web-server
mode |
Optional |
| Sample.odf.xml |
Object format(s) for the other data |
Optional |
| Sample.odd.xml |
Instance of the other data |
Optional |
| Sample.dff.xml |
Problem data object format |
Optional |
(The problem name can be changed by setting a plugin parameter.)Once the
problem definition is sent to Vishnu, the assets are translated and sent
(at least once) as resource data for the problem. Then, the tasks are translated
and sent. Now the problem is completely defined and ready to be solved.
The bridge then submits a request to Vishnu to create a schedule. The bridge
waits until a result is ready, and then parses the assignments that are
returned to generate plan elements.The Bridge has four orthogonal behaviors
that can be controlled through parameters or through subclassing of Vishnu
client objects.
-
Internal or Web Server
-
Incremental or Batch
-
XML or Direct Translation
-
Automatic or Custom Translation
Internal or Web Server
Vishnu can run in either internal or web-server mode. In
the internal mode, everything happens within a single VM. There
is no web server, no separate scheduler process, and no GUI to view the
results. However, performance is better. This is controlled by the runInternal
flag,
which is in the vishnu_parameters file. The direct translation mode is
only available when running internally. The web-server mode is the basic
Vishnu architecture described in section 2.
In web-sever mode, each instance of a bridge plugin gets its own Vishnu
problem name. Each instance of a bridge plugin maps to a problem in the
Vishnu database that will appear on the problem list page on the web server.
Incremental or Batch mode
The plugin has a choice of running in incremental, or batch
mode. This is controlled by the incrementalScheduling flag in the
parameters file. In incremental mode, previous assignments are remembered
and influence future problems. In batch mode, all problem data is re-submitted
every time. In this mode, the prior use of the asset must be indicated
in one of the scheduling specs, typically the resource unavailability.
The implication is that there may be solutions developed that are sub-optimal,
in the sense that a resource that is only partially used (for instance
a truck with only one box on it) would be seen as used and unavailable
for further tasks.
In incremental mode, Vishnu maintains incremental state, remembering
previous assignments. This allows the scheduler to continue assigning tasks
to nearly empty resources. The default mode for GLMTrans, for example,
is incremental. In addition, the number of tasks in a batch is not as important
in incremental mode, allowing smaller batches and in larger societies,
better performance. The reason for this is if one agent depends on the
results of another, it is better to have the dependent agent process many
small batches quickly, instead of doing one large batch, returning one
large set of results after a long wait.
Not all types of problems benefit from incremental mode. Grouping problems
would tend to be better run in incremental mode.
XML or Direct Translation
The plugin has a number of choices as to the nature of the translation
:
This mode is set by the runInternal and runDirectly flags.
If runInternal is false, the communication between bridge and scheduler
must be through XML. If runInternal is true and runDirectly is
false, the communication medium is XML.
LDM objects are translated into XML of a form that Vishnu understands,
and Vishnu assignments, expressed in XML are returned, and used to create
plan elements.
This mode is set by having both runInternal and runDirectly
flags
set to true. Here, Vishnu objects are created directly from Cougaar objects,
without XML as an intermediary representation.
In neither mode is the plugin developer required to decide whether XML
or Direct translation is being done. This handling is at the dataHelper
level of abstraction.
Automatic or Custom Translation
The translation process can either be automatic, requiring no effort on
the part of the plugin developer, or custom requiring some coding and object
format definition.
Automatic mode has the advantage that all the information about
the tasks and resources is discovered and sent automatically, so it may
be easier to quickly develop a prototype using this mode. The disadvantage
is that a great deal of information is sent, much of which may not be relevant
to the scheduling task. This can be especially taxing when in web-server
mode.
Custom mode has the advantage that only the fields that are necessary
for the problem are defined and sent. This can greatly increase performance.
The GLMTrans society runs in this mode. The disadvantage is that the plugin
developer is forced to write translation code.
Custom Translation
This requires specifying a <ClusterName>.dff.xml (Default format) file
and writing code that works with the translation process to generate the
appropriate XML or objects.
Default file format
For an example of a dff file, this is part of the format from a GLMTrans
agent:
<?xml version='1.0'?>
<PROBLEM name="TRANSCOM" >
<DATAFORMAT>
<OBJECTFORMAT name="Transport" is_task="true" is_resource="false"
>
<FIELDFORMAT name="id" datatype="string" is_subobject="false" is_globalptr="false"
is_list="false" is_key="true" />
<FIELDFORMAT name="arrival" datatype="datetime" is_subobject="false"
is_globalptr="false" is_list="false" is_key="false" />
....
This says that objects named "Transport" are tasks (is_task="true").
It's first field is named "id" and it is of type "string."
This file must be written by hand. There are many examples in the GLMTrans
project.
Custom code
Within the Vishnu client code there is support for custom translation.
Essentially this means creating an object that implements the XMLizer and
DirectTranslator interfaces. An object that does this already is the CustomDataXMLizer.
To do custom translation, you must :
1) Override VishnuPlugIn.createXMLizer and make it return your XMLizer.
Typically this is a subclass of CustomDataXMLizer.
2) Override CustomDataXMLizer.processTask and processAsset to send
the fields of the tasks and assets you wish to send.
Nested objects, lists, and all the other Vishnu datatypes can be sent.
For example, here's a snippet from a GLMTrans plugin:
protected boolean processTask
(Object object, Object taskOrAsset) {
super.processTask (object,
taskOrAsset);
Task task = (Task) taskOrAsset;
dataHelper.createDateField(object,
"arrival", UTILPreference.getBestDate(task));
....
This will attach a field arrival of type date to the task
being sent to Vishnu. The dataHelper is an object that allows you
to send either XML or directly create Vishnu objects, depending on the
setting of the runDirectly flag. If runDirectly is false,
it will generate XML that looks like:
<OBJECT type="Transport">
....
<FIELD name="arrival" value="2001-09-21 13:00:00"/>
....
There are many example implementations of custom bridges in the GLMTrans
society.
Automatic Translation
The object format of the tasks and resources is automatically generated
from the plugin's tasks and assets, but the other parts of the problem
definition are defined by files associated with the plugin.
The translation from Cougaar objects to Vishnu XML is done directly.
Two XML formats are created for Vishnu : the XML that describes the object
format or meta-data and the object data itself. The Cougaar objects are
traversed twice, once to create the object format XML and once to create
the data XML. (These two XML formats are described separately.) A Format
XMLizer traverses the Cougaar objects to create the format XML and a Data
XMLizer traverses these same objects again to create the data XML.
Cougaar-Vishnu bridge implementation. The bridge sends
as input to Vishnu the object format, scheduling specs, genetic algorithm
parameters, and other data (not pictured). This defines the problem. Then,
the data for the specific job is sent. When the scheduler is finished,
XML assignments are returned, and used to create plan elements.
Post processing - The Format and Data XMLizers perform some post
processing to give unique names to types and fields that have the same
name in the corresponding Java object. For instance, a preposition can
have any type of object as an indirect object, so the bridge must figure
out what types of indirect objects are present on the tasks and give them
separate, unique field names. In addition, commonly used property groups
are given unique names and turned into global data. These shared property
groups are referenced by name in the tasks and resources.
Other notes:
Tasks for setup and wrapup durations - Also, note that if a setup
or wrapup duration is defined in the specs, separate tasks are created
to represent these durations. These tasks need their allocation results
handled differently than those for the task itself, since their time spans
may well fall outside of the preferences of the original task. For example,
the time spent for a plane to fly back to base should not be included in
the time spent performing the delivery of an item that was on the plane.
This is handled automatically by the Vishnu bridge with a special allocation
result aggregator.
The creation of these wrapup and setup tasks is slightly different for
each plugin flavor. For expanders, a one-to-one expansion becomes a one-to-two
expansion if one of the specs is defined, and one-to-three if both are.
For aggregators, the MP task created by the aggregation is expanded. And
for allocators, there is a one-to-two or three expansion, and each subtask
gets allocated to the assigned resource.
Assignment Freezing
There is another facility provided by the bridge for expanders and
aggregators. Since resource availability is represented in the role schedule,
and since the role schedule does not reflect an assignment until an allocation
is made, there is a gap of time between when an assignment is returned
and when the resource's availability reflects the assignment. During this
period, a new task could come in and be scheduled against the asset during
the interval of a previous assignment. To protect against this, expanders
and aggregators freeze task assignments until the plugin detects, through
the allocation result, that an allocation has been made against the asset.
Once this happens, the assignment is unfrozen and can be cleared from the
Vishnu database.
Note : This facility is only active in batch mode.
Parameters
There are a number of parameters set in the Cluster's env.xml file
that affect the behavior of the bridge.
Required Parameters
| Parameter Name |
Use |
Default Value |
| hostName |
Host name of the web server |
dante.bbn.com |
| phpPath |
Path to the php directory |
~dmontana/vishnu |
| user |
User name for the mysql database |
tops |
| password |
Password for the mysql database |
tops |
File Parameters
| Parameter Name |
Use |
Default Value |
| postProblemFile |
Php file that?s part of the URL to post a problem |
postproblem.php |
| postDataFile |
Php file that?s part of the URL to post the
data for a problem |
postdata.php |
| kickoffFile |
Php file that?s part of the URL to post a scheduling
request |
postkickoff.php |
| readStatusFile |
Php file that?s part of the URL to get the scheduler
status |
readstatus.php |
| assignmentsFile |
Php file that?s part of the URL to get the generated
assignments |
assignments.php |
Misc Parameters
| Parameter Name |
Use |
Default Value |
| runInternal |
Run using an internal scheduler. Don't use the
Vishnu web server. |
false |
| makeSetupAndWrapupTasks |
Create separate tasks that correspond to the
setup and wrapup durations of the original task. |
true |
| vishnuEpochStartTime |
The start of the Vishnu epoch. Effects the width
of the gantt chart display. |
2000 01-01 00:00:00 |
| vishnuEpochEndTime |
The start of the Vishnu epoch. Effects the gantt
chart display. |
2002 01-01 00:00:00 |
| alwaysClearDatabase |
Clear the assets and tasks from previous jobs. |
false |
| waitTime |
How long to wait between polls |
5 seconds |
| maxWaitCycles |
How many times to poll. |
10 |
| problemName |
Name of the problem. Defaults to "cluster name"_"machine
name" . |
cluster_machine |
| showTiming |
Show time necessary to complete scheduling. |
true |
Debugging Parameters
| Parameter Name |
Use |
Default Value |
| testing |
Prints out XML that is sent to Vishnu |
false |
| showALPXML |
Prints out output of XMLize |
false |
| showFormatXML |
Prints out result of Format XMLizer |
false |
| showDataXML |
Prints out result of Data XMLizer |
false |
| ignoreSpecsFile |
Don?t send the Cluster.vsh.xml file. Useful
if you don?t want to step on the specs on the server. |
false |
| sendSpecsEveryTime |
Send problem definition, including scheduling
specs, every time. Useful if you want to alter the specs from job to job. |
false |
Appendix D: DTD for XML
The following is a DTD showing the expected XML data formats for
specifying a problem. (It is available as a text file in testdata/problem.dtd.)
<?xml version='1.0' encoding='UTF-8' ?>
<!-- Vishnu Problem Specification -->
<!ELEMENT PROBLEM (DATAFORMAT, SPECS, GAPARMS, (DATA)?)>
<!ATTLIST PROBLEM
name CDATA #REQUIRED >
<!-- sets up the object formats, i.e. metadata -->
<!ELEMENT DATAFORMAT (OBJECTFORMAT)*>
<!ELEMENT OBJECTFORMAT (FIELDFORMAT)*>
<!ATTLIST OBJECTFORMAT
name CDATA #REQUIRED
is_task (true|false) #REQUIRED
is_resource (true|false) #REQUIRED >
<!ELEMENT FIELDFORMAT EMPTY>
<!ATTLIST FIELDFORMAT
name CDATA #REQUIRED
datatype CDATA #REQUIRED
is_subobject (true|false) "false"
is_list (true|false) "false"
is_key (true|false) "false"
is_globalptr (true|false) "false" >
<!-- sets up scheduling specifications -->
<!ELEMENT SPECS (OPTCRITERION|DELTACRITERION|BESTTIME|CAPABILITY|
TASKDURATION|SETUPDURATION|WRAPUPDURATION|PREREQUISITES|
TASKUNAVAIL|RESOURCEUNAVAIL|CAPACITYCONTRIB|CAPACITYTHRESH|
GROUPABLE|TASKTEXT|GROUPEDTEXT|ACTIVITYTEXT|COLORTESTS)*>
<!ATTLIST SPECS
direction (minimize|maximize) "minimize"
multitasking (none|grouped|ungrouped|ignoring_time) "none"
setupdisplay (left|right|line|color) "left"
wrapupdisplay (left|right|line|color) "right"
taskobject CDATA #IMPLIED
resourceobject CDATA #IMPLIED >
<!ELEMENT OPTCRITERION (OPERATOR|LITERAL) >
<!ELEMENT DELTACRITERION (OPERATOR|LITERAL) >
<!ELEMENT BESTTIME (OPERATOR|LITERAL) >
<!ELEMENT CAPABILITY (OPERATOR|LITERAL) >
<!ELEMENT TASKDURATION (OPERATOR|LITERAL) >
<!ELEMENT SETUPDURATION (OPERATOR|LITERAL) >
<!ELEMENT WRAPUPDURATION (OPERATOR|LITERAL) >
<!ELEMENT PREREQUISITES (OPERATOR|LITERAL) >
<!ELEMENT TASKUNAVAIL (OPERATOR|LITERAL) >
<!ELEMENT RESOURCEUNAVAIL (OPERATOR|LITERAL) >
<!ELEMENT CAPACITYCONTRIB (OPERATOR|LITERAL) >
<!ELEMENT CAPACITYTHRESH (OPERATOR|LITERAL) >
<!ELEMENT GROUPABLE (OPERATOR|LITERAL) >
<!ELEMENT TASKTEXT (OPERATOR|LITERAL) >
<!ELEMENT GROUPEDTEXT (OPERATOR|LITERAL) >
<!ELEMENT ACTIVITYTEXT (OPERATOR|LITERAL) >
<!ELEMENT OPERATOR (OPERATOR|LITERAL)* >
<!ATTLIST OPERATOR
operation CDATA #REQUIRED >
<!ELEMENT LITERAL EMPTY >
<!ATTLIST LITERAL
value CDATA #REQUIRED
type (constant|variable) #REQUIRED
datatype CDATA #REQUIRED >
<!ELEMENT COLORTESTS (COLORTEST)* >
<!ELEMENT COLORTEST (OPERATOR|LITERAL) >
<!ATTLIST COLORTEST
color CDATA #REQUIRED
obj_type CDATA #REQUIRED
title CDATA #REQUIRED >
<!-- sets up genetic algorithm specifications -->
<!ELEMENT GAPARMS (GAOPERATORS) >
<!ATTLIST GAPARMS
pop_size CDATA #REQUIRED
parent_scalar CDATA #REQUIRED
max_evals CDATA #REQUIRED
max_time CDATA #REQUIRED
max_duplicates CDATA #REQUIRED
max_top_dog_age CDATA #REQUIRED
report_interval CDATA #IMPLIED
initializer CDATA #REQUIRED
decoder CDATA #REQUIRED >
<!ELEMENT GAOPERATORS (GAOPERATOR)+ >
<!ELEMENT GAOPERATOR EMPTY >
<!ATTLIST GAOPERATOR
name CDATA #REQUIRED
prob CDATA #REQUIRED
parms CDATA #IMPLIED >
<!-- sets up data -->
<!ELEMENT DATA ((CLEARDATABASE|FREEZEALL|UNFREEZEALL)?, WINDOW?,
NEWOBJECTS?, CHANGEDOBJECTS?, DELETEDOBJECTS?,
(FREEZE|UNFREEZE)*) >
<!ELEMENT CLEARDATABASE EMPTY >
<!ELEMENT FREEZEALL EMPTY >
<!ELEMENT UNFREEZEALL EMPTY >
<!ELEMENT FREEZE EMPTY >
<!ATTLIST FREEZE
task CDATA #REQUIRED
resource CDATA #IMPLIED
starttime CDATA #IMPLIED
endtime CDATA #IMPLIED >
<!ELEMENT UNFREEZE EMPTY >
<!ATTLIST UNFREEZE
task CDATA #REQUIRED >
<!ELEMENT DATA (CLEARDATABASE?, WINDOW?, NEWOBJECTS?,
CHANGEDOBJECTS?, DELETEDOBJECTS?) >
<!ELEMENT CLEARDATABASE EMPTY >
<!ELEMENT WINDOW EMPTY >
<!ATTLIST WINDOW
starttime CDATA #IMPLIED
endtime CDATA #IMPLIED >
<!ELEMENT NEWOBJECTS (OBJECT|GLOBAL)* >
<!ELEMENT CHANGEDOBJECTS (OBJECT|GLOBAL)* >
<!ELEMENT DELETEDOBJECTS (OBJECT|GLOBAL)* >
<!ELEMENT GLOBAL (OBJECT) >
<!ATTLIST GLOBAL
name CDATA #REQUIRED >
<!ELEMENT OBJECT (FIELD)* >
<!ATTLIST OBJECT
type CDATA #REQUIRED >
<!ELEMENT FIELD (OBJECT|LIST)? >
<!ATTLIST FIELD
name CDATA #REQUIRED
value CDATA #IMPLIED >
<!ELEMENT LIST (VALUE)* >
<!ELEMENT VALUE (OBJECT)? >
<!ATTLIST VALUE
value CDATA #IMPLIED >
The following is a DTD showing the XML reported out from the web server
to an external client or the scheduler to the web server or the scheduler
to a calling routine (for internal mode). When the scheduler reports to
the web server, there is more data than in the other cases, because the
web server needs to store data internally that it cannot deduce. The rules
for which data will only be in the data reported from the scheduler to
the web server (and hence that a user will never see) are:
-
An ACTIVITY tag/object is only sent to the web server.
-
All IMPLIED attributes are only sent to the web server.
-
For either grouped or ungrouped multitasking, both ASSIGNMENT objects and
MULTITASK objects are sent to the web server. For ungrouped multitasking,
only ASSIGNMENT objects are sent to a client, while for grouped multitasing,
only MULTITASK objects are sent to a client.
This DTD is available as a text file in testdata/assignments.dtd.
<?xml version='1.0' encoding='UTF-8'?>
<!-- Vishnu Assignments Specification -->
<!ELEMENT ASSIGNMENTS (ASSIGNMENT|MULTITASK|ACTIVITY)*>
<!ELEMENT ASSIGNMENT EMPTY>
<!ATTLIST ASSIGNMENT
task CDATA #REQUIRED
resource CDATA
#REQUIRED
setup CDATA
#REQUIRED
start CDATA
#REQUIRED
end CDATA #REQUIRED
wrapup CDATA
#REQUIRED
frozen CDATA
#IMPLIED
color CDATA
#IMPLIED
text CDATA #IMPLIED
>
<!ELEMENT MULTITASK (TASK)*>
<!ATTLIST MULTITASK
resource CDATA
#REQUIRED
setup CDATA
#REQUIRED
start CDATA
#REQUIRED
end CDATA #REQUIRED
wrapup CDATA
#REQUIRED
color CDATA
#IMPLIED
text CDATA #IMPLIED
capacities CDATA
#IMPLIED
capacities_used
CDATA #IMPLIED >
<!ELEMENT TASK EMPTY>
<!ATTLIST TASK
task CDATA #REQUIRED
>
<!ELEMENT ACTIVITY EMPTY>
<!ATTLIST ACTIVITY
resource CDATA
#REQUIRED
start CDATA
#REQUIRED
end CDATA #REQUIRED
color CDATA
#IMPLIED
text CDATA #IMPLIED
>
Appendix E: Sample Problems
We have applied Vishnu to a variety of classic scheduling/assignment problems.
Loadable files containing the specifications and data for these problems
are contained in the testdata directory. We also list the specifications
here, since they are good and simple examples of how to configure Vishnu
for a particular problem.
Job-Shop Scheduling Problem (testdata/jobshop/mt06.vsh)
The classic NxM research problem is as follows. There are M machines
and N manufacturing jobs to be completed. Each job has M tasks/stages,
with each stage corresponding to a different specified machine. There is
a specified order in which the tasks for a certain job must be performed,
with one task not able to start until the previous task has ended. The
criterion to minimize is the makespan, which is defined as the end time
of the last task completed. (Note that this research problem bears little
resemblance to the problem that real job shops face. Unlike other systems,
our reconfigurable scheduler can be easily modified to the constraints
of a particular real-world job shop.)
The resources for this problem are of type machine, and the tasks
for this problem are of type step. The metadata for these two object
types are:
| step |
machine |
| Field
Name |
Field
Type |
| id |
string |
| job |
string |
| step |
string |
| duration_in_seconds |
number |
| preceeding_steps |
list of string |
|
| Field
Name |
Field
Type |
| id |
string |
|
The (non-default) scheduling specifications for this problem are:
| Constraint |
Expression |
| Optimization
Criterion |
maxover
(resources, "resource", complete (resource)) - start_time |
| Capability
Criterion |
task.assigned_machine
= resource.id |
| Task Duration |
task.duration_in_seconds |
| Prerequisites |
task.preceeding_steps |
| Task Unavailable
Times |
mapover
(prerequisites, "preceeding_task",
interval (start_time, taskendtime (preceeding_task))) |
| Task Text |
task.step |
Here are a few points to note about the scheduling specifications. First,
the optimization criterion needs to be a number; subtracting the start
time of the scheduling window (a constant) from the end time of the final
task provides a number that is the difference between these two times in
seconds. Second, the preceeding_steps field of each step object need only
contain its immediate predecessor; the rest of the steps that must be completed
before it will be enforced implicitly. Third, the prerequisites constraint
only specifies constraints in which order the decoding can be done; the
task unavailable times constraint is required to constrain the task to
have a start time not earlier than its prerequisites' end times.
The color specifications are:
| Color |
Type |
Title |
Expression |
| red |
task |
Job 1 |
task.job
= "1" |
| green |
task |
Job 2 |
task.job
= "2" |
| blue |
task |
Job 3 |
task.job
= "3" |
| yellow |
task |
Job 4 |
task.job
= "4" |
| cyan |
task |
Job 5 |
task.job
= "5" |
| magenta |
task |
Job 6 |
task.job
= "6" |
This color coding will allow easy visual separation of steps by job.
Traveling Salesman Problem (testdata/TSP/bays29.vsh)
The traveling salesman problem is as follows. There is a salesman
who needs to start at a given city, travel to a set of other cities visiting
each city once, and then return to the starting city. The distances from
any city to any other city is provided. The objective is to minimize the
total distance traveled.
There are two different approaches we have used to configure Vishnu
for the traveling salesman problem. Both approaches consider each city
other than the starting city to be a task. The first approach considers
starting from the starting city to be a zero-duration task that must be
performed first and returning to the starting city to be a task that must
be performed last. The second approach (which is probably the superior
one) instead has the setup time for the first city calculate its distance
automatically from the starting city and has a wrapup time for the last
city based on distance to the starting city. We use the second approach
for the vehicle routing problem (which is largely just a multiple traveling
salesman problem) because it extends easily to the multiple salesman case.
So, we provide the first approach here to provide more variety.
The resource for this problem is of type salesman, and the tasks
for this problem are of type city. The metadata for these two object
types are:
| city |
salesman |
| Field
Name |
Field
Type |
| id |
string |
| index |
number |
|
| Field
Name |
Field
Type |
| id |
string |
|
A global variable distances of type matrix is defined that contains
all the distances between cities. The (non-default) scheduling specifications
for this problem are:
| Constraint |
Expression |
| Optimization
Criterion |
maxover
(resources, "resource", complete (resource)) - start_time |
| Setup Duration |
matentry
(distances, task.index, previous.index) |
| Prerequisites |
if (task.id
!= "Start",
if (task.id = "City 1",
mapover (tasks, "task2",
if (task2.id != "City 1", task2.id)),
list ("Start"))) |
| Task Text |
task.index |
One thing to note is that distances and durations are treated interchangeably,
basically assuming that the salesman travels one unit of distance in a
second.
Vehicle Routing Problem with Time Windows (testdata/VRP/solomon101.vsh)
The vehicle routing problem with time windows (VRPTW) is an extension
of the capacitated vehicle routing problem (CVRP). In CVRP, there are M
vehicles and N customers from whom to pick up cargo. Each vehicle has a
limited capacity for cargo, and each piece of cargo contributes different
amounts towards this capacity. Each vehicle that is utilized starts at
a central depot, makes a circuit of all its customers, and then returns
to the depot. The objective is to minimize the total distance traveled
by the vehicles. In VRPTW, an extra constraint is added that there is a
certain window of time in which each pickup must be initiated. The pickups
require a certain non-zero time (for loading of the cargo).
The resources for this problem are of type vehicle, and the tasks for
this problem are of type customer. Another object type, extradata, holds
all the global data. The metadata for these object types are:
| customer |
vehicle |
extradata |
| Field
Name |
Field
Type |
| id |
string |
| load |
number |
| ready_time |
number |
| due_date |
number |
| location |
xy_coord |
|
| Field
Name |
Field
Type |
| id |
string |
|
| Field
Name |
Field
Type |
| capacity |
number |
| service_time |
number |
| depot_location |
xy_coord |
|
There is a single global variable of type extradata called extradata.
The (non-default) scheduling specifications for this problem are:
| Constraint |
Expression |
| Optimization
Criterion |
sumover
(resources, "resource", preptime (resource)) +
sumover (tasks, "task", if (hasvalue (resourcefor (task)), 0, 1000)) |
| Delta Criterion |
preptime
(resource) - previousdelta (resource) |
| Task Duration |
extradata.service_time |
| Wrapup Duration |
if (hasvalue
(next), 0, dist (task.location, extradata.depot_location)) |
| Task Unavailable
Times |
list (interval
(start_time, start_time + task.ready_time),
interval (start_time + task.due_date + extradata.service_time),
end_time)) |
| Capacity
Contributions |
task.load |
| Capacity
Thresholds |
extradata.capacity |
| Task Text |
task.load |
One thing to note is how the delta criterion tells the incremental increase
in the optimization criterion due to adding a task to a resource.
Generalized Assignment Problem (testdata/assignment/c515-1.vsh)
The generalized assignment problem is not a true scheduling problem
in that there are no times associated with the assignments of tasks to
resources. There are N jobs to be assigned to M agents. There is a predefined
set of assignment costs associated, one associated with each pairing of
a job and an agent. Each agent also has a defined capacity, and each job
contributes a defined amount towards the capacity of each agent (with this
amount depending on the agent). The objective is to maximize the total
costs. The metadata are:
| job |
agent |
| Field
Name |
Field
Type |
| id |
string |
| index |
number |
| costs |
list of number |
| loads |
list of number |
|
| Field
Name |
Field
Type |
| id |
string |
| index |
number |
| capacity |
number |
|
The (non-default) scheduling specifications for this problem are:
| Constraint |
Expression |
| Optimization
Criterion |
sumover
(tasks, "task", entry (task.costs, resourcefor (task).index)) |
| Delta Criterion |
entry (task.costs,
resource.index) |
| Capacity
Contributions |
task.loads |
| Capacity
Thresholds |
loop (length
(resources), "i",
if (i = resource.index,
resource.capacity, 100000)) |
Appendix F: Installation and Setup Procedure
There are two pieces of Vishnu. One is (predominantly) PHP code that runs
on a web server. The other is the Java code for the scheduler and compiler
that can run either on the web server or on (an)other machine(s). We start
by describing how to get the base code on the web server set up. This requires
a variety of open-source applications (primarily Apache, MySQL, PHP and
GD). We then describe how to get the Java runtime environment set up. Finally,
we describe how to get the Vishnu code installed and executing. By far,
the easiest way to install the required web server setup is to use the
product AbriaSQL Standard from
Abriasoft,
or alternatively NuSphere MySQL from NuSphere.
However, if you do not wish to pay for this product, or it does not work
for your particular configuration, here is the step-by-step approach for
a UNIX machine.
Goal: Install an apache web server (DSO), with php4, which talks
to mysql & gd.
Versions:
mysql-3.22.32-pc-linux-gnu-i686.tar.gz (Binary) (USE Gnu tar !!!)
apache_1.3.14
php-4.0.3pl1
zlib-1.1.3
libpng-1.0.8
jpeg-6b
gd-1.8.3
Assumptions: Linux box. (Not too differant) Install to /usr/local/*
from /usr/local/src/*
mysql binary:
% su # Become root.
% cd /usr/local # location of mysql dir
% gzip -dc mysql-VERSION-OS.tar.gz | tar xvf -
% ln -s mysql-VERSION-OS mysql
% cd mysql
% ./scripts/mysql_install_db
% ./bin/safe_mysqld & # FOR TESTING
# System startup...
% cp support-files/mysql.server /etc/rc.d/init.d # (Lose rc.d for Solaris)
% chmod 755 /etc/rc.d/init.d/mysql.server
# -> Create links in rc3.d to start/stop the server.
# Start server.
# -> Kill safe_mysqld
% /etc/rc.d/init.d/mysql.server start # (Lose rc.d for Solaris)
# Set the root password.
% /usr/local/mysqladmin -u root password abc123
% /usr/local/mysql/bin/mysql -u root -pabc123 mysql
mysql> USE mysql
mysql> UPDATE user SET Password=password('abc123') WHERE User='root';
zlib:
% cd /usr/local/src/
% gzip -dc zlib-1.1.3.tar.gz | tar xvf -
% cd zlib-1.1.3
% ./configure
% make
% make install
libpng:
# Note: zlib MUST already be built.
% cd /usr/local/src
% gzip -dc libpng-1.0.8 | tar xvf -
% cd libpng
% cp scripts/makefile.linux Makefile # Choose appropriate make file.
% make
% make install
jpeg:
% cd /usr/local/src
% gzip -dc jpeg-6b.tar.gz | tar xvf -
% cd jpeg-6b
% ./configure
% make
% make install
gd (Depends upon libpng and jpeg):
% cd /usr/local/src
% gzip -dc gd-1.8.3.tar.gz | tar xvf -
% cd gd-1.8.3
# Read Makefile
% make
% make install
Apache 1.3.14
% cd /usr/local/src
% gzip -dc apache_1.3.14.tar.gz | tar xvf -
% cd /usr/local/src/apache_1.3.14
% ./configure \
--prefix=/usr/local/http-80 \
--with-layout=Apache \
--enable-rule=SHARED_CORE \
--enable-module=so \
--enable-module=info \
--enable-module=rewrite \
--enable-module=headers \
--enable-module=usertrack
% make
% make install
PHP4
% cd /usr/local/src
% gzip -dc php-4.0.3pl1.tar.gz | tar xvf -
% cd /usr/local/src/php-4.0.3pl1
% cat INSTALL # !!!!
% vi /etc/ld.so.conf
vi> Add: /usr/local/lib
vi> Add: /usr/local/mysql/lib
% ldconfig
% rm config.cache
% ./configure \
--with-apxs=/usr/local/http-80/bin/apxs \
--with-mysql=/usr/local/mysql \
--with-zlib=/usr/local/ \
--with-gd=/usr/local/ \
--with-jpeg-dir=/usr/local/bin \
--with-libpng=/usr/local/ \
--with-config-file-path=/usr/local/lib \
--with-xml \
--enable-track-vars
% make
% make install
% cp php.ini-dist /usr/local/lib/php.ini # To path specified above.
# Notes: --with-zlib, --with-jepeg-dir --withlibpng are all questionable.
Configure Apache:
% cd /usr/local/http-80/config
% vi httpd.conf
- Change/Uncomment:
DirectoryIndex index.html index.htm index.shtml index.cgi index.php
index.php3 index.phtml
AddType application/x-httpd-php .html .php .php3 .phtml
AddType application/x-httpd-php-source .phps
- Other non-php configs...
ie: hostname, cgi, includes, logs, ...
- Group -> www
% /usr/local/http-80/bin/httpd -t # Test the syntax of the the config
files.
# System startup...
% cd /etc/rc.d/init.d (/etc/init.d for Solaris)
% ln -s /usr/local/http-80/bin/apachectl httpd-80
% ../rc3.d
% ln -s ../init.d/httpd-80 S80httpd-80
% cd ../rc5.d
% ln -s ../init.d/httpd-80 S80httpd-80
% cd ../rc1.d
% ln -s ../init.d/httpd-80 K15httpd-80
% cd ../rc2.d
% ln -s ../init.d/httpd-80 K15httpd-80
% cd ../rc6.d
% ln -s ../init.d/httpd-80 K15httpd-80
# - Remove the existing apache S and K files if needed.
# - Stop the old server if running.
# - Start the new server.
# - Check Errors in /usr/local/http-80/logs/errors
Misc:
# Create a local 'www' group.
# Let the userver run as nobody.www.
# Change dir permissions.
# Give acces to trusted users.
#--
% vi /etc/group
www:x:8080:foouser,baruser
% cd /usr/local
% chgrp -R www mysql
% chgrp -R www http-80
% cd /usr/local/http-80
% chmod 775 htdocs
% chmod u+s htdocs
Sources:
Apache 1.3.14 - http://www.apache.org/dist/apache_1.3.14.tar.gz
PHP v. 4.0.3pl1 - http://www.php.net/downloads.php
Zlib - ftp://ftp.uu.net/graphics/png/src/zlib-1.1.3.tar.gz
Gd - http://www.boutell.com/gd/http/
MySQL - http://www.mysql.com/downloads/index.html
Libpng - http://www.libpng.org/pub/png/src/libpng-1.0.8.tar.gz
JPEG-6b - http://cygutils.netpedia.net/V1.1/jpeg-6b/jpegsrc.v6b.tar.gz
Dependancies:
We have used Sun's Java 1.2.2 as our environment. This code is available
from Sun's Javasoft
web site. The other component of the Java environment that Vishnu requires
is an XML Java library. We have used the Xerces library available at
this
web site. For convenience, we have included the same xerces.jar file
you would get from this site in the Vishnu package in the directory lib.
After either downloading xerces.jar or copying it from lib, you must add
its full path to your CLASSPATH environment variable.
The tar file vishnu.tar.gz contains code/files that go in three different
places.
-
The php and sql directories go on the web server. The sql directory can
go anywhere, but the php directory should go somewhere, or be linked to
from somewhere, that is visible via the web server. Perhaps the best way
to do this on a UNIX machine is to type
> ln -s <fullpath>/php </home/httpd>/html/vishnu
where <fullpath> is the full pathname of the parent directory of
php and </home/httpd> should be replaced with the home directory of
Apache if /home/httpd is not the home directory.
-
The vishnu.jar file should go on whatever machines are executing the server
and/or compiler. On these machines, make sure to add/vishnu.jar to your
CLASSPATH environment variable.
-
The testdata directory should go on whatever machine is going to be used
for running the web browser for testing the system.
On the web server, you should one time run the command
> mysql -u[username] -p[password] < initializesql
This should initialize the tables in the MySQL database. Once you have
run this once, you should not need to run it again.
To start the automated scheduler, execute the command
java -Dvishnu.host=[hostname] -Dvishnu.path=[pathname] -Dvishnu.user=[username]
-Dvishnu.password=[password] -Dvishnu.port=[portnumber] org.cougaar.lib.vishnu.server.Scheduler
Start the formula compiler with the same command with ExpressionCompiler
substituted for Scheduler. Note that it is best to make a small script
file for starting the scheduler and compiler. Some examples of such script
files are given in the scripts directory. Also note that the defaults are
hostname=[localhost], path="/~vishnu/", user=vishnu, password="", and portnumber=80.
You should now be set up to run.
Vishnu is still in its early stages. There are many improvements to
be made and holes to be filled. Here is a list of some of the enhancements
we are considering:
-
Manual Assignments - The user should be able to perform an assignment
or unassignment of a task to a resource.
-
Better Capacity Logic - The current logic does not allow for resetting
of capacity (due to unloading or the end of a time interval).
-
Synchronization of Multiple Clients - There should be better locking
of database tables to ensure that no inconsistencies arise when we start
using multiple clients, particularly multiple schedulers.
-
Sparse Distance Matrices - The user should be able to specify distances
only between nearby locations, and the scheduler should be able to fill
out the full set of distances between a set of locations by finding minimum
paths through the network.
-
Rollback for Data Error - When there is an error loading data, the
database should roll back to a state where it was consistent rather than
be in an inconsistent state. This will necessitate using Berkeley BDB tables
to provide rollback capability. Remember to delete the problem name if
there is an error loading the problem definition.
-
Access Control and Security - We should use https instead of http
for greater security. We should consider defining the concept of privileges
so that certain users can perform certain operations and access certain
problems. We should consider some way of better hiding the username and
password used by the scheduler and compiler.
-
Schedule Stability Soft Constraint - It should be possible to express
a preference for keeping the schedule the same as much as possible without
freezing the assignments.
-
Automatic Freezing of Past Assignments - The automated scheduler
should automatically not modify any assignment earlier than the start of
the scheduler window.
-
Geographic Display - For those problems where the tasks have associated
geographic data (latlongs or xy_coords), we should provide a way to view
this data graphically.
-
Evaluation of Specs in Browser - To allow debugging of scheduler
specifications, provide a way for the user to evaluate a formula for a
constraint in a desired context (i.e., with the variables and assignments
set appropriately).
-
Recheck Constraints for Frozen Tasks - Instead of just assigning
the frozen task to the same resource with the same start and end time,
first check to make sure that the task is still of the same duration, that
the task is still available, that the resource is still available, etc.
Updating the frozen assignments can get complicated if the effects ripple
into other frozen assignments.
-
User-selectable Alerting - Using formulas, let the user define certain
conditions under which he or she wants to be alerted. Generally, this will
be when the assignment (or lack of assignment) for a particular task is
far enough from the ideal to warrant human intervention.
-
Display reference field - The key field for tasks and resources
that provides a unique internal reference is also used for referencing
these objects in the display. We should consider adding an option for a
separate (or additional) field for referencing these objects in the display.
-
Command-Line Compiler - Currently, there is now way to execute the
compiler without the web server. We should implement something analogous
to the internal scheduler so that the compiler can be run from a command
line.
-
Runtime Check of Legality of Specs - Since data structures may have
changed since the last compilation of the scheduling specifications, do
a quick check before scheduling that the specs are still legal.
-
Resource Utilization Display - Make functional again the code that
displays the fraction of the resources and their capacities used as a function
of time.
Appendix G: Documentation Notes
Document includes a number of changes in terminology from what is currently
on the Vishnu site. The changes were made to use language easier
to understand and less ambiguous. The Appendices have not been changed
from the original document written by Gordon Vidaver and may be inconsistent
with the main sections.
The original document was embedded in php. All php information
has been removed for ease of editting.
The Sample problems in Appendix E need reworking to correct errors and
make easy to understand
Developed using Netscape Composer 4.77
Written by Talib Hussain, based upon earlier documentation written by
Gordon Vidaver
Copyright 2001 BBN Technologies
Version: October 12, 2001
|