# Re: [proto] Manipulating an expression tree

On Thu, Apr 7, 2011 at 12:45 AM, Karsten Ahnert
<karsten.ahn...@ambrosys.de> wrote:
> Another question is: can a node have a state. In my algorithm it would
> be nice, if every proto::multiplies< > node stores some intermediate
> values which are used during later evaluations of the tree.

I did something similar to this to resolve the issue I had with the
Eigen matrix library. I am replacing multiplies nodes with an
expression that uses proto::extends to add extra state, in this case a
correctly sized matrix to store the temporary matrix Eigen generates.

I've attached the header that does the node replacement in all the
cases that match the WrappableElementExpressions ("Wrap" in the header
means replacing the node). Note that this header is ripped out of the
context of a larger application (used for finite elements), so some
stuff will not make sense, but the general idea might be helpful.

I am using a primitive transform (WrapMatrixExpression) to do the
actual node replacement here. An alternative would be to create a
domain, and then use the make_... family of transforms to create nodes
in that domain. I went for the primitive transform because it seemed
to compile faster and with less memory.

I intend to post a more detailed example on how I solved the problem
with Eigen later on, with examples that are more stand-alone.

Cheers,

--
Bart
// Copyright (C) 2010 von Karman Institute for Fluid Dynamics, Belgium
//
// GNU Lesser General Public License version 3 (LGPLv3).
// See doc/lgpl.txt and doc/gpl.txt for the license text.

#ifndef CF_Solver_Actions_Proto_ElementExpressionWrapper_hpp
#define CF_Solver_Actions_Proto_ElementExpressionWrapper_hpp

#include "ElementGrammar.hpp"

namespace CF {
namespace Solver {
namespace Actions {
namespace Proto {

/// Matches expressions that can be wrapped
struct WrappableElementExpressions :
boost::proto::or_
<
boost::proto::multiplies<boost::proto::_, boost::proto::_>,
boost::proto::function< boost::proto::terminal< IntegralTag<boost::proto::_> >, boost::proto::_ >,
boost::proto::function<boost::proto::terminal<LinearizeOp>, boost::proto::_, FieldTypes>,
boost::proto::function< boost::proto::terminal< SFOp< CustomSFOp<boost::proto::_> > >, boost::proto::_ >
>
{
};

/// Less restricitve grammar to get the result of expressions that are in an integral as well
struct LazyElementGrammar :
boost::proto::or_
<
ElementGrammar,
ElementMathImplicit // Normally this is only legal inside an integral
>
{
};

/// Wraps a given expression, so the value that it represents can be stored inside the expression itself
template<typename ExprT, typename MatrixT>
struct StoredMatrixExpression :
boost::proto::extends< ExprT, StoredMatrixExpression<ExprT, MatrixT> >
{
EIGEN_MAKE_ALIGNED_OPERATOR_NEW

typedef boost::proto::extends< ExprT, StoredMatrixExpression<ExprT, MatrixT> > base_type;

typedef MatrixT ValueT;

explicit StoredMatrixExpression(ExprT const &expr = ExprT())
: base_type(expr)
{
}

/// Temporary storage for the result of the expression
mutable ValueT value;
};

struct WrapMatrixExpression : boost::proto::transform< WrapMatrixExpression >
{
template<typename ExprT, typename StateT, typename DataT>
struct impl : boost::proto::transform_impl<ExprT, StateT, DataT>
{
/// Helper to select if the expression is to be wrapped
template<bool, int Dummy = 0>
struct WrapperSelector;

/// Expression must not be wrapped
template<int Dummy>
struct WrapperSelector<false, Dummy>
{
typedef typename impl::expr_param result_type;

result_type operator()(typename impl::expr_param expr, typename impl::state_param , typename impl::data_param)
{
return expr;
}
};

/// Expression is to be wrapped
template<int Dummy>
struct WrapperSelector<true, Dummy>
{
/// Calculate the type to store
typedef typename boost::remove_const<typename boost::remove_reference
<
typename boost::result_of<LazyElementGrammar(typename impl::expr_param, typename impl::state_param, typename impl::data_param)>::type
>::type>::type ValueT;

typedef StoredMatrixExpression<typename boost::remove_const<typename boost::remove_reference<ExprT>::type>::type, ValueT> result_type;

result_type operator()(typename impl::expr_param expr, typename impl::state_param, typename impl::data_param)
{
return result_type(expr);
}
};

typedef WrapperSelector< boost::proto::matches<ExprT, WrappableElementExpressions>::value > ResultSelectorT;
typedef typename ResultSelectorT::result_type result_type;

result_type operator()(typename impl::expr_param expr, typename impl::state_param state, typename impl::data_param data)
{
return ResultSelectorT()(expr, state, data);
}
};
};

/// Grammar to do the expression wrapping
struct WrapExpression :
boost::proto::or_
<
boost::proto::when
<
boost::proto::multiplies<boost::proto::_, boost::proto::_>,
WrapMatrixExpression(boost::proto::functional::make_multiplies
(
WrapExpression(boost::proto::_left), WrapExpression(boost::proto::_right)
))
>,
boost::proto::when
<
boost::proto::function< boost::proto::terminal< IntegralTag<boost::proto::_> >, boost::proto::_ >,
WrapMatrixExpression(boost::proto::functional::make_function
(
WrapExpression(boost::proto::_child0), WrapExpression(boost::proto::_child1)
))
>,
boost::proto::when
<
boost::proto::function<boost::proto::terminal<LinearizeOp>, boost::proto::_, FieldTypes>,
WrapMatrixExpression(boost::proto::functional::make_function
(
WrapExpression(boost::proto::_child0), WrapExpression(boost::proto::_child1), WrapExpression(boost::proto::_child2)
))
>,
boost::proto::when
<
boost::proto::function< boost::proto::terminal< SFOp< CustomSFOp<boost::proto::_> > >, boost::proto::_ >,
WrapMatrixExpression
>,
boost::proto::nary_expr< boost::proto::_, boost::proto::vararg<WrapExpression> >
>
{};

} // namespace Proto
} // namespace Actions
} // namespace Solver
} // namespace CF

#endif // CF_Solver_Actions_Proto_ElementExpressionWrapper_hpp
_______________________________________________
proto mailing list
proto@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/proto