File: llsq_obj.cpp

package info (click to toggle)
cppad 2026.00.00.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,584 kB
  • sloc: cpp: 112,960; sh: 6,146; ansic: 179; python: 71; sed: 12; makefile: 10
file content (160 lines) | stat: -rw-r--r-- 4,082 bytes parent folder | download | duplicates (2)
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
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2024 Bradley M. Bell
// ---------------------------------------------------------------------------
/*
{xrst_begin valvector_llsq_obj.cpp}

Using valvector to Represent Linear Least Squares Objective
###########################################################

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

{xrst_end valvector_llsq_obj.cpp}
-------------------------------------------------------------------------------
*/
// BEGIN C++
# include <cppad/example/valvector/sum.hpp>
# include <cppad/example/valvector/class.hpp>
# include <cppad/cppad.hpp>
bool llsq_obj(void)
{  // ok
   bool ok = true;
   //
   // scalar_type
   typedef valvector::scalar_type scalar_type;
   //
   // eps99
   scalar_type eps99 = CppAD::numeric_limits<scalar_type>::epsilon();
   eps99            *= scalar_type(99);
   //
   // ad_valvector
   typedef CppAD::AD<valvector> ad_valvector;
   //
   // asum
   valvector_ad_sum asum;
   //
   // n_data
   // number of data points in the fit
   size_t n_data = 100;
   //
   // time, data
   // argument and data values in the function being fit
   valvector time, data;
   if( n_data == 1 )
   {  time[0] = 0.0;
      data[0] = 0.0;
   }
   else
   {  time.resize(n_data);
      data.resize(n_data);
      //
      for(size_t i = 0; i < n_data; ++i)
      {  time[i] = -1.0 + scalar_type(2 * i) / scalar_type(n_data - 1);
         if( time[i] < 0.0 )
            data[i] = -1.0;
         else if( 0.0 < time[i] )
            data[i] = +1.0;
         else
            data[i] = 0.0;
      }
   }
   // data
   if( n_data % 2 == 1 )
   {  // in case time[n_data/2] was not exactly zero due to roundoff
      data[n_data / 2] = 0.0;
   }
   //
   // nx
   // number of coefficients in the function being fit
   size_t nx = 3;
   //
   // ax
   // coefficients in the function being fit
   CPPAD_TESTVECTOR( ad_valvector ) ax(nx);
   for(size_t j = 0; j < nx; ++j)
      ax[j] = valvector(0.0);
   CppAD::Independent(ax);
   //
   // amodel
   valvector time_j(1.0);
   ad_valvector amodel(0.0);
   for(size_t  j = 0; j < nx; ++j)
   {  amodel += time_j * ax[j];
      time_j *= time;
   }
   //
   // aobj
   ad_valvector ares = data - amodel;
   ad_valvector asq  = ares * ares;
   ad_valvector aobj;
   asum(asq, aobj);
   //
   // ay
   CPPAD_TESTVECTOR( ad_valvector ) ay(1);
   ay[0] = aobj;
   CppAD::ADFun<valvector> f(ax, ay);
   //
   // x
   CPPAD_TESTVECTOR( valvector ) x(nx);
   for(size_t j = 0; j < nx; ++j)
      x[j][0] = 1.0;
   //
   // y
   CPPAD_TESTVECTOR( valvector ) y(1);
   y = f.Forward(0, x);
   //
   // res
   CPPAD_TESTVECTOR( scalar_type ) res(n_data);
   for(size_t i = 0; i < n_data; ++i)
   {  scalar_type tj = 1.0;
      scalar_type model = 0.0;
      for(size_t j = 0; j < nx; ++j)
      {  model += tj * x[j][0];
         tj    *= time[i];
      }
      res[i] = data[i] - model;
   }
   //
   // ok
   scalar_type check = 0.0;
   for(size_t i = 0; i < n_data; ++i)
      check += res[i] * res[i];
   ok   &= CppAD::NearEqual(y[0][0], check, eps99, eps99);
   //
   // dw
   CPPAD_TESTVECTOR( valvector ) w(1), dw(nx);
   w[0][0] = 1.0;
   dw = f.Reverse(1, w);
   //
   //
   // dres_sq
   CPPAD_TESTVECTOR( scalar_type ) dres_sq(nx);
   for(size_t j = 0; j < nx; ++j)
      dres_sq[j] = 0.0;
   for(size_t i = 0; i < n_data; ++i)
   {  scalar_type tj = 1.0;
      for(size_t j = 0; j < nx; ++j)
      {  dres_sq[j] += - 2.0 * res[i] * tj;
         tj         *= time[i];
      }
   }
   //
   // ok
   // reverse mode does not know that x[j] had size one and represents
   // a valvector of size n_data and with x[j][k] constant w.r.t k.
   for(size_t j = 0; j < nx; ++j)
   {  /*
      std::cout << "j = " << j;
      std::cout << ", dw[j] = " << dw[j];
      std::cout << ", dres_sq[j] = " << dres_sq[j] << "\n";
      */
      ok   &= dw[j].size() == n_data;
      ok   &= CppAD::NearEqual(dw[j].sum(), dres_sq[j], eps99, eps99);
   }
   return ok;
}
// END C++