Boost logo

Boost :

From: Brian Davis (bitminer_at_[hidden])
Date: 2008-07-24 19:55:12


>Stjepan Rajko writes:
> I have tried to tackle the value/domain transformation problem a while
> back, inspired by Brook Milligan's (CC-d) probability library (which
> can nicely transition probability values between linear and log
> domains).

> Brook Milligan also worked on a generic domain transformation library,
> so he might comment on this as well. There is also the Boost.Units
> library which might offer transformations for some cases.

>Thanks, Stjepan. I've continued to refactor that, actually, to make
>it support the more generic problem under discussion here. So far it
>is mostly done. I think the only issues are some silly overloading
>resolution issues that have little to do with the basic ideas. For
>the discussion I'll outline my approach.

The goal I have/desire is to preform type transformations and allow the
programmer to specify these transformations in a generic way

For type T1 and T2 allow the programmer to specify f(T1 t1, T2 t2 ) and g(T1
t1, T2 t2 ) where f and g are transformation functions from T1 -> T2 and
T2->T1 respectively.

Overloading operator= and specifying f(T1 t1, T2 t2 ) := t2 = t* 1/2 and
g(T1 t1, T2 t2 ):= t1 = t2*2 allowing the programmer to type

float t1;
float t2;
bind_values<float ,float > t1t2ValueBinder( t1, t2 );

t1 = 12;
printf( "%f", t2 );
// produces output of 6

Transformations shall allow chaining/cascaded to be specified.

int a;
int b;
float c;
boost::uint32_t d;

bind_values<int,int> abBinder( a, b );
bind_values<int,float> abBinder( b, c );
bind_values<float,boost::uint32_t> abBinder( c, d );

// a->b->c->d
a = 12;
printf( "%f", d );
// produces output of 6

Transformations shall allow for fanout

int a;
int b;
float c;
boost::uint32_t d;
boost::uint32_t e;
boost::uint32_t f;

bind_values<int,int> abBinder( a, b );
bind_values<int,float> abBinder( a, c );
bind_values<float,boost::uint32_t> abBinder( c, d );
bind_values<float,boost::uint32_t> abBinder( c, e );
bind_values<float,boost::uint32_t> abBinder( c, f );

// a-+->b
// |
// +->c-+->d
// |
// +->e
// |
// +->f

// a->b->c->d
a = 12;
printf( "%f", f );
// produces output of 12 as f and g default to 1 to one mapping
a = 12;
printf( "%f", f );
// produces output of 12 as f and g default to 1 to one mapping
printf( "%f",e);
// produces output of 12 as f and g default to 1 to one mapping

f=32;
printf( "%f", a );
// produces output of 32 as f and g default to 1 to one mapping
printf( "%f",f );
// produces output of 32 as f and g default to 1 to one mapping
printf( "%f",c );
// produces output of 32 as f and g default to 1 to one mapping

Transformations shall support bidirectional and unidirectional updates.

>The basic observation that motivates this is that in some (many?)
>situations there exist a group of related types that clearly have
>common semantics in the application domain but may impose different
>constraints in their implementation.

Yes. Agreed

>Indeed, some operations may not
>be practical or feasible for some of the types but could be for others
>and there may exist transformations from one to another.

Where if there exists no clear transformation... the programmer shall be
allowed to specify one.

>In the case
>of probabilities think of two types, one for a probability and one for
>its logarithm with appropriate operators defined for each domain and
> the interconversions. Another example involves the representation of
> polynomials, which can be in terms of coefficients or in spectral
> terms that ease their multiplication. In this case, it may be
> completely undesirable to implement a polynomical multiplication for
> the coefficient representation.

Yes so some types can not be automatically transformed. My example provides
absolutely no support for this except for 1 to 1 translation... for
disparate types it is... well... compiler errors waiting to happen if no
translation functions are supplied.

> Conceptually then, the Domain library seeks to create a framework for
> implementing sets of such types that work smoothly together, and
> enable the compiler to make choices about how to handle mixed domain
> operations (e.g., adding a probability and a log probability) or
> operations that must be performed in another domain (e.g., multiplying
> two polynomials represented as coefficients). I think these are most
> of the salient points, all of which are currently supported.

The software engineer shall be allowed to specify a transform is the
compiler cannot automatically figure it out.
How difficult is it to specify new types and tranforms.... Are we talking
about the types like thoes defined by the section titled "A Deeper Look at
Meatafunctions - 3.1 Dimensional Analysis" in "C++ Template Metaprogramming"
by David and Aleksey? If so ... ouch... could be quite painful to specify
new types and conversions... What is your approach?

> - Allow definition of families of types (domains) based upon each
> member of a family sharing common semantics in the application
> domain.

Providing type conversions across known domains where they exist. Yes sounds
great.

> - Allow implementation (or not) of any within-domain operators that
> make sense in the application domain.

Yes sounds great with the exception of the "operators portion"... like every
one in boost using operators for new purposes (think Spirit - and I don't
mean this in a bad way) we are running out of operators which provide
meaningful schematics... Food for thought: Wouldn't it be nice if we had
our compilers be able to compile unicode source files ... call them .ucpp...
and define new operators in the C++ language... then we would be able to
utilize these new operators to write code which looks ascetically pleasing
and readable. Another benifit could be easier support internationalization
of software. I'll digress.

> - Allow implementation (or not) of any appropriate interdomain type
 transformations.

> - Decouple the domain type information from the value types used to
> represent the internal domain-specific information.

This I also provided for in my simple example. Though kinda a cheesy
example as "domain" is completely specified by the programmer and there is
no automatic domain logic .

> - Allow specification of a default value type for any domain type so
> that unspecified templates (i.e., T<>) provide meaningful results.

> - Allow specification of which domains are interconvertible as a
> series of pairwise conversions.

so you have a chain a->b->c->d
change a and b, c, and d are changed... correct? This was in my example

Should also allow for fanout
// a-+->b
// |
// +->c-+->d
// |
// +->e
// |
// +->f

and avoid recursion.
a->b->c->a->a->b->c->a... you get the idea

> - Allow specification of which domains support which operations so
> that the compiler can seek an appropriate domain for arguments that
> may (or may not) be directly usable.

What happens when and operation cannot be found in a domain, but the
programmer can or needs to specify one? Is it extensible?

> The goal is to clearly define all these points of extension so that
> the "real" types (e.g., probabilities or polynomials) can be
> constructed on top of the Domain library, thereby simplifying the
> specification of domain families for any application or library.

The easier it is to provide new specifications for types and their
transformations the better.... you'll never think of every domain and
translation. Need to supply a clear path to adding new types, domains, and
translations.

> I have been using this to refactor the Probability library as a proof
> of concept. As mentioned, most of what the old version could do, the
> new one will also do.

> There are a few issues with overloads that are
> confusing to me, so help is welcome.

How do I obtain the code and where is the problem?

> Thus, I am certain that there is
> some merit in this approach to a generic domain solution. However, I
> am also certain that there are other ideas out there that could
> improve this.

Gerneric domain is exactly what I am after. We have type T1, T2, T3,....TN
and we have to translate between them... What's the easiest way to specify
this for the programmer?

> Because of the interaction in development between the two libraries
> (Domain and Probability) I haven't quite finished everything. I'll
> try to roll them up for viewing shortly, though.

> I look forward to continuing discussion, receiving input, and
> discovering how these ideas might be put to use in other contexts.

Context.... Let me speak to context... Let's say your one of thoes down to
earth engineer types... you got to get your product out... you have all this
incoming and out going data at multiple layers of the software form
hardware<->driver<->user space lib<->executable<->network<->client and you
have to translate between types for each interface... Bitfields... don't
get me started on bit fields... Why is a bit such a degenerative type in C++
(try typeid(bit.in_a_bitfield).name() and wonder why you get back
unsigned... would be nice to get the position info of where the bit or bits
are withing a bit field) ... I'll digress again... any way you want to
easily specify type conversions at each layer. You've received the event in
the past and called the appropriate conversion routine after conversion
routine and thought to yourself.. Hey is there any way to get rid of all of
these calls to conversion functions in my callback routine... they're kinda
making the code messy. Sure would be nice if I had a data_binding library
where I could specify the types and specify the conversion functions and
when the value arrives just set it and have the conversion take place
bidirectionally. Then you write it up... think to yourself who might be
able to use this... maybe those boost guys :-)

Hope my input is helpful.

Brain


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk