Giter VIP home page Giter VIP logo

joaoleal / cppadcodegen Goto Github PK

View Code? Open in Web Editor NEW
155.0 10.0 35.0 15.08 MB

Source Code Generation for Automatic Differentiation using Operator Overloading

License: Other

CMake 2.90% Shell 0.20% C++ 94.99% TeX 0.08% JavaScript 0.12% C 1.54% Python 0.12% HTML 0.01% CSS 0.01% Dockerfile 0.03%
differentiation c-plus-plus algorithmic-differentation mathml dae latex automatic-differentiation jit

cppadcodegen's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cppadcodegen's Issues

cppad_ipopt dependency

cmake/FindCppAD.cmake searches for cppad_ipopt library (libcppad_ipopt.so/.a), but I don't see any other references to ipopt in the code. Does CppADCodeGen use ipopt? If not, can we instead search for the default library cppad_lib (libcppad_lib.so/.a)?

For example, Pinocchio dynamics library uses this Findcppad.cmake:

# Copyright 2020 CNRS INRIA
# Author: Guilhem Saurel, Rohan Budhiraja
# Try to find cppad in standard prefixes and in ${cppad_PREFIX} Once done this
# will define cppad_FOUND - System has cppad cppad_INCLUDE_DIR - The cppad
# include directories cppad_LIBRARY - The libraries needed to use cppad
# cppad_DEFINITIONS - Compiler switches required for using cppad cppad_VERSION -
# Version of cppad found

find_path(
  cppad_INCLUDE_DIR
  NAMES cppad/configure.hpp
  PATHS ${cppad_PREFIX}
  PATH_SUFFIXES include)
find_library(
  cppad_LIBRARY
  NAMES cppad_lib
  PATHS ${cppad_PREFIX}
  PATH_SUFFIXES lib)

if(cppad_INCLUDE_DIR AND EXISTS "${cppad_INCLUDE_DIR}/cppad/configure.hpp")
  file(STRINGS "${cppad_INCLUDE_DIR}/cppad/configure.hpp" cppad_version_str
       REGEX "^# *define[\t ]+CPPAD_PACKAGE_STRING[\t ]+\"cppad-.*\"")
  string(
    REGEX
    REPLACE "^# *define[\t ]+CPPAD_PACKAGE_STRING[\t ]+\"cppad-([^\"]*)\".*"
            "\\1" cppad_VERSION "${cppad_version_str}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
  cppad
  REQUIRED_VARS cppad_LIBRARY cppad_INCLUDE_DIR
  VERSION_VAR cppad_VERSION)
mark_as_advanced(cppad_INCLUDE_DIR cppad_LIBRARY)

Large computational graphs fail at link time

Hello,

I wanted to share a problem I ran into using this very well written and very useful library. I work using high dimensional models and my computational graphs tend to be large.

If the computational graph reaches a certain threshold, and the number of arrays and symbols exceed 2GB, we run into a relocation truncated to fit error. You can read more about this kind of error here
https://stackoverflow.com/questions/6093547/what-do-r-x86-64-32s-and-r-x86-64-64-relocation-mean/33289761#33289761

This problem can in principle be addressed by linking with -mcmodel=large or mcmodel=medium flags. However in this case the library generated by CppADCodeGen requires linking to libc.a, which is built in 32 bit mode. Therefore the problem persists.

I believe that if the generated code was C++ with linkage to libgcc.a instead, the problem would be addressed. This in principle should require very little change since from my observations of the generated code all the mathematical operations are supported in C++ and the only difference should be changing the header to include <cmath> and of course renaming the files to use a cpp extension.

I would be happy to make the code changes, but I wanted to understand if that is in principle possible and whether the subsequent loading of the library after compilation would fail if the code was compiled with C++ mangling in the method signatures.

Using CppADCodeGen and CppAD together, both as header only?

I'm trying to use CppADCodegen, CppAD, and eigen3 in a project, all as header-only libraries. Is there a way to do this in a project using CMake? I try to include all three directories in my project, as such:

target_include_directories(AutodiffEngine PRIVATE ${PROJECT_SOURCE_DIR}/../ExternalLibs/eigen3/Eigen)
target_include_directories(AutodiffEngine PRIVATE ${PROJECT_SOURCE_DIR}/../ExternalLibs/eigen3/unsupported)
target_include_directories(AutodiffEngine PRIVATE ${PROJECT_SOURCE_DIR}/../ExternalLibs/CppAD)
target_include_directories(AutodiffEngine PRIVATE ${PROJECT_SOURCE_DIR}/../ExternalLibs/CppADCodeGen/include)

This works fine for Eigen3 and CppAD, but not for codegen. Is there a way to use CppADCodegen in a similar way?

multiple definition of readStringFromFile

Using version 2.4.1 I get the following message

... snip ...
multiple definition of `CppAD::cg::readStringFromFile(
    std::__cxx11::basic_string<char, std::char_traits<char>, 
    std::allocator<char> > const&)'; 
... snip ...

The following patch seems to fix the problem:

sed -i include/cppad/cg/util.hpp \
    -e 's|^std::string readStringFromFile(|inline &|'

Using Eigen::Vector instead of std::vector in example fails

First: Great Work! This provides sparse derivatives without memory allocations as far as I
understand. Before, I was using Eigen::AutoDiffScalar<Eigen::SparseVector>.

Here a slightly adapted code from the trivial example. The code uses Eigen::Vector inplace of std::vector, but somehow this does not compile with gcc-5 oder clang-3.7.
``
#include
#include
#include <cppad/cg.hpp>
#include <cppad/example/cppad_eigen.hpp>

int main() {
// use a special object for source code generation
typedef CppAD::cg::CG CGD; // this is the code generation type
typedef CppAD::AD ADCG;

// independent variable vector
Eigen::Matrix<ADCG,Eigen::Dynamic,1> x(1);
CppAD::Independent(x);

// dependent variable vector 
Eigen::Matrix<ADCG,Eigen::Dynamic,1> y(1);

y = 1. * x;
// This works: 
//y = CGD(1.) * x;

CppAD::ADFun<CGD> fun(x, y);

}
``
Most important is also, that this code works when using
typedef CppAD::AD ADCG;

I tried to dig into this and from my guesswork somewhere in the clang error messages it says:
/home_local/wern_al/optimalwalk_env_gcc5/install/include/eigen3/Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:50:29: note:
candidate template ignored: substitution failure [with T = double]: no type named 'type'
in 'Eigen::internal::promote_scalar_arg<CppAD::AD<CppAD::cg::CG >, double,
false>'
EIGEN_MAKE_SCALAR_BINARY_OP(operator*,product)


Here Eigen tries to promote the type (double->ADCG), but this fails. I do not understand this
because the NumTraits are available for the CppAD<T> template.

Stack overflow during code generation

Hello,

calling "createDynamicLibrary(...)" causes fatal stack overflow
when the code (e.g. for a "zero-order forward") is to be generated for
more complex models.

These contain a one-deimensional "dependent" vector and a high dimensional "independent" one.
The dependencies in the respective function are implemented, i.a., via nested loops (of nesting order > 2) .
Dependent on the complexity of the function body everything works fine below a particular low threshold dimension of the "independent" vector.
Above such a threshold dimension, however, the stack overflow occurs.
This problem is obviously originated in the recursion methods in code_handler_impl.hpp and /lang/c/language_c.hpp. Among the very bad behaving methods seems to be "markCodeBlockUsed(...)" in code_handler_impl.hpp .

Error case for sparse Jacobian creation

Hello,
there occurs a "cppad" error during the code creation of a "sparse" Jacobian.
Please see a code example below (tested in Ubuntu (Wsl, g++) and Windows (VS 2015)):

#include <string.h>
#include <cppad/cg.hpp>
#include <cppad/cg/support/cppadcg_eigen.hpp>  

using namespace CppAD;
using namespace CppAD::cg;

typedef CppAD::cg::CG<double> CGD; 
typedef CppAD::AD<CGD> ADCG;
typedef Eigen::Matrix<ADCG, Eigen::Dynamic, 1> ADCGvec;

void ThisAdFunc(ADCGvec& adscalar, const ADCGvec& advec, int dim1, int dim2, int dim3) {
        adscalar(0) = 0;
        double testCoeff = 0;
	for (int ii = 0; ii < dim2; ++ii) {
		for (int jj = 0; jj < dim1; ++jj) {			
			adscalar[0] = adscalar[0] + advec((ii*dim1 + jj) * dim3 + 0)*advec((ii*dim1 + jj) * dim3 + 0)
				+ testCoeff*advec((ii*dim1 + jj) * dim3 + 1)*advec((ii*dim1 + jj) * dim3 + 1)
				+ advec((ii*dim1 + jj) * dim3 + 2)*advec((ii*dim1 + jj) * dim3 + 2);
		}
	}
}

int main(void) {
        int dim1 = 40;
	int dim2 = 10;
        int dim3 = 3;

        ADCGvec thisAdvec(dim1*dim2*dim3);
	ADCGvec thisAdscalar(1);
	CppAD::Independent(thisAdvec);
	ThisAdFunc(thisAdscalar, thisAdvec, dim1, dim2, dim3);

        CppAD::ADFun<CGD> adfun(thisAdvec, thisAdscalar);
        CppAD::cg::ModelCSourceGen<double> cgen(adfun, "adModel");
	
        //  test sparsity:
        cgen.setCreateSparseJacobian(true);
	std::vector<size_t> mappingCols, mappingRows;
	for (int jj = 0; jj < thisAdvec.size(); ++jj) {			
		mappingCols.push_back( jj);
		mappingRows.push_back(0);			
	}
	cgen.setCustomSparseJacobianElements(mappingRows, mappingCols);

        CppAD::cg::ModelLibraryCSourceGen<double> libcgen(cgen);
        CppAD::cg::DynamicModelLibraryProcessor<double> dynLibProc(libcgen, "<path of dynamic lib.>");
        CppAD::cg::GccCompiler<double> compiler("<compiler path>");
        string storageDir = "<code storage directory>";
	compiler.setSaveToDiskFirst(true);
	compiler.setTemporaryFolder(storageDir );
	compiler.setSourcesFolder(storageDir );
	dynLibProc.createDynamicLibrary(compiler); 		

        return 0;
}

Note, that the error appears if one sets "testCoeff = 0" in the code above.
Moreover, it's obviously unrelated to the values of the dimensions dim1, dim2, dim3.

How does sparsity detection work?

I have a few quick questions about the sparsity detection that I couldn't figure out from the docs:

  1. It seems from the code that the system evaluates the function once on dummy variables, see which elements of the result are non-empty, and from that, determines the sparsity. Is this correct? If so, how are conditionals in an expression handled? Are they safe here?

  2. How does, say, SparseJacobian() work? Is using :
    ```
    cgen.setCreateSparseJacobian(true);
    cgen.setCustomSparseJacobianElements(rows, cols);


The same as using:

`fun.SparseJacobian(x0)`
with
`cgen.setCreateForwardZero(true);`

3. I haven't tried this yet, nor do I know if it's supported, but how would this play with Eigen's SparseMatrix (on input elements)?

Build Error with getCustomLibraryExtension()

/usr/include/cppad/cg/model/dynamic_lib/dynamic_library_processor.hpp: In member function ‘const string* CppAD::cg::DynamicModelLibraryProcessor<Base>::getCustomLibraryExtension() const’:
/usr/include/cppad/cg/model/dynamic_lib/dynamic_library_processor.hpp:84:16: error: cannot convert ‘const std::unique_ptr<const std::__cxx11::basic_string<char> >’ to ‘const string*’ {aka ‘const std::__cxx11::basic_string<char>*’} in return
   84 |         return _customLibExtension;
      |                ^~~~~~~~~~~~~~~~~~~
      |                |
      |                const std::unique_ptr<const std::__cxx11::basic_string<char> >

OS: ArchLinux
GCC: 9.3.0
CppAD: 20200000.2

CppADCodeGen support for Eigen `.transpose()` operation

Hi João,

I'm trying to understand the performance benefits of using CppADCodeGen for doing sparse eigen multiplications.
There is an issue that I'm facing, which I hope you might be able to help with.

In order to do a multiplication of two matrices in Eigen, A*B, and A.transpose() * B are almost equivalent in terms of performance. There is no additional computation burder imposed in Eigen because of the .transpose() operation.

However, when I try to code-generate these two computations, I see a difference in the computation time taken by codegen(A*B) and codegen(A.transpose() * B).

I've added a small unit-test that checks this computation. https://gist.github.com/proyan/76edb14c2835c53e66e086239a7e828f

In this file, there is a code-generated function calc that computes A*transpose() * B, where A is a triangular matrix, and B is a diagonal matrix.

When running this calc function in normal, and code-generated (and compiled) modes, I get the following timings:

$ ./test-cg 
calc code-gen = 		16.1503 us
calc = 		25.685 us

So there is some performance benefit in code-generation.

However, if I remove the .transpose() operation from the above calc operation i.e., replace Line 119 of the script with

  tmp.OSIMinv_tmp.noalias() = -tmp.U1inv * M.diagonal().asDiagonal();                                                                                                             

I get the following timings after compiling the new calc, which computes A*B:

$ ./test-cg 
calc code-gen = 		10.1578 us
calc = 		25.0839 us

As you can see, there is a difference of 5us (quite high when compared to the total time taken), while the operation in Eigen is following the same computation performance.

I've checked other parts of this function, and solveInPlace work as it should, and the other matrix multiplication works as it should. Eigen simply changes the order of operations when doing the .transpose() multiplication, so I'm guessing that there is a flag that is not being taken care of here. But this is only my guess, I wonder if you understand what the issue is here?

Thanks, and best,
Rohan

Loops reusing intermediate results

Hi João,

I would like to generate code for loops where the intermediate results from prior iterations are reused. For example, I define a dynamics function that computes the change in state given the current state, and then define the integrator that for N time steps has to call this function, and integrate the state derivatives that are added up to the current state.

Following your response in issue #10, I adapted one of your pattern examples that generates for-loops. But, as you also mentioned, the pattern detection assumes each entry in the output vector is independent from previous calculations. This seems to be the case even when I manually define the dependent variables that related (see below). Unfortunately, this wouldn't work for my integration example where I have to accumulate results from earlier iterations. The generated code reflects this, when I include a previously computed y element, this index cannot be part of the generated loop anymore, the calculation gets unrolled for the N iterations:

Extract from the C++ example code:

  // independent variable vector
  std::vector<ADCG> x(5, ADCG(1));
  Independent(x);

  // dependent variable vector
  std::vector<ADCG> y(8);

  // temporary variables
  ADCG a, b;

  // the model
  a = exp(3 * x[1]);

  b = 5 * x[0] * x[4];
  y[0] = a / 2 + b;
  // one equation not defined!
  y[1] = x[2] - b;

  b = 5 * x[1] * x[3];
  y[2] = a / 2 + b + y[0];  // !!! we reuse the result from the previous iteration
  y[3] = x[4] * x[1] + b;
  y[4] = x[3] - b;

  b = 5 * x[2] * x[2];
  y[5] = a / 2 + b + y[2];  // !!! we reuse the result from the previous iteration
  y[6] = x[4] * x[2] + b;
  y[7] = x[4] - b;

  ADFun<CGD> fun(x, y);

  // ...
  // set up the related dependencies as before:
  std::vector<std::set<size_t>> relatedDep{{0, 2, 5}, {3, 6}, {1, 4, 7}};
  // ...

Generated C code (forward zero pass):

   // independent variables
   const double* x = in[0];

   //dependent variables
   double* y = out[0];

   // auxiliary variables
   double v[2];
   unsigned long j;

   v[0] = exp(3. * x[1]);
   y[0] = v[0] / 2. + 5. * x[0] * x[4];
   for(j = 0; j < 3; j++) {
      v[1] = 5. * x[j] * x[j * -1 + 4];
      if(1 <= j) {
         y[j * 3] = x[4] * x[j] + v[1];
      }
      y[j * 3 + 1] = x[j + 2] - v[1];
   }
   y[2] = v[0] / 2. + 5. * x[1] * x[3] + y[0];
   y[5] = v[0] / 2. + 5. * x[2] * x[2] + y[2];  // !!! {0, 2, 5} are not part of the loop anymore

I also tried to wrap my dynamics function into an inner atomic function and then call it from the outer function (option 2 from your suggestions in #33):

  Simulation<...> simulation;
  std::vector<ADCG> ax(simulation.input_dim(), ADCG(0));
  CppAD::Independent(ax);
  std::vector<ADCG> ay(simulation.output_dim());
  // First create an ADFun for your inner model:
  ADFun<CGD> innerModelFun;
  ay = simulation(ax);
  innerModelFun.Dependent(ax, ay);

  // Then use it during the outer model taping
  CGAtomicFunBridge<double> atomicFun("innerModel", innerModelFun, true);
  std::vector<ADCG> x_outer(simulation.input_dim(), ADCG(0));
  CppAD::Independent(x_outer);
  std::vector<ADCG> y_outer(simulation.output_dim());
  std::vector<ADCG> state = x_outer, derivative(simulation.output_dim());
  for (int t = 0; t < 10; ++t) {  // Euler integration
    atomicFun(state, derivative);
    for (std::size_t i = 0; i < simulation.output_dim(); ++i) {
      state[i] += 1e-3 * derivative[i];
    }
  }
  y_outer = state;
  ADFun<CGD> outerModelFun;
  outerModelFun.Dependent(x_outer, y_outer);
  // compile both models in the same lib
  ModelCSourceGen<double> cSourceInner(innerModelFun, "innerModel");
  ModelCSourceGen<double> cSourceOuter(outerModelFun, "outerModel");
  // try to set dependent variables that are related (unsuccessful)
  std::vector<std::set<size_t>> relatedDepCandidates;
  for (std::size_t i = 0; i < simulation.output_dim(); ++i) {
    relatedDepCandidates.push_back({i});
  }
  cSourceOuter.setRelatedDependents(relatedDepCandidates);
  // ...

In the generated code for the outer model, however, the loop is unrolled.

Is there any way to generate code for-loops that reuse intermediate results?

Many `_FORTIFY_SOURCE` requires compiling with optimization (-O)` warnings

When I try to build the tests (make build_tests) I get a flood of warnings like shown below:

In file included from /usr/include/c++/9.2.0/x86_64-pc-linux-gnu/bits/os_defines.h:39,
                 from /usr/include/c++/9.2.0/x86_64-pc-linux-gnu/bits/c++config.h:524,
                 from /usr/include/c++/9.2.0/bits/stl_algobase.h:59,
                 from /usr/include/c++/9.2.0/vector:60,
                 from /home/acxz/vcs/git/github/joaoleal/CppADCodeGen/test/CppADCGTest.hpp:19,
                 from /home/acxz/vcs/git/github/joaoleal/CppADCodeGen/test/cppad/cg/patterns/CppADCGPatternTest.hpp:18,
                 from /home/acxz/vcs/git/github/joaoleal/CppADCodeGen/test/cppad/cg/patterns/simple_atomic_2.cpp:15:
/usr/include/features.h:382:4: warning: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Wcpp]
  382 | #  warning _FORTIFY_SOURCE requires compiling with optimization (-O)
      |    ^~~~~~~

Add. Info.
GCC: 9.2.0
OS: ArchLinux
Master branch

Best practice for deleting dynamic libraries at program exit

In my applications, I use CppADCodeGen in the JIT-mode, therefore I compile dynamic libraries at runtime.
After every program execution, a *.so file is left somewhere in my directories. So far, I have used a script to simply clean up after CppADCG - but anyway I've been wondering for a while now: is there an officially supported way to delete the *.so files after they are not needed any more, e.g. at destruction time?
Thanks a lot in advance, and keep up the great work!

New release of CppADCodeGen

Hi Joel,
Thanks for this nice piece of software.
I wonder if you have any plans to release a new version that is compatible with cppad 2020? I see that the last release was made for v2018, and it was more that a year ago.
It would be helpful for us to maintain build compatibility for our software as well.

Best,
Rohan

Compilation speed for large derivatives

Hi João,

first of all, thank you for making such a great project open source! I am actively using CppADCodeGen in my research projects and it performs great!

I am mostly working with Rigid Body Dynamics, which are (fairly) large differential equations. This results in generated code for the derivatives that is easily 45k of lines. As suggested, I am using CLANG for compiling them and it makes it bearable. However, I have seen some code in CppADCodeGen that looks like you can break down the derivative code in smaller chunks, i.e. several functions?

So I was wondering whether you are dealing with equally large or larger derivatives? If so, do you have any experience in further reducing compilation time?
If you have any leads, I would highly appreciate it! In return, I could contribute a little example to CppADCodeGen.

Thanks again,
Michael

Need to gaurd against including cppad.hpp before cppadcg.hpp

Using gcc 9.2.1 the program below generates a compile error. It can be fixed by switching the order of the include commands:

# include <cppad/cppad.hpp>
# include <cppad/cg/cppadcg.hpp>
int main(void)
{
    typedef CppAD::cg::CG<double>        cg_double;
    typedef CppAD::AD<cg_double>         cppadcg_double;
    cppadcg_double r;
    r = 0.0;
    if( CppAD::IdenticalZero(r) )
        return 0;
    return 1;
}

Compiler error with newest release on Ubuntu 16.04

I am trying to compile code which employs CppAD-CG on Ubuntu 16.04 with clang++ (3.6).
I run into the following compiler error, coming directly from one of the pattern headers...:

In file included from /usr/local/include/cppad/cg.hpp:18:
In file included from /usr/local/include/cppad/cg/cppadcg.hpp:183:
/usr/local/include/cppad/cg/patterns/iter_equation_group.hpp:253:68: fatal error: default initialization of an object of const type 'const std::map<size_t, std::set<size_t> >' (aka 'const map<unsigned long, set<unsigned long> >') without a user-provided default constructor
const std::map<size_t, std::set<size_t> > IterEquationGroup<Base>::EMPTYMAPSETS;         

If I understand it right, the problem might be the following: the default constructor for std::set() has only been made availble from C++14 onwards, for C++11 only compilers it does not exist, see also here and here.

[Feature Request] Add support for LLVM 10

Now that LLVM 10.0 has been released, it would be nice if CppAD CG supports it. As of now LlvmModelLibrary and LlvmModelLibraryProcessor are not created for LLVM 10.

addAtomicFunction

Hello @joaoleal ,
I created my own atomic function by deriving from CppAD::cg::CGAbstractAtomicFun.
When invoking the Jacobian method on the dynamicLib model (I'm following the linux example), I get a missingAtomicFunction error.

cppad-20160000.1 error from a known source: Some atomic functions used by the compiled model have not been specified yet Error detected by false result for _missingAtomicFunctions == 0

I saw that the GenericModel class has an addAtomicFunction method. This method however takes an object of the type atomic_base<Base>. My custom atomic class only has atomic_base<CppAD::cg::CG<Base> > as a parent.

Could you please hint me into the right direction on how to use user defined atomic functions in code generation models?

Thank you very much
Johannes

Use CppADCodeGen with variable number of independent variable arrays

I managed to define and generate code for functions of the form ADFun adFun(x, y);, but this is not desirable if x must always be assembled from an array of independent variable vectors. Luckily, in the file generic_model.hpp I found the following declaration:

/**
     * Determines the dependent variable values using a variable number of 
     * independent variable arrays.
     * This method can be useful if the generic model was prepared
     * considering that the independent variables are provided by several
     * arrays.
     * 
     * @param x Contains the several independent variable vectors
     * @param dep The values of the dependent variables
     */
    virtual void ForwardZero(const std::vector<const Base*> &x,
                             ArrayView<Base> dep) = 0;

I would really like to use this functionality! However, I cannot manage to create an ADFun object that satisfies the above interface (it seems that an adequate constructor is missing). Also, I could not find any examples about this matter. How can I enable my models to be used as in the above snippet?

Handling Dynamic parameters in CppADCodeGen

Current master branch of CppAD allows the use of dynamic parameters.
In other words, it is possible to change at running time some parameters values that are not consider as Independent variables.
See https://github.com/coin-or/CppAD/blob/46be2e2dbcaba47d8a38e8d9110efc48c7245754/cppad/core/new_dynamic.hpp#L103 for further details.

I want to know how to implement this feature in CppADCOdeGen.
@joaoleal can you explain me where I need to edit this new feature?

Found CppAD version '' but at least version '20200000.1' is required

Attempting to install CppAD and CppADCodeGen using CMake 3.18.4 on macOS 10.15.6 and running into some issues.

First, I clone the master branch of CppAD, and run:

cd CppAD
mkdir build
cd build
cmake ..
make
sudo make install

Everything runs fine, no issues.

Next, I clone the master branch of CppADCodeGen, and run:

cp CppADCodeGen
mkdir build
cd build
cmake ..

and get the error:

CMake Error at cmake/FindCppAD.cmake:99 (MESSAGE):
  Found CppAD version '' but at least version '20200000.1' is required
Call Stack (most recent call first):
  CMakeLists.txt:42 (FIND_PACKAGE)

Following the instructions here I run grep '^SET(cppad_version' CMakeLists.txt and get:

SET(cppad_version "20200905")

Evidently the version is high enough but it isn't getting pulled in by FindCppAD.cmake.

Let me know if I made some mistake in the above. I would expect this approach to "just work"... Thanks.

How to get the value of a CppADCodeGen scalar type

Hi,

First of all, thanks for developing this great tool! I'm new to CppADCodeGen, I'd like to ask is there any way to get the value of a scalar type CppAD::AD<CppAD::cg::CG<double>> (or convert this type to the double type). I know in CppAD this is possible by using CppAD::Value() of Var2Par() function, but I don't know how to do that in CppADCodeGen. Would you please give me any advice? Thanks a lot!

Windows: basic compatibilty issues

In case there is some interest regarding the usability of CppADCodeGen within Windows (e.g. VS 2015) I'd like to share a few basic compatibilty issues.
In fact, these are rather minor but have quite an impact since they appear in several places throughout all the source code.
Therefore, in the following I list representative examples and suggestions for their principle replacements which should work for both, Windows and Linux (g++):

  1. suggested change of, e.g., std::max(size_t(123), 124) to std::max<size_t>(size_t(123), 124)
    and std::min(size_t(123), 124) to std::min<size_t>(size_t(123), 124), i.e. std::max/std::min should carry a template argument specifying the data type which is relevant for the two passed numbers.

  2. suggested change of, e.g., std::numeric_limits<int>::max() to (std::numeric_limits<int>::max)()
    and std::numeric_limits<int>::min() to (std::numeric_limits<int>::min)()

  3. there exist some problems with the operator <<, it's overloading and the type size_t/__int64 in Windows. This, at least, applies only to recent changes (commit from Jun 13, 2019) and, so far, can be easily fixed in /lang/lang_stream_stack.hpp by adding:

friend inline LangStreamStack<Base>& operator<<(LangStreamStack<Base>& lss, size_t i) {
	return (lss << std::to_string(i));
}

Code generation with if/else statements

I have modified the simple example in the documentation by changing the line

y[0] = a / 2;

to

if (a > 1.0) {
    y[0] = a / 2;
  } else {
    y[0] = a * 2;
  }

but this results in the following error:

terminate called after throwing an instance of 'CppAD::cg::CGException'
  what():  GreaterThanOrZero cannot be called for non-parameters

This means that to generate the code for if/else statements I should use CppAD parameters. However, to the best of my knowledge, this feature is currently missing in CppADCodeGen, where parameters can only be emulated by editing the sparsity patterns of the models. Is there a way to generate the derivatives for code containing if/else statements? If yes, how should I modify the above example to make it work?

Branching

Hi,
I am not an AD expert, I have nested conditions and I am wondering if booleans are supported ?
Is this possible "If{ //some code } then{//some code} else{//some code}" (with conditions inside braces) ?
Thank you.

GreaterThanZero cannot be called for non-parameters for eigen determinant

Hi,

I am trying to use eigen determinant together with CppADCG. However, it reports "GreaterThanZero cannot be called for non-parameters" error when the codes are generated for eigen determinant. The codes are compiled ok though. This error occurs at run-time when auto diff codes are generated. My code snippets are listed below:

`void RigidBodyDynamicsPinocchio::CreateManipulabilityAutoDiff(const ADDataStruct& arguments)
{
body_id_ = robot_ad_model_.getFrameId(arguments.body_name_);
auto func = [&, this](const ad_vector_t& x, ad_vector_t& y) {
ad_matrix_t J(6, robot_ad_model_.nq);
pinocchio::computeFrameJacobian(
robot_ad_model_, robot_ad_data_, x, body_id_, pinocchio::LOCAL_WORLD_ALIGNED, J);
y.resize(1);
y[0] = (J * J.eval().transpose()).determinant();
};
manipulability_deriv_ptr_.reset(
new CppAdInterface(func, robot_ad_model_.nq, arguments.model_name_, arguments.model_folder_));

CreateAutoDiffFunc(arguments, manipulability_deriv_ptr_);
}`

If the determinant() is commented out, the codes are generated successfully. Any suggestions for how to fix this? Thanks!

Best regards,
Chris.

getting started with CppADCodeGen

I am having trouble getting started using the current version of CppADCodeGen. To be specific, I would like a prescription for how to run a simple example ?

I began with the following:

git clone https://github.com/joaoleal/CppADCodeGen.git cppad_cg.git
cd cppad_cg.git
mkdir build
cd build
cmake ..

And I got the following error message:

CMake Error at test/CMakeLists.txt:54 (MESSAGE):
    GoogleTest source folder not found

I tried installing gtest (googletest) on my Fedora-31 system and still got the same error.

Dynamic Parameters Workaround

So if I understand correctly, it should be possible to add the parameters to the independent variables and then leave them out of the Jacobian calculation by calling setCustomSparseJacobianElements.

So here's what I'm doing to just compute the left columns in the Jacobian that are of interest:

// Jacobian sparsity
std::vector<size_t> rows;
std::vector<size_t> cols;
for (size_t row = 0; row < jacobian_t::RowsAtCompileTime; row++)
{
    for (size_t col = 0; col < jacobian_t::ColsAtCompileTime; col++)
    {
        rows.push_back(row);
        cols.push_back(col);
    }
}

cgen.setCustomSparseJacobianElements(rows, cols);

Now this would work if the Jacobian didn't already have zero-elements in it, right? Mine however does have those and I assume this is why it fails with:

cppad-20190200.5 error from unknown source
Error detected by false result for
    pattern.is_element(row[k], col[k])

Is there a way to get the rows, cols of the current sparsity, so that I can remove the ones that are not needed? Or is there a completely different way that I'm missing?

Thanks a lot, CppADCG is a great tool.

Calling CppAD::ipopt::solve from CppADCodeGen

Hi, Would you be able to help me run this ipopt example using CppADCodeGen? What changes should I make to replicate this example but with the AD performed by CppADCodeGen? I have successfully compiled and run this example with my local ipopt and CppAD builds and it works well.

Many thanks,

Unable to use DynamicModelLibraryProcessor

Hi all,

I'm trying to run the Lagrangian example in the examples folder. I'm using cppad-20180000.0, and everything else follows the requirements from the README.md. Eigen 3.4 and CppAD are installed system-wide. I copy the Lagrangian code into my main.cpp file, and invoke:

$ g++ -std=gnu++11 main.cpp

/tmp/ccdPwdGa.o: In function `CppAD::cg::LinuxDynamicLib<double>::LinuxDynamicLib(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)':
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdEC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi[_ZN5CppAD2cg15LinuxDynamicLibIdEC5ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi]+0x1d9): undefined reference to `dlopen'
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdEC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi[_ZN5CppAD2cg15LinuxDynamicLibIdEC5ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi]+0x206): undefined reference to `dlerror'
/tmp/ccdPwdGa.o: In function `CppAD::cg::LinuxDynamicLib<double>::~LinuxDynamicLib()':
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdED2Ev[_ZN5CppAD2cg15LinuxDynamicLibIdED5Ev]+0xdc): undefined reference to `dlclose'
/tmp/ccdPwdGa.o: In function `CppAD::cg::LinuxDynamicLib<double>::loadFunction(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)':
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb[_ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb]+0x46): undefined reference to `dlsym'
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb[_ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb]+0x55): undefined reference to `dlerror'
collect2: error: ld returned 1 exit status
/tmp/ccdPwdGa.o: In function `CppAD::cg::LinuxDynamicLib<double>::LinuxDynamicLib(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)':
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdEC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi[_ZN5CppAD2cg15LinuxDynamicLibIdEC5ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi]+0x1d9): undefined reference to `dlopen'
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdEC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi[_ZN5CppAD2cg15LinuxDynamicLibIdEC5ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi]+0x206): undefined reference to `dlerror'
/tmp/ccdPwdGa.o: In function `CppAD::cg::LinuxDynamicLib<double>::~LinuxDynamicLib()':
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdED2Ev[_ZN5CppAD2cg15LinuxDynamicLibIdED5Ev]+0xdc): undefined reference to `dlclose'
/tmp/ccdPwdGa.o: In function `CppAD::cg::LinuxDynamicLib<double>::loadFunction(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)':
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb[_ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb]+0x46): undefined reference to `dlsym'
main.cpp:(.text._ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb[_ZN5CppAD2cg15LinuxDynamicLibIdE12loadFunctionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb]+0x55): undefined reference to `dlerror'
collect2: error: ld returned 1 exit status

Adding the -ldl flag doesn't solve this. Is there a bug, or am I missing a step?

Generating Jacobians as Tensors

There are use cases e.g. in optimal control where the trajectories and associated gradients and jacobians are required to be calculated in parallel. An simple example would be generating optimal trajectories in phase space using some statistical objective for uncertain initial conditions.

Other AD frameworks such as Google Jax do a poor job of calculating Jacobians explicitly, but a very good job vectorizing the calculations in parallel using a GPU.

Is there a way to generate tensors (e.g. pytorch tensors) as the output of CppAD instead of matrix jacobians? This would allow for the efficient calculation of explicit Jacobians on a GPU without much effort. I don't think this would be a huge change. I am not asking you to do this but if you could point out which files need to be modified I can tackle it.

Examples on using CppADCodeGen with Eigen

I am struggling to generate AD code involving Eigen vectors (both with fixed and dynamic sizes) and matrices (both sparse and dense). Until now, I have been using autodiff with great satisfaction. Unfortunately, now I require very efficient code, and since autodiff does not separately generate the derivatives, it is not sufficient anymore. Hence my decision to switch to CppADCodeGen! However, its documentation is very succinct and not user-friendly -- at least, for an AD layman like myself. This is especially true when talking about the differentiation of Eigen-based functions.

Would it be possible for some advanced users/developers of CppADCodeGen to add more examples using Eigen types? The more articulated, the better! As a starting point, you may consider the examples from the autodiff library I mentioned, which are clear and exhaustive in my opinion. As a user, that is exactly what I would like to have when I start using a new library: it quickly sets me on track to employ it and, eventually, contribute to it.

Thank you very much!

P.S.: if such examples exist and I missed them, could you kindly address me to them?

Hessian computation via CGAtomicGenericModel nested in a larger CppAD::ADFun

I am trying to use a cg::CGAtomicGenericModel to compute the Hessian of a CppAD::ADFun. For example in this schematic code:

...
CGAtomicGenericModel<double> atomic_model;
ADFun<double> fun;
...
std::vector<AD<double>> X, Y, Z;
Y = atomic_model(X, Y);
Z = Y * Y; // some nonlinear function
fun(X, Z);
...
fun.sparse_hes(x, w, hess_subset, hess_pattern, "cppad.general", hes_work);

This would result in the following error:

cppad-20190806 error from a known source:
Second-order reverse mode failed: py[2*i] (i=0...m) must be zero.
Error detected by false result for
    ret != 1
at line 552 in the file 
    /Users/rguseino/sdk/cppadcodegen/include/cppad/cg/model/functor_generic_model.hpp
Assertion failed: (false), function Default, file /Users/rguseino/sdk/cppad/include/cppad/utility/error_handler.hpp, line 206.

In case Z is linear in Y, the error is not reproduced.
Does this mean that for now CGAtomicGenericModel is not supposed to be used in such scenario? Is there a workaround for this problem?
P.S. This happens in my large project but, if necessary, I can write simple code to reproduce this behavior.

PkgConfig and CppAD version

I did a fresh install of CppAD (v 2020) and of CppADCodeGen. Everything seems to be fine for now, except for one minor issue with PkgConfig (probably related to #41 and #43?): after configuring pkgconfig/cppadcg.pc.in, the version of CppAD is left blank, i.e., the corresponding line reads as

Requires:     cppad >=

I am not sure if I did some mistake - perhaps I forgot to set some variable/option while running CMake...
To install CppAD is simply cloned it and followed the "classical" build flow:

cmake ..
make
make install

and the same for CppADCodeGen (skipping the plain make step). Do you have any suggestion of what I could have done wrong? Thanks in advance!

CppAD::cg::CGException : GreaterThanZero cannot be called for non-parameters

Hello,

First I want to thank you for your awesome work, which is very useful to me. I'm trying to perform some code generation but I have the following exception :

terminate called after throwing an instance of 'CppAD::cg::CGException'
what (): GreaterThanZero cannot be called for non-parameters, Aborted (core dumped)

This exception occurs only when I run the code, the latter is indeed compiled with no errors.
Here is my code :

#include "pinocchio/parsers/urdf.hpp"
#include "pinocchio/algorithm/joint-configuration.hpp"
#include "pinocchio/algorithm/kinematics.hpp"
#include <iostream>
#include <urdf_parser/urdf_parser.h>
#include "pinocchio/codegen/cppadcg.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/utility/binary.hpp>
#include <Eigen/Geometry>
// PINOCCHIO_MODEL_DIR is defined by the CMake but you can define your own directory here.
#ifndef PINOCCHIO_MODEL_DIR
#define PINOCCHIO_MODEL_DIR "path_to_the_model_dir"
#endif


using namespace CppAD;
using namespace CppAD::cg;
using namespace pinocchio;
typedef double Scalar;
typedef CppAD::cg::CG<Scalar> CGScalar;
typedef CppAD::AD<CGScalar> ADScalar;
typedef Eigen::Matrix<ADScalar,Eigen::Dynamic,Eigen::Dynamic> ADRotMat;
typedef Eigen::Matrix<ADScalar,Eigen::Dynamic,1> ADVector;

int main(int argc, char ** argv)
{

/**Generate a random robot ADScalar configuration ad_q from Scalarconfiguration q**/
typedef ADModel::ConfigVectorType ADConfigVectorType;
ADConfigVectorType ad_q(model.nq);
Model::ConfigVectorType q = pinocchio::randomConfiguration(model);
ad_q = q.cast<ADScalar>();

/**Generate independent variables X and start recording operations sequence**/
ADConfigVectorType & X = ad_q;
CppAD::Independent(X);

ADVector Quat_ad(4); //This is the ADScalar quaternion vector

/**Perform forward kinematics and get rotation matrix R of the End Effector**/
pinocchio::forwardKinematics(ad_model, ad_data, X); //Compute forward kinematics
ADRotMat R; R = ad_data.oMi[model.nq].rotation();     //Get rotation matrix of End Effector

/**Convert the rotation matrix into a Quaternion**/
rotMatToQuaternion(R, Quat_ad);

/**Stop recording and generate AD function**/
CppAD::ADFun<CGScalar> fun(X,Quat_ad);

/**Generate source code **/
CppAD::cg::ModelCSourceGen<Scalar> cgen(fun, "fkine_angular");
cgen.setCreateJacobian(true);
cgen.setCreateForwardZero(true);
cgen.setCreateForwardOne(true);
cgen.setCreateReverseOne(true);
cgen.setCreateReverseTwo(true);
CppAD::cg::ModelLibraryCSourceGen<Scalar> libcgen(cgen);

/**Compile source code **/
CppAD::cg::DynamicModelLibraryProcessor<Scalar> p(libcgen);
CppAD::cg::GccCompiler<Scalar> compiler;
std::unique_ptr<CppAD::cg::DynamicLib<Scalar>> dynamicLib = p.createDynamicLibrary(compiler);

}

I think the problem comes from the function rotMatToQuaternion() which converts a rotation matrix into a quaternion, but inside this function there are some GreaterThanZero() tests. Here is the function :

void rotMatToQuaternion(ADRotMat const & R, ADVector & Quat_ad){
    ADScalar tr = R(0,0) + R(1,1) + R(2,2);
    if (tr > 0){
        ADScalar S = 0.5 / sqrt(tr+1);
        Quat_ad(0) = (R(2,1) - R(1,2))*S;
        Quat_ad(1) = (R(0,2) - R(2,0))*S;
        Quat_ad(2) = (R(1,0) - R(0,1))*S;
        Quat_ad(3) = 0.25 / S;
    } else {
      if (R(0,0) > R(1,1) && R(0,0) > R(2,2)){
        ADScalar S = 2 * sqrt(1 + R(0,0) - R(1,1) - R(2,2));
        Quat_ad(0) = 0.25 * S;
        Quat_ad(1) = (R(0,1) + R(1,0)) / S;
        Quat_ad(2) = (R(0,2) + R(2,0)) / S;
        Quat_ad(3) = (R(2,1) - R(1,2)) / S;
      } else if (R(1,1) > R(2,2)) {
        ADScalar S = 2 * sqrt(1 + R(1,1) - R(0,0) - R(2,2));
        Quat_ad(0) = (R(0,1) + R(1,0)) / S;
        Quat_ad(1) = 0.25 * S;
        Quat_ad(2) = (R(1,2) + R(2,1)) / S;
        Quat_ad(3) = (R(0,2) - R(2,0)) / S;
      } else {
        ADScalar S = 2 * sqrt(1 + R(2,2) - R(0,0) - R(1,1));
        Quat_ad(0) = (R(0,2) + R(2,0)) / S;
        Quat_ad(1) = (R(1,2) + R(2,1)) / S;
        Quat_ad(2) = 0.25 * S;
        Quat_ad(3) = (R(1,0) - R(0,1)) / S;
      }
    }
}

As you can see, the GreaterThan tests are performed on the values of the rotation matrix, which are not a part of the independent variables vector X. I think that is probably why the exception says GreaterThanZero cannot be called for non parameters.
Indeed, this rotation matrix R is calculated from the independent variables vector X using pinocchio::forwardKinematics(ad_model, ad_data, X);. And then, once the forward Kinematics performed, I get the rotation matrix using ADRotMat R; R = ad_data.oMi[model.nq].rotation();. Actually, I really need to convert the rotation matrix R into a quaternion because I want to compute the gradient of my Quaternion relatively to the vector X, that is why I have CppAD::ADFun<CGScalar> fun(X,Quat_ad). I hope I was clear enough, otherwise feel free to ask me further questions. Thank you again :)

ADFun::optimize() eliminates conditional statements

CppADCodegen generates wrong code if there are conditional statements in the tape and if I add an optimization pass in CppAD, for example, the output of the following code:

#include <iosfwd>
#include <vector>
using namespace std;
#include <cppad/cg/cppadcg.hpp>

using namespace CppAD;
using namespace CppAD::cg;

int main(void) {        
    typedef CG<double> CGD;
    typedef AD<CGD> ADCG;

    CppAD::vector<ADCG> U(2);
    U[0] = 0.;
    U[1] = 0.;
    Independent(U);

    CppAD::vector<ADCG> Z(1);

    ADCG a = U[0] * U[1];
    Z[0] = CondExpEq(U[0], ADCG(1.0), a, ADCG(0.0));    

    ADFun<CGD> fun(U, Z); 
    fun.optimize();

    CodeHandler<double> handler;

    CppAD::vector<CGD> indVars(2);
    handler.makeVariables(indVars);

    CppAD::vector<CGD> fwd = fun.Forward(0, indVars);

    LanguageC<double> langC("double");
    LangCDefaultVariableNameGenerator<double> nameGen;

    std::ostringstream code;
    handler.generateCode(code, langC, fwd, nameGen);
    std::cout << code.str();
}

is:

   // dependent variables without operations
   y[0] = 0;

If I remove the fun.optimize() line, the output becomes:

   if( x[0] == 1 ) {
      y[0] = x[0] * x[1];
   } else {
      y[0] = 0;
   }

I notice that CppADCodeGen does some optimizations on its own. Does it mean that I do not need to call fun.optimize() at all?

Multiple declaration of class ADFun

I installed CppAD and CppADCodeGen, and tested all CppADCodeGen examples on two different PCs both running Ubuntu 16.4, and I always get the following error.

g++ -std=c++11 lagrangian.cpp -o lagrangian
In file included from /usr/local/include/cppad/cg/cppadcg.hpp:77:0,
from /usr/local/include/cppad/cg.hpp:18,
from lagrangian.cpp:18:
/usr/local/include/cppad/cg/declare_cg.hpp:28:7: error: redeclared with 1 template parameter
class ADFun;
^
In file included from /usr/include/cppad/base_require.hpp:163:0,
from /usr/local/include/cppad/cg/cppadcg.hpp:71,
from /usr/local/include/cppad/cg.hpp:18,
from lagrangian.cpp:18:
/usr/include/cppad/local/declare_ad.hpp:53:50: note: previous declaration ‘template<class Base, class RecBase> class CppAD::ADFun’ used 2 template parameters template <class Base, class RecBase=Base> class ADFun;

Does someone know what I did wrong, or is this an issue due to changes in CppAD?

Thanks,
Alex

How does CppADCG export compile definitions?

Dear @joaoleal,

I have been trying to use llvm-based JIT (without creating dynamic libraries) in an external project.

I noticed that I cannot find any place where a previously installed instance of CppADCG exports the compile definitions that were allocated in the original CMakeLists.txt in the CppADCG root folder (e.g. found version of llvm, etc.)
For instance, when including LLVM and CppADCG, an external project needs to access the LLVM version compile definitions in this header.

How does CppADCG currently export its compile definitions, and what is the appropriate way for other projects to retrieve them?


Since CppADCG is header-only, one possible workflow would be to declare cppadcg as an interface library, e.g. include something like

add_library(cppadcg INTERFACE)
target_compile_definitions(cppadcg INTERFACE ${<some_compile_definitions>})

in which case an external project will receive all CppADCG internal compile-definitions automatically when linking against the interface library
target_link_libraries(<some_external_project> INTERFACE cppadcg)_

Option to declare loops explicitly

Hi,
I have a number of for loops in my algorithm. They have a fixed iteration number, hence work perfectly fine with CppAD codegen, but they produce a lot of (unnecessary?) temporary variables in the generated code and massively bloat the size of the code.

Is there a way to declare such for loops explicitly to CppADGC such that it results also in loop expressions in the generated code? I found some references to loops in CppADCodeGen/include/cppad/cg/model/patterns , but I'm not sure if it's for this purpose.

A tiny example how to use such functionality would be great :) Thank you!

Using LLVM to improve CppAD

Introduciton
This is really a request for help in CppAD development that is closely related to CppADCodegen.
I have questions about how to use LLVM and I hoping this group can help me.

Optimization
I am working on using the llvm optimizer as a replacement for the CppAD optimizer; see the example:
https://github.com/coin-or/CppAD/blob/llvm/example/llvm/optimize.cpp
I am close to being able to test how this compares to the CppAD optimizer for a simple example.

Complied Object Files
As a side benefit, inspired by CppADCodeGen, CppAD should be able to directly general object libraries corresponding to the llvm IR representation of an ADFun; see the example
https://github.com/coin-or/CppAD/blob/llvm/example/llvm/grad_det_minor.cpp
I am not sure how this will compare to the CppADCodeGen method for generating code.

Development
Work on this effect is happening on the llvm branch of CppAD in the following files and directories
https://github.com/coin-or/CppAD/blob/llvm/include/cppad/core/llvm_ir.hpp
https://github.com/coin-or/CppAD/blob/llvm/include/cppad/core/llvm_link.hpp
https://github.com/coin-or/CppAD/tree/llvm/cppad_lib/llvm
https://github.com/coin-or/CppAD/tree/llvm/example/llvm
https://github.com/coin-or/CppAD/blob/llvm/test_more/general/llvm_tst.cpp

LLVM Version
This work is currently only tested with the following version of llvm:
https://github.com/llvm/llvm-project/tree/release/11.x

Questions
I will post individual questons below.

Temporary folder location

Hi João Rui Leal,
I've been trying to use your CppADCodeGen library to generate fast c code for our problems, and have recently integrated it in our optimization solver Crocoddyl(https://github.com/loco-3d/crocoddyl).

I have a problem which deals with the temporary folder cppadcg_tmp that gets created by the compiler (https://github.com/joaoleal/CppADCodeGen/blob/master/include/cppad/cg/model/compiler/abstract_c_compiler.hpp#L45). This hardcoded value is quite restrictive if the user does not have permission to create a folder in that directory.

Could we move this directory to /tmp for example? Or would you have some suggestion to deal with this?

Best,
Rohan

Save LinuxDynamicLib and corresponding model

Hello,

First I want to thank you for code and your help.
I actually have a problem. I would like to load a LinuxDynamicLib (lets call it myLib) and the corresponding model (lets call it myModel) at the beggining of my main(). And then, I want to send both as argument for different functions, to be able to use myModel inside those functions. In fact, for the moment, I have to load myLib and myModel, inside those functions, which takes pretty much time as myLib and myModel are loaded at every call of those functions. The code would run much faster if I instantiate only once myModel and myLib at the beggining of main(), and then send them as argument for the functions that need myModel.

To do so, I coded the following function to load myModel and myLib and save them:

LinuxDynamicLib<Scalar> loadLibrary(std::vector<std::unique_ptr<GenericModel<double>>> & models){

            LinuxDynamicLib<Scalar> myLib("./fkine_angular_IMU1.so");  //Instantiation of the dynamic library
            std::unique_ptr<GenericModel<double>> myModel = myLib.model("fkine_angular_IMU1"); //Instantiation of the model, from the dynamic library
            models.push_back(std::move(myModel));
            return myLib;
}

This function takes as input a std::vector of GenericModel<double>s, loads myLib, loads myModel, adds myModel to my vector models (which can contain several models from different libs), then returns myLib. Actually, I have to return myLib, otherwise myModel will be deleted. But when I do return myLib I get the following compilation error :
error : use of deleted function 'cppAD::cg::LinuxDynamicLib<Base>::LinuxDynamicLib(const cppAD::cg::LinuxDynamicLib<Base>&) [with Base = double]'
This error is actually pointing on the line return myLib.

I also have a note : declared here , which is pointing on LinuxDynamicLib(const LinuxDynamicLib&) = delete; code line, in linux_dynamiclib.hpp file.

Thank you very much for your help, I don't know if i'm misunderstanding someting, as i'm a begginer on C++. I wish you a nice day

icpc build fails for dynamic_linux.cpp example

Hi,

Is it expected that icpc (from intel oneAPI) can't build codeGen? Happy to post compile error, just wanted to check that it should build using icpc first before requesting help?

Thanks,
Andy

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.