|
Boost Users : |
Subject: Re: [Boost-users] [Proto] implementing an computer algebra system with proto
From: Eric Niebler (eric_at_[hidden])
Date: 2009-01-22 17:33:12
Kim Kuen Tang wrote:
> Hi all,
>
> considering the following expression created with proto:
>
> "3 *var_+5=2;
>
> .. The tree would be :
> =
> / \
> + 2
> / \
> * 5
> / \
> 3 var_
>
> Here the term "var_" is somewhat a placeholder.
>
> I wonder wheter it is possible now to change the structure of the tree.
> That is i want to define a grammar that is able to produce another
> expression like this.
>
> "var_=(2-5)/3;"
>
> In tree:
>
> =
> / \
> var_ div
> / \
> - 3
> / \
> 2 5
>
> With this expression i can now define a context that return the final
> result of the right hand side.
> But is this possible in proto with the existing functions?
Yes.
> This
> situation is somewhat different from the examples in the documentation.
> Here i dont want to replace the child node. The whole structure of the
> input tree should be transformed in another one.
A general equation solver will be challenging to write, but should be
possible. You'll need to familiarize yourself with Proto grammars and
transforms. Here is a toy example to get you started. Hope it helps.
#include <iostream>
#include <boost/proto/proto.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;
using proto::_;
struct placeholder
{
friend std::ostream &operator <<(std::ostream &sout, placeholder)
{
return sout << "var_";
}
};
proto::terminal<placeholder>::type const var_ = {{}};
// Work around annoyng msvc compiler bugs ...
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
#define _left(x) call<proto::_left(x)>
#define _right(x) call<proto::_right(x)>
#define _make_minus(x,y) call<proto::_make_minus(x,y)>
#define _make_assign(x,y) call<proto::_make_assign(x,y)>
#endif
struct Solve
: proto::or_<
// Solved:
proto::assign<proto::terminal<placeholder>, _>
// Rewrite "var_ + x = y" to "var_ = y - x"
, proto::when<
proto::assign<
proto::plus<proto::terminal<placeholder>, _>
, _
>
, proto::_make_assign(
proto::_left(proto::_left)
, proto::_make_minus(
proto::_right
, proto::_right(proto::_left)
)
)
>
>
{};
int main()
{
proto::display_expr( var_ + 1 = 2 );
proto::display_expr( Solve()( var_ + 1 = 2 ) );
}
It displays the following:
> assign(
> plus(
> terminal(var_)
> , terminal(1)
> )
> , terminal(2)
> )
> assign(
> terminal(var_)
> , minus(
> terminal(2)
> , terminal(1)
> )
> )
HTH,
-- Eric Niebler BoostPro Computing http://www.boostpro.com
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