normal(float x, float y, float z) : x(x), y(y), z(z) { if (hasnan()) { printf("SEVERE: normal: Tried to construct a normal with a " "NaN: x=%f, y=%f, z=%f ", x, y, z); } }
VectorBase ADFun<Base>::Reverse(size_t p, const VectorBase &w) { // constants const Base zero(0); // temporary indices size_t i, j, k; // number of independent variables size_t n = ind_taddr_.size(); // number of dependent variables size_t m = dep_taddr_.size(); pod_vector<Base> Partial; Partial.extend(total_num_var_ * p); // update maximum memory requirement // memoryMax = std::max( memoryMax, // Memory() + total_num_var_ * p * sizeof(Base) // ); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( size_t(w.size()) == m || size_t(w.size()) == (m * p), "Argument w to Reverse does not have length equal to\n" "the dimension of the range for the corresponding ADFun." ); CPPAD_ASSERT_KNOWN( p > 0, "The first argument to Reverse must be greater than zero." ); CPPAD_ASSERT_KNOWN( taylor_per_var_ >= p, "Less that p taylor_ coefficients are currently stored" " in this ADFun object." ); // initialize entire Partial matrix to zero for(i = 0; i < total_num_var_; i++) for(j = 0; j < p; j++) Partial[i * p + j] = zero; // set the dependent variable direction // (use += because two dependent variables can point to same location) for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < total_num_var_ ); if( size_t(w.size()) == m ) Partial[dep_taddr_[i] * p + p - 1] += w[i]; else { for(k = 0; k < p; k++) // ? should use += here, first make test to demonstrate bug Partial[ dep_taddr_[i] * p + k ] = w[i * p + k ]; } } // evaluate the derivatives ReverseSweep( p - 1, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(), p, Partial.data(), cskip_op_ ); // return the derivative values VectorBase value(n * p); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < total_num_var_ ); // independent variable taddr equals its operator taddr CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == InvOp ); // by the Reverse Identity Theorem // partial of y^{(k)} w.r.t. u^{(0)} is equal to // partial of y^{(p-1)} w.r.t. u^{(p - 1 - k)} if( size_t(w.size()) == m ) { for(k = 0; k < p; k++) value[j * p + k ] = Partial[ind_taddr_[j] * p + p - 1 - k]; } else { for(k = 0; k < p; k++) value[j * p + k ] = Partial[ind_taddr_[j] * p + k]; } } CPPAD_ASSERT_KNOWN( ! ( hasnan(value) && check_for_nan_ ) , "dw = f.Reverse(p, w): has a nan,\n" "but none of its Taylor coefficents are nan." ); return value; }
Vector Rosen34( Fun &F , size_t M , const Scalar &ti , const Scalar &tf , const Vector &xi , Vector &e ) { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; // check numeric type specifications CheckNumericType<Scalar>(); // check simple vector class specifications CheckSimpleVector<Scalar, Vector>(); // Parameters for Shampine's Rosenbrock method // are static to avoid recalculation on each call and // do not use Vector to avoid possible memory leak static Scalar a[3] = { Scalar(0), Scalar(1), Scalar(3) / Scalar(5) }; static Scalar b[2 * 2] = { Scalar(1), Scalar(0), Scalar(24) / Scalar(25), Scalar(3) / Scalar(25) }; static Scalar ct[4] = { Scalar(1) / Scalar(2), - Scalar(3) / Scalar(2), Scalar(121) / Scalar(50), Scalar(29) / Scalar(250) }; static Scalar cg[3 * 3] = { - Scalar(4), Scalar(0), Scalar(0), Scalar(186) / Scalar(25), Scalar(6) / Scalar(5), Scalar(0), - Scalar(56) / Scalar(125), - Scalar(27) / Scalar(125), - Scalar(1) / Scalar(5) }; static Scalar d3[3] = { Scalar(97) / Scalar(108), Scalar(11) / Scalar(72), Scalar(25) / Scalar(216) }; static Scalar d4[4] = { Scalar(19) / Scalar(18), Scalar(1) / Scalar(4), Scalar(25) / Scalar(216), Scalar(125) / Scalar(216) }; CPPAD_ASSERT_KNOWN( M >= 1, "Error in Rosen34: the number of steps is less than one" ); CPPAD_ASSERT_KNOWN( e.size() == xi.size(), "Error in Rosen34: size of e not equal to size of xi" ); size_t i, j, k, l, m; // indices size_t n = xi.size(); // number of components in X(t) Scalar ns = Scalar(double(M)); // number of steps as Scalar object Scalar h = (tf - ti) / ns; // step size Scalar zero = Scalar(0); // some constants Scalar one = Scalar(1); Scalar two = Scalar(2); // permutation vectors needed for LU factorization routine CppAD::vector<size_t> ip(n), jp(n); // vectors used to store values returned by F Vector E(n * n), Eg(n), f_t(n); Vector g(n * 3), x3(n), x4(n), xf(n), ftmp(n), xtmp(n), nan_vec(n); // initialize e = 0, nan_vec = nan for(i = 0; i < n; i++) { e[i] = zero; nan_vec[i] = nan(zero); } xf = xi; // initialize solution for(m = 0; m < M; m++) { // time at beginning of this interval Scalar t = ti * (Scalar(int(M - m)) / ns) + tf * (Scalar(int(m)) / ns); // value of x at beginning of this interval x3 = x4 = xf; // evaluate partial derivatives at beginning of this interval F.Ode_ind(t, xf, f_t); F.Ode_dep(t, xf, E); // E = f_x if( hasnan(f_t) || hasnan(E) ) { e = nan_vec; return nan_vec; } // E = I - f_x * h / 2 for(i = 0; i < n; i++) { for(j = 0; j < n; j++) E[i * n + j] = - E[i * n + j] * h / two; E[i * n + i] += one; } // LU factor the matrix E # ifndef NDEBUG int sign = LuFactor(ip, jp, E); # else LuFactor(ip, jp, E); # endif CPPAD_ASSERT_KNOWN( sign != 0, "Error in Rosen34: I - f_x * h / 2 not invertible" ); // loop over integration steps for(k = 0; k < 3; k++) { // set location for next function evaluation xtmp = xf; for(l = 0; l < k; l++) { // loop over previous function evaluations Scalar bkl = b[(k-1)*2 + l]; for(i = 0; i < n; i++) { // loop over elements of x xtmp[i] += bkl * g[i*3 + l] * h; } } // ftmp = F(t + a[k] * h, xtmp) F.Ode(t + a[k] * h, xtmp, ftmp); if( hasnan(ftmp) ) { e = nan_vec; return nan_vec; } // Form Eg for this integration step for(i = 0; i < n; i++) Eg[i] = ftmp[i] + ct[k] * f_t[i] * h; for(l = 0; l < k; l++) { for(i = 0; i < n; i++) Eg[i] += cg[(k-1)*3 + l] * g[i*3 + l]; } // Solve the equation E * g = Eg LuInvert(ip, jp, E, Eg); // save solution and advance x3, x4 for(i = 0; i < n; i++) { g[i*3 + k] = Eg[i]; x3[i] += h * d3[k] * Eg[i]; x4[i] += h * d4[k] * Eg[i]; } } // Form Eg for last update to x4 only for(i = 0; i < n; i++) Eg[i] = ftmp[i] + ct[3] * f_t[i] * h; for(l = 0; l < 3; l++) { for(i = 0; i < n; i++) Eg[i] += cg[2*3 + l] * g[i*3 + l]; } // Solve the equation E * g = Eg LuInvert(ip, jp, E, Eg); // advance x4 and accumulate error bound for(i = 0; i < n; i++) { x4[i] += h * d4[3] * Eg[i]; // cant use abs because cppad.hpp may not be included Scalar diff = x4[i] - x3[i]; if( diff < zero ) e[i] -= diff; else e[i] += diff; } // advance xf for this step using x4 xf = x4; } return xf; }
VectorBase ADFun<Base>::Reverse(size_t q, const VectorBase &w) { // constants const Base zero(0); // temporary indices size_t i, j, k; // number of independent variables size_t n = ind_taddr_.size(); // number of dependent variables size_t m = dep_taddr_.size(); pod_vector<Base> Partial; Partial.extend(num_var_tape_ * q); // update maximum memory requirement // memoryMax = std::max( memoryMax, // Memory() + num_var_tape_ * q * sizeof(Base) // ); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( size_t(w.size()) == m || size_t(w.size()) == (m * q), "Argument w to Reverse does not have length equal to\n" "the dimension of the range for the corresponding ADFun." ); CPPAD_ASSERT_KNOWN( q > 0, "The first argument to Reverse must be greater than zero." ); CPPAD_ASSERT_KNOWN( num_order_taylor_ >= q, "Less that q taylor_ coefficients are currently stored" " in this ADFun object." ); // special case where multiple forward directions have been computed, // but we are only using the one direction zero order results if( (q == 1) & (num_direction_taylor_ > 1) ) { num_order_taylor_ = 1; // number of orders to copy size_t c = cap_order_taylor_; // keep the same capacity setting size_t r = 1; // only keep one direction capacity_order(c, r); } CPPAD_ASSERT_KNOWN( num_direction_taylor_ == 1, "Reverse mode for Forward(q, r, xq) with more than one direction" "\n(r > 1) is not yet supported for q > 1." ); // initialize entire Partial matrix to zero for(i = 0; i < num_var_tape_; i++) for(j = 0; j < q; j++) Partial[i * q + j] = zero; // set the dependent variable direction // (use += because two dependent variables can point to same location) for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); if( size_t(w.size()) == m ) Partial[dep_taddr_[i] * q + q - 1] += w[i]; else { for(k = 0; k < q; k++) // ? should use += here, first make test to demonstrate bug Partial[ dep_taddr_[i] * q + k ] = w[i * q + k ]; } } // evaluate the derivatives CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); CPPAD_ASSERT_UNKNOWN( load_op_.size() == play_.num_load_op_rec() ); ReverseSweep( q - 1, n, num_var_tape_, &play_, cap_order_taylor_, taylor_.data(), q, Partial.data(), cskip_op_.data(), load_op_ ); // return the derivative values VectorBase value(n * q); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); // independent variable taddr equals its operator taddr CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == InvOp ); // by the Reverse Identity Theorem // partial of y^{(k)} w.r.t. u^{(0)} is equal to // partial of y^{(q-1)} w.r.t. u^{(q - 1 - k)} if( size_t(w.size()) == m ) { for(k = 0; k < q; k++) value[j * q + k ] = Partial[ind_taddr_[j] * q + q - 1 - k]; } else { for(k = 0; k < q; k++) value[j * q + k ] = Partial[ind_taddr_[j] * q + k]; } } CPPAD_ASSERT_KNOWN( ! ( hasnan(value) && check_for_nan_ ) , "dw = f.Reverse(q, w): has a nan,\n" "but none of its Taylor coefficents are nan." ); return value; }
Vector OdeErrControl( Method &method, const Scalar &ti , const Scalar &tf , const Vector &xi , const Scalar &smin , const Scalar &smax , Scalar &scur , const Vector &eabs , const Scalar &erel , Vector &ef , Vector &maxabs, size_t &nstep ) { // check simple vector class specifications CheckSimpleVector<Scalar, Vector>(); size_t n = size_t(xi.size()); CPPAD_ASSERT_KNOWN( smin <= smax, "Error in OdeErrControl: smin > smax" ); CPPAD_ASSERT_KNOWN( size_t(eabs.size()) == n, "Error in OdeErrControl: size of eabs is not equal to n" ); CPPAD_ASSERT_KNOWN( size_t(maxabs.size()) == n, "Error in OdeErrControl: size of maxabs is not equal to n" ); size_t m = method.order(); CPPAD_ASSERT_KNOWN( m > 1, "Error in OdeErrControl: m is less than or equal one" ); bool ok; bool minimum_step; size_t i; Vector xa(n), xb(n), eb(n), nan_vec(n); // initialization Scalar zero(0); Scalar one(1); Scalar two(2); Scalar three(3); Scalar m1(m-1); Scalar ta = ti; for(i = 0; i < n; i++) { nan_vec[i] = nan(zero); ef[i] = zero; xa[i] = xi[i]; if( zero <= xi[i] ) maxabs[i] = xi[i]; else maxabs[i] = - xi[i]; } nstep = 0; Scalar tb, step, lambda, axbi, a, r, root; while( ! (ta == tf) ) { // start with value suggested by error criteria step = scur; // check maximum if( smax <= step ) step = smax; // check minimum minimum_step = step <= smin; if( minimum_step ) step = smin; // check if near the end if( tf <= ta + step * three / two ) tb = tf; else tb = ta + step; // try using this step size nstep++; method.step(ta, tb, xa, xb, eb); step = tb - ta; // check if this steps error estimate is ok ok = ! (hasnan(xb) || hasnan(eb)); if( (! ok) && minimum_step ) { ef = nan_vec; return nan_vec; } // compute value of lambda for this step lambda = Scalar(10) * scur / step; for(i = 0; i < n; i++) { if( zero <= xb[i] ) axbi = xb[i]; else axbi = - xb[i]; a = eabs[i] + erel * axbi; if( ! (eb[i] == zero) ) { r = ( a / eb[i] ) * step / (tf - ti); root = exp( log(r) / m1 ); if( root <= lambda ) lambda = root; } } if( ok && ( one <= lambda || step <= smin * three / two) ) { // this step is within error limits or // close to the minimum size ta = tb; for(i = 0; i < n; i++) { xa[i] = xb[i]; ef[i] = ef[i] + eb[i]; if( zero <= xb[i] ) axbi = xb[i]; else axbi = - xb[i]; if( axbi > maxabs[i] ) maxabs[i] = axbi; } } if( ! ok ) { // decrease step an see if method will work this time scur = step / two; } else if( ! (ta == tf) ) { // step suggested by the error criteria is not used // on the last step because it may be very small. scur = lambda * step / two; } } return xa; }
Vector ADFun<Base>::Forward( size_t p , const Vector& x_p , std::ostream& s ) { // temporary indices size_t i, j; // number of independent variables size_t n = ind_taddr_.size(); // number of dependent variables size_t m = dep_taddr_.size(); // check Vector is Simple Vector class with Base type elements CheckSimpleVector<Base, Vector>(); CPPAD_ASSERT_KNOWN( size_t(x_p.size()) == n, "Second argument to Forward does not have length equal to\n" "the dimension of the domain for the corresponding ADFun." ); CPPAD_ASSERT_KNOWN( p <= taylor_per_var_, "The number of taylor_ coefficient currently stored\n" "in this ADFun object is less than p." ); // check if the taylor_ matrix needs more columns if( taylor_col_dim_ <= p ) capacity_taylor(p + 1); CPPAD_ASSERT_UNKNOWN( taylor_col_dim_ > p ); // set the p-th order taylor_ coefficients for independent variables for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < total_num_var_ ); // ind_taddr_[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == InvOp ); // It is also variable taddr for j-th independent variable taylor_[ind_taddr_[j] * taylor_col_dim_ + p] = x_p[j]; } // evaluate the derivatives if( p == 0 ) { # if CPPAD_USE_FORWARD0SWEEP compare_change_ = forward0sweep(s, true, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data() ); # else compare_change_ = forward_sweep(s, true, p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data() ); # endif } else forward_sweep(s, false, p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data() ); // return the p-th order taylor_ coefficients for dependent variables Vector y_p(m); for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < total_num_var_ ); y_p[i] = taylor_[dep_taddr_[i] * taylor_col_dim_ + p]; } # ifndef NDEBUG if( hasnan(y_p) ) { if( p == 0 ) { CPPAD_ASSERT_KNOWN(false, "y = f.Forward(0, x): has a nan in y." ); } else { CPPAD_ASSERT_KNOWN(false, "y_p = f.Forward(p, x_p): has a nan in y_p for p > 0, " "but not for p = 0." ); } } # endif // now we have p + 1 taylor_ coefficients per variable taylor_per_var_ = p + 1; return y_p; }