Giter VIP home page Giter VIP logo

Comments (7)

joaoleal avatar joaoleal commented on June 4, 2024

Hello Johannes,

You have three options:

  • Compile the model in your atomic function the same way you did for dynamicLib but before you tape and compile the outer model (your original dynamicLib).
    Once the inner model is compiled, you can it as an atomic function for taping the outer model:
CGAtomicFun<double> innerModelForTaping(innerCompiledModel->asAtomic(), x);
// (..)
// Use it during the creation of the tape for the outer model
innerModelForTaping(x, y);
// (...)
// After the outer model is compiled:
modelLibOuter->addAtomicFunction(innerCompiledModel->asAtomic());
  • Compile both models in the same library:
// First create an ADFun for your inner model:
ADFun<CG<double>> innerModelFun;
// (...)
// Then use it during the outer model taping
 CGAtomicFunBridge<double> atomicFun("innerModel", innerModelFun, true);
// (...)
 atomicFun(ax, ay);
// (...)
// compile both models in the same lib
ModelCSourceGen<double> cSourceInner(innerModelFun, "innerModel"));
ModelCSourceGen<double> cSourceOuter(outerModelFun, "outerModel");
ModelLibraryCSourceGen<double> compDynHelp(*cSourceInner, cSourceOuter);
// (...)
// then use the inner in the outer model:
auto innerCompiledModel = dynamicLib->model("innerModel");
auto outerCompiledModel = dynamicLib->model("outerModel");
outerCompiledModel->addAtomicFunction(innerCompiledModel->asAtomic());
  • Use a checkpoint for your inner model (it will never get compiled and the structure should never change):
checkpoint<double> atomicFun("innerModel", innerModelFunction, ax, ay); // https://coin-or.github.io/CppAD/doc/chkpoint_one.htm
CGAtomicFun<double> cgAtomicFun(atomicFun, x, true);
// use cgAtomicFun to tape the outer model
cgAtomicFun(ax, ay);
// (...)
// once the outer model is compiled:
outerCompiledModel->addAtomicFunction(atomicFun);

I hope this helps.

from cppadcodegen.

JohannesPankert avatar JohannesPankert commented on June 4, 2024

Hello,
thank you very much for your response.
I'm not sure, whether any of the proposed solutions solves my problem.
In my inner model, I actually want to calculate the derivatives numerically (my x vector is a coordinate, I query the y value and the jacobian and hessian from an external resource) . Since the state of the external resource is not static, I cannot compile it.

With option 3 I tried to pass an instance of my custom atomic function
class CustomAtomicFun : public CppAD::cg::CGAbstractAtomicFun<double>
as the innerFunctionModel but this would yield to the following error during the instantiation of the checkpoint:

/home/johannes/catkin_ws/src/ocs2_dev/ocs2_thirdparty/include/cppad/local/dependent.hpp:262:38: error: ‘CppAD::cg::CG<double> CppAD::AD<CppAD::cg::CG<double> >::value_ is private within this context
    y_taddr = tape->RecordParOp( y[i].value_ );

Another thing I've tried is to implement two different classes:

class CustomAtomicFunCG : public CppAD::cg::CGAbstractAtomicFun<double> { ... };

class CustomAtomicFun : public CppAD::atomic_base<double>{ ... };

that share the same implementations of forward(...) and reverse(...). This gives me the correct result when calling
model->ForwardZero(vx) but the computed Jacobian is always zero and when querying the Hessian I would get the following error:
No Hessian function defined in the dynamic library

from cppadcodegen.

joaoleal avatar joaoleal commented on June 4, 2024

Which version of CppAD are you using?

When you create compiled models you can choose which functions it should have.
For instance:

ModelCSourceGen<double> cSourceOuter(fun, "outerModel");
cSourceOuter.setCreateForwardZero(true);
cSourceOuter.setCreateForwardOne(true);
cSourceOuter.setCreateReverseOne(true);
cSourceOuter.setCreateReverseTwo(true);
cSourceOuter.setCreateJacobian(true);
cSourceOuter.setCreateHessian(true);
cSourceOuter.setCreateSparseJacobian(true);
cSourceOuter.setCreateSparseHessian(true);

You can also consider using:

class CustomAtomicFun : public CppAD::atomic_base<double>{ ... };
// and then 
CustomAtomicFun atomicFun;
CGAtomicFun<double> cgAtomicFun(atomicFun, x, true); // for taping the outer model

If you know which coordinate variables/parameters are going to be provided to the model before you call the outer model, then you can include them in the model.
I'm assuming they are parameters for which no derivatives need to be computed but the derivatives of other variables depend on these parameters.
If that is the case, include them in the outer model which will then forward them to the atomic function.
The atomic function receives the parameters in the independent variables and excludes them from the jacobian and hessian sparsity patterns.

It is also possible to compile the inner model considering these parameters.
You can define custom sparsity patterns for the jacobian and hessian (the original patterns without the parameters).
For instance:

// compute innerModelJacPattern and innerModelHessPattern
// remove entries for the parameters
cSourceInner.setCustomSparseJacobianElements(innerModelJacPattern);
cSourceInner.setCustomSparseHessianElements(innerModelHessPattern);

from cppadcodegen.

JohannesPankert avatar JohannesPankert commented on June 4, 2024

Hello,
I updated to the latest version of CppADCodegen and use CppAD version 20190200.5.
Unfortunately the number of parameters my atomic function varies so I cannot pass them into the cost as a parameter.

I tried to use CGAtomicFun to wrap my atomic function but that has not been successful. The atomic function is not in the list provided by the model_[...]_atomic_functions of the auto-generated code.

I modified your example to use an atomic function. For the CustomAtomicExample I used the atomic function defined in the atomic_rev_sparse_hes example of CppAD.
https://www.coin-or.org/CppAD/Doc/atomic_rev_sparse_hes.cpp.htm

  using namespace CppAD;
  using namespace CppAD::cg;
  // use a special object for source code generation
  typedef CG<double> CGD;
  typedef AD<CGD> ADCG;

  /****************************************************************************
   *                               the model
   **************************************************************************/

  // independent variable vector
  CppAD::vector<ADCG> au(3);
  Independent(au);

  // dependent variable vector
  CppAD::vector<ADCG> y(2);

  CustomAtomicExample customAtomicExample;
  CppAD::vector<double> xSparsityTest(3);
  xSparsityTest[0] = 2;
  xSparsityTest[1] = 2;
  xSparsityTest[2] = 2;
  CGAtomicFun<double> cgAtomicFun(customAtomicExample, xSparsityTest, true);

  // the model equation
  cgAtomicFun(au, y);
  ADFun<CGD> fun(au, y);

  /****************************************************************************
   *                       Create the dynamic library
   *                  (generates and compiles source code)
   **************************************************************************/
  // generates source code
  ModelCSourceGen<double> cgen(fun, "model_cppADCustomAtomicTest");
  cgen.setCreateJacobian(true);
  cgen.setCreateHessian(true);
  cgen.setCreateForwardZero(true);
  cgen.setCreateForwardOne(true);
  cgen.setCreateReverseOne(true);
  cgen.setCreateReverseTwo(true);
  ModelLibraryCSourceGen<double> libcgen(cgen);

  SaveFilesModelLibraryProcessor<double> p2(libcgen);
  p2.saveSourcesTo("/home/johannes/.ros/cppad");

  // compile source code
  DynamicModelLibraryProcessor<double> p(libcgen);

  GccCompiler<double> compiler;
  std::unique_ptr<DynamicLib<double>> dynamicLib = p.createDynamicLibrary(compiler);
  /***************************************************************************
   *                       Use the dynamic library
   **************************************************************************/

  std::unique_ptr<GenericModel<double>> model = dynamicLib->model("model_cppADCustomAtomicTest");
  model->addAtomicFunction(customAtomicExample);

  CppAD::vector<double> xv(3);
  xv[0] = 1;
  xv[1] = 2;
  xv[2] = 3;

  // print out the result
  std::cout << "CPPAD results: " << std::endl;

  std::cout << "isForwardZeroAvailable: " << model->isForwardZeroAvailable() << std::endl;
  CppAD::vector<double> distance = model->ForwardZero(xv);
  std::cout << "ForwardZero: " << distance << std::endl;

  std::cout << "isJacobianAvailable: " << model->isJacobianAvailable() << std::endl;
  CppAD::vector<double> jac = model->Jacobian(xv);
  Eigen::Map<Eigen::Matrix<double, 2, 3, Eigen::RowMajor>> jacobian(jac.data());
  std::cout << "Jacobian: " << std::endl << jacobian << std::endl;

  std::cout << "isHessianAvailable: " << model->isHessianAvailable() << std::endl;
  CppAD::vector<double> hess = model->Hessian(xv, 0);
  Eigen::Map<Eigen::Matrix<double, 3, 3, Eigen::RowMajor>> hessian1(hess.data());
  std::cout << "Hessian 1: " << std::endl << hessian1 << std::endl;
  hess = model->Hessian(xv, 1);
  Eigen::Map<Eigen::Matrix<double, 3, 3, Eigen::RowMajor>> hessian2(hess.data());
  std::cout << "Hessian 2: " << std::endl << hessian2 << std::endl;

The code gives me this output:

isForwardZeroAvailable: 1
ForwardZero: { 0, 0 }
isJacobianAvailable: 1
Jacobian: 
0 0 0
0 0 0
isHessianAvailable: 1
Hessian 1: 
0 0 0
0 0 0
0 0 0
Hessian 2: 
0 0 0
0 0 0
0 0 0

Do you have an idea of what I am doing wrong?

from cppadcodegen.

joaoleal avatar joaoleal commented on June 4, 2024

Make sure to implement the sparsity methods in your CustomAtomicExample:

    bool for_sparse_jac(size_t q,
                        const CppAD::vector<std::set<size_t> >& r,
                        CppAD::vector<std::set<size_t> >& s) override;

    bool for_sparse_jac(size_t q,
                        const CppAD::vector<std::set<size_t> >& r,
                        CppAD::vector<std::set<size_t> >& s,
                        const CppAD::vector<double>& x) override;

    bool rev_sparse_jac(size_t q,
                        const CppAD::vector<std::set<size_t> >& rt,
                        CppAD::vector<std::set<size_t> >& st,
                        const CppAD::vector<double>& x) override;

    bool rev_sparse_hes(const CppAD::vector<bool>& vx,
                        const CppAD::vector<bool>& s,
                        CppAD::vector<bool>& t,
                        size_t q,
                        const CppAD::vector<std::set<size_t> >& r,
                        const CppAD::vector<std::set<size_t> >& u,
                        CppAD::vector<std::set<size_t> >& v) override;

from cppadcodegen.

joaoleal avatar joaoleal commented on June 4, 2024

By the way, there was a missing return value check for rev_sparse_jac() in the code.
The code now throws an exception if rev_sparse_jac() returns false which happens when it is not implemented.

from cppadcodegen.

joaoleal avatar joaoleal commented on June 4, 2024

Closing due to lack of activity.

from cppadcodegen.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.