Library Extensions

Extending libFAUDES in general involves

Note that you may very well extend the library by data-types and functions only, further integration is optional. However, the remaining tasks are recommended in order to advertise your add-on to the user.

We give a walk-through to the above steps by the example plug-in.

Relevant Files

The standard library distribution comes with a number of plug-ins, including the example plug-in. The latter integrates an alternative accessibility function AlternativeAccessible() into libFAUDES and is meant as a template for your own plug-in. The example plug-in directory is organized as follows:

example -+- README                            short overview on purpose of this plug-in
         |
         |- Makefile.plugin                   makefile to integrate this plug-in with the build system
         |
         |- src --+- pex_altaccess.h          declaration of function AlternativeAcessible()
         |        |- pex_altaccess.cpp        definition of function AlternativeAcessible()
         |        |- pex_include.h            header to include all other headers of this plug-in
         |        +- doxygen/faudes_images    images for doxygen documentation
         |        +- registry/pex_*.rti       run-time interface defintions, see below
         |        +- registry/example_*.gtml  run-time interface documentation, see below
         |        +- registry/pex_interface.i SWIG interface, see below
         |
         +- Makefile.tutorial                 extra dependencies for this plug-in's tutorial
         +- tutorial --- pex_tutorial.cpp     mini application to illustrate intended usage
         +- data     --- g_notacc.gen         data to run tutorial with        

The directory name implicitely defines the libFAUDES plug-in name i.e. example. Futhermore, all source files start with a common prefix, i.e. pex_, in order to avoid confusion with other plug-ins.

Algorithm Implementation

The example algorithm to implement converts a given generator to an accessible generator without affecting the closed and marked languages. This is done by removing all states that cannot be reached from any initial state. For the below generator G, the states to remove are labeled 7, 8 and 9.

The proposed implementation in src/pex_altaccess.cpp is organized in two stages


void AlternativeAccessible(vGenerator& rGen) {
  // create a todo stack for state indices
  std::stack<Idx> todo;
  // create an empty StateSet for the set of accessible state
  StateSet accessible_states;
  // iterator for a StateSet
  StateSet::Iterator sit;
  // initialize the algorithm by pushing all initial states on the todo stack
  for (sit = rGen.InitStatesBegin(); sit != rGen.InitStatesEnd(); ++sit) {
    todo.push(*sit);
  }
  // process the todo stack until it's empty
  while (not todo.empty()) {
    // get and delete the next state index from the todo stack
    const Idx current = todo.top();
    todo.pop();
    // insert the current state in the set of accessible states
    accessible_states.Insert(current);
    // create transition iterator for the states of the current state
    TransSet::Iterator tit = rGen.TransRelBegin(current);
    TransSet::Iterator tit_end = rGen.TransRelEnd(current);
    // push successor states ton todo stack if not already discovered
    while (tit != tit_end) {
      if (not accessible_states.Exists(tit->X2)) {
        todo.push(tit->X2);
      }
      ++tit;
    }
  }
  // delete the states and transitions which are not accessible
  rGen.DelStates(rGen.States() - accessible_states);
}

The function starts by setting up required data structures. These consist of a todo stack and a so-calledStateSet, which is the FAUDES implementation of a container to hold a set of unique states. Then all initial states are pushed on the todo stack as they are reachable by definition. The main processing is done by removing the current top element of the todo stack, storing this state in the set of accessible states and following all transition paths that lead from this state to an unprocessed state. At last the non-accessible states and the transitions leading to these states are removed by calling a single operation on the set difference of the automatons's states and the accessible states.

As it can be seen, the algorithm is implemented by using abstract data-types from either the C++ standard library or from the FAUDES library. In particular, it does not depend on the internal data structure of the Generator class.

Doxygen Documentation

The build system runs doxygen on all *.cpp and *.h files in the make search path and thus includes the plug-in sources to the doxygen documentation. By convention, the overall include file of each plug-in is used to give an overview, perhaps including key functions and data-types as well as licensing and copyright information. Provided the all further plug-in source code complies with doxygen documentation coments, all relevant functions will nicely appear in the libFAUDES C++ API reference.

For the example plug-in overview, we add a doxygen section to pex_include.h and define it to belong to the doxygen group AllPlugins:

/**
@defgroup ExamplePlugin Example Plugin

@ingroup AllPlugins

@section Overview

This example demonstrates the libfaudes plug-in mechanism and  
may serve as a template for setting up ... etc.

@section License

The example plug-in is distributed with libFAUDES and under the terms of
the LGPL.

@section Contents

*/

We document our add-on function in pex_altaccess.h by a technical description. We also tag the function to be a member of the doxygen group ExamplePlugin, such that it will appear in our overview section Contents.

/**
 * Alternative accessibility algorithm. 
 * We use the alternative accessibility algorithm from tutorial 6 
 * for our example plug-in. The implementation uses a todo stack ... etc.
 *
 * <h4>Example:</h4>
 * <table width=100%> 
 * <tr>
 * <td> @image html pex_g_notacc.png </td>
 * </tr>
 * </table>
 *
 * @param rGen
 *   Input generator
 *
 * @ingroup ExamplePlugin 
 */
 void AlternativeAccessible(vGenerator& rGen);

Note that the above doxygen documentation refers to an image file, namely pex_g_notacc.png. You are meant to supply the file in the source directory .plugins/example/src/doxygen/faudes_images. Since the build system merges all image filed to one destination directiory, the plug-in prefix pex_ is essential. It is good practice to provide a tutorial that actually produces any example data, incl. images files.

Tutorial

Each plug-in is meant to provide a number of small C++ applications that demonstrate the intended usage of the implemented C++ API. These tutorials are located in example/tutorial/ and operate on input data in example/tutorial/data. In particular when the generated output data is substantial, it is good practice to obey the naming convention example/tutorial/tmp_ or example/tutorial/results/* in order for the build system to remove generated files on make clean.

/**
 * @file pex_tutorial.cpp  
 * Tutorial, example plugin. More text ...
 * @ingroup Tutorials
 * @include pex_tutorial.cpp
 */

#include "libfaudes.h"

int main() {
  Generator gen("data/g_notacc.gen");
  AlternativeAccessible(gen);
  gen.Write("tmp_altacc.gen");
  return 0;
}

Note that by specifying the source to be in group Tutorials and by sourcing the file through doxygen, the tutorial will be listed in the C++ API reference, Section see Tutorials.

Dependencies to build the tutorials are included by Makefile.plugin from Makefile.tutorial.

Makefile.plugin

The libFAUDES main makefile copies headers to the libfaudes include directory, compiles sources to objects and, finaly, links objects to obtain the libFAUDES library and utility executables. While processing the main makefile, the build system includes plugins/example/Makefile.plugin. The latter extends the variables SOURCES, OBJECTS, and HEADERS in order to indicate additional targets. It also extends the make search path VPATH. The example Makefile.plugin is organized as follows:

1. Define relevant paths and source files.

Note that we only use variables with prefix PEX in order to avoid confusion with variables in the main makefile.

PEX_NAME   = example
PEX_BASE   = ./plugins/$(PEX_NAME)
PEX_SRCDIR = ./plugins/$(PEX_NAME)/src

PEX_CPPFILES = pex_altaccess.cpp
PEX_INCLUDE = pex_include.h

PEX_HEADERS = $(PEX_CPPFILES:.cpp=.h) $(PEX_INCLUDE)
PEX_SOURCES = $(PEX_CPPFILES:%=$(PEX_SRCDIR)/%)
PEX_OBJECTS = $(PEX_CPPFILES:%.cpp=$(OBJDIR)/%.o)
2. Contribute to auto-generated header files.

Applications that use libFAUDES are meant to include all relevant headers by the #include "libfaudes.h" directive. This in turn includes the auto-generated files include/allplugins.h and include/configuration.h. They list include directives for all activated plug-ins and define runtime bahaviour macros, respectively.

The example plug-in requires pex_include.h to be registered with allplugins.h and adds the macro FAUDES_PLUGIN_EXAMPLE to configuration.h.

# Append my overall include file to libfaudes.h
$(INCLUDEDIR)/$(PEX_INCLUDE): $(PEX_SRCDIR)/$(PEX_INCLUDE)  
	cp -pR $< $@
	echo "#include \"$(PEX_INCLUDE)\"" >> $(INCLUDEDIR)/allplugins.h
	echo "/* example plugin configuration */" >> $(INCLUDEDIR)/configuration.h
	echo "#define  FAUDES_PLUGIN_EXAMPLE" >> $(INCLUDEDIR)/configuration.h
	echo " " >> $(INCLUDEDIR)/configuration.h
3. Advertise plug-in to the libFAUDES build system.

This includes all additional sources, headers and objects. The variable VPATH directs the make tool to find sources when resolving (implicit) rules.

SOURCES += $(PEX_SOURCES)
OBJECTS += $(PEX_OBJECTS)
HEADERS += $(PEX_HEADERS)
VPATH   += $(PEX_SRCDIR)

Run-Time Interface

libFAUDES provides a registry for data-types and functions as a basis for applications that transparently pass on libFAUDES extensions to the user; see C++ API, Section RTI, for technical details. The build system tries to minimze the effort that is required for a plug-in to participate in this optional feature.

The example plug-in provides only one function, which is registered via the token file src/registry/pex_definitions.rti:

<FunctionDefinition>
"AltAccessible" +faudes::AlternativeAccessible+

<TextDoc>
"Alternative implementation to remove inaccessible states and related transitions." 
</TextDoc>

<HtmlDoc>
"example_index.html"
</HtmlDoc>

<Keywords>
"Example PlugIn" "reachable" "accessible"
</Keywords>

<VariantSignatures>
<Signature>
"Default"
"Gen"  "Generator"   +InOut+
</Signature>
</VariantSignatures>

</FunctionDefinition>

The above token stream declares a function with name AltAccessible to be implemented by the C++ function faudes::AlternativeAccessible. It gives a short description and a reference to a more detailed html documentation. It is up to you whether you design one html document per function or whether you collect groups of related functions.

The list of keywords by convention must contain the name of the plug-in as indicated (Example PlugIn for the plug-in named example). Thus, the build system can set up an index of all functions provided by one plug-in. Furthermore, some applications may use the keyword list in an hierarchical manner (top- to bottom-level).

Regarding signature(s), the libFAUDES run-time interface imposes the following restrictions:

Of course, any referenced HTML documentation must be provided. For convenience, the build-system pre-processes any documentation by the perl script gtml (provided in the tools directory). The example plug-in is fine with one page of documentation only, as given in the below src/registry/example_index.gtml. Note that, by convention, each plugin that participates in the registry must provide exactly one index file named as indicated.

<h1>Example Plugin</h1>

<p>The example plug-in addresses ... etc. etc.</p>

<<FUNCTIONBEGIN(AltAccessible)>>

<<DETAILS>>
<p>More text ... etc.</p>

<<CONDITIONS>>
<p>Arguments must be such that ... etc.</p>

<<FUNCTIONEND>>

The macros FUNCTIONBEGIN, DETAILS, CONDITIONS, FUNCTIONEND are used be the build-system to fill in apprriate headings and signature information.

The libFAUDES build system expects run-time interface files to be advertised via Makefile.plugin. For our example plug-in, we announce one *.rti file and one *.gtml file by appending the following lines to Makefile.plugin:

PEX_RTIDEFS = pex_definitions.rti
PEX_RTIGTML = example_index.gtml

PEX_RTIDEFS := $(PEX_RTIDEFS:%=$(PEX_SRCDIR)/registry/%)
PEX_RTIHTML := $(PEX_RTIGTML:%.gtml=$(PEX_NAME)/%.html)
PEX_RTIGTML := $(PEX_RTIGTML:%=$(PEX_SRCDIR)/registry/%)

RTIPLUGINS += $(PEX_NAME)
RTIDEFS += $(PEX_RTIDEFS)
RTIGTML += $(PEX_RTIGTML)
RTIHTML += $(PEX_RTIHTML)

To trigger the re-build of the rti registry, run the main makefile with targets make rti-clean and make rti-prepare. The libFAUDES archive provides a copy of SWIG for convenience, however, installation is required.

Lua-bindings

The build system tries to minimze the effort that is required to access additional functions via luafaudes. It does so using the tool SWIG to automatically convert so called interface definitions to C wrapper code; see http://www.swig.org.

The libFAUDES build system expects interface files to be advertised via Makefile.plugin. For our example plug-in, we announce one SWIG module and one interface file by appending the following lines to Makefile.plugin:

LBP_INTERFACES += $(PEX_SRCDIR)/registry/pex_interface.i 
LBP_LUAMODULES += example

Note the prefix LBP that refers to the luabindings plug-in.

The actual interface pex_interface.i file resides in the example plug-in:

// Set SWIG module name
// Note: must match libFAUDES plug-in name
%module example

// Indicate plugin to rti function definitions
#ifndef SwigModule
#define SwigModule "SwigExample"
#endif

// Load std faudes interface
%include "faudesmodule.i"

// Extra Lua functions: copy to faudes name space
%luacode {
-- Copy example to faudes name space
for k,v in pairs(example) do faudes[k]=v end
}

// Add topic to mini help system
SwigHelpTopic("Example","Example plugin function");

// Include rti generated functioninterface 
#if SwigModule=="SwigExample"
%include "../../../include/rtiautoload.i"
#endif

Since our plug-in provides only functions are registered with the run-time interface, the interface file in this case is just a skeleton. The build system will fill in our function by generating the file include/rtiautoload.i.

It is good practice to supply comprehensive lua scripts in the tutorial directory that illustrate the intended usage of the plug-ins data-types and functions.

To trigger the re-build of luabindings, run the main makefile with targets make luabindings-clean and make luabindings-prepare. The libFAUDES archive provides a copy of SWIG for convenience, however, installation is required.