next up previous contents
Next: Algorithmic Research Up: The FRISCO Project Previous: Common Algebraic Runtime   Contents

Subsections


Software Interoperability

The aim of the software interoperability task was to develop tools to allow FRISCO components written in different high-level languages to interact with one another, and to be embedded in conventional software packages written in the industry-standard languages C++ and Fortran. There were two broad approaches adopted: tight coupling where components are linked together in a single executable file and run as a single process; and loose coupling where different components execute as separate processes or threads inside some framework which controls the flow of computation and allows them to exchange data.

Since this work-package was specified in 1995, there have been a number of changes which have influenced the work done in this area. Chief amongst them are the emergence of Windows and its object model DCOM as serious platforms for scientific computation; the development of CORBA and associated tools such as IDL for describing language-independent interfaces to components; and the popularity of the Java language. This has led to several changes of emphasis in the work we have performed.

The principal approach we adopted was to develop mechanisms which would allow code written in C++ and Fortran to be viewed as natural Aldor objects, and vice-versa. So an Aldor programmer would not need to know anything about C++ or Fortran, while a C++ or Fortran programmer would not need to understand Aldor. In both cases there were essentially two steps involved: first we had to design a semantic correspondence between the different languages; and second we had to develop an implementation to facilitate the interaction.

Aldor/C++ Interoperability

The Aldor language is based around a two-level type system. A category is a description of an abstract data type in terms of the methods it exports, while a domain is a concrete implementation of one of more categories. Inheritance is handled in two ways: in the categories we have multiple inheritance of exports; while for domains we have single inheritance of definitions and representation.

The object model in C++ is based on classes which are basically collections of items such as functions, constants etc. The visibility of these items can be controlled, so that a method might be public, protected or private. Usually only public members may be used outside a class, except in the case where class A inherits from class B, when the protected members of B can be used by A. Inheritance in C++ works by extending one or more base classes to produce a derived class. In effect, a derived class is a sub-type of all its base classes.

So while Aldor separates the notions of interfaces (categories) and implementations (domains), C++ does not. This is important for Aldor since it also supports parameterisation of types, for example the domain Polynomial(R:Ring) implements polynomials over any coefficient ring R. This means that we can build polynomials with coefficients from any ring, but does not imply any connection between the implementations of the different Rs. This is a much stronger facility than that provided by C++ templates.

Both Aldor and C++ have well-defined standard interfaces to C, and this mechanism is used to call the functions in one language from the other. There are some subtle details about ensuring that the exact meanings of types like short and long are the same in both, environments, but in practice this can be achieved by compiling both pieces of code with a standard set of compiler options.

A C++ class is represented in Aldor as a category plus a domain. The exports of the category take an extra argument corresponding to an object of the type, so that the C++ command a.foo() becomes the Aldor command foo(a). The domain provides Aldor wrappers to the C forms of the C++ methods. So for example, the C++ class:


class Complex {
  int real_part;
  int im_part;
public:
  Complex(int i, int j);
  int re() { return real_part; }
  int im() { return im_part; }
  virtual void print();
};
can be viewed as the Aldor category:

define Complex__Cat: Category ==  with {
    re: (%) -> SingleInteger;
    im: (%) -> SingleInteger;
    print: (%) -> ();
}
plus the domain:

Complex: Complex__Cat with {
    bracket: (SingleInteger,SingleInteger) -> %;
} == add { 
    Rep ==> Record (real__part: SingleInteger,im__part: SingleInteger);
    import from Rep; 
    bracket (parm0: SingleInteger,parm1: SingleInteger) : % == 
      cpp__create______7Complexii0(parm0,parm1);
    re (ob: %) : SingleInteger == cpp__Complex__re____7Complex0(ob);
    im (ob: %) : SingleInteger == cpp__Complex__im____7Complex0(ob);
    print (ob: %) : () == cpp__Complex__print____7Complex0(ob);
}
(Note that the underscore character is the escape character in Aldor, hence the profusion of ``_''s in the above!)

Where we have (several) base classes, the category part features a Join of the category components of the base classes. In C++ the constructor function is not inherited, and so except in the simplest case we cannot include it in the category. Hence (as above) it is an explicit export of the domain (in Aldor bracket is used as a constructor function by convention, and bracket(1,2) is syntactically equivalent to [1,2]).

An Aldor category can be viewed in C++ as an abstract template class. The first template parameter is class PercentType which corresponds to Aldor's %, the idea being that each derived class will give itself as the template argument. A domain is viewed as an abstract class (representing the exports) and a class which implements stub calls to all the exported Aldor operations. So for example the Aldor domain:


Complex : with {
  bracket : (Integer, Integer) -> %;
  re : % -> Integer;
  im : % -> Integer;
} == add {

     ...
}
can be viewed as the following C++ classes (provided that the Aldor functions are exported to C and then called in the appropriate way):

template <class PercentType>
class ALDORCategoryComplex0 {
public:
        virtual ~ALDORCategoryComplex0() {}
        virtual Integer * re() = 0;
        virtual Integer * im() = 0;
};

class Complex:  virtual public ALDORCategoryComplex0<Complex> {
        Complex *ptr;
public:
        Complex() { ... };
        virtual Integer * re() { ... }; 
        virtual Integer * im() { ... };
};

Software Tools

The tools for exporting Aldor to C++ have been incorporated into the Aldor compiler and are invoked using the -Fc++ option. This creates two stub files: an Aldor file containing the necessary statements to allow all the exported functions to be called from C, and a C++ header file which contains the C++ class definitions of the Aldor domains and categories.

The tools for calling C++ from Aldor are a little more complicated. To process the C++ header files requires a C++ parser, and so rather than write our own it seemed logical to use an existing C++ compiler such as g++ from the GNU project. In principal we could have provided a  -Aldor option which would produce the necessary stub files. Unfortunately the licensing conditions attached to g++ made such a course of action unappealing, so instead we adopted a two-stage strategy:

Summary

When this work was originally specified, most C++ code only used a subset of the features available in the language because this was the only way to ensure portability between different compilers. However by the time we came to implement these tools the available C++ compilers had matured with the result that we found it necessary to deal with a much larger set of features. With hindsight it might have been better to adapt an existing generic mechanism such as IDL, but this does not yet support all the features that Aldor has (such as parameterised constructors). The tools have been tested with the PoSSo library, Open Inventor (a toolkit for visualisation) and various GNU libraries (for calling C++ from Aldor), and with axllib and BasicMath (for calling Aldor from C++).

Relevant Deliverables

The public reports relating to Aldor/C++ interoperability are:

Parts of this software will be made available as part of the Aldor distribution in the future (the exception is the C++ to XML translator which may become available as part of the g++ distribution). For the moment, the C++ to XML, and its associated documentation, as well as the C++ to Aldor tools may be downloaded.

Aldor/Fortran Interoperability

An interface between Aldor and Fortran was deemed necessary for two principal reasons:

  1. to allow the use of standard numerical tools by FRISCO components;
  2. to allow FRISCO components to be embedded in industrial applications, many of which are written in Fortran.
When this task was initially specified, it was assumed that by the time this work came to be carried out the dominant dialect of Fortran would be Fortran-90. However although Fortran-90 (and now Fortran-95) is becoming more popular, the vast majority of Fortran code in use is still written in Fortran-77, and so we decided to concentrate on that. In contrast with the work with C++, the main difference which had to be addressed in this case was concerned with data representation. There were also some semantic differences which had to be dealt with in a natural way.

There were four main problems with the data correspondence between the two languages:

The model which was adopted was as follows. We provided facilities to indicate to the Aldor compiler that an Aldor object could be viewed as a particular kind of Fortran object. So for example to indicate that objects of the BasicMath domain BLDoubleFloat correspond to a Fortran double precision object, we extended BLDoubleFloat to belong to the category FortranDouble. In the short term we provided special types to represent array objects, but in the longer term work is in progress to enhance the Aldor compiler to use arrays of objects rather than arrays of pointers to objects in cases where the objects are of a fixed size. This will not only make the Fortran interface more natural, it will improve general Aldor performance as well.

To reproduce call by reference semantics, we decided to use a variation of copy-in/copy-out. We introduced a new Aldor type Ref(T:Type) to represent parameters of type T whose values could be updated on exit (this only applies to scalar objects, all arrays in Aldor are effectively passed by reference). The compiler then adds code to copy the values of all values declared to be of a Ref type back into the original location when a function exits. For example, the following code represents a function designed to be passed to Fortran to evaluate sin at its first argument and put the result in its second:


  f(x:DoubleFloat, fc:Ref DoubleFloat):() == {
    update!(fc, sin(x));
  }
A piece of Fortran code which updates some of its arguments might be imported into Aldor as follows:

import { c05adf : (
         a : DoubleFloat ,
         b : DoubleFloat ,
         eps : DoubleFloat ,
         eta : DoubleFloat ,
         f : (DoubleFloat) -> DoubleFloat  ,
         x : Ref DoubleFloat ,
         ifail : Ref SingleInteger) -> ();
} from Foreign Fortran;
Note that in reality all the arguments to c05adf could be modified (except the function f), but the user only needs to declare the ones whose return value he or she is interested in to be of type Ref.

To use Aldor in Fortran is very similar to the way Aldor can be called from C. One first exports some code to Fortran:


export {primep : (SingleInteger, Ref Boolean) -> ();} to Foreign Fortran;
and then uses it as if it were native Fortran:

       INTEGER I
       LOGICAL B
       EXTERNAL PRIMEP
C
       DO 100 I=1,100
         B=.FALSE.
         CALL PRIMEP(I,B)
         IF (B) THEN
            PRINT*,I," is prime"
         ENDIF
 100  CONTINUE
C
      END

Software Implementation

The updates to the Aldor compiler described above were first introduced in version 1.1.12 although further improvements are expected to be introduced in subsequent versions. Implementations of Fortran domains and categories are included in the BasicMath library.

One issue which has not yet been touched on is the different ways in which Fortran compilers pass function arguments and decorate names. There is no standard for this and code compiled by two different Fortran compilers (or indeed one compiler using different compiler options) may not be compatible. To overcome this a set of options have been added to the Aldor configuration file ( axiomxl.conf) to allow a user to configure Aldor to work with their favourite Fortran compiler. Configurations for common compilers are provided.

Aldor/NAG Library interface

To demonstrate the Aldor/Fortran interface in practice a set of include files were produced to allow any routine from the NAG mark 18 Fortran library (which contains over 1100 user-callable routines) to be called from Aldor. This has since been used by a number of people outside the project, most notably perhaps by a group at the University of Western Ontario who are developing algorithms for solving problems which involve polynomials with floating-point coefficients.

Relevant Deliverables

The public reports relating to Aldor/Fortran interoperability are:

The software will be made available through Aldor and BasicMath, as described above.

Component Software Architecture

As stated earlier, this part of the work package was designed to track emerging technologies for loose connection of components inside a framework. Early on in the project, a survey was done of the various technologies available (principally at that time OLE from Microsoft and CORBA from the Object Management Group). The attributes of these technologies were then compared with the perceived requirements of components for computer algebra. It was noted that both frameworks were suitable for coupling large components which needed to exchange relatively little data, and that the issue of data representation was not addressed in either case.

As a proof of concept, a demonstrator was produced which used OLE to embed a Gröbner server based on the PoSSo library in an Excel spreadsheet (more details can be found in the report). Work then continued on defining a more generic framework which could be used to link FRISCO components.

During the second half of the project a framework was designed which used CORBA as the basic architecture, and dealt with the issue of data representation by using the emerging OpenMath standard. The basic idea is that there would be two classes of objects: standard which are specified centrally, and proprietary which can be developed by individual users. A standard component might be a Gröbner server, for which a number of implementations would exist (i.e. a user could ``plug-and-play'' any suitable component into their application). When a piece of data (for example a set of polynomials) needed to be copied from one component to another, it would be transferred in OpenMath format. Thus each component would only need to understand a single common data format, simplifying the interface problems.

It is worth noting that software technology has advanced to the point where there are many frameworks, some public and some proprietary, which can be used to link components together. During the lifetime of the project we have used socket connections ( Ilog Solver application), HTTP and Netscape ( FRISCO for Filters and Filter Banks application), the MuPAD dynamic linking features (with the RS and Gb servers) to name but three. It seems that generic technologies are now mature enough for us to link components into a variety of environments in a variety of different ways.

Relevant Deliverables

The public reports relating to component software architectures are:

Interoperability Summary

The mechanisms that we have developed for inter-language linking and communication have proved more general than we initially anticipated, and the tools will be continue to be used after the project has finished. The work on component software architectures allowed us to stay abreast of what became a rapidly developing area and develop expertise which may well be deployed in future activities.

The emergence of Java has led to some preliminary work on Aldor/Java interoperability. A basic object correspondance between the two languages has been identified (modelled on the correspondance between Aldor and C++) and some code has been linked by hand using the Java Native Interface and Aldor's Foreign C mechanism. Java itself is developing in a number of interesting ways and may in fact become more like Aldor over time. This is an area for future work.


next up previous contents
Next: Algorithmic Research Up: The FRISCO Project Previous: Common Algebraic Runtime   Contents
The FRISCO Consortium