Boost logo

Boost Users :

From: Stephen Gross (sgross_at_[hidden])
Date: 2006-04-05 09:35:34


Ok, at least one person said they were interested in seeing my idea for an
equation toolkit, so here goes... The files a few hundred lines, so
hopefully that's ok for this group. If I've exceed some message size, I'm
sorry in advance...

======== e.cpp (client code) follows =========
#include "equation.h"
#include "equation_enable_macros.h"

int main()
{
  equation::Equation a;

  a = _y + _z;

  std::cout << a(_y is 5, _z is 10) << std::endl;

  a = _x + 8 * (_y - _z);

  std::cout << a(_x is 2, _y is 3, _z is -9000.9) << std::endl;

  return 0;
}

======== equation.h follows (the real work) =========
// Copyright Stephen Gross 2006
#ifndef api_equation
#define api_equation

#include <string>
#include <iostream>
#include <map>
#include "boost/function.hpp"
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/bind.hpp"

namespace equation {

class ArgTable
{
  typedef std::map<std::string, double> MapType;

  public:

    ArgTable & setArg(const std::string & name, double val)
    {
      my_map[name] = val;

      return *this;
    }

    virtual double getArg (const std::string & name) const
    {
      MapType::const_iterator f = my_map.find(name);

      if(f == my_map.end())
      {
        std::cout << "Error: Equation requested argument '" << name << "'
which was not given." << std::endl;
        exit(0);
      }
      else
      {
        return f->second;
      }
    }

  private:

    MapType my_map;
};

class ArgTableReporter : public ArgTable
{
  public:

    virtual double getArg(const std::string & name) const
    {
      my_last_var = name;
      return 0;
    }

    const std::string & getLastVar() const { return my_last_var; }

  private:

    mutable std::string my_last_var;
};

///
/// Represents an Equation, simply put.
///
/// The idea here is that, for any Equation that takes named arguments ("x",
"y", etc.) and manipulates them
/// arithmetically, such an Equation can in fact be encapsulated in an
Equation instance.
///
///
class Equation
{
  public:

    typedef boost::function1<double, const ArgTable &> FunctorType;

  /// @name Constructors
  //@{

    Equation() : my_ftr(boost::lambda::constant(0)) { ; }

    Equation(const Equation & other) : my_ftr(other.my_ftr) { }

    template<typename T> Equation(const T & t) : my_ftr(t) { }

  //@}

  /// @name The underlying function that invokes the functor:
  //@{

    double go (const ArgTable & args) const { return my_ftr(args); }

  //@}

  /// @name operator()
  //@{

  double operator() () { return go(ArgTable()); }

  template<typename A1>
  double operator() (const A1 & a1, double v1) const
  {
    ArgTable args;
    ArgTableReporter names;

    a1(names); args.setArg(names.getLastVar(), v1);

    return go(args);
  }

  template<typename A1, typename A2>
  double operator() (const A1 & a1, double v1, const A2 & a2, double v2)
const
  {
    ArgTable args;
    ArgTableReporter names;

    a1(names); args.setArg(names.getLastVar(), v1);
    a2(names); args.setArg(names.getLastVar(), v2);

    return go(args);
  }

  template<typename A1, typename A2, typename A3>
  double operator() (const A1 & a1, double v1, const A2 & a2, double v2,
const A3 & a3, double v3) const
  {
    ArgTable args;
    ArgTableReporter names;

    a1(names); args.setArg(names.getLastVar(), v1);
    a2(names); args.setArg(names.getLastVar(), v2);
    a3(names); args.setArg(names.getLastVar(), v3);

    return go(args);
  }

  template<typename A1, typename A2, typename A3, typename A4>
  double operator() (const A1 & a1, double v1, const A2 & a2, double v2,
const A3 & a3, double v3, const A4 & a4, double v4) const
  {
    ArgTable args;
    ArgTableReporter names;

    a1(names); args.setArg(names.getLastVar(), v1);
    a2(names); args.setArg(names.getLastVar(), v2);
    a3(names); args.setArg(names.getLastVar(), v3);
    a4(names); args.setArg(names.getLastVar(), v4);

    return go(args);
  }

  //@}

  private:

    FunctorType my_ftr;
};

namespace Private {

class Sigma
{
  public:

    Sigma() : my_start(0), my_stop(0), my_iter(boost::lambda::constant(0.0))
{ }

    Sigma(double start, double stop, const Equation & eq) :
my_start((int)start), my_stop((int)stop), my_iter(eq) { }

    Sigma(const Sigma & other) : my_start(other.my_start),
my_stop(other.my_stop), my_iter(other.my_iter) { }

    Sigma& operator=(const Sigma & other)
    {
      if(this != &other)
      {
        my_start = other.my_start;
        my_stop = other.my_stop;
        my_iter = other.my_iter;
      }

      return *this;
    }

    double go (const ArgTable & args) const
    {
      ArgTable newargs = args;
      double result = 0.0;

      for(int i = my_start; i <= my_stop; ++i)
      {
        newargs.setArg("i", (double)i);
        result += my_iter.go(newargs);
      }

      return result;
    }

  private:

    int my_start;
    int my_stop;
    Equation my_iter;
};

///
/// Helper struct so that unary math functions can be easily macro-ified for
constructing Equations.
struct UnaryFunc
{
  UnaryFunc(double (*fn) (double), const Equation::FunctorType & arg_getter)
: my_fn(fn), my_arg_getter(arg_getter) { }

  UnaryFunc(double (*fn) (double), double v) : my_fn(fn),
my_arg_getter(boost::lambda::constant(v)) { }

  UnaryFunc(const UnaryFunc & other) : my_fn(other.my_fn),
my_arg_getter(other.my_arg_getter) { }

  UnaryFunc& operator=(const UnaryFunc & other) { if(this != &other) { my_fn
= other.my_fn; my_arg_getter = other.my_arg_getter; } return *this; }

  double go(const ArgTable & args) const { return (*my_fn)
(my_arg_getter(args)); }

  double (*my_fn) (double);

  Equation::FunctorType my_arg_getter;
};

///
/// Helper struct so that binary math functions can be easily macro-ified
for construction Equations.
struct BinaryFunc
{
  BinaryFunc(
    double (*fn) (double, double),
    const Equation::FunctorType & arg1_getter,
    const Equation::FunctorType & arg2_getter) :
      my_fn(fn), my_arg1_getter(arg1_getter), my_arg2_getter(arg2_getter)
{ }

  BinaryFunc(
    double (*fn) (double, double),
    double arg1,
    const Equation::FunctorType & arg2_getter) :
      my_fn(fn), my_arg1_getter(boost::lambda::constant(arg1)),
my_arg2_getter(arg2_getter) { }

  BinaryFunc(
    double (*fn) (double, double),
    const Equation::FunctorType & arg1_getter,
    double arg2) :
      my_fn(fn), my_arg1_getter(arg1_getter),
my_arg2_getter(boost::lambda::constant(arg2)) { }

  BinaryFunc(
    double (*fn) (double, double),
    double arg1,
    double arg2) :
      my_fn(fn), my_arg1_getter(boost::lambda::constant(arg1)),
my_arg2_getter(boost::lambda::constant(arg2)) { }

  BinaryFunc(const BinaryFunc & other) : my_fn(other.my_fn),
my_arg1_getter(other.my_arg1_getter), my_arg2_getter(other.my_arg2_getter)
{ }

  BinaryFunc& operator=(const BinaryFunc & other)
  {
    if(this != &other)
    {
      my_fn = other.my_fn;
      my_arg1_getter = other.my_arg1_getter;
      my_arg2_getter = other.my_arg2_getter;
    }

    return *this;
  }

  double go(const ArgTable & args) const
  {
    return (*my_fn) (my_arg1_getter(args), my_arg2_getter(args));
  }

  double (*my_fn) (double, double);

  Equation::FunctorType my_arg1_getter;
  Equation::FunctorType my_arg2_getter;
};

} // End namespace Private
} // End namespace equation

#define VAR(name) boost::lambda::bind<double>(&equation::ArgTable::getArg,
boost::lambda::_1, std::string(#name))
#define EQ(name) boost::lambda::bind<double>(&equation::Equation::go, &name,
boost::lambda::_1)

#endif

=========== equation_enable_macros.h follows ============
#ifndef api_equation_enable_macros
#define api_equation_enable_macros

// Disable macros now available:
#undef api_equation_disable_macros

#define is ,
#define _a VAR(a)
#define _b VAR(b)
#define _c VAR(c)
#define _d VAR(d)
#define _e VAR(e)
#define _f VAR(f)
#define _g VAR(g)
#define _h VAR(h)
#define _i VAR(i)
#define _j VAR(j)
#define _k VAR(k)
#define _l VAR(l)
#define _m VAR(m)
#define _n VAR(n)
#define _o VAR(o)
#define _p VAR(p)
#define _q VAR(q)
#define _r VAR(r)
#define _s VAR(s)
#define _t VAR(t)
#define _u VAR(u)
#define _v VAR(v)
#define _w VAR(w)
#define _x VAR(x)
#define _y VAR(y)
#define _z VAR(z)

#define _sigma(start, stop, iter) boost::lambda::bind<double>
(&equation::Private::Sigma::go, equation::Private::Sigma (start,
stop, iter), boost::lambda::_1)
#define _sqrt(x) boost::lambda::bind<double>
(&equation::Private::UnaryFunc::go, equation::Private::UnaryFunc (&sqrt,
x), boost::lambda::_1)
#define _pow(x, y) boost::lambda::bind<double>
(&equation::Private::BinaryFunc::go, equation::Private::BinaryFunc (&pow,
x, y), boost::lambda::_1)

#endif

========= end of code snippets ==============


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