|
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