SAR<em>bayes</em>: SORAL Documentation
(SARBayes) Main Related Pages Class List Hierarchy Methods Files

SORAL Developer's Guide

1

Charles Twardy & Andre Oboler

Version 2.0

Date:
8 May 2003
SORAL is the SARBayes Optimal Resource Allocation Library, a programmer's API of optimization algorithms tailored to Search And Rescue (SAR). From an end-user's perspective, SORAL provides functions to best allocate a given set of SAR resources to most effectively find a lost person. The SORAL API is a simple, clean, modular collection of algorithms, each of which is optimal in its own domain. By virtue of plugging in to SORAL, each also provides important values for the end-user, such as probability of detection, coverage, and others.

The SARBayes project is based at Monash University (Australia). SORAL is free (libre) software available under the Gnu GPL. It was officially released mid-May, 2003. The most recent documentation and information is available at the web site: http://sarbayes.org

We have taken inspiration for this Guide from the Data Conditioning API Developers Guide by Philip Charlton. Indeed, much of The Coding Standard comes straight from his guide.


Overview

This document is intended to provide a set of guidelines for developers when writing new components for the SORAL library. If you are reading a printed version, the source-code documentation follows. If you are reading online, there are links to the source-code documentation in the header and footer bars. Because this is the Developer's Guide, these will include all the private class members, not just the interface.

If you are an application programmer who wants to use SORAL, or if you want to know more about resource allocation and what to do with it, you should look at the User's Manual.

The Developer's Guide describes SORAL's structure more generally and gives coding standards, instructions for getting the code from CVS, examples, and so forth. Here is the outline:

  1. Overview
  2. Licensing for SORAL
  3. Review of what SORAL does
  4. SORAL Library Structure
  5. Getting the Code
  6. Policy:
  7. The Coding Standard
  8. Documentation Standard
  9. Writing New Allocation Algorithms
  10. Final Notes
  11. References

Getting this document

Versions of this document in HTML, RTF, and PDF can be found linked from the SORAL section of this page:
http://www.sarbayes.org/projects.shtml


Licensing for SORAL

SORAL is free (libre) software released under the Gnu GPL, and copyright (some of) the authors and Monash University (the SARBayes project). A copy of the GPL should be included in your copy of SORAL. In short, you are basically free to do what you want with the software so long as anything you create with it is also GPL. If you want to use it in proprietary software, you must negotiate a separate agreement with us.

The SORAL Documentation is free documentation, copyright the authors and the SARBayes project at Monash University. You may copy, distribute, transform, and alter it, so long as you do not restrict the right of others to do the same to your derivative version. Of course, we would prefer that you submit your changes to us.

If you would like your algorithms included in the official SARBayes distribution, you will need to share copyright with Monash, or, equivalently, grant Monash unlimited license to reproduce. The reason for this is so that we can offer SORAL to proprietary (non-GPL) users without having to contact everyone who ever contributed.

Sharing copyright means you keep all your rights. Specifically, you can also make non-GPL versions of your stuff, include it in proprietary code, etc. But you also give us those rights.

If you want your code in the official SARBayes distribution, please insert the following text in your file headers:

//===========================================================================//
// Written by ****AUTHORS HERE*****                                          //
//                                                       http://sarbayes.org //
//---------------------------------------------------------------------------//
// The SORAL implementation is free software, but it is Copyright (C)        //
// 2001-2003 the authors and Monash University (the SARBayes project).       //
// It is distributed under the terms of the GNU General Public License.      //
// See the file COPYING for copying permission.                              //
//                                                                           //
// If those licensing arrangements are not satisfactory, please contact us!  //
// We are willing to offer alternative arrangements if the need should arise.//
//                                                                           //
// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR //
// IMPLIED.  ANY USE IS AT YOUR OWN RISK.                                    //
//                                                                           //
// Permission is hereby granted to use or copy this program for any purpose, //
// provided the above notices are retained on all copies.  Permission to     //
// modify the code and to distribute modified code is granted, provided the  //
// above notices are retained, in accordance with the GNU GPL.               //
//===========================================================================//
 * 

If you want to develop but aren't sure you don't want to share copyright, send us a note or give a call. At worst, you can develop for it GPL, and we'll link to your stuff, but won't include it in the official SARBayes distribution. But we can probably allay any worries. We're not in this to make money.


Review of what SORAL does

SORAL is a library of algorithms for Search And Rescue and related problems. It's primary goal is to find the lost person faster, by finding the most efficient way to use your resources.

SORAL takes some basic (but theoretical) information about your resources, areas, and initial probabilities, and creates optimal allocations, given the constraints of the algorithm chosen. It also computes for any allocation (including arbitrary ones) important information like Coverage, Probability of Detection (POD), Probability of Success (POS), and new Probability of Containment (POC) [POC is also known as Probability of Area (POA)].

(If this does not make sense to you, you should read either the User's Manual, or some of the background Search Theory material available from the SARBayes website.)

In particular, SORAL methods ask for:


SORAL Library Structure

SORAL has many different algorithms, because different algorithms are better suited to different problems. For example, is it reasonable to assume you can split your resources as finely as you wish, or do they come in predetermined chunks? Indeed, one of the main goals for SORAL was a modular structure encouraging plug-in algorithms. There are many algorithms available in the Operations Research literature.

However, the calling program (a search management GUI perhaps) wants to know as little about those algorithms as possible. After all, the primary goal of SORAL is to provide a library that does all the hard math reliably so programmers can get on with using the algorithms. So insofar as possible, the calling program interacts only with the base methods. Everything is an Allocation, meaning that any new algorithm you develop will be a descendant of Allocation.

Different algorithms will make their allocation in different ways, or use different internal data structures, but this is all hidden from the user. Once the user has created an allocation object, he interacts with it using the base methods.

One way to do this would be to require developers to re-implement a lot of virtual methods. We didn't do that.

You have to implement about 6 virtual methods. These methods provide handles for the base-level iterators to use to walk your data structure. All the calculations and reporting can be done by the base Allocation from there.

So SORAL provides a fast way to implement a new algorithm with minimal fuss. At least we think so. And we've put a lot of design work into making it so.

The current structure is captured in the automatically-generated source-code documentation. The HTML version should provide clickable class diagrams and interaction diagrams. Note: what Doxygen calls a ``collaboration diagram'' is not a UML collaboration diagram. But it's useful anyway.

The current design (desired structure) as a UML diagram is in the soral.dia file in the SORAL/Docs directory. This is not automatically generated, but created by hand in Dia. Ideally, it is accurate and slightly ahead of the code, but it is easy to get out of sync. It is available in viewable format on the website as either.

The core of SORAL is the Allocation class and its 3 iterators. The current structure allows for these very same iterators to work on any kind of allocation, so users have a single, standard interface, no matter how fancy the underlying footwork.

In an early version of SORAL, every new algorithm inherited the allocation from Allocation, and each kind of iterator from the basic iterators. That made for a very complicated parallel inheritance hierarchy, with each algorithm defining 3 new iterators, declaring them as Friends, and having them inherit from the base iterators while it inherited from Allocation. It was unwieldy and easy to make mistakes. It created a high burden on an algorithm developer. It broke encapsulation. And it also seemed to require general classes like "Iterator" and "Container", which were really useless since we never had a container (or iterator) without knowing its type. That was SORAL 1.0. Effectively no one outside our group saw it.

For SORAL 2.0, we made two key structural changes, the second giving us the new iterator design. First, we put all the common calcuations into the base class. Therefore new algorithms don't have to bother writing routines for calculating Coverage, POS, POD, etc.

Second, the base Allocation class does not store an allocation. Each algorithm may have developed a very clever, very fast data structure which it can uses. There is no reason to convert to some ``generic'' allocation, possibly duplicating storage, slowing access, or reducing flexibility. All we need to do is provide a common way to get at any data structure natively.

In order to do that, each data structure needs to provide a few basic functions. It has to show us which areas have allocations (often many or most will not), and it has to let us read those allocations, whether we are interested mostly in what's been assigned to a given area, or whether we are interested mostly in the areas that Team Alpha has been assigned to. So we define the following 6 virtual functions:

Third, we have at least one matrix parameter: Effectiveness. We need some sort of matrix class. Right now we don't need much matrix performance, but later we might. So we created a simple abstract matrix class, Array2D, which has all the important operations defined. So we can leave it simple for now, or later use a very clever matrix class inside Array2D.

Future Plans and Ideas

SORAL takes theoretical values for its Effectiveness. It takes a lot of work to determine a Sweep Width, and for land SAR, we usually don't know them, though there is progress on that front. It might be nice to have a library which assisted the user in calculating Effectiveness. Right now it has to be calculated or guessed manually. This may also be a database issue: there are some land-search sweep-width experiments now, so it may be more appropriate to just import a database than to approximate by quick field estimates such as one-half average-maximum-detection-range.

The search methods now instantiated all assume the subject has stopped moving. There are algorithms to handle a moving person. These require not just an initial probability map, but a probability map that evolves with time, independent of search effort. That may be something we can add to SORAL or we may want a separate library or bit of code.

Please let us know of any further libraries or library functions that could be useful for search and rescue software. (We prefer to concentrate on search theory since we have some expertise there, and not many land searchers do.) If you build any additional libraries or programs, please let the us know.

Current contact details can be found on the SARBayes website at: http://sarbayes.org


Getting the Code

Before beginning development on SORAL, you must get the source code. We maintain SORAL code in a CVS archive and strive to have the checked-in code in good running condition, so you should be able to check it out and compile it most any time. In this section we tell you how to get the code, how to compile and test it, how to update it, how to get an account so you can check in, and how to use your new super powers.

Getting Code online via CvsTrac

The SARBayes website has a web interface to our CVS system. It provides for source browsing and checkout, bug tracking, and a Wiki server, which is a set of web pages modifiable white-board style by most users. To see the CvsTrac for SORAL, browse to http://sarbayes.org/cgi-bin/run-cvstrac.cgi/SORAL/index Then you can do several things:

Going beyond the web interface

This section covers how to use CVS either anonymously or with an account. You'll need an account to commit changes back to the repository, otherwise everything else here applies. The anonymous account is, "anonymous" with password "anonymous". Tricky, eh?

If you want to develop for SORAL, you should ask for a CVS account before you get too far. Say hi, tell us about yourself and what you want to do. If you want to write a new algorithm, or basically do anything but modify existing code, no problem: we can give you access to your own subdirectory or files. If you want to modify the base classes or existing algorithms, we're going to ask you to submit patches for review until we're really sure you know what you're doing.

So you've written to us, and we've given you an account. We'll probably ask you to log in via CvsTrac and change your password. Then you can begin using CVS as below.

The first login / check out:

The first thing you do is log in to CVS and "check out" a module, SORAL in this case. You only need to do this once, unless you wish to wipe the slate and start over.

Here's how to log in and check out SORAL from a Unix environment with the 'sh' or 'bash' shell or relatives. Please use your username (or "anonymous") for . Type your password (or "anonymous") when prompted.
First, change to the directory where you want to have SORAL (mine is in ~/Projects/SARBayes/). Then:

 export CVSROOT=:pserver:anonymous@sarbayes.org:/home/sarbayes/cvs/SARBayes
 cvs login
 cvs -z3 co SORAL
 
You now have the code! You can change to the SORAL directory and begin to explore. (See Compiling and Testing the Code ) Note: don't use the "co" (checkout) command any more unless you want to remove the SORAL directory and start again.

The life of CVS in two commands

Before we go into details, here's the basic picture. Pretend you're a developer. Your CVS life is pretty simple and routine.

Updating your local source (from the repository):

You come back on Monday and are about to get to work. WAIT! First make sure you've got the most recent code: someone else may have made changes over the weekend. Go to the directory with your local copy of the code and type:
cvs -z3 update

Your local copy will be updated with newer version of files in the repository If you want a quieter update, type

 cvs -z3 -q update 
instead. And "up" is equivalent to "update". The "-z3" means, "compress in transit".

CVS remembers all that :pserver: stuff in the CVS subdirectory, and it remembers you password in ~/.cvspass. That's why you don't need to type it anymore.

Posting to the repository:

So you've made some changes, checked that the code is in a clean state (see Policy: ), and want to share the joy. Go to the directory where your local copy of the code lurks (you should be there if you've just been editing and testing). Then type:
cvs commit

You will enter a vi session (or your default editor). Add a comment about this update, save and exit. (Or if you have only a brief comment, type

 cvs commit -m "My brief comment...."
and you can skip the vi session. (Much rejoicing.)

You will see the files being updated Repository is now updated: you have contributed to the accumulated wisdom of humanity.

Compiling and Testing the Code

So you just got SORAL. Now what? Where do you start? The code is in SORAL/C++ (unless you're interested in the Matlab stuff). Therein you will find a Makefile. You have come to the right place. (If you are on Windows, there are also Visual C++ project files, so you can do this from the GUI.)

Here are the options. You would normally only need to use the first couple.

Todo:
Right now, only on unix systems, so you may have to link statically. -"make libinstall" will eventually put libsoral.a and the header files in convenient places. -"make test" is the same as "make exec" except that it sets the TESTMODE flag, generating lots of debug info. If any of those don't work, please contact us immediately. Chances are, you caught us during some active patching.

Consider a soral namespace. See dcAPI page 7.

This is just an example of a ``To-Do'' item.

CVS GUIs and other CVS info

If you are unfamiliar with CVS, you may wish to read the man pages, or browse one of:

Generally, you only need two commands (plus the first login), so a GUI is overkill. But CVS is often intimidating at first. If you wish to use a GUI front-end to CVS, Go for it! Suggestions:


Policy:

We strive to keep the repository clean. Clean code compiles without warnings or errors on both Windows and Unix, and passes the tests. Right now the compile standards are:

Don't check in dirty code. At least not if it affects the main build. If you're working on a new algorithm that is not yet in the main build, don't worry about it. But if you're working on a module in the main build, try to make and test localized changes so that you can check in clean code either:

For the main build especially, manually-generated class diagrams should be updated and checked in before coding where possible. They provide the best and maybe only way to check the implementation against the design.

If you have added no functionality, then make sure that you do:

If you have added functionality, you should also define test cases and include those in your own test package, or in the two existing test programs (sample.cpp and TestBed.cpp).


The Coding Standard

The library code is designed to be readable. Here are some basic commandments:

        int aFunction(void)
        {
		  // some code
        }
 

A class in SORAL is an implementation of a particular algorithm. For example, the Charnes-Cooper algorithm which generates theoretically optimal allocations for a single resource pool, without heuristic search. All algorithms create an allocation, for which the base Allocation class provides a number of standard operations that you don't have to write.

File organization

Despite the fact that the original classes may not (yet) obey this convention, please declare new classes in a single header file named ClassName.h.

Please put the class definition in ClassName.cpp

Lay out your header (.h) files this way:

  1. Descriptive header as described in Documentation Standard
  2. File guard of the form:
    #ifndef CLASSNAME_H
    #define CLASSNAME_H
    
  3. System includes, #include <>
  4. Application includes, #include ""
    Only include required files. Remember that any types which are referred to via pointers or references only need not be defined, just forward-declared.
  5. (Pre-processor directives such as #define, if required.)
    Use const variables in preference to #define.
  6. Forward declarations
  7. External functions declarations
  8. External variables declarations
  9. External constant declarations
    Where possible, constants will be declared in a header but defined in a source file so that changing the value of a constant doesn't trigger recompilation of a large number of files.
  10. Struct declarations
  11. Class declaration. Declare sections of the class explicitly in the following order (ideally we will set up a template).
    1. Public
    2. Protected
    3. Private
  12. Close for the file guard, of the form:
    #endif // CLASSNAME_H

Lay out your source (.cpp) files to follow the header files. Don't include things that are already included in the header.

Create new classes with the following template:

    class MyClass 
	{
        public:
        private:
            MyClass();                                  // default constructor
            MyClass(const MyClass&);                    // copy constructor
            ~MyClass();                                 // destructor
            const MyClass& operator=(const MyClass&);   // copy assignment
    };
If left undefined, these functions are implicitly defined by the compiler. Putting them in private: prevents them from being called inadvertently. As you define each function, you can move it to the public section, or perhaps remove it entirely if the implicit definition is appropriate.

That's enough for now. We might choose to add more later, referring to the dcAPI or other examples. But I'd rather not get TOO picky here. Often it's easier to just use previous code as an example, or have a template file to start with.


Documentation Standard

We strive to use dOxygen for as much of our documentation as possible, including this manual. We also maintain our main UML design diagram (soral.dia) separately with the package Dia. In the future, we may use LaTeX directly for theory papers or general introductions to search theory that are not so closely linked to the code.

Whether we write in LaTeX or dOxygen, we can generate HTML and PDF from the same source, and make the documents available online.

Tools

Source Code Commenting

The source code is commented in four ways:

Although there are many ways of using dOxygen, the style outlined below is closest to the original (pre dOxygen) commenting style of this project.

More information on dOxygen commenting styles can be found at: http://www.stack.nl/~dimitri/doxygen/docblocks.html

File Header Block

Each file contains a head block with the project name, the file name, a description of the functionality in the file, a brief history of significant changes, and a license.

Format (excluding the license):

/********************************************************************* 
 *      SARBayes OPTIMAL RESOURCE ALLOCATION LIBRARY 2001-03         *         
 *                                                                   *
 *********************************************************************/
/** \file containr.h
 *  \brief containr.h contains AreaAssignment and ResourceAssignment
 *  
 * These objects are used to return area and resource information to 
 * the user. The information is wrappered in this class so that the   
 * user can not do  harmful operations on the allocation list.
 *
 * <b>Version History</b>
 *
 * \verbatim
 *-----+----------+-----+--------------------------------------------
 * Who |   When   | Ver | What                                       
 *-----+----------+-----+--------------------------------------------
 * ME  | 05/12/01 |  1  | Created.                                   
 *-------------------------------------------------------------------
 * GT  | 25/02/02 |  2  | Modifications.  AreaAssignment now         
 *     |          |     | encapsulates a resource number rather than  
 *     |          |     | an area number, whilst ResourceAssignment  
 *     |          |     | now encapsulates an area number rather than 
 *     |          |     | a resource number.                         
 *-------------------------------------------------------------------
 * ASO | 10/12/02 |  3  | Modified. Removed base class "container"   
 *     |          |     | and updated "child" classes as needed.     
 *-------------------------------------------------------------------
 * \ endverbatim
 */
(Note: put no space between "\" and "endverbatim".)

Class Header Block

Each class is preceded with a header block briefly describing it and its purpose. The description should contain enough information to decide if new functionality falls within the class' purpose (and should be part of the class) or outside of it. Following the description is the original author's name. Except when a class has been completely redone (i.e. nothing but the name remains) no further version history is contained at the class level.

Format:

   /**** Magic **************************************************************/
   ///  A brief (1 line) description of class magic
   /**
    *  A more elaborate class description.
    *  This description may span multiple lines.
    *
    *  Author: The white Rabbit
    */
    
    class magic
    {
     

NB: note that row of asterisks is not for dOxygen but for visual separation. Put the class name in the row of asterisks. It makes it easier to find things when reading the code.

Property (data member) description

All public properties, and most private ones, should have a brief one-line description of what they are, even if it is obvious. The description does not contain its type or name, just what it is for.

Format 1:

     /// Brief (1 line) description of magic beans
     int magicBeans; /**< Longer additional description */

Or Format 2:

     /// Brief (1 line) description of magic beans
     /**
      * Extended description of
      * of magic beans
      */
     int magicBeans;

Method and Function description

Almost all methods and functions should contain at least one-line descriptions of what the method or function does, even if obvious. The non-obvious ones will need more. If appropriate, explain why the function is there.

Put these descriptions at the definition -- where the code lives -- rather than the declaration! In other words, don't comment the declaration (stuff in the .h file) unless that's where the code is (or there is no code). Otherwise it is too easy to get comments out-of- sync with the code, especially since C++ ignores the variable names given at declaration.

The description should not contain its return type, name or parameters unless these need explaining.

Format:


/**** grow() ***********************************/
/// Brief (1 line) description of grow()
/**
 * Extended description of the grow() method:
 * Note: <em>amount</em> is in meters.
 */
void grow(int amount);

Maintenance comments

Use regular (non-dOxygen) comments for maintenance commenting such as:

Other useful dOxygen Commands:

Todo List

The "\todo" command inserts a "Todo" tag into the documentation, and also includes that item in the ``To Do'' page under ``Related Pages''. Applies to the whole paragraph. For example:

Lists

Bullets are created using - for unnumbered lists or -# for numbered lists. The - symbol must in either case be in the same column (character position) for it to be regarded as the same list level. (Alternatively, you can use HTML-style lists, and then have column freedom. HTML-style may be better for longer lists.)

Example:

  /** 
   *  A list:
   *    - Bullet Item 1
   *         -# Numbered Item 1
   *         -# Numbered Item 2 \n
   *            More info about Numbered Item 2
   *         -# Numbered Item 3
   *    - Bullet Item 2
   *         -# Numbered Item 1
   *         -# Numbered Item 2
   *
   *  Some other text.
   */

A list:

Some other text.

Bold

<b> This in bold </b>
This in bold

Emphasis

<em> This in emphasis </em>
This in emphasis

More at: http://www.stack.nl/~dimitri/doxygen/commands.html


Writing New Allocation Algorithms

Why you may want to create a new allocation object

The allocation objects are the core of SORAL. ``Charnes-Cooper'', ``Washburn'', and ``UserDef'' are all allocation objects. Each implements a different algorithm and serves different situations. If you have a new algorithm, or an extension to an existing one, then you need to write a new allocation object. The whole library has been designed to make it as easy as possible to do this. If you already have the internals for some fancy algorithm, there are very few things you need to add to make it a SORAL object.

How to create a new Allocation object.

A new allocation object must inherit from Allocation and implement the following general functions:

It must also implement the following movement functions (the iterators use these for moving through your data structure, about which they know nothing):

Finally store your allocations in an attribute called myAssignments. This can have any structure whatsoever. But it's nice to other programmers if they know where that structure is.

Friend Functions

You need to declare the following classes friends of your allocation class (copy and paste this at the end of your class description):
	// External methods
	public:
		/// So that the AreaIterator can access the first & next functions
		friend class AreaIterator;
		/// So that the ResourceIterator can access the first & next functions
		friend class ResourceIterator;
		/// So that the ActiveAreasIterator can access the first & next functions
		friend class ActiveAreasIterator;

Using the containers

There are three types of containers:

Creating an ActiveArea

For example, to create the ActiveArea* for the movement function ActiveArea * firstArea(void) const, you must return something like this:

Creating an AreaAssignment

For example, for the function AreaAssignment * firstArea (const int resource), you must return something like this:

Example:

If your allocation storage object is an Array2D called myAssignments (as in Charnes Cooper and UserDef), you could use the following complete code (taken from CharnesCooper):

AreaAssignment* CharnesCooper::firstArea(const int resource) const
{
  // Find index of first non zero area for this resource
  for(int i=0; i<myNumAreas; i++)
  {
    if (myAssignments[i][resource]!=0)
    {
      return new AreaAssignment(i, myAssignments[i][resource]);
    }
  }

  //Check in case this resource not assigned to any areas
  return NULL;
}

Creating a ResourceAssignment

For example, to create the ResourceAssignment* for the function: ResourceAssignment * nextRes(const int Area, int currentResource) const, you must return something like this:

Example:

If your allocation storage object is an Array2D called myAssignments, (as in CharnesCooper and UserDef) you could use the following code fragment:

    if (myAssignments[area][tempResource] > 0)
    {
      return new ResourceAssignment(tempResource,
				                    myAssignments[area][tempResource]);
    }
 

Note: A word of caution: read carefully the descriptions of the functions you must implement. The iterators rely on these movement functions and will not work if your functions do not meet the specification. (Variables won't. Constants aren't. Functions don't.)


Final Notes

We may add more examples here. Tell us what you need. Feel free to browse the User's Guide as well.


References

tbd
Generated on Fri May 9 17:03:51 2003 for SORAL by dOxygen 1.3-rc3
(SARBayes) Main Related Pages Class List Hierarchy Methods Files