Code Monkey home page Code Monkey logo

dcpp's Introduction




dCppv0.1.0

dCpp

Automatic differentiation in C++; infinite differentiability of conditionals, loops, recursion and all things C++

dCpp is a tool for automatic differentiation made to be intuitive to the mind of a C++ programmer and non-invasive to his process. Despite its easy to use nature it retains flexibility, allowing implementations of differentiable (sub) programs operating on differentiable derivatives of other (sub) programs, where the entire process may again be differentiable. This allows trainable training processes, and flexible program analysis through operational calculus.

dCpp was originally developed as an example of how automatic differentiation can be viewed through Tensor and Operational Calculus. It has since been applied to a variety of tasks from dynamical systems analysis and digital geometry, to general program analysis and optimization by various parties.

Note that this was the authors first c++ project, which is reflected in the repository :).

Tutorial

We demonstrate the utilities of dCpp on a simple encapsulating example.

First we include the necessities

#include <iostream>
#include <dCpp.h>

We initialize an n-differentiable programming space

using namespace dCpp;
int n_differentiable = 3;
dCpp::initSpace(n_differentiable);

The Basics

The API of var complies with those for the standard C++ types, and when an instance of var is left uninitialized it behaves as the type double would have. We may envision an instance of var as an element of the differentiable virtual memory algebra, elevating C++ to a differentiable programming space dCpp. This means that any program can be made differentiable by simply substituting the type double for type var and that the coding process of the user can be left unchanged towards the initially intended goal.

By coding a simple recursive function foo we see that the usual usage of constructs such as conditionals, loops and recursion remains unchanged.

var foo(const var& x, const var& y)
{
    if(x < 1)
        return y;
    else if(y < 1)
        return x;
    else
        return x / foo(x / 2, y) + y * foo(x, y / 3);
}

To test it, we declare two instances of var.

var x=10;
var y=13;

Variables with respect to which differentiation is to be performed need to be initialized as such. This assures that uninitialized instances behave as the type double does. With the difference that all instances of var are differentiable with respect to all initialized instances.

dCpp::init(x);
dCpp::init(y);

The derivatives are extracted by specifying the memory location of the variable with respect to which differentiation is to be performed.

var f = foo(x,y);
std::cout <<  f << std::endl;
std::cout <<  f.d(&x) << std::endl;
std::cout << f.d(&y) << std::endl;

884.998
82.1202
193.959

Differentiable derivatives

The virtual memory space is constructed through tensor products of C++ internal representation of the memory. This means that derivatives are themselves elements of the differentiable virtual memory.

var fx = f.d(&x);
std::cout <<  fx.d(&x) << std::endl;
std::cout <<  fx.d(&y) << std::endl;
var fy = f.d(&y);
std::cout <<  fy.d(&x) << std::endl;
std::cout <<  fy.d(&y) << std::endl;

-0.103319
18.7722
18.7722
28.8913

We can thus employ derivatives of f in further n-1-differentiable calculations.

var F = dCpp::sqrt((fx^2) + (fy^2));
std::cout <<  F << std::endl;
std::cout <<  F.d(&x) << std::endl;
std::cout <<  F.d(&y) << std::endl;

210.627
17.2464
33.9239

As the derivatives of f are n-1-differentiable (twice, in our case), we can interweave them in calculations containing f itself.

var t = dCpp::sqrt(((fx^2) + (fy^2)) / f);
std::cout <<  t << std::endl;
std::cout <<  t.d(&x) << std::endl;
std::cout <<  t.d(&y) << std::endl;

7.08016
0.251241
0.364486

This is particularly useful when analyzing and optimizing differential equations, where usually both f and its (higher) derivatives appear in the same expression.

A note on the order of differentiability

The order of an expression is that of the lowest order of the expressions appearing in its construction.

Expression Order
f 3
fx = f.d(&x) 2
fy = f.d(&y) 2
(fx^2 + fy^2) / f 2
fxx = fx.d(&x) 1
fxy = fx.d(&y) 1
f * (fxy + fxx) / (fx - fy) 1

This means, that when we want to perform some non-differentiable operation on an expression, such as incrementing a variable in a gradient descent iteration, we should extract the value of its derivative using the id attribute of the instance var.

double lambda = 0.1;
double fx_double = f.d(&x).id
x += lambda * fx_double;
double fy_double = f.d(&x).id
y += lambda * fy_double

An example of a gradient descent can be found in examples/barycenterGD with a detailed explanation available in the closed issue here.

Operator dTau

If a certain mapping the user desires is not provided in the dCpp namespace, but its derivative exists, he may create the desired map by employing the operator tau.

Lets assume that the map log is not provided and create it using tau, by providing it with two maps, log: double --> double and log_primitive: var --> var.

var log_primitive(const var& v)
{   
   return 1 / v;
}

tau log(std::log, log_primitive);

The map is now ready to use

var l=log(((x^2) - (y^0.23))^2.1);
std::cout <<  l << std::endl;
std::cout <<  l.d(&x) << std::endl;
std::cout <<  l.d(&y) << std::endl;

9.63263
0.427715
-0.000682522

Examples

Further reading

As the presenting tutorial is quite brief, please consult the discussions regarding common mistakes and solutions.

Or consult the concerning papers.

Citation

If you use dCpp in your work, please cite one of the following papers

Žiga Sajovic, et al.: Operational Calculus for Differentiable Programming. arXiv e-prints arXiv:1610.07690 (2016)

@article{
    Author = {Žiga Sajovic, et al.},
    Title = {Operational Calculus for Differentiable Programming},
    journal = {arXiv e-prints},
    Year = 2016,
    volume = {arXiv:1610.07690},
    Eprint = {1610.07690},
    Eprinttype = {arXiv},
}

Žiga Sajovic: Automatic Differentiation: a look through Tensor and Operational Calculus. arXiv e-prints arXiv:1612.02731 (2016)

@article{
    Author = {Žiga Sajovic},
    Title = {Automatic Differentiation: a look through Tensor and Operational Calculus},
    journal = {arXiv e-prints},
    Year = 2016,
    volume = {arXiv:1612.02731},
    Eprint = {1612.02731},
    Eprinttype = {arXiv},
}

Creative Commons License
dC++ by Žiga Sajovic is licensed under a Creative Commons Attribution 4.0 International License.

dcpp's People

Contributors

zigasajovic avatar

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  avatar  avatar  avatar

dcpp's Issues

How to calculate derivative when multiplying matrixes with Eigen?

Considering the following snippet of code:

  #include <iostream>
  #include <dCpp.h> 
  #include <dEigen.h>
  #include <Eigen/Dense>

  #define BATCH_SIZE 3
  #define NUM_FEATURES 2
  #define NUM_CLASSES 4

  template<typename A, typename B>
  void print_derivative(A &input, B &w) {
      auto nRows = input.rows();
      auto nCols = input.cols();
      Eigen::MatrixXd toprint(nRows, nCols);
      for (size_t i = 0; i < nRows; ++i){
          for (size_t j = 0; j < nCols; ++j) {
              toprint(i, j) = input(i, j).d(&w);
          }
      }
      std::cout << toprint << std::endl;
  }

  int main() {
      dCpp::initSpace(1);

      // x.W + b
      Eigen::Matrix<dCpp::var, BATCH_SIZE, NUM_FEATURES> x;
      x = Eigen::Matrix<dCpp::var, BATCH_SIZE, NUM_FEATURES>::Ones(BATCH_SIZE, 
  NUM_FEATURES);
      dCpp::init(x);

      Eigen::Matrix<dCpp::var, NUM_FEATURES, NUM_CLASSES> w;
      w = Eigen::Matrix<dCpp::var, NUM_FEATURES, NUM_CLASSES>::Zero(NUM_FEATURES, NUM_CLASSES);
      dCpp::init(w);

      Eigen::Matrix<dCpp::var, BATCH_SIZE, NUM_CLASSES> b;
      b = Eigen::Matrix<dCpp::var, BATCH_SIZE, NUM_CLASSES>::Zero(BATCH_SIZE, NUM_CLASSES);
      dCpp::init(b);


      Eigen::Matrix<dCpp::var, BATCH_SIZE, NUM_CLASSES> y = x*w + b;
      print_derivative(y, w);

      return 0;
  }

The previous snippet of code does not compile because of the following line:

  toprint(i, j) = input(i, j).d(&w);

My question is how, while leveraging dCpp, can I obtain a matrix representing the first derivate of y in respect to w?

Auto-initializing all instances of var as differetiable

Hi,

I'm playing a bit with your nice AD tool and I'm having a bug with C++ operator and expressions.

Please have a look to https://gist.github.com/dcoeurjo/ce2b7f5e16edd348b7e4ca061ae6ceb5

For short: I have four points in the plane and I compute a kind of energy (sum of squared euclidean distance to a anchor point) and I want to differentiate this energy w.r.t. the anchor point.

If I expand the for loop when computing the energy (line 28), everything looks fine. When I use a for loop (line 17), then the differentiation fails (returning 0.0 for de/dx for instance). In terms of C++ operators, both energy expressions look similar.

Would you have any idea ?

No comments in the code

Could you please add comments inside the code to explain how to construct the differentiable virtual memory?

Infinite diffraction is better.

Try "return​ x / ​foo​(x / ​2​, y) + y * ​foo​(x, y / 4);"
It's cpp and binary, you know..

Infinite differentials + free integration at signature, just test it with 1/x and see if you find 2/x. It's easy.

Is dCpp thread safe?

Hi,

what would be the implications if one runs dCpp in a multithreaded environment?

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.