Problem with Solver
"John Fletcher" <[email protected]> Thu, 19 Jan 2006 11:50:17 -0000
| Newsgroups | gmane.comp.lib.daixtrose.help |
|---|---|
| Message-ID | <43CF7CF9.13652.A46D42@localhost> |
Marcus Here is a copy of a program which fails when compiled with -DPROBLEM to illustrate the problem I amhaving when I pass expressions to a function and then attempt to add them to the solver. I have not tried this with the new release of Daixtrose. John-- Dr John P. Fletcher Tel: (44) 121 204 3389 (direct line) Chemical Engineering and Applied Chemistry (CEAC), School of Engineering and Applied Science (SEAS), Aston University, Aston Triangle, BIRMINGHAM B4 7ET U.K. CEAC Web site http://www.ceac.aston.ac.uk/ FAX: (44) 121 204 3679 // mysolver_6.cc adapted and extended 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. // Modified to illustrate the problem of Expression<n>. // Compile with -DPROBLEM to see the problem. // John Fletcher ([email protected]) 2006 #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; Accessor *Determinant_; 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<typename T1, typename T2> inline void StoreDeterminant(Daixt::Expr<T1> const & e1,Daixt::Expr<T2> const & e2) { using namespace Daixt::ExprManip; using namespace Daixt::Differentiation; Variable<1> Diff1; Variable<2> Diff2; Determinant_ = Daixt::ChangeDisambiguation<Accessor> (Simplify (Diff(e1, Diff1)*Diff(e2, Diff2) - Diff(e2, Diff1)*Diff(e1, Diff2) ) ).DeepCopy(); std::cerr << "Determinant = " << Determinant_->GetName() << std::endl; } 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 << "registering expression '" << Expressions_(Row)->GetName() << "'" << std::endl; // this stores all d(e)/d(var(i)) // This code has to be commented to save the call being compiled. //if (diffs) StoreDiff<Row, NumberOfVars>::Apply(e, Jacobian_); } template<typename T> void AddExpression1(Daixt::Expr<T> const & e) { AddExpression<1>(e); } template<typename T> void AddExpression2(Daixt::Expr<T> const & e) { AddExpression<2>(e); } template<typename T> void AddExpression3(Daixt::Expr<T> const & e) { AddExpression<3>(e); } template<typename T> void AddExpression4(Daixt::Expr<T> const & e) { AddExpression<4>(e); } 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 double 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 = g11*g22 - g12*g21; double det = Determinant_->GetValue(Values_, index); std::cout << "det = " << det << std::endl; //std::cout << "det2 = " << det2 << std::endl; // compute corrections double delx = (Expressions_(3)->GetValue(Values_,index))/det; //double delx = (f2*g12 - f1*g22)/det; std::cout << "delx = " << delx << std::endl; //std::cout << "delx2 = " << delx2 << std::endl; //double dely = (-f2*g11 + f1*g21)/det; double dely = (Expressions_(4)->GetValue(Values_,index))/det; // adjust variables for the next step. std::cout << "dely = " << dely << std::endl; //std::cout << "dely2 = " << dely2 << std::endl; Values_[i * NumberOfVars] = x + delx; Values_[i * NumberOfVars + 1] = y + dely; // need to check for convergence. return f1*f1 + f2*f2; } }; //////////////////////////////////////////////////////////////////////////////// // ************************************************************************** // //////////////////////////////////////////////////////////////////////////////// DECLARE_VARIABLE(x, 1, "x"); DECLARE_VARIABLE(y, 2, "y"); //DECLARE_VARIABLE(z, 3, "z"); // Versions like this with the expressions e1 and e2 as parameters // failed to compile. // The failures are at the calls to AddExpression<n> with the message // error: invalid use of member (did you forget the '&' ?) // The call to StoreDeterminant is O.K. // In version 4 the same code is compiled O.K. and runs where the expression is not an argument. // This looks like a problem with the compiler, something to do with the integer template value. // The solution is to add new member functions AddExpressionN. The calls compile and so does the body // containing the call which did not compile here. Reason??? // Advantage: Consistent code where each expression is entered once at the user's level. template <class T1, class T2> int problem(Daixt::Expr<T1> const & e1,Daixt::Expr<T2> const & e2) { using namespace Daixt::DefaultOps; using namespace TinyMatAndVec; using namespace Daixt::ExprManip; using namespace Daixt::Differentiation; typedef AccessibleBaseClass<2> Accessor_t; typedef TinyVector<Accessor_t *, 4> Vector_t; //typedef TinyQuadraticMatrix<Accessor_t *, 4> Matrix_t; typedef Solver<2, Vector_t> Solver_t; Solver_t MySolver; #ifdef PROBLEM MySolver.AddExpression<1>(e1); #else MySolver.AddExpression1(e1); #endif MySolver.AddExpression2(e2); // This is how to make a variable into an expression. //MySolver.AddExpression<3>(Daixt::make_expr(z)); MySolver.AddExpression3( Simplify(e2*Diff(e1,y)-(e1*Diff(e2,y))) ); MySolver.AddExpression4( Simplify(e1*Diff(e2,x)-(e2*Diff(e1,x))) ); // Compile time evaluation of 2 by 2 determinant from expressions. // I have not been able to do this from the stored versions. MySolver.StoreDeterminant(e1, e2); 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++) { double residual = MySolver.Step(i); std::cout << "Residual = " << residual << std::endl; if (residual < 1.e-16) { std::cout << "Converged" << std::endl; break; } } } int main() { using namespace Daixt::DefaultOps; using namespace Daixt::Convenience; problem(x+y,x*x + y*y -3.); }