Vishnu Home Page

Vishnu Home

Full Documentation


Frequently Asked Questions

 

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:
  1. All user-defined types must have unique names.
  2. 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
  3. 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.
  4. 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.
  5. 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
  6. 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:
  1. All task instances must have a unique KEY value.
  2. All resource instances must have a unique KEY value.
    • These are permitted to be the same as the KEY values of task instances.
  3. Global instances may be instances of a predefined object type or of a user-defined global type.
  4. 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.
  5. 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
  6. 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).
  7. 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 Data Types Description
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).
  1. 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.
  2. 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.
  3. Evaluate how good each assignment is
  4. 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.
 
  1. 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.
  2. 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.
  3. 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.
  4. 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.
      1. Starting at best-time, find the next non-zero, available interval after best-time.
      2. For that interval, temporarily assign A to that interval.  Generally, A will be slotted in between two tasks previous and next.
      3. 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).
      4. If A can still fit in between previous and next, we have found a valid interval.
      5. If A does not fit, return to step a and continue until a valid interval is found
      6. Repeat, searching for a valid interval before best-time.
      7. Return the valid interval that is closest to best-time.
  5. 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:

  1. 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.
  1. 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.
  2. 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 eit