File: sparse_hessian.cpp

package info (click to toggle)
cppad 2025.00.00.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 11,552 kB
  • sloc: cpp: 112,594; sh: 5,972; ansic: 179; python: 71; sed: 12; makefile: 10
file content (162 lines) | stat: -rw-r--r-- 4,737 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-22 Bradley M. Bell
// ----------------------------------------------------------------------------

/*
{xrst_begin sparse_hessian.cpp}

Sparse Hessian: Example and Test
################################

{xrst_literal
   // BEGIN C++
   // END C++
}

{xrst_end sparse_hessian.cpp}
*/
// BEGIN C++
# include <cppad/cppad.hpp>
bool sparse_hessian(void)
{  bool ok = true;
   using CppAD::AD;
   using CppAD::NearEqual;
   size_t i, j, k, ell;
   typedef CPPAD_TESTVECTOR(AD<double>)               a_vector;
   typedef CPPAD_TESTVECTOR(double)                     d_vector;
   typedef CPPAD_TESTVECTOR(size_t)                     i_vector;
   typedef CPPAD_TESTVECTOR(bool)                       b_vector;
   typedef CPPAD_TESTVECTOR(std::set<size_t>)         s_vector;
   double eps = 10. * CppAD::numeric_limits<double>::epsilon();

   // domain space vector
   size_t n = 12;  // must be greater than or equal 3; see n_sweep below
   a_vector a_x(n);
   for(j = 0; j < n; j++)
      a_x[j] = AD<double> (0);

   // declare independent variables and starting recording
   CppAD::Independent(a_x);

   // range space vector
   size_t m = 1;
   a_vector a_y(m);
   a_y[0] = a_x[0]*a_x[1];
   for(j = 0; j < n; j++)
      a_y[0] += a_x[j] * a_x[j] * a_x[j];

   // create f: x -> y and stop tape recording
   // (without executing zero order forward calculation)
   CppAD::ADFun<double> f;
   f.Dependent(a_x, a_y);

   // new value for the independent variable vector, and weighting vector
   d_vector w(m), x(n);
   for(j = 0; j < n; j++)
      x[j] = double(j);
   w[0] = 1.0;

   // vector used to check the value of the hessian
   d_vector check(n * n);
   for(ell = 0; ell < n * n; ell++)
      check[ell] = 0.0;
   ell        = 0 * n + 1;
   check[ell] = 1.0;
   ell        = 1 * n + 0;
   check[ell] = 1.0 ;
   for(j = 0; j < n; j++)
   {  ell = j * n + j;
      check[ell] = 6.0 * x[j];
   }

   // -------------------------------------------------------------------
   // second derivative of y[0] w.r.t x
   d_vector hes(n * n);
   hes = f.SparseHessian(x, w);
   for(ell = 0; ell < n * n; ell++)
      ok &=  NearEqual(w[0] * check[ell], hes[ell], eps, eps );

   // --------------------------------------------------------------------
   // example using vectors of bools to compute sparsity pattern for Hessian
   b_vector r_bool(n * n);
   for(i = 0; i < n; i++)
   {  for(j = 0; j < n; j++)
         r_bool[i * n + j] = false;
      r_bool[i * n + i] = true;
   }
   f.ForSparseJac(n, r_bool);
   //
   b_vector s_bool(m);
   for(i = 0; i < m; i++)
      s_bool[i] = w[i] != 0;
   b_vector p_bool = f.RevSparseHes(n, s_bool);

   hes = f.SparseHessian(x, w, p_bool);
   for(ell = 0; ell < n * n; ell++)
      ok &=  NearEqual(w[0] * check[ell], hes[ell], eps, eps );

   // --------------------------------------------------------------------
   // example using vectors of sets to compute sparsity pattern for Hessian
   s_vector r_set(n);
   for(i = 0; i < n; i++)
      r_set[i].insert(i);
   f.ForSparseJac(n, r_set);
   //
   s_vector s_set(m);
   for(i = 0; i < m; i++)
      if( w[i] != 0. )
         s_set[0].insert(i);
   s_vector p_set = f.RevSparseHes(n, s_set);

   // example passing sparsity pattern to SparseHessian
   hes = f.SparseHessian(x, w, p_set);
   for(ell = 0; ell < n * n; ell++)
      ok &=  NearEqual(w[0] * check[ell], hes[ell], eps, eps );

   // --------------------------------------------------------------------
   // use row and column indices to specify upper triangle of
   // non-zero elements of Hessian
   size_t K = n + 1;
   i_vector row(K), col(K);
   hes.resize(K);
   k = 0;
   for(j = 0; j < n; j++)
   {  // diagonal of Hessian
      row[k] = j;
      col[k] = j;
      k++;
   }
   // only off diagonal non-zero elemenet in upper triangle
   row[k] = 0;
   col[k] = 1;
   k++;
   ok &= k == K;
   CppAD::sparse_hessian_work work;

   // can use p_set or p_bool.
   size_t n_sweep = f.SparseHessian(x, w, p_set, row, col, hes, work);
   for(k = 0; k < K; k++)
   {  ell = row[k] * n + col[k];
      ok &=  NearEqual(w[0] * check[ell], hes[k], eps, eps );
   }
   ok &= n_sweep == 2;

   // now recompute at a different x and w (using work from previous call
   w[0]       = 2.0;
   x[1]       = 0.5;
   ell        = 1 * n + 1;
   check[ell] = 6.0 * x[1];
   s_vector   not_used;
   n_sweep    = f.SparseHessian(x, w, not_used, row, col, hes, work);
   for(k = 0; k < K; k++)
   {  ell = row[k] * n + col[k];
      ok &=  NearEqual(w[0] * check[ell], hes[k], eps, eps );
   }
   ok &= n_sweep == 2;



   return ok;
}
// END C++