Boost logo

Glas :

Re: [glas] mapping expressions to backend

From: Andreas Pokorny (andreas.pokorny_at_[hidden])
Date: 2006-01-17 08:16:19


On Tue, Jan 17, 2006 at 12:18:24PM +0100, Toon Knapen <toon.knapen_at_[hidden]> wrote:
> As stated from the beginning, see
> http://glas.sourceforge.net/doc/requirements.html , we plan to support
> multiple backends. Thus using the glas-interface, the expressions might
> be mapped to the glas-implementation but also to BLAS-calls or any other
> optimised backend.

> And since we are starting to implement expressions, my question now is:
> How will the user have to specify the desired backend?
>
> The first option is that the user asks glas to automatically try to
> dispatch all expressions to a specific backend. If the backend does not
> provide a corresponding function, the expression will be evaluated by
> the fallback (which is the glas implementation itself for instance).
> For instance: If the user wishes to use BLAS as backend, writing
> 'y+=a*x' will automatically result in a call to axpy.
>
> A second option is that the user needs to indicate explicitly the
> backend to be used for evaluating a specific expression. For instance by
> writing 'y+=mult<blas>(a,x)' or 'y+=blas(a*x)' or 'add_assign<blas>(y,a*x)'
>
> A third option is that the user just calls a high-level binding
> directly. For instance 'blas::axpy(y,a,x)'.
>
> The third option is the least ambiguous (in respect to options 1 and 2,
> see later) but also the least syntactically transparant. But do we need
> syntactic transparancy? And after all, the implementation of 1 and 2
> will have to use such a high-level binding anyway.
>
> The first option is syntactically transparant but might result in
> ambiguous situations: For instance what if the user writes 'y = a*x +
> w'. Should that result in w first being copied to y followed by an axpy
> or should that result in an error or should that result in the
> expression being evaluated by the fallback implementation?
>
> The main difference between option 1 and 2 is that option 1 requires a
> system-wide setting while option 2 requires the backend to be specified
> for each and every expression.
>
> What do you prefer?

You could have both, you could attach the info about the backend to your
types. And you could have a kind of override syntax in your expressions.
So for every backend a small backend tag type, and an instance of each
of them.

struct glas_lib_tag {};
struct atlas_lib_tag {};
struct example_library_tag {};

const glas_tag glas_lib;
const atlas_tag atlas_lib;
const example_library_tag example_library;

is required. These tags then can be attached to types. E.g:

  matrix<float,atlas_lib_tag> mat;
  matrix<float> some_other_matrix; // glas_lib_tag could be the default

  mat *= some_other_matrix;

and this expression will be evaluated using atlas. And to override that
setting, the user could write:
   
  mat[example_library] *= some_other_matrix;

and a different implementation will be used.

Picking the backend using a tag type can also be used for algorithms and
functions, which is what you do in two of your examples above.

I am proposing that syntax because I currently work on a
diploma thesis with that topic. Currently there are these so
called strategy tags:

struct basic_system{}; // default implementation
struct doubled_accuracy{}; // doubles accuracy inside of expressions then
                           // casts back to target type during
                           // assignment
struct system_3dnow{}; // tries to make use of 3dnow instructions,
struct gmp_system{}; // uses the gnu multiple precision arithmetic library

template<size_t K>
struct kfold_dot_product{}; // all dot products are evaluated using
                            // kfold working precision

Some strategies only change certain poritions of the expression
evaluation. Since it is possible to simply reuse existing backends, only
the modified parts have to be implemented, e.g. for gmp_system and
doubled_accuracy only those nodes that handle assignment and accessing
data structures had to be implemented.
That way "basic_system" does impose a certain structure requirement, for
all derived backends, but it is also possible to implement a backend not
fitting into that layout, by not extending basic_system.
So other backends, like using a blas interface of a third party library is
still possible, but involves writing more backend code, well at least once.

I would like to explain more details if you are interested in the
backend layout imposed by basic_system.

Regards,
Andreas Pokorny