![]() | ||||||
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.
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:
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.
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:
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:
firstArea: returns the first area with an allocationnextArea: goes to the next area with an alloationfirstArea(resource): the first area that resource is assigned tonextArea(resource): the next area that resource is assigned tofirstRes(area): the first resource assigned to areanextRes(area): the next resource assigned to area Once those are defined, the data structures are irrelevant. The 3 base iterators can use those 6 functions to get whatever is needed.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.
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
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.
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
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
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.
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...."
You will see the files being updated Repository is now updated: you have contributed to the accumulated wisdom of humanity.
Here are the options. You would normally only need to use the first couple.
Consider a soral namespace. See dcAPI page 7.
This is just an example of a ``To-Do'' item.
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:
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).
Array2D(const int p_rows, const int p_columns);
myReallyLongVariableName, p_array2D, aReallyLongFunctionName()
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.
Please put the class definition in ClassName.cpp
Lay out your header (.h) files this way:
#ifndef CLASSNAME_H #define CLASSNAME_H
#include <>#include ""#define, if required.)#define.#endif // CLASSNAME_HLay 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
};
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.
Whether we write in LaTeX or dOxygen, we can generate HTML and PDF from the same source, and make the documents available online.
We use Dia primarily for design work in UML. The controlling design for SORAL itself is in soral.dia. We strive to make design changes first to that file and then to work on source code. After 2.0 we hope there will be very few changes to the base structure, and only the addition of new algorithms. It probably makes more sense to design and create the new algorithm separately, and add it to soral.dia only after it is working. (Right now, we're not sure how much algorithm detail we want in soral.dia anyway.) Dia does not export directly to PDF, but it exports to Xfig, which exports nicely to PDF.
Like JavaDoc, dOxygen creates file- and class-based documentation from the source code. Output from dOxygen is in the following formats: HTML, LaTeX, Man pages, PDF, RTF and others. In addition, dOxygen allows you to write additional documentation (like this manual) in LaTeX-like markup, and so we strive to put as much as possible into dOxygen.
Note on settings: To work correctly with the style used for this project JAVADOC_AUTOBRIEF should be set to no (the default). Please pay attention to the following sections on how to comment your source code.
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
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 */
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.
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;
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);
// Programmers-Initials Date Reason - code // [code] // . // . // .
/* ... */
// crt 01may03: Trap for the case where from == to code
Do not document small maintenance changes that result from larger documented changes. For example, if you change the type of a variable, comment at the declaration, and not in all the formal parameter lists where it is used.
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.
<b> This in bold </b>
<em> This in emphasis </em>
calcAllocation and call Make sure to call calcAllocation from the constructor. (Mostly this is for the ease of other programmers, but also possibly for future built-in error-checking of new objects.)
calcAllocation --- The function that does the allocation. It may call other private functions.It must also implement the following movement functions (the iterators use these for moving through your data structure, about which they know nothing):
ActiveArea * firstArea(void) const --- Returns the area number of the first area with something assigned to it (as an ActiveArea*).
ActiveArea * nextArea(const int currentArea) const --- Given an area number, returns the next area that has something assigned to it (as an ActiveArea*).
AreaAssignment * firstArea(const int resource) const --- Returns the area number of the first area to which the passed resource has been assigned (as an AreaAssignment*).
AreaAssignment * nextArea(const int resource, const int currentArea) const --- Given a resource number and an area number, returns the next area to which this resource was assigned to (as an AreaAssignment*).
ResourceAssignment * firstRes(const int area) const --- Returns the first resource assigned to the passed area (as a ResourceAssignment*).
ResourceAssignment * nextRes(const int Area, int currentResource) const --- Given a resource number and an area number, returns the next resource assigned to that area (as a ResourceAssignment*).
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.
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;
ActiveArea* for the movement function ActiveArea * firstArea(void) const, you must return something like this:return new ActiveArea(areaNum); where areaNum is an integer representing one of the areas in this allocation.AreaAssignment * firstArea (const int resource), you must return something like this:return new AreaAssignment(tempArea, timeAllocated); where tempArea is an int referring to an area number and timeAllocated is a double indicating how long the passed-in resource was assigned to this area.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;
}
ResourceAssignment* for the function: ResourceAssignment * nextRes(const int Area, int currentResource) const, you must return something like this:return new ResourceAssignment(tempResource, timeAllocated); where tempResources is an int referring to a resource number and timeAllocated is a double referring to the time for which this resource has been assigned to this area.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.)
| (SARBayes) | Main | Related Pages | Class List | Hierarchy | Methods | Files |
|---|