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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-24 Bradley M. Bell
// ----------------------------------------------------------------------------
/*
{xrst_begin adolc_sparse_hessian.cpp}
Adolc Speed: Sparse Hessian
###########################
Specifications
**************
See :ref:`link_sparse_hessian-name` .
Implementation
**************
{xrst_spell_off}
{xrst_code cpp} */
// suppress conversion warnings before other includes
# include <cppad/wno_conversion.hpp>
//
# include <adolc/adolc.h>
# include <adolc/adolc_sparse.h>
# include <cppad/utility/vector.hpp>
# include <cppad/utility/index_sort.hpp>
# include <cppad/speed/uniform_01.hpp>
# include <cppad/utility/thread_alloc.hpp>
# include <cppad/speed/sparse_hes_fun.hpp>
// list of possible options
# include <map>
extern std::map<std::string, bool> global_option;
bool link_sparse_hessian(
size_t size ,
size_t repeat ,
const CppAD::vector<size_t>& row ,
const CppAD::vector<size_t>& col ,
CppAD::vector<double>& x_return ,
CppAD::vector<double>& hessian ,
size_t& n_color )
{
if( global_option["atomic"] || (! global_option["colpack"]) )
return false;
if( global_option["memory"] || global_option["optimize"] || global_option["boolsparsity"] )
return false;
// -----------------------------------------------------
// setup
typedef unsigned int* IntVector;
typedef double* DblVector;
typedef adouble ADScalar;
typedef ADScalar* ADVector;
size_t order = 0; // derivative order corresponding to function
size_t m = 1; // number of dependent variables
size_t n = size; // number of independent variables
// setup for thread_alloc memory allocator (fast and checks for leaks)
using CppAD::thread_alloc; // the allocator
size_t capacity; // capacity of an allocation
// tape identifier
short tag = 0;
// AD domain space vector
ADVector a_x = thread_alloc::create_array<ADScalar>(n, capacity);
// AD range space vector
ADVector a_y = thread_alloc::create_array<ADScalar>(m, capacity);
// double argument value
DblVector x = thread_alloc::create_array<double>(n, capacity);
// double function value
double f;
// options that control sparse_hess
int options[2];
options[0] = 0; // safe mode
options[1] = 0; // indirect recovery
// structure that holds some of the work done by sparse_hess
int nnz; // number of non-zero values
IntVector rind = nullptr; // row indices
IntVector cind = nullptr; // column indices
DblVector values = nullptr; // Hessian values
// ----------------------------------------------------------------------
if( ! global_option["onetape"] ) while(repeat--)
{ // choose a value for x
CppAD::uniform_01( size_t(n), x);
// declare independent variables
int keep = 0; // keep forward mode results
trace_on(tag, keep);
for(size_t j = 0; j < n; j++)
a_x[j] <<= x[j];
// AD computation of f (x)
CppAD::sparse_hes_fun<ADScalar>(n, a_x, row, col, order, a_y);
// create function object f : x -> y
a_y[0] >>= f;
trace_off();
// is this a repeat call with the same sparsity pattern
int same_pattern = 0;
// calculate the hessian at this x
rind = nullptr;
cind = nullptr;
values = nullptr;
sparse_hess(tag, int(n),
same_pattern, x, &nnz, &rind, &cind, &values, options
);
// free raw memory allocated by sparse_hess
// (keep on last repeat for correctness testing)
if( repeat != 0 )
{ free(rind);
free(cind);
free(values);
}
}
else
{ // choose a value for x
CppAD::uniform_01( size_t(n), x);
// declare independent variables
int keep = 0; // keep forward mode results
trace_on(tag, keep);
for(size_t j = 0; j < n; j++)
a_x[j] <<= x[j];
// AD computation of f (x)
CppAD::sparse_hes_fun<ADScalar>(n, a_x, row, col, order, a_y);
// create function object f : x -> y
a_y[0] >>= f;
trace_off();
// is this a repeat call at the same argument
int same_pattern = 0;
while(repeat--)
{ // choose a value for x
CppAD::uniform_01( size_t(n), x);
// calculate the hessian at this x
sparse_hess(tag, int(n),
same_pattern, x, &nnz, &rind, &cind, &values, options
);
same_pattern = 1;
}
}
// Adolc returns upper triangle in row major order while row, col are
// lower triangle in row major order.
CppAD::vector<size_t> keys(nnz), ind(nnz);
for(int ell = 0; ell < nnz; ++ell)
{ // transpose to get lower triangle
size_t i = size_t( cind[ell] );
size_t j = size_t( rind[ell] );
keys[ell] = i * n + j; // row major order for lower triangle
}
CppAD::index_sort(keys, ind);
size_t k = 0; // initialize index in row, col
size_t r = row[k];
size_t c = col[k];
for(int ell = 0; ell < nnz; ++ell)
{ // Adolc version of lower triangle of Hessian in row major order
size_t ind_ell = ind[ell];
size_t i = size_t( cind[ind_ell] );
size_t j = size_t( rind[ind_ell] );
while( (r < i) || ( (r == i) && (c < j) ) )
{ // (r, c) not in Adolc sparsity pattern
hessian[k++] = 0.0;
if( k < row.size() )
{ r = row[k];
c = col[k];
}
else
{ r = n;
c = n;
}
}
if( (r == i) && (c == j) )
{ // adolc value for (r, c)
hessian[k++] = values[ind_ell];
if( k < row.size() )
{ r = row[k];
c = col[k];
}
else
{ r = n;
c = n;
}
}
else
{ // Hessian at (i, j) must be zero (but Adolc does not know this)
assert( values[ind_ell] == 0.0 );
}
}
// free raw memory allocated by sparse_hessian
free(rind);
free(cind);
free(values);
//
// return argument
for(size_t j = 0; j < n; j++)
x_return[j] = x[j];
// do not know how to return number of sweeps used
n_color = 0;
// tear down
thread_alloc::delete_array(a_x);
thread_alloc::delete_array(a_y);
thread_alloc::delete_array(x);
return true;
}
/* {xrst_code}
{xrst_spell_on}
{xrst_end adolc_sparse_hessian.cpp}
*/
|