From a40d941153d6fba5ec045acfe0251bf369254a8c Mon Sep 17 00:00:00 2001 From: Christophe Meynard Date: Wed, 28 Feb 2024 17:04:10 +0100 Subject: [PATCH] MMVII: Code generation: can add programmer's comments to generated code --- MMVII/Doc/Programmer/NonLinearOptim.tex | 36 ++++++++++++-- MMVII/include/SymbDer/SymbolicDerivatives.h | 39 +++++++++++----- MMVII/src/SymbDerGen/Formulas_Geom2D.h | 52 ++++++++++++++++++--- 3 files changed, 104 insertions(+), 23 deletions(-) diff --git a/MMVII/Doc/Programmer/NonLinearOptim.tex b/MMVII/Doc/Programmer/NonLinearOptim.tex index ffeab4f189..012d546914 100755 --- a/MMVII/Doc/Programmer/NonLinearOptim.tex +++ b/MMVII/Doc/Programmer/NonLinearOptim.tex @@ -297,19 +297,45 @@ \subsection{class for specifying the formulas} single value, because in general, when we want to compute several values (like $x$ and $y$ residual in BA) its more efficient and convenient to group a multiple residual in a single formula that generating different formulas; - \item the commented lines show how to use {\tt SymbPrint()} and - {\tt SymbPrintDer()} to display at run time computed value of - expressions or parts of expression in the formula. + \item below this function, there is another version which is commented. It's showing + how to use {\tt SymbPrint()}, {\tt SymbPrintDer()}, {\tt SymbComment()} and + {\tt SymbCommentDer()} to document the generated code or to output (print) + values of expressions or parts of expression in the formula. \begin{itemize} - \item {\tt SymbPrint(expr, mesg)} will display + \item {\tt SymbComment(expr, comment)} will place {\tt comment} as a comment + on the line in the generated code where a tempory variable will be assigned + the value of expr. + \item {\tt SymbCommentDer(expr, k, comment)} will place {\tt comment} as a comment + on the line in the generated code where a tempory variable will be assigned + the value of the derivative of expr with respect to the kth unknown. + \item {\tt SymbPrint(expr, mesg)} will generate code to display at runtime "[i] mesg = (value of expr)", i being the current iteration of the loop when multiple values are calculated simultaneously. - \item {\tt SymbPrintDer(expr, k, mesg)} will display + \item {\tt SymbPrintDer(expr, k, mesg)} will generate code to display at runtime "[i] mesg = (value of derivative)", derivative being the derivative of expr with respect to the kth Unknown. \item to enable the output of this value, SetDebugEnabled(true) must be called before on the calculator. See \ref{CreateCalc} \end{itemize} + With this (commented) example formula, the generated code would look like this: + \begin{lstlisting} +<...> +double F31_ = (F30_ - 1); // f +double F28_ = (F27_ / F14_); // d(|v|)/d(p2.y) +double F18_ = (F17_ / F14_); // d(|v|)/d(p1.x) +double F33_ = (D * F18_); +double F39_ = (D * F28_); +double F34_ = (F33_ / F32_); // d(f)/d(p1.x) +double F40_ = (F39_ / F32_); // d(f)/d(p2.y) +if (IsDebugEnabled()) { + MMVII::StdOut()<< "[" << aK << "] Vx=" << F9_ << std::endl; + MMVII::StdOut()<< "[" << aK << "] Vy=" << F8_ << std::endl; + MMVII::StdOut()<< "[" << aK << "] Dist2DConst=" << F31_ << std::endl; + MMVII::StdOut()<< "[" << aK << "] d(dist2DConst)/d(p1.x)=" << F34_ << std::endl; + MMVII::StdOut()<< "[" << aK << "] d(Dist2DConst)/d(p2.y)=" << F40_ << std::endl; +} +<...> + \end{lstlisting} \end{itemize} As a slightly more complex example, the reader can investigate example {\tt cRatioDist2DConservation} diff --git a/MMVII/include/SymbDer/SymbolicDerivatives.h b/MMVII/include/SymbDer/SymbolicDerivatives.h index c5dbc27984..03b207eb11 100755 --- a/MMVII/include/SymbDer/SymbolicDerivatives.h +++ b/MMVII/include/SymbDer/SymbolicDerivatives.h @@ -389,7 +389,10 @@ template class cCoordinatorF : public cCalculator // { mVDebugF.emplace_back(aPF,aMesg); } - const std::vector& VDebug() const {return mVDebugF;} + inline void AddComment(const tFormula& aPF, const std::string& aComment) + { + mVCommentF.emplace_back(aPF,aComment); + } size_t NbCurFonc() const {return mVAllFormula.size();} @@ -420,6 +423,7 @@ template class cCoordinatorF : public cCalculator // std::vector mVCurF; ///< Current evaluted formulas std::vector mVReachedF; ///< Formula "reachable" i.e. necessary to comput mVCurF std::vector> mVDebugF; ///< Formula whose value must be displayed + std::vector> mVCommentF; ///< Formula which will be commented in generated code std::string mHeaderIncludeSymbDer; ///< Compilation environment may want to change it std::string mDirGenCode; ///< Want to put generated code in a fixed folde ? @@ -1166,9 +1170,16 @@ std::pair cCoordinatorF::GenCodeCommon(const aOs << " " << aTypeName << " &" << aForm->GenCodeFormName() << " = " << aForm->GenCodeExpr() << ";\n"; } for (const auto & aForm : mVReachedF) { - if (!aForm->isAtomic()) - aOs << " " << aTypeName << " " << aForm->GenCodeFormName() << " = " << aForm->GenCodeExpr() << ";\n"; + if (!aForm->isAtomic()) { + aOs << " " << aTypeName << " " << aForm->GenCodeFormName() << " = " << aForm->GenCodeExpr() << ";"; + auto aCommentIt = std::find_if(mVCommentF.begin(),mVCommentF.end(),[&aForm](auto& aF) {return aF.first->GenCodeFormName() == aForm->GenCodeFormName();}) ; + if (aCommentIt != mVCommentF.end()) { + aOs << " // " << aCommentIt->second; + } + aOs << "\n"; + } } + if (mVDebugF.size()) aOs << " if (IsDebugEnabled()) {\n"; for (const auto & aDebugF: mVDebugF) { @@ -1231,28 +1242,32 @@ inline std::string cCoordinatorF::TypeElemName() const // SymbPrintDer(aDist,1,"d(dist)/dy") -template -inline const T SymbPrint(const T & t, const std::string& aMesg) +template +inline const cFormula SymbPrint(const cFormula & aF, const std::string& aMesg) { - return t; + aF->CoordF()->AddDebug(aF, aMesg); + return aF; } -template -inline void SymbPrintDer(const T & t, int aK, const std::string& aMesg) +template +inline void SymbPrintDer(const cFormula & aF, int aK, const std::string& aMesg) { + aF->CoordF()->AddDebug(aF->Derivate(aK), aMesg); } + template -inline const cFormula SymbPrint(const cFormula & aF, const std::string& aMesg) +inline const cFormula SymbComment(const cFormula & aF, const std::string& aComment) { - aF->CoordF()->AddDebug(aF, aMesg); + aF->CoordF()->AddComment(aF, aComment); return aF; } template -inline void SymbPrintDer(const cFormula & aF, int aK, const std::string& aMesg) +inline const cFormula SymbCommentDer(const cFormula & aF, int aK, const std::string& aComment) { - aF->CoordF()->AddDebug(aF->Derivate(aK), aMesg); + aF->CoordF()->AddComment(aF->Derivate(aK), aComment); + return aF; } diff --git a/MMVII/src/SymbDerGen/Formulas_Geom2D.h b/MMVII/src/SymbDerGen/Formulas_Geom2D.h index fe41d1a321..319ac98b28 100755 --- a/MMVII/src/SymbDerGen/Formulas_Geom2D.h +++ b/MMVII/src/SymbDerGen/Formulas_Geom2D.h @@ -68,6 +68,7 @@ class cDist2DConservation std::string FormulaName() const { return "Dist2DCons";} +/* template static std::vector formula ( @@ -78,19 +79,58 @@ class cDist2DConservation cPtxd p1 = VtoP2(aVUk,0); cPtxd p2 = VtoP2(aVUk,2); cPtxd v = p2-p1; - const auto & ObsDist = aVObs[0]; - const auto aCst1 = CreateCste(1.0,p1.x()); // create a symbolic formula for constant 1 - // SymbPrint(v,"v"); - // SymbPrint(Norm2(v)/ObsDist - aCst1,"Dist2DConst"); - // SymbPrintDer(Norm2(v)/ObsDist - aCst1,0,"d(Dist2DConst)/d(p1.x)"); - // SymbPrintDer(Norm2(v)/ObsDist - aCst1,3,"d(Dist2DConst)/d(p2.y)"); + const auto & ObsDist = aVObs[0]; + const auto aCst1 = CreateCste(1.0,p1.x()); // create a symbolic formula for constant 1 return { Norm2(v)/ObsDist - aCst1 } ; // return { sqrt(square(v.x())+square(v.y()))/ObsDist - aCst1 } ; } +*/ + + // Alternate version of the same formula, showing use case of SymbPrint and SymbComment + + template + static std::vector formula + ( + const std::vector & aVUk, + const std::vector & aVObs + ) // const + { + cPtxd p1 = VtoP2(aVUk,0); + cPtxd p2 = VtoP2(aVUk,2); + cPtxd v = p2-p1; + SymbComment(v.x(),"Vx"); + SymbComment(v.y(),"Vy"); + SymbComment(Norm2(v),"|v|"); + SymbCommentDer(Norm2(v),0,"d(|v|)/d(p1.x)"); + SymbCommentDer(Norm2(v),1,"d(|v|)/d(p1.y)"); + SymbCommentDer(Norm2(v),2,"d(|v|)/d(p2.x)"); + SymbCommentDer(Norm2(v),3,"d(|v|)/d(p2.y)"); + + const auto & ObsDist = aVObs[0]; + const auto aCst1 = CreateCste(1.0,p1.x()); // create a symbolic formula for constant 1 + + auto result = Norm2(v)/ObsDist - aCst1; + + SymbComment(result,"f"); + SymbCommentDer(result,0,"d(f)/d(p1.x)"); + SymbCommentDer(result,1,"d(f)/d(p1.y)"); + SymbCommentDer(result,2,"d(f)/d(p2.x)"); + SymbCommentDer(result,3,"d(f)/d(p2.y)"); + + SymbPrint(v.x(),"Vx"); + SymbPrint(v.y(),"Vy"); + SymbPrint(result,"Dist2DConst"); + SymbPrintDer(result,0,"d(dist2DConst)/d(p1.x)"); + SymbPrintDer(result,3,"d(Dist2DConst)/d(p2.y)"); + + return { result } ; + // return { sqrt(square(v.x())+square(v.y()))/ObsDist - aCst1 } ; + } }; + /** Class for generating code relative to 2D-"RATIO of distance" */ class cRatioDist2DConservation