Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] generation of adaptive precision floating-point geometric predicates
From: Kim Kuen Tang (kuentang_at_[hidden])
Date: 2010-03-21 05:07:56


Hi Andrew,

just my thoughts on this chat.

Andrew Durward schrieb:
>
> The central concept is that for any expression (a # b) where # is {+, -, *},
> the result can be expressed as (x + y) where x is the floating-point

How about transform the expression a+b to sum_approx(a,b)+sum_diff(a,b)
instead to fusion::cons<sum_approx(a,b),fusion::cons<sum_diff(a,b)> > ?
The advantage of this approach is that you still get an ast where childs
are held in terminal (instead in cons).

> approximation of (a # b), and y is an error term whose value can also be
> computed as a floating-point value.
>
> In toying with proto, I've been able to transform simple expressions
> successfully but I can't seem to figure out how to define a grammar that
> will handle arbitrary combinations of {+, -, *} recursively. Here's what
> I've got so far:
>
> struct sum_approx{/* */};
> struct sum_error{/* */};
>
> struct diff_approx{/* */};
> struct diff_error{/* */};
>
> struct prod_approx{/* */};
> struct prod_error{/* */};
>
> struct Transform :
> proto::or_<
> proto::when<
> proto::plus< proto::terminal< _ >, proto::terminal< _ > >
> , fusion::cons<
> proto::_make_function(
> sum_approx()
> , proto::_left
> , proto::_right
> )

I dont see the meaning behind this step. If you use
proto::_make_function you create a child in the ast, but you put this
child in a fusion::cons.

> , fusion::cons<
> proto::_make_function(
> sum_error()
> , proto::_left
> , proto::_right
> )
> >
> >()
> >
> // ... similar substitutions for minus and multiplies
> >
> {};
>
> So the expression (a + b) yields the sequence:
> sum_approx(a,b)
> sum_error(a,b)
>
> Here's where I'm stuck. In the case of the expression (a + b)*(c - d), the
> addition and subtraction should be replaced by the appropriate sequences
> before the multiplication gets expanded to yield the final sequence:
> prod_approx( sum_approx(a,b), diff_approx(c,d) )
> prod_error( sum_approx(a,b), diff_approx(c,d) )
> prod_approx( sum_approx(a,b), diff_error(c,d) )
> prod_error( sum_approx(a,b), diff_error(c,d) )
> prod_approx( sum_error(a,b), diff_approx(c,d) )
> prod_error( sum_error(a,b), diff_approx(c,d) )
> prod_approx( sum_error(a,b), diff_error(c,d) )
> prod_error( sum_error(a,b), diff_error(c,d) )

Are you sure that you want to get a sequence of expression instead an
ast. In case you really want to get a sequence you can use
proto::tag::comma to separate your child.

> Obviously I need a recursive transform here but I'm not sure how to pass it
> the sequences generated by both the left and right subtrees.
>
>

Cheers,
Kim

Here is a toy project.
Hth.



# include <boost/cstdlib.hpp>
# include <boost/proto/proto.hpp>
# include <boost/fusion/container/list/cons.hpp>

# include <boost/proto/tags.hpp>
# include <boost/proto/make_expr.hpp>

# define PRECISION_MAKE_tag(name) \
struct name \
{ \
        friend std::ostream& operator<< (std::ostream& s, name const&) \
        { \
        return s<< #name; \
        } \
};

# define PRECISION_MAKE_terminal(name) \
proto::terminal< tag::name >::type const name = {{}}

namespace proto = boost::proto;

namespace tag{
        PRECISION_MAKE_tag(a);
        PRECISION_MAKE_tag(b);
        PRECISION_MAKE_tag(c);
        PRECISION_MAKE_tag(d);
        PRECISION_MAKE_tag(sum_approx);
        PRECISION_MAKE_tag(sum_error);
        PRECISION_MAKE_tag(diff_approx);
        PRECISION_MAKE_tag(diff_error);
}

namespace mpl = boost::mpl;
namespace fusion = boost::fusion;
using proto::_;

struct transform
{
        BOOST_PROTO_CALLABLE()
        
        template<typename Sig>
        struct result;
        
        template<typename This,typename A0,typename A1>
        struct result<This(proto::tag::plus const,A0,A1)>
                : proto::result_of::make_expr<
                          proto::tag::plus
                        , typename proto::result_of::make_expr<
                                  proto::tag::function ,tag::sum_approx, A0, A1
>::type
                        , typename proto::result_of::make_expr<
                                  proto::tag::function ,tag::sum_error, A0, A1
>::type
>
        {};
        
        template<typename This,typename A0,typename A1>
        struct result<This(proto::tag::minus const,A0,A1)>
                : proto::result_of::make_expr<
                        proto::tag::minus, A0, A1
>
        {};
        
        template<typename A0,typename A1>
        typename result<transform(proto::tag::plus const ,A0 const&, A1 const&)>::type
        operator()(proto::tag::plus const ,A0 const& a0,A1 const& a1) const
        {
                return proto::make_expr<proto::tag::plus>(
                        proto::make_expr<proto::tag::function>(
                                  tag::sum_approx()
                                , boost::ref(a0)
                                , boost::ref(a1))
                        
                        ,proto::make_expr<proto::tag::function>(
                                  tag::sum_error()
                                , boost::ref(a0)
                                , boost::ref(a1))
                );
                //return proto::make_expr<proto::tag::plus>(boost::ref(a0), boost::ref(a1));
        };
        
        template<typename A0, typename A1>
        typename result<transform(proto::tag::minus const ,A0 const&, A1 const&)>::type
        operator()(proto::tag::minus const ,A0 const& a0, A1 const& a1) const
        {
                return proto::make_expr<proto::tag::minus>(boost::ref(a0), boost::ref(a1));
        };
};

struct Transform
        : proto::or_<
                proto::when<
                          proto::plus< proto::terminal< _ >, proto::terminal< _ > >
                        , transform(
                                  proto::tag::plus()
                                , proto::_value(proto::_left)
                                , proto::_value(proto::_right)
                          )
>
                ,proto::when<
                          proto::minus< proto::terminal< _ >, proto::terminal< _ > >
                        , transform(
                                  proto::tag::minus()
                                , proto::_value(proto::_left)
                                , proto::_value(proto::_right)
                          )
>
                , proto::otherwise<proto::nary_expr<_, proto::vararg<Transform> > >
>
{};
        



PRECISION_MAKE_terminal(a);
PRECISION_MAKE_terminal(b);
PRECISION_MAKE_terminal(c);
PRECISION_MAKE_terminal(d);

# undef PRECISION_MAKE_tag
# undef PRECISION_MAKE_terminal

int main()
{
        proto::display_expr(a+b);
        BOOST_AUTO(expr, Transform()( (a+b)*(c-d) ) );
        proto::display_expr(expr);
        return boost::exit_success;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net