Boost logo

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