Comments (7)
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.
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.
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.
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.
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.
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.
Closing due to lack of activity.
from cppadcodegen.
Related Issues (20)
- CppADCodeGen support for Eigen `.transpose()` operation HOT 6
- Found CppAD version '' but at least version '20200000.1' is required HOT 5
- Loops reusing intermediate results HOT 1
- Using LLVM to improve CppAD HOT 4
- Question about wrong type argument error
- Examples on using CppADCodeGen with Eigen HOT 5
- Use CppADCodeGen with variable number of independent variable arrays HOT 2
- GreaterThanZero cannot be called for non-parameters for eigen determinant HOT 2
- Code generation with if/else statements HOT 18
- Large computational graphs fail at link time HOT 4
- cppad_ipopt dependency HOT 3
- Calling CppAD::ipopt::solve from CppADCodeGen HOT 8
- How to get the value of a CppADCodeGen scalar type HOT 1
- Generating Jacobians as Tensors HOT 12
- icpc build fails for dynamic_linux.cpp example HOT 1
- make build_tests fails HOT 1
- Supporting runtime compilation and dynamic linking in MacOSX M1,2 chips HOT 2
- model->Domain() returns size for previous model
- Running the test program Jacobian module listwith cppAD library gives a lot of errors HOT 6
- error when complie function library
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cppadcodegen.