autodiff.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * autodiff.h
  3. *
  4. * Created on: 16 Apr 2013
  5. * Author: s0965328
  6. */
  7. #ifndef AUTODIFF_H_
  8. #define AUTODIFF_H_
  9. #include <boost/unordered_set.hpp>
  10. #include <boost/numeric/ublas/matrix_proxy.hpp>
  11. #include <boost/numeric/ublas/matrix.hpp>
  12. #include <boost/numeric/ublas/matrix_sparse.hpp>
  13. #include <boost/numeric/ublas/io.hpp>
  14. #include "auto_diff_types.h"
  15. #include "Node.h"
  16. #include "VNode.h"
  17. #include "OPNode.h"
  18. #include "PNode.h"
  19. #include "ActNode.h"
  20. #include "EdgeSet.h"
  21. /*
  22. * + Function and Gradient Evaluation
  23. * The tapeless implementation for function and derivative evaluation
  24. * Advantage for tapeless:
  25. * Low memory usage
  26. * Function evaluation use one stack
  27. * Gradient evaluation use two stack.
  28. * Disadvantage for tapeless:
  29. * Inefficient if the expression tree have repeated nodes.
  30. * for example:
  31. * root
  32. * / \
  33. * * *
  34. * / \ / \
  35. * x1 x1 x1 x1
  36. * Tapeless implementation will go through all the edges.
  37. * ie. adjoint of x will be updated 4 times for the correct
  38. * gradient of x1.While the tape implemenation can discovery this
  39. * dependence and update adjoint of x1 just twice. The computational
  40. * graph (DAG) for a taped implemenation will be look like bellow.
  41. * root
  42. * /\
  43. * *
  44. * /\
  45. * x1
  46. *
  47. * + Forward Hessian Evaluation:
  48. * This is an inefficient implementation of the forward Hessian method. It will evaluate the diagonal
  49. * and upper triangular of the Hessian. The gradient is also evaluation in the same routine. The result
  50. * will be returned in an array.
  51. * To use this method, one have to provide a len parameter. len = (nvar+3)*nvar/2 where nvar is the number
  52. * of independent variables. ie. x_1 x_2 ... x_nvar. And the varaible id need to be a consequent integer start
  53. * with 0.
  54. * ret_vec will contains len number of doubles. Where the first nvar elements is the gradient vector,
  55. * and the rest of (nvar+1)*nvar/2 elements are the upper/lower plus the diagonal part of the Hessian matrix
  56. * in row format.
  57. * This algorithm is inefficient, because at each nodes, it didn't check the dependency of the independent
  58. * variables up to the current node. (or it is hard to do so for this setup). Therefore, it computes a full
  59. * for loops over each independent variable (ie. assume they are all dependent), for those independent
  60. * variables that are not dependent at the current node, zero will be produced by computation.
  61. * By default the forward mode hessian routing is disabled. To enable the forward hessian interface, the
  62. * compiler marco FORWARD_ENABLED need to be set equal to 1 in auto_diff_types.h
  63. *
  64. * + Reverse Hessian*Vector Evaluation:
  65. * Simple, building a tape in the forward pass, and a reverse pass will evaluate the Hessian*vector. The implemenation
  66. * also discovery the repeated subexpression and use one piece of memory on the tape for the same subexpression. This
  67. * allow efficient evaluation, because the repeated subexpression only evaluate once in the forward and reverse pass.
  68. * This algorithm can be called n times to compute a full Hessian, where n equals the number of independent
  69. * variables.
  70. * */
  71. typedef boost::numeric::ublas::compressed_matrix<double,boost::numeric::ublas::column_major,0,std::vector<std::size_t>,std::vector<double> > col_compress_matrix;
  72. typedef boost::numeric::ublas::matrix_row<col_compress_matrix > col_compress_matrix_row;
  73. typedef boost::numeric::ublas::matrix_column<col_compress_matrix > col_compress_matrix_col;
  74. namespace AutoDiff{
  75. //node creation methods
  76. extern PNode* create_param_node(double value);
  77. extern VNode* create_var_node(double v=NaN_Double);
  78. extern OPNode* create_uary_op_node(OPCODE code, Node* left);
  79. extern OPNode* create_binary_op_node(OPCODE code, Node* left,Node* right);
  80. //single constraint version
  81. extern double eval_function(Node* root);
  82. extern unsigned int nzGrad(Node* root);
  83. extern double grad_reverse(Node* root,vector<Node*>& nodes, vector<double>& grad);
  84. extern unsigned int nzHess(EdgeSet&);
  85. extern double hess_reverse(Node* root, vector<Node*>& nodes, vector<double>& dhess);
  86. //multiple constraints version
  87. extern unsigned int nzGrad(Node* root, boost::unordered_set<Node*>& vnodes);
  88. extern double grad_reverse(Node* root, vector<Node*>& nodes, col_compress_matrix_row& rgrad);
  89. extern unsigned int nzHess(EdgeSet&,boost::unordered_set<Node*>& set1, boost::unordered_set<Node*>& set2);
  90. extern double hess_reverse(Node* root, vector<Node*>& nodes, col_compress_matrix_col& chess);
  91. #if FORWARD_ENDABLED
  92. //forward methods
  93. extern void hess_forward(Node* root, unsigned int nvar, double** hess_mat);
  94. #endif
  95. //utiliy methods
  96. extern void nonlinearEdges(Node* root, EdgeSet& edges);
  97. extern unsigned int numTotalNodes(Node*);
  98. extern string tree_expr(Node* root);
  99. extern void print_tree(Node* root);
  100. extern void autodiff_setup();
  101. extern void autodiff_cleanup();
  102. };
  103. #endif /* AUTODIFF_H_ */