Re: Help with Differentiation
"John Fletcher" <[email protected]> Tue, 13 Dec 2005 11:34:28 -0000
| Newsgroups | gmane.comp.lib.daixtrose.help |
|---|---|
| Message-ID | <439EB1C4.16669.59F8E2@localhost> |
Markus
Thank you for the reply. The new examples help a lot to understand
how to use it.
I would like to be able to have expressions with constants e.g.
x + y + 1
but that will not compile. What I have to do is to add a variable z
x + y + z
and give z a value, but then it has increased the size of the
problem to 3. I then found that I needed a third function and when I
put in just z it would not compile, as that is a variable, not an
expression.
Ideally, I would like to have a set of variables which are parameters
and not differentiated. That could be done by changing the interior
of the Solver object, which I have started to do.
I attach an example which I have built which solves a two
dimensional newton problem with two variables and one parameter.
Just playing at the moment. I can see a lot of uses for this.
Daixtrose Versions
==============
So far I have only run Solver with the old 0.0.2 daixtrose which I
use on one system which has the old boost. That worked fine.
I will compare your new one with what I have done, which checks
the version of boost and will run with either. It also checks the
version of Loki as well, as they have changed the name of the
TYPELIST macros and also have a template version which
replaces the macros.
I will then report back on that.
Thanks
John
// mysolver_2.cc adapted from Solver_2.C
//
// This has two variables x and y and two functions. These are differentiated wrt x and y and
// the resulting jacobian problem is solved.
#include "daixtrose/Daixt.h"
#include "tiny/TinyMatAndVec.h"
// FIXIT: find out why wstring did not work on some gcc
#define DISABLE_WIDE_CHAR_SUPPORT
#include <boost/lexical_cast.hpp>
#include <boost/mpl/int.hpp>
#include <iostream>
#include <string>
#include <vector>
// code for ML response December 2005
////////////////////////////////////////////////////////////////////////////////
// ************************************************************************** //
////////////////////////////////////////////////////////////////////////////////
// A named and compile-time-numbered variable which can be used for
// differentiation.
struct DisambiguatedVariable {};
template <std::size_t Number>
class Variable
{
public:
inline Variable() {} // intel's C++-70 needs this one
typedef DisambiguatedVariable Disambiguation;
std::string GetName() const;// { return "undefined"; }
};
////////////////////////////////////////////////////////////////////////////
// convenience macros
#define DECLARE_VARIABLE(NAME, NUMBER, LATEX_NAME) \
template <> \
std::string Variable<NUMBER>::GetName() const \
{ \
return LATEX_NAME; \
} \
\
Variable<NUMBER> NAME
#define EXTERN_DECLARE_VARIABLE(NAME, NUMBER) \
extern Variable<NUMBER> NAME
////////////////////////////////////////////////////////////////////////////
// access to the expression name
template <std::size_t Number>
inline std::string GetName(const Variable<Number> & v)
{
return v.GetName();
}
template <class ARG, class OP>
inline std::string GetName(const Daixt::UnOp<ARG, OP>& UO)
{
return std::string("(") + OP::Symbol() + " " + GetName(UO.arg()) + ")";
}
template <class LHS, class RHS, class OP>
inline std::string GetName(const Daixt::BinOp<LHS, RHS, OP>& BO)
{
return
"(" + GetName(BO.lhs())
+ " " + OP::Symbol() + " "
+ GetName(BO.rhs()) + ")";
}
template<class T>
inline std::string GetName(const Daixt::Expr<T>& E)
{
return GetName(E.content());
}
inline std::string
GetName(Daixt::IsNull<DisambiguatedVariable>)
{
return "0";
}
inline std::string
GetName(Daixt::IsOne<DisambiguatedVariable>)
{
return "1";
}
inline std::string
GetName(const Daixt::Scalar<DisambiguatedVariable> & v)
{
return boost::lexical_cast<std::string>(v.Value());
}
template<typename ARG, int m, int n>
inline std::string
GetName(const Daixt::UnOp<ARG, Daixt::DefaultOps::RationalPower<m, n> >& UO)
{
return "(" + GetName(UO.arg()) + ")^("
+ boost::lexical_cast<std::string>(m)
+ "/"
+ boost::lexical_cast<std::string>(n) + ")";
}
////////////////////////////////////////////////////////////////////////////
// some features for our expressions
template <int NumberOfVars>
struct AccessibleBaseClass
{
virtual std::string GetName() const = 0;
virtual double
GetValue(std::vector<double> const & V,
std::size_t index) const = 0;
virtual AccessibleBaseClass<NumberOfVars> * DeepCopy() const = 0;
virtual ~AccessibleBaseClass() {}
};
// specializations which allows us to plug polymorphic behviour to our
// expressions
namespace Daixt
{
template <class T, int NumberOfVars>
class FeaturesOfExpression<AccessibleBaseClass<NumberOfVars>, T>
: public AccessibleBaseClass<NumberOfVars>
{
public:
std::string GetName() const
{
return ::GetName(static_cast<const T&>(*this));
}
////////////////////////////////////////////////////////////////////////
// getting values
private:
////////////////////////////////////////////////////////////////////////
// access to the expression values:
template <std::size_t Number>
inline double GetValue(const Variable<Number> & v,
std::vector<double> const & V,
std::size_t index) const
{
// assuming memory layout
//
// var_1[0]
// var_2[0]
// ...
// var_N[0]
// var_1[1]
// var_2[1]
// ...
// var_N[1]
// etc ...
// please check this quick hack access formula, it might be wrong!
// Number starts at index 1, but std::vector at index 0
std::size_t const myindex = index * NumberOfVars + Number - 1;
#ifndef NDEBUG
return V.at(myindex);
#else
return V[myindex];
#endif
}
template <class ARG, class OP>
inline double GetValue(const Daixt::UnOp<ARG, OP>& UO,
std::vector<double> const & V,
std::size_t index) const
{
return OP::Apply(this->GetValue(UO.arg(), V, index),
Daixt::Hint<double>());
}
template <class LHS, class RHS, class OP>
inline double GetValue(const Daixt::BinOp<LHS, RHS, OP>& BO,
std::vector<double> const & V,
std::size_t index) const
{
return OP::Apply(this->GetValue(BO.lhs(), V, index),
this->GetValue(BO.rhs(), V, index),
Daixt::Hint<double>());
}
template<class TT>
inline double GetValue(const Daixt::Expr<TT>& E,
std::vector<double> const & V,
std::size_t index) const
{
return this->GetValue(E.content(), V, index);
}
inline double
GetValue(Daixt::IsNull<DisambiguatedVariable>,
std::vector<double> const & V,
std::size_t index) const
{
return 0.0;
}
inline double
GetValue(Daixt::IsOne<DisambiguatedVariable>,
std::vector<double> const & V,
std::size_t index) const
{
return 1.0;
}
inline double
GetValue(const Daixt::Scalar<DisambiguatedVariable> & v,
std::vector<double> const & V,
std::size_t index) const
{
return v.Value();
}
public:
////////////////////////////////////////////////////////////////////////
double GetValue(std::vector<double> const & V,
std::size_t index) const
{
return this->GetValue(static_cast<const T&>(*this), V, index);
}
FeaturesOfExpression<
AccessibleBaseClass<NumberOfVars>, T>* DeepCopy() const
{
return new T(static_cast<const T&>(*this));
}
virtual ~FeaturesOfExpression() {};
};
} // namespace Daixt
////////////////////////////////////////////////////////////////////////////
// ********************************************************************** //
////////////////////////////////////////////////////////////////////////////
template <int NumberOfVars,
typename VectorT,
typename MatrixT>
class Solver
{
VectorT Expressions_;
MatrixT Jacobian_;
typedef AccessibleBaseClass<NumberOfVars> Accessor;
typedef boost::mpl::int_<NumberOfVars> number_of_vars_t;
// storing values outside the variable objects !!!!
// this allows sharing with f77 or C legacy code
std::vector<double> Values_;
public:
void Resize(std::size_t size)
{
Values_.resize(NumberOfVars * size);
// fill in some useful values, please replace by your own
// initialize method
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < NumberOfVars; ++j)
{
std::cerr << "Values_[" << i * NumberOfVars + j << "] = "
<< j + 1.0 << std::endl;
Values_[i * NumberOfVars + j] = j + 1.0;
}
}
}
private:
template<int Row, int Col = NumberOfVars>
struct StoreDiff
{
template<typename T>
static inline void
Apply(Daixt::Expr<T> const & e, MatrixT & Jacobian)
{
using namespace Daixt::ExprManip;
using namespace Daixt::Differentiation;
Variable<Col> Differ;
Jacobian(Row, Col) =
Daixt::ChangeDisambiguation<Accessor>
(Simplify(Diff(e, Differ))).DeepCopy();
std::cerr << "Stored d(" << GetName(e)
<< ") / d(" << Differ.GetName()
<< ") = "
<< Jacobian(Row, Col)->GetName()
<< " at (" << Row << ", " << Col << ")" << std::endl;
// recursive call
StoreDiff<Row, Col-1>::Apply(e, Jacobian);
}
};
// end of recursion
template<int Row>
struct StoreDiff<Row, 1>
{
template<typename T>
static inline void
Apply(Daixt::Expr<T> const & e, MatrixT & Jacobian)
{
using namespace Daixt::ExprManip;
using namespace Daixt::Differentiation;
Variable<1> Differ;
Jacobian(Row, 1) =
Daixt::ChangeDisambiguation<Accessor>
(Simplify(Diff(e, Differ))).DeepCopy();
std::cerr << "Stored d(" << GetName(e)
<< ") / d(" << GetName(Differ)
<< ") = "
<< Jacobian(Row, 1)->GetName()
<< " at (" << Row << ", " << 1 << ")" << std::endl;
// no more recursive call
}
};
public:
template<int Row, typename T>
void AddExpression(Daixt::Expr<T> const & e)
{
// you must delete this pointer in the destructor
Expressions_(Row) =
Daixt::ChangeDisambiguation<Accessor>(e).
DeepCopy();
std::cerr << "registrating expression '"
<< Expressions_(Row)->GetName() << "'" << std::endl;
// this stores all d(e)/d(var(i))
StoreDiff<Row, NumberOfVars>::Apply(e, Jacobian_);
}
public:
template<typename T>
inline void PrintValue(Daixt::Expr<T> const & e,
std::size_t index)
{
std::cout << "Value of "
<< (Daixt::ChangeDisambiguation<Accessor>(e)
.GetName())
<< "[" << index << "] = "
<< (Daixt::ChangeDisambiguation<Accessor>(e)
.GetValue(Values_, index))
<< std::endl;
}
inline void PrintJacobian(std::size_t index)
{
std::cout << "\nValues of Jacobian at " << index << ":\n";
for (int j = 1; j < NumberOfVars + 1; ++j)
{
for (int i = 1; i < NumberOfVars + 1; ++i)
{
std::cout << Jacobian_(i, j)->GetValue(Values_, index) << " ";
}
std::cout << std::endl;
}
}
inline void Step(std::size_t index)
{
std::size_t i = index + 1;
std::cout << "\nStep of solution at " << index << ":\n";
// This is where to find the values of the variables
double x = Values_[index * NumberOfVars];
double y = Values_[index * NumberOfVars + 1];
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
// This is where to find the values of the functions
double f1 = Expressions_(1)->GetValue(Values_,index);
double f2 = Expressions_(2)->GetValue(Values_,index);
std::cout << "f1 = " << f1 << std::endl;
std::cout << "f2 = " << f2 << std::endl;
// This is where to find the values of the jacobian
double g11 = Jacobian_(1, 1)->GetValue(Values_, index);
double g12 = Jacobian_(1, 2)->GetValue(Values_, index);
double g21 = Jacobian_(2, 1)->GetValue(Values_, index);
double g22 = Jacobian_(2, 2)->GetValue(Values_, index);
// compute determinant
double det = g22*g11 - g12*g21;
// compute corrections
double delx = (f2*g12 - f1*g22)/det;
double dely = (f2*g11 - f1*g21)/det;
// adjust variables for the next step.
Values_[i * NumberOfVars] = x + delx;
Values_[i * NumberOfVars + 1] = y - dely;
// need to check for convergence.
}
};
////////////////////////////////////////////////////////////////////////////////
// ************************************************************************** //
////////////////////////////////////////////////////////////////////////////////
DECLARE_VARIABLE(x, 1, "x");
DECLARE_VARIABLE(y, 2, "y");
DECLARE_VARIABLE(z, 3, "z");
int main()
{
using namespace Daixt::DefaultOps;
using namespace TinyMatAndVec;
Solver<3,
TinyVector<AccessibleBaseClass<3> *, 3>,
TinyQuadraticMatrix<AccessibleBaseClass<3> *, 3>
> MySolver;
MySolver.AddExpression<1>(x + y);
MySolver.AddExpression<2>(x * x + y * y - z);
MySolver.AddExpression<3>(z - z);
int n = 10;
MySolver.Resize(n+1);
MySolver.PrintValue(Daixt::make_expr(x), 2);
MySolver.PrintValue(Daixt::make_expr(y), 2);
MySolver.PrintValue(Daixt::make_expr(z), 2);
//MySolver.PrintJacobian(2);
for (int i = 0; i < n; i++)
MySolver.Step(i);
}