bool LuRatio(void) { bool ok = true; size_t n = 2; // number rows in A double ratio; // values for independent and dependent variables CPPAD_TEST_VECTOR<double> x(n*n), y(n*n+1); // pivot vectors CPPAD_TEST_VECTOR<size_t> ip(n), jp(n); // set x equal to the identity matrix x[0] = 1.; x[1] = 0; x[2] = 0.; x[3] = 1.; // create a fnction object corresponding to this value of x CppAD::ADFun<double> *FunPtr = NewFactor(n, x, ok, ip, jp); // use function object to factor matrix y = FunPtr->Forward(0, x); ratio = y[n*n]; ok &= (ratio == 1.); ok &= CheckLuFactor(n, x, y, ip, jp); // set x so that the pivot ratio will be infinite x[0] = 0. ; x[1] = 1.; x[2] = 1. ; x[3] = 0.; // try to use old function pointer to factor matrix y = FunPtr->Forward(0, x); ratio = y[n*n]; // check to see if we need to refactor matrix ok &= (ratio > 10.); if( ratio > 10. ) { delete FunPtr; // to avoid a memory leak FunPtr = NewFactor(n, x, ok, ip, jp); } // now we can use the function object to factor matrix y = FunPtr->Forward(0, x); ratio = y[n*n]; ok &= (ratio == 1.); ok &= CheckLuFactor(n, x, y, ip, jp); delete FunPtr; // avoid memory leak return ok; }
/* $$ $head Use Atomic Function$$ $codep */ bool get_started(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; double eps = 10. * CppAD::numeric_limits<double>::epsilon(); /* $$ $subhead Constructor$$ $codep */ // Create the atomic get_started object atomic_get_started afun("atomic_get_started"); /* $$ $subhead Recording$$ $codep */ // Create the function f(x) // // domain space vector size_t n = 1; double x0 = 0.5; vector< AD<double> > ax(n); ax[0] = x0; // declare independent variables and start tape recording CppAD::Independent(ax); // range space vector size_t m = 1; vector< AD<double> > ay(m); // call user function and store get_started(x) in au[0] vector< AD<double> > au(m); afun(ax, au); // u = 1 / x // now use AD division to invert to invert the operation ay[0] = 1.0 / au[0]; // y = 1 / u = x // create f: x -> y and stop tape recording CppAD::ADFun<double> f; f.Dependent (ax, ay); // f(x) = x /* $$ $subhead forward$$ $codep */ // check function value double check = x0; ok &= NearEqual( Value(ay[0]) , check, eps, eps); // check zero order forward mode size_t p; vector<double> x_p(n), y_p(m); p = 0; x_p[0] = x0; y_p = f.Forward(p, x_p); ok &= NearEqual(y_p[0] , check, eps, eps); return ok; }
bool forward_order(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; size_t j, k; double eps = 10. * CppAD::numeric_limits<double>::epsilon(); // domain space vector size_t n = 23, m = n; CPPAD_TESTVECTOR(AD<double>) X(n), Y(m); for(j = 0; j < n; j++) X[j] = 0.0; // declare independent variables and starting recording CppAD::Independent(X); // identity function values size_t i = 0; size_t identity_begin = i; Y[i] = cos( acos( X[i] ) ); i++; // AcosOp, CosOp Y[i] = sin( asin( X[i] ) ); i++; // AsinOp, SinOp Y[i] = tan( atan( X[i] ) ); i++; // AtanOp, TanOp Y[i] = CondExpGt(X[i], X[i-1], X[i], X[i-2]); i++; // CExpOp Y[i] = X[i-1] * X[i] / X[i-1]; i++; // DivvvOp, MulvvOp Y[i] = X[i] * X[i] * 1.0 / X[i]; i++; // DivpvOp Y[i] = 5.0 * X[i] / 5.0; i++; // DivvpOp, MulpvOp Y[i] = exp( log( X[i] ) ); i++; // ExpOp, LogOp Y[i] = pow( sqrt( X[i] ), 2.0); i++; // PowvpOp, SqrtOp Y[i] = log( pow( std::exp(1.), X[i] ) ); i++; // PowpvOp Y[i] = log( pow( X[i], X[i] ) ) / log( X[i]); i++; // PowvvOp Y[i] = -2. - ((X[i-1] - X[i]) - 2.) + X[i-1]; i++; // Sub*Op: pv, vv, vp size_t identity_end = i; // other functions Y[i] = abs( X[i] ); i++; // AbsOp Y[i] = X[i-1] + X[i] + 2.0; i++; // AddvvOp, AddvpOp Y[i] = cosh( X[i] ); i++; // CoshOp Y[i] = my_discrete( X[i] ); i++; // DisOp Y[i] = 4.0; i++; // ParOp Y[i] = sign( X[i] ); i++; // SignOp Y[i] = sinh( X[i] ); i++; // SinhOp Y[i] = tanh(X[i]); i++; // TanhOp // VecAD operations CppAD::VecAD<double> V(n); AD<double> index = 1.; V[index] = 3.0; Y[i] = V[index]; i++; // StppOp, LdpOp V[index] = X[0]; Y[i] = V[index]; i++; // StpvOp, LdpOp index = double(n) * X[3]; V[index] = X[1]; Y[i] = V[index]; i++; // StvvOp, LdvOp // create f: X -> Y and stop tape recording assert( i == m ); CppAD::ADFun<double> f; f.Dependent(X, Y); // initially, no values stored in f ok &= f.size_order() == 0; // Set X_j (t) = x + t size_t p = 2, p1 = p+1; CPPAD_TESTVECTOR(double) x(n), x_p(n * p1), y_p(m * p1); for(j = 0; j < n; j++) { x[j] = double(j) / double(n); x_p[j * p1 + 0] = x[j]; // order 0 x_p[j * p1 + 1] = 1.; // order 1 x_p[j * p1 + 2] = 0.; // order 2 } // compute orders 0, 1, 2 y_p = f.Forward(p, x_p); // identity functions CPPAD_TESTVECTOR(double) y(p1); i = 0; for(j = identity_begin; j != identity_end; j++) { y[0] = x[j]; y[1] = 1.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); i++; } // y_i = abs( x_i ) y[0] = CppAD::abs( x[i] ); y[1] = CppAD::sign( x[i] ); y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = x_[i-1] + x_i + 2 i++; y[0] = x[i-1] + x[i] + 2.0; y[1] = 2.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = cosh( x_i ) i++; y[0] = CppAD::cosh( x[i] ); y[1] = CppAD::sinh( x[i] ); y[2] = CppAD::cosh( x[i] ) / 2.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = my_discrete( x_i ) i++; y[0] = my_discrete( x[i] ); y[1] = 0.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = 4 i++; y[0] = 4.0; y[1] = 0.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = sign( x_i ) i++; y[0] = CppAD::sign( x[i] ); y[1] = 0.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = sinh( x_i ) i++; y[0] = CppAD::sinh( x[i] ); y[1] = CppAD::cosh( x[i] ); y[2] = CppAD::sinh( x[i] ) / 2.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = tanh( x_i ) i++; y[0] = CppAD::tanh( x[i] ); y[1] = 1.0 - y[0] * y[0]; y[2] = - 2.0 * y[0] * y[1] / 2.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = 3.0; i++; y[0] = 3.0; y[1] = 0.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = x_0 i++; y[0] = x[0]; y[1] = 1.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); // y_i = x_1 i++; y[0] = x[1]; y[1] = 1.0; y[2] = 0.0; for(k = 0; k < p1; k++) ok &= NearEqual(y[k] , y_p[i * p1 + k], eps, eps); return ok; }
/* $$ $head Use Atomic Function$$ $codep */ bool reciprocal(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; double eps = 10. * CppAD::numeric_limits<double>::epsilon(); /* $$ $subhead Constructor$$ $codep */ // -------------------------------------------------------------------- // Create the atomic reciprocal object atomic_reciprocal afun("atomic_reciprocal"); /* $$ $subhead Recording$$ $codep */ // Create the function f(x) // // domain space vector size_t n = 1; double x0 = 0.5; vector< AD<double> > ax(n); ax[0] = x0; // declare independent variables and start tape recording CppAD::Independent(ax); // range space vector size_t m = 1; vector< AD<double> > ay(m); // call user function and store reciprocal(x) in au[0] vector< AD<double> > au(m); afun(ax, au); // u = 1 / x // now use AD division to invert to invert the operation ay[0] = 1.0 / au[0]; // y = 1 / u = x // create f: x -> y and stop tape recording CppAD::ADFun<double> f; f.Dependent (ax, ay); // f(x) = x /* $$ $subhead forward$$ $codep */ // check function value double check = x0; ok &= NearEqual( Value(ay[0]) , check, eps, eps); // check zero order forward mode size_t p; vector<double> x_p(n), y_p(m); p = 0; x_p[0] = x0; y_p = f.Forward(p, x_p); ok &= NearEqual(y_p[0] , check, eps, eps); // check first order forward mode p = 1; x_p[0] = 1; y_p = f.Forward(p, x_p); check = 1.; ok &= NearEqual(y_p[0] , check, eps, eps); // check second order forward mode p = 2; x_p[0] = 0; y_p = f.Forward(p, x_p); check = 0.; ok &= NearEqual(y_p[0] , check, eps, eps); /* $$ $subhead reverse$$ $codep */ // third order reverse mode p = 3; vector<double> w(m), dw(n * p); w[0] = 1.; dw = f.Reverse(p, w); check = 1.; ok &= NearEqual(dw[0] , check, eps, eps); check = 0.; ok &= NearEqual(dw[1] , check, eps, eps); ok &= NearEqual(dw[2] , check, eps, eps); /* $$ $subhead for_sparse_jac$$ $codep */ // forward mode sparstiy pattern size_t q = n; CppAD::vectorBool r1(n * q), s1(m * q); r1[0] = true; // compute sparsity pattern for x[0] // afun.option( CppAD::atomic_base<double>::bool_sparsity_enum ); s1 = f.ForSparseJac(q, r1); ok &= s1[0] == true; // f[0] depends on x[0] // afun.option( CppAD::atomic_base<double>::set_sparsity_enum ); s1 = f.ForSparseJac(q, r1); ok &= s1[0] == true; // f[0] depends on x[0] /* $$ $subhead rev_sparse_jac$$ $codep */ // reverse mode sparstiy pattern p = m; CppAD::vectorBool s2(p * m), r2(p * n); s2[0] = true; // compute sparsity pattern for f[0] // afun.option( CppAD::atomic_base<double>::bool_sparsity_enum ); r2 = f.RevSparseJac(p, s2); ok &= r2[0] == true; // f[0] depends on x[0] // afun.option( CppAD::atomic_base<double>::set_sparsity_enum ); r2 = f.RevSparseJac(p, s2); ok &= r2[0] == true; // f[0] depends on x[0] /* $$ $subhead rev_sparse_hes$$ $codep */ // Hessian sparsity (using previous ForSparseJac call) CppAD::vectorBool s3(m), h(q * n); s3[0] = true; // compute sparsity pattern for f[0] // afun.option( CppAD::atomic_base<double>::bool_sparsity_enum ); h = f.RevSparseHes(q, s3); ok &= h[0] == true; // second partial of f[0] w.r.t. x[0] may be non-zero // afun.option( CppAD::atomic_base<double>::set_sparsity_enum ); h = f.RevSparseHes(q, s3); ok &= h[0] == true; // second partial of f[0] w.r.t. x[0] may be non-zero return ok; }
bool old_reciprocal(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; double eps = 10. * CppAD::numeric_limits<double>::epsilon(); // -------------------------------------------------------------------- // Create the function f(x) // // domain space vector size_t n = 1; double x0 = 0.5; vector< AD<double> > ax(n); ax[0] = x0; // declare independent variables and start tape recording CppAD::Independent(ax); // range space vector size_t m = 1; vector< AD<double> > ay(m); // call atomic function and store reciprocal(x) in au[0] vector< AD<double> > au(m); size_t id = 0; // not used reciprocal(id, ax, au); // u = 1 / x // call atomic function and store reciprocal(u) in ay[0] reciprocal(id, au, ay); // y = 1 / u = x // create f: x -> y and stop tape recording CppAD::ADFun<double> f; f.Dependent (ax, ay); // f(x) = x // -------------------------------------------------------------------- // Check forward mode results // // check function value double check = x0; ok &= NearEqual( Value(ay[0]) , check, eps, eps); // check zero order forward mode size_t q; vector<double> x_q(n), y_q(m); q = 0; x_q[0] = x0; y_q = f.Forward(q, x_q); ok &= NearEqual(y_q[0] , check, eps, eps); // check first order forward mode q = 1; x_q[0] = 1; y_q = f.Forward(q, x_q); check = 1.; ok &= NearEqual(y_q[0] , check, eps, eps); // check second order forward mode q = 2; x_q[0] = 0; y_q = f.Forward(q, x_q); check = 0.; ok &= NearEqual(y_q[0] , check, eps, eps); // -------------------------------------------------------------------- // Check reverse mode results // // third order reverse mode q = 3; vector<double> w(m), dw(n * q); w[0] = 1.; dw = f.Reverse(q, w); check = 1.; ok &= NearEqual(dw[0] , check, eps, eps); check = 0.; ok &= NearEqual(dw[1] , check, eps, eps); ok &= NearEqual(dw[2] , check, eps, eps); // -------------------------------------------------------------------- // forward mode sparstiy pattern size_t p = n; CppAD::vectorBool r1(n * p), s1(m * p); r1[0] = true; // compute sparsity pattern for x[0] s1 = f.ForSparseJac(p, r1); ok &= s1[0] == true; // f[0] depends on x[0] // -------------------------------------------------------------------- // reverse mode sparstiy pattern q = m; CppAD::vectorBool s2(q * m), r2(q * n); s2[0] = true; // compute sparsity pattern for f[0] r2 = f.RevSparseJac(q, s2); ok &= r2[0] == true; // f[0] depends on x[0] // -------------------------------------------------------------------- // Hessian sparsity (using previous ForSparseJac call) CppAD::vectorBool s3(m), h(p * n); s3[0] = true; // compute sparsity pattern for f[0] h = f.RevSparseHes(p, s3); ok &= h[0] == true; // second partial of f[0] w.r.t. x[0] may be non-zero // ----------------------------------------------------------------- // Free all temporary work space associated with atomic_one objects. // (If there are future calls to atomic functions, they will // create new temporary work space.) CppAD::user_atomic<double>::clear(); return ok; }
bool old_tan(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; float eps = 10.f * CppAD::numeric_limits<float>::epsilon(); // domain space vector size_t n = 1; float x0 = 0.5; CppAD::vector< AD<float> > ax(n); ax[0] = x0; // declare independent variables and start tape recording CppAD::Independent(ax); // range space vector size_t m = 3; CppAD::vector< AD<float> > af(m); // temporary vector for old_tan computations // (old_tan computes tan or tanh and its square) CppAD::vector< AD<float> > az(2); // call user tan function and store tan(x) in f[0] (ignore tan(x)^2) size_t id = 0; old_tan(id, ax, az); af[0] = az[0]; // call user tanh function and store tanh(x) in f[1] (ignore tanh(x)^2) id = 1; old_tan(id, ax, az); af[1] = az[0]; // put a constant in f[2] = tanh(1.) (for sparsity pattern testing) CppAD::vector< AD<float> > one(1); one[0] = 1.; old_tan(id, one, az); af[2] = az[0]; // create f: x -> f and stop tape recording CppAD::ADFun<float> F; F.Dependent(ax, af); // check function value float tan = std::tan(x0); ok &= NearEqual(af[0] , tan, eps, eps); float tanh = std::tanh(x0); ok &= NearEqual(af[1] , tanh, eps, eps); // check zero order forward CppAD::vector<float> x(n), f(m); x[0] = x0; f = F.Forward(0, x); ok &= NearEqual(f[0] , tan, eps, eps); ok &= NearEqual(f[1] , tanh, eps, eps); // compute first partial of f w.r.t. x[0] using forward mode CppAD::vector<float> dx(n), df(m); dx[0] = 1.; df = F.Forward(1, dx); // compute derivative of tan - tanh using reverse mode CppAD::vector<float> w(m), dw(n); w[0] = 1.; w[1] = 1.; w[2] = 0.; dw = F.Reverse(1, w); // tan'(x) = 1 + tan(x) * tan(x) // tanh'(x) = 1 - tanh(x) * tanh(x) float tanp = 1.f + tan * tan; float tanhp = 1.f - tanh * tanh; ok &= NearEqual(df[0], tanp, eps, eps); ok &= NearEqual(df[1], tanhp, eps, eps); ok &= NearEqual(dw[0], w[0]*tanp + w[1]*tanhp, eps, eps); // compute second partial of f w.r.t. x[0] using forward mode CppAD::vector<float> ddx(n), ddf(m); ddx[0] = 0.; ddf = F.Forward(2, ddx); // compute second derivative of tan - tanh using reverse mode CppAD::vector<float> ddw(2); ddw = F.Reverse(2, w); // tan''(x) = 2 * tan(x) * tan'(x) // tanh''(x) = - 2 * tanh(x) * tanh'(x) // Note that second order Taylor coefficient for u half the // corresponding second derivative. float two = 2; float tanpp = two * tan * tanp; float tanhpp = - two * tanh * tanhp; ok &= NearEqual(two * ddf[0], tanpp, eps, eps); ok &= NearEqual(two * ddf[1], tanhpp, eps, eps); ok &= NearEqual(ddw[0], w[0]*tanp + w[1]*tanhp , eps, eps); ok &= NearEqual(ddw[1], w[0]*tanpp + w[1]*tanhpp, eps, eps); // Forward mode computation of sparsity pattern for F. size_t p = n; // user vectorBool because m and n are small CppAD::vectorBool r1(p), s1(m * p); r1[0] = true; // propagate sparsity for x[0] s1 = F.ForSparseJac(p, r1); ok &= (s1[0] == true); // f[0] depends on x[0] ok &= (s1[1] == true); // f[1] depends on x[0] ok &= (s1[2] == false); // f[2] does not depend on x[0] // Reverse mode computation of sparsity pattern for F. size_t q = m; CppAD::vectorBool s2(q * m), r2(q * n); // Sparsity pattern for identity matrix size_t i, j; for(i = 0; i < q; i++) { for(j = 0; j < m; j++) s2[i * q + j] = (i == j); } r2 = F.RevSparseJac(q, s2); ok &= (r2[0] == true); // f[0] depends on x[0] ok &= (r2[1] == true); // f[1] depends on x[0] ok &= (r2[2] == false); // f[2] does not depend on x[0] // Hessian sparsity for f[0] CppAD::vectorBool s3(m), h(p * n); s3[0] = true; s3[1] = false; s3[2] = false; h = F.RevSparseHes(p, s3); ok &= (h[0] == true); // Hessian is non-zero // Hessian sparsity for f[2] s3[0] = false; s3[2] = true; h = F.RevSparseHes(p, s3); ok &= (h[0] == false); // Hessian is zero // check tanh results for a large value of x x[0] = std::numeric_limits<float>::max() / two; f = F.Forward(0, x); tanh = 1.; ok &= NearEqual(f[1], tanh, eps, eps); df = F.Forward(1, dx); tanhp = 0.; ok &= NearEqual(df[1], tanhp, eps, eps); // -------------------------------------------------------------------- // Free all temporary work space associated with old_atomic objects. // (If there are future calls to user atomic functions, they will // create new temporary work space.) CppAD::user_atomic<float>::clear(); return ok; }
/* %$$ $head Use Atomic Function$$ $srccode%cpp% */ bool norm_sq(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; double eps = 10. * CppAD::numeric_limits<double>::epsilon(); /* %$$ $subhead Constructor$$ $srccode%cpp% */ // -------------------------------------------------------------------- // Create the atomic reciprocal object atomic_norm_sq afun("atomic_norm_sq"); /* %$$ $subhead Recording$$ $srccode%cpp% */ // Create the function f(x) // // domain space vector size_t n = 2; double x0 = 0.25; double x1 = 0.75; vector< AD<double> > ax(n); ax[0] = x0; ax[1] = x1; // declare independent variables and start tape recording CppAD::Independent(ax); // range space vector size_t m = 1; vector< AD<double> > ay(m); // call user function and store norm_sq(x) in au[0] afun(ax, ay); // y_0 = x_0 * x_0 + x_1 * x_1 // create f: x -> y and stop tape recording CppAD::ADFun<double> f; f.Dependent (ax, ay); /* %$$ $subhead forward$$ $srccode%cpp% */ // check function value double check = x0 * x0 + x1 * x1; ok &= NearEqual( Value(ay[0]) , check, eps, eps); // check zero order forward mode size_t q; vector<double> x_q(n), y_q(m); q = 0; x_q[0] = x0; x_q[1] = x1; y_q = f.Forward(q, x_q); ok &= NearEqual(y_q[0] , check, eps, eps); // check first order forward mode q = 1; x_q[0] = 0.3; x_q[1] = 0.7; y_q = f.Forward(q, x_q); check = 2.0 * x0 * x_q[0] + 2.0 * x1 * x_q[1]; ok &= NearEqual(y_q[0] , check, eps, eps); /* %$$ $subhead reverse$$ $srccode%cpp% */ // first order reverse mode q = 1; vector<double> w(m), dw(n * q); w[0] = 1.; dw = f.Reverse(q, w); check = 2.0 * x0; ok &= NearEqual(dw[0] , check, eps, eps); check = 2.0 * x1; ok &= NearEqual(dw[1] , check, eps, eps); /* %$$ $subhead for_sparse_jac$$ $srccode%cpp% */ // forward mode sparstiy pattern size_t p = n; CppAD::vectorBool r1(n * p), s1(m * p); r1[0] = true; r1[1] = false; // sparsity pattern identity r1[2] = false; r1[3] = true; // s1 = f.ForSparseJac(p, r1); ok &= s1[0] == true; // f[0] depends on x[0] ok &= s1[1] == true; // f[0] depends on x[1] /* %$$ $subhead rev_sparse_jac$$ $srccode%cpp% */ // reverse mode sparstiy pattern q = m; CppAD::vectorBool s2(q * m), r2(q * n); s2[0] = true; // compute sparsity pattern for f[0] // r2 = f.RevSparseJac(q, s2); ok &= r2[0] == true; // f[0] depends on x[0] ok &= r2[1] == true; // f[0] depends on x[1] /* %$$ $subhead rev_sparse_hes$$ $srccode%cpp% */ // Hessian sparsity (using previous ForSparseJac call) CppAD::vectorBool s3(m), h(p * n); s3[0] = true; // compute sparsity pattern for f[0] // h = f.RevSparseHes(p, s3); ok &= h[0] == true; // partial of f[0] w.r.t. x[0],x[0] is non-zero ok &= h[1] == false; // partial of f[0] w.r.t. x[0],x[1] is zero ok &= h[2] == false; // partial of f[0] w.r.t. x[1],x[0] is zero ok &= h[3] == true; // partial of f[0] w.r.t. x[1],x[1] is non-zero // return ok; }
bool change_param(void) { bool ok = true; // initialize test result typedef CppAD::AD<double> a1type; // for first level of taping typedef CppAD::AD<a1type> a2type; // for second level of taping size_t nu = 3; // number components in u size_t nx = 2; // number components in x size_t ny = 2; // num components in f(x) size_t nJ = ny * nx; // number components in Jacobian of f(x) // temporary indices size_t j; // declare first level of independent variables // (Start taping now so can record dependency of a1f on a1p.) CPPAD_TESTVECTOR(a1type) a1u(nu); for(j = 0; j < nu; j++) a1u[j] = 0.; CppAD::Independent(a1u); // parameter in computation of Jacobian a1type a1p = a1u[2]; // declare second level of independent variables CPPAD_TESTVECTOR(a2type) a2x(nx); for(j = 0; j < nx; j++) a2x[j] = 0.; CppAD::Independent(a2x); // compute dependent variables at second level CPPAD_TESTVECTOR(a2type) a2y(ny); a2y[0] = sin( a2x[0] ) * a1p; a2y[1] = sin( a2x[1] ) * a1p; // declare function object that computes values at the first level // (make sure we do not run zero order forward during constructor) CppAD::ADFun<a1type> a1f; a1f.Dependent(a2x, a2y); // compute the Jacobian of a1f at a1u[0], a1u[1] CPPAD_TESTVECTOR(a1type) a1x(nx); a1x[0] = a1u[0]; a1x[1] = a1u[1]; CPPAD_TESTVECTOR(a1type) a1J(nJ); a1J = a1f.Jacobian( a1x ); // declare function object that maps u = (x, p) to Jacobian of f // (make sure we do not run zero order forward during constructor) CppAD::ADFun<double> g; g.Dependent(a1u, a1J); // remove extra variables used during the reconding of a1f, // but not needed any more. g.optimize(); // compute the Jacobian of f using zero order forward // sweep with double values CPPAD_TESTVECTOR(double) J(nJ), u(nu); for(j = 0; j < nu; j++) u[j] = double(j+1); J = g.Forward(0, u); // accuracy for tests double eps = 100. * CppAD::numeric_limits<double>::epsilon(); // y[0] = sin( x[0] ) * p // y[1] = sin( x[1] ) * p CPPAD_TESTVECTOR(double) x(nx); x[0] = u[0]; x[1] = u[1]; double p = u[2]; // J[0] = partial y[0] w.r.t x[0] = cos( x[0] ) * p double check = cos( x[0] ) * p; ok &= fabs( check - J[0] ) <= eps; // J[1] = partial y[0] w.r.t x[1] = 0.; check = 0.; ok &= fabs( check - J[1] ) <= eps; // J[2] = partial y[1] w.r.t. x[0] = 0. check = 0.; ok &= fabs( check - J[2] ) <= eps; // J[3] = partial y[1] w.r.t x[1] = cos( x[1] ) * p check = cos( x[1] ) * p; ok &= fabs( check - J[3] ) <= eps; return ok; }
bool link_poly( size_t size , size_t repeat , CppAD::vector<double> &a , // coefficients of polynomial CppAD::vector<double> &z , // polynomial argument value CppAD::vector<double> &ddp ) // second derivative w.r.t z { // speed test global option values if( global_atomic ) return false; // ----------------------------------------------------- // setup typedef CppAD::AD<double> ADScalar; typedef CppAD::vector<ADScalar> ADVector; size_t i; // temporary index size_t m = 1; // number of dependent variables size_t n = 1; // number of independent variables ADVector Z(n); // AD domain space vector ADVector P(m); // AD range space vector // choose the polynomial coefficients CppAD::uniform_01(size, a); // AD copy of the polynomial coefficients ADVector A(size); for(i = 0; i < size; i++) A[i] = a[i]; // forward mode first and second differentials CppAD::vector<double> p(1), dp(1), dz(1), ddz(1); dz[0] = 1.; ddz[0] = 0.; // AD function object CppAD::ADFun<double> f; // -------------------------------------------------------------------- if( ! global_onetape ) while(repeat--) { // choose an argument value CppAD::uniform_01(1, z); Z[0] = z[0]; // declare independent variables Independent(Z); // AD computation of the function value P[0] = CppAD::Poly(0, A, Z[0]); // create function object f : A -> detA f.Dependent(Z, P); if( global_optimize ) f.optimize(); // skip comparison operators f.compare_change_count(0); // pre-allocate memory for three forward mode calculations f.capacity_order(3); // evaluate the polynomial p = f.Forward(0, z); // evaluate first order Taylor coefficient dp = f.Forward(1, dz); // second derivative is twice second order Taylor coef ddp = f.Forward(2, ddz); ddp[0] *= 2.; } else { // choose an argument value CppAD::uniform_01(1, z); Z[0] = z[0]; // declare independent variables Independent(Z); // AD computation of the function value P[0] = CppAD::Poly(0, A, Z[0]); // create function object f : A -> detA f.Dependent(Z, P); if( global_optimize ) f.optimize(); // skip comparison operators f.compare_change_count(0); while(repeat--) { // sufficient memory is allocated by second repetition // get the next argument value CppAD::uniform_01(1, z); // evaluate the polynomial at the new argument value p = f.Forward(0, z); // evaluate first order Taylor coefficient dp = f.Forward(1, dz); // second derivative is twice second order Taylor coef ddp = f.Forward(2, ddz); ddp[0] *= 2.; } } return true; }
bool mul_cond_rev(void) { bool ok = true; using CppAD::vector; using CppAD::NearEqual; double eps = 10. * std::numeric_limits<double>::epsilon(); // typedef CppAD::AD<double> a1double; typedef CppAD::AD<a1double> a2double; // a1double a1zero = 0.0; a2double a2zero = a1zero; a1double a1one = 1.0; a2double a2one = a1one; // // -------------------------------------------------------------------- // create a1f = f(x) size_t n = 1; size_t m = 25; // vector<a2double> a2x(n), a2y(m); a2x[0] = a2double( 5.0 ); Independent(a2x); // size_t i = 0; // variable that is greater than one when x[0] is zero // and less than one when x[0] is 1.0 or greater a2double a2switch = a2one / (a2x[0] + a2double(0.5)); // variable that is infinity when x[0] is zero // and a normal number when x[0] is 1.0 or greater a2double a2inf_var = a2one / a2x[0]; // variable that is nan when x[0] is zero // and a normal number when x[0] is 1.0 or greater a2double a2nan_var = ( a2one / a2inf_var ) / a2x[0]; // variable that is one when x[0] is zero // and less then one when x[0] is 1.0 or greater a2double a2one_var = a2one / ( a2one + a2x[0] ); // div a2y[i++] = CondExpGt(a2x[0], a2zero, a2nan_var, a2zero); // abs a2y[i++] = CondExpGt(a2x[0], a2zero, abs( a2y[0] ), a2zero); // add a2y[i++] = CondExpGt(a2x[0], a2zero, a2nan_var + a2nan_var, a2zero); // acos a2y[i++] = CondExpGt(a2x[0], a2zero, acos(a2switch), a2zero); // asin a2y[i++] = CondExpGt(a2x[0], a2zero, asin(a2switch), a2zero); // atan a2y[i++] = CondExpGt(a2x[0], a2zero, atan(a2nan_var), a2zero); // cos a2y[i++] = CondExpGt(a2x[0], a2zero, cos(a2nan_var), a2zero); // cosh a2y[i++] = CondExpGt(a2x[0], a2zero, cosh(a2nan_var), a2zero); // exp a2y[i++] = CondExpGt(a2x[0], a2zero, exp(a2nan_var), a2zero); // log a2y[i++] = CondExpGt(a2x[0], a2zero, log(a2x[0]), a2zero); // mul a2y[i++] = CondExpGt(a2x[0], a2zero, a2x[0] * a2inf_var, a2zero); // pow a2y[i++] = CondExpGt(a2x[0], a2zero, pow(a2inf_var, a2x[0]), a2zero); // sin a2y[i++] = CondExpGt(a2x[0], a2zero, sin(a2nan_var), a2zero); // sinh a2y[i++] = CondExpGt(a2x[0], a2zero, sinh(a2nan_var), a2zero); // sqrt a2y[i++] = CondExpGt(a2x[0], a2zero, sqrt(a2x[0]), a2zero); // sub a2y[i++] = CondExpGt(a2x[0], a2zero, a2inf_var - a2nan_var, a2zero); // tan a2y[i++] = CondExpGt(a2x[0], a2zero, tan(a2nan_var), a2zero); // tanh a2y[i++] = CondExpGt(a2x[0], a2zero, tanh(a2nan_var), a2zero); // azmul a2y[i++] = CondExpGt(a2x[0], a2zero, azmul(a2x[0], a2inf_var), a2zero); // // Operations that are C+11 atomic // // acosh a2y[i++] = CondExpGt(a2x[0], a2zero, acosh( a2x[0] ), a2zero); // asinh a2y[i++] = CondExpGt(a2x[0], a2zero, asinh( a2nan_var ), a2zero); // atanh a2y[i++] = CondExpGt(a2x[0], a2zero, atanh( a2one_var ), a2zero); // erf a2y[i++] = CondExpGt(a2x[0], a2zero, erf( a2nan_var ), a2zero); // expm1 a2y[i++] = CondExpGt(a2x[0], a2zero, expm1(a2nan_var), a2zero); // log1p a2y[i++] = CondExpGt(a2x[0], a2zero, log1p(- a2one_var ), a2zero); // ok &= i == m; CppAD::ADFun<a1double> a1f; a1f.Dependent(a2x, a2y); // -------------------------------------------------------------------- // create h = f(x) vector<a1double> a1x(n), a1y(m); a1x[0] = 5.0; // Independent(a1x); i = 0; a1double a1switch = a1one / (a1x[0] + a1double(0.5)); a1double a1inf_var = a1one / a1x[0]; a1double a1nan_var = ( a1one / a1inf_var ) / a1x[0]; a1double a1one_var = a1one / ( a1one + a1x[0] ); // div a1y[i++] = CondExpGt(a1x[0], a1zero, a1nan_var, a1zero); // abs a1y[i++] = CondExpGt(a1x[0], a1zero, abs( a1y[0] ), a1zero); // add a1y[i++] = CondExpGt(a1x[0], a1zero, a1nan_var + a1nan_var, a1zero); // acos a1y[i++] = CondExpGt(a1x[0], a1zero, acos(a1switch), a1zero); // asin a1y[i++] = CondExpGt(a1x[0], a1zero, asin(a1switch), a1zero); // atan a1y[i++] = CondExpGt(a1x[0], a1zero, atan(a1nan_var), a1zero); // cos a1y[i++] = CondExpGt(a1x[0], a1zero, cos(a1nan_var), a1zero); // cosh a1y[i++] = CondExpGt(a1x[0], a1zero, cosh(a1nan_var), a1zero); // exp a1y[i++] = CondExpGt(a1x[0], a1zero, exp(a1nan_var), a1zero); // log a1y[i++] = CondExpGt(a1x[0], a1zero, log(a1x[0]), a1zero); // mul a1y[i++] = CondExpGt(a1x[0], a1zero, a1x[0] * a1inf_var, a1zero); // pow a1y[i++] = CondExpGt(a1x[0], a1zero, pow(a1inf_var, a1x[0]), a1zero); // sin a1y[i++] = CondExpGt(a1x[0], a1zero, sin(a1nan_var), a1zero); // sinh a1y[i++] = CondExpGt(a1x[0], a1zero, sinh(a1nan_var), a1zero); // sqrt a1y[i++] = CondExpGt(a1x[0], a1zero, sqrt(a1x[0]), a1zero); // sub a1y[i++] = CondExpGt(a1x[0], a1zero, a1inf_var - a1nan_var, a1zero); // tan a1y[i++] = CondExpGt(a1x[0], a1zero, tan(a1nan_var), a1zero); // tanh a1y[i++] = CondExpGt(a1x[0], a1zero, tanh(a1nan_var), a1zero); // azmul a1y[i++] = CondExpGt(a1x[0], a1zero, azmul(a1x[0], a1inf_var), a1zero); // // Operations that are C+11 atomic // // acosh a1y[i++] = CondExpGt(a1x[0], a1zero, acosh( a1x[0] ), a1zero); // asinh a1y[i++] = CondExpGt(a1x[0], a1zero, asinh( a1nan_var ), a1zero); // atanh a1y[i++] = CondExpGt(a1x[0], a1zero, atanh( a1one_var ), a1zero); // erf a1y[i++] = CondExpGt(a1x[0], a1zero, erf( a1nan_var ), a1zero); // expm1 a1y[i++] = CondExpGt(a1x[0], a1zero, expm1(a1nan_var), a1zero); // log1p a1y[i++] = CondExpGt(a1x[0], a1zero, log1p(- a1one_var ), a1zero); // ok &= i == m; CppAD::ADFun<double> h; h.Dependent(a1x, a1y); // -------------------------------------------------------------------- // create g = f'(x) vector<a1double> a1dy(m), a1w(m); a1x[0] = 2.0; for(i = 0; i < m; i++) a1w[i] = 0.0; // Independent(a1x); a1f.Forward(0, a1x); // for(i = 0; i < m; i++) { a1w[i] = 1.0; vector<a1double> dyi_dx = a1f.Reverse(1, a1w); a1dy[i] = dyi_dx[0]; a1w[i] = 0.0; } CppAD::ADFun<double> g; // g uses reverse mode derivatives g.Dependent(a1x, a1dy); // -------------------------------------------------------------------- // check case where x[0] > 0 vector<double> x(1), dx(1), dg(m), dh(m); x[0] = 2.0; dx[0] = 1.0; h.Forward(0, x); dh = h.Forward(1, dx); // dh uses forward mode derivatives dg = g.Forward(0, x); for(i = 0; i < m; i++) ok &= NearEqual(dg[i], dh[i], eps, eps); // -------------------------------------------------------------------- // check case where x[0] = 0 x[0] = 0.0; dg = g.Forward(0, x); h.Forward(0, x); dh = h.Forward(1, dx); for(i = 0; i < m; i++) { ok &= dg[i] == 0.0; ok &= dh[i] == 0.0; } // -------------------------------------------------------------------- return ok; }
bool old_mat_mul(void) { bool ok = true; using CppAD::AD; // matrix sizes for this test size_t nr_result = 2; size_t n_middle = 2; size_t nc_result = 2; // declare the AD<double> vectors ax and ay and X size_t n = nr_result * n_middle + n_middle * nc_result; size_t m = nr_result * nc_result; CppAD::vector< AD<double> > X(4), ax(n), ay(m); size_t i, j; for(j = 0; j < X.size(); j++) X[j] = (j + 1); // X is the vector of independent variables CppAD::Independent(X); // left matrix ax[0] = X[0]; // left[0,0] = x[0] = 1 ax[1] = X[1]; // left[0,1] = x[1] = 2 ax[2] = 5.; // left[1,0] = 5 ax[3] = 6.; // left[1,1] = 6 // right matrix ax[4] = X[2]; // right[0,0] = x[2] = 3 ax[5] = 7.; // right[0,1] = 7 ax[6] = X[3]; // right[1,0] = x[3] = 4 ax[7] = 8.; // right[1,1] = 8 /* [ x0 , x1 ] * [ x2 , 7 ] = [ x0*x2 + x1*x3 , x0*7 + x1*8 ] [ 5 , 6 ] [ x3 , 8 ] [ 5*x2 + 6*x3 , 5*7 + 6*8 ] */ // The call back routines need to know the dimensions of the matrices. // Store information about the matrix multiply for this call to mat_mul. call_info info; info.nr_result = nr_result; info.n_middle = n_middle; info.nc_result = nc_result; // info.vx gets set by forward during call to mat_mul below assert( info.vx.size() == 0 ); size_t id = info_.size(); info_.push_back(info); // user defined AD<double> version of matrix multiply mat_mul(id, ax, ay); //---------------------------------------------------------------------- // check AD<double> results ok &= ay[0] == (1*3 + 2*4); ok &= Variable( ay[0] ); ok &= ay[1] == (1*7 + 2*8); ok &= Variable( ay[1] ); ok &= ay[2] == (5*3 + 6*4); ok &= Variable( ay[2] ); ok &= ay[3] == (5*7 + 6*8); ok &= Parameter( ay[3] ); //---------------------------------------------------------------------- // use mat_mul to define a function g : X -> ay CppAD::ADFun<double> G; G.Dependent(X, ay); // g(x) = [ x0*x2 + x1*x3 , x0*7 + x1*8 , 5*x2 + 6*x3 , 5*7 + 6*8 ]^T //---------------------------------------------------------------------- // Test zero order forward mode evaluation of g(x) CppAD::vector<double> x( X.size() ), y(m); for(j = 0; j < X.size() ; j++) x[j] = j + 2; y = G.Forward(0, x); ok &= y[0] == x[0] * x[2] + x[1] * x[3]; ok &= y[1] == x[0] * 7. + x[1] * 8.; ok &= y[2] == 5. * x[2] + 6. * x[3]; ok &= y[3] == 5. * 7. + 6. * 8.; //---------------------------------------------------------------------- // Test first order forward mode evaluation of g'(x) * [1, 2, 3, 4]^T // g'(x) = [ x2, x3, x0, x1 ] // [ 7 , 8, 0, 0 ] // [ 0 , 0, 5, 6 ] // [ 0 , 0, 0, 0 ] CppAD::vector<double> dx( X.size() ), dy(m); for(j = 0; j < X.size() ; j++) dx[j] = j + 1; dy = G.Forward(1, dx); ok &= dy[0] == 1. * x[2] + 2. * x[3] + 3. * x[0] + 4. * x[1]; ok &= dy[1] == 1. * 7. + 2. * 8. + 3. * 0. + 4. * 0.; ok &= dy[2] == 1. * 0. + 2. * 0. + 3. * 5. + 4. * 6.; ok &= dy[3] == 1. * 0. + 2. * 0. + 3. * 0. + 4. * 0.; //---------------------------------------------------------------------- // Test second order forward mode // g_0^2 (x) = [ 0, 0, 1, 0 ], g_0^2 (x) * [1] = [3] // [ 0, 0, 0, 1 ] [2] [4] // [ 1, 0, 0, 0 ] [3] [1] // [ 0, 1, 0, 0 ] [4] [2] CppAD::vector<double> ddx( X.size() ), ddy(m); for(j = 0; j < X.size() ; j++) ddx[j] = 0.; ddy = G.Forward(2, ddx); // [1, 2, 3, 4] * g_0^2 (x) * [1, 2, 3, 4]^T = 1*3 + 2*4 + 3*1 + 4*2 ok &= 2. * ddy[0] == 1. * 3. + 2. * 4. + 3. * 1. + 4. * 2.; // for i > 0, [1, 2, 3, 4] * g_i^2 (x) * [1, 2, 3, 4]^T = 0 ok &= ddy[1] == 0.; ok &= ddy[2] == 0.; ok &= ddy[3] == 0.; //---------------------------------------------------------------------- // Test second order reverse mode CppAD::vector<double> w(m), dw(2 * X.size() ); for(i = 0; i < m; i++) w[i] = 0.; w[0] = 1.; dw = G.Reverse(2, w); // g_0'(x) = [ x2, x3, x0, x1 ] ok &= dw[0*2 + 0] == x[2]; ok &= dw[1*2 + 0] == x[3]; ok &= dw[2*2 + 0] == x[0]; ok &= dw[3*2 + 0] == x[1]; // g_0'(x) * [1, 2, 3, 4] = 1 * x2 + 2 * x3 + 3 * x0 + 4 * x1 // g_0^2 (x) * [1, 2, 3, 4] = [3, 4, 1, 2] ok &= dw[0*2 + 1] == 3.; ok &= dw[1*2 + 1] == 4.; ok &= dw[2*2 + 1] == 1.; ok &= dw[3*2 + 1] == 2.; //---------------------------------------------------------------------- // Test forward and reverse Jacobian sparsity pattern /* [ x0 , x1 ] * [ x2 , 7 ] = [ x0*x2 + x1*x3 , x0*7 + x1*8 ] [ 5 , 6 ] [ x3 , 8 ] [ 5*x2 + 6*x3 , 5*7 + 6*8 ] so the sparsity pattern should be s[0] = {0, 1, 2, 3} s[1] = {0, 1} s[2] = {2, 3} s[3] = {} */ CppAD::vector< std::set<size_t> > r( X.size() ), s(m); for(j = 0; j < X.size() ; j++) { assert( r[j].empty() ); r[j].insert(j); } s = G.ForSparseJac( X.size() , r); for(j = 0; j < X.size() ; j++) { // s[0] = {0, 1, 2, 3} ok &= s[0].find(j) != s[0].end(); // s[1] = {0, 1} if( j == 0 || j == 1 ) ok &= s[1].find(j) != s[1].end(); else ok &= s[1].find(j) == s[1].end(); // s[2] = {2, 3} if( j == 2 || j == 3 ) ok &= s[2].find(j) != s[2].end(); else ok &= s[2].find(j) == s[2].end(); } // s[3] == {} ok &= s[3].empty(); //---------------------------------------------------------------------- // Test reverse Jacobian sparsity pattern /* [ x0 , x1 ] * [ x2 , 7 ] = [ x0*x2 + x1*x3 , x0*7 + x1*8 ] [ 5 , 6 ] [ x3 , 8 ] [ 5*x2 + 6*x3 , 5*7 + 6*8 ] so the sparsity pattern should be r[0] = {0, 1, 2, 3} r[1] = {0, 1} r[2] = {2, 3} r[3] = {} */ for(i = 0; i < m; i++) { s[i].clear(); s[i].insert(i); } r = G.RevSparseJac(m, s); for(j = 0; j < X.size() ; j++) { // r[0] = {0, 1, 2, 3} ok &= r[0].find(j) != r[0].end(); // r[1] = {0, 1} if( j == 0 || j == 1 ) ok &= r[1].find(j) != r[1].end(); else ok &= r[1].find(j) == r[1].end(); // r[2] = {2, 3} if( j == 2 || j == 3 ) ok &= r[2].find(j) != r[2].end(); else ok &= r[2].find(j) == r[2].end(); } // r[3] == {} ok &= r[3].empty(); //---------------------------------------------------------------------- /* Test reverse Hessian sparsity pattern g_0^2 (x) = [ 0, 0, 1, 0 ] and for i > 0, g_i^2 = 0 [ 0, 0, 0, 1 ] [ 1, 0, 0, 0 ] [ 0, 1, 0, 0 ] so for the sparsity pattern for the first component of g is h[0] = {2} h[1] = {3} h[2] = {0} h[3] = {1} */ CppAD::vector< std::set<size_t> > h( X.size() ), t(1); t[0].clear(); t[0].insert(0); h = G.RevSparseHes(X.size() , t); size_t check[] = {2, 3, 0, 1}; for(j = 0; j < X.size() ; j++) { // h[j] = { check[j] } for(i = 0; i < n; i++) { if( i == check[j] ) ok &= h[j].find(i) != h[j].end(); else ok &= h[j].find(i) == h[j].end(); } } t[0].clear(); for( j = 1; j < X.size(); j++) t[0].insert(j); h = G.RevSparseHes(X.size() , t); for(j = 0; j < X.size() ; j++) { // h[j] = { } for(i = 0; i < X.size(); i++) ok &= h[j].find(i) == h[j].end(); } // -------------------------------------------------------------------- // Free temporary work space. (If there are future calls to // old_mat_mul they would create new temporary work space.) CppAD::user_atomic<double>::clear(); info_.clear(); return ok; }
bool link_det_minor( size_t size , size_t repeat , CppAD::vector<double> &matrix , CppAD::vector<double> &gradient ) { // ----------------------------------------------------- // setup // object for computing determinant typedef CppAD::AD<double> ADScalar; typedef CppAD::vector<ADScalar> ADVector; CppAD::det_by_minor<ADScalar> Det(size); size_t i; // temporary index size_t m = 1; // number of dependent variables size_t n = size * size; // number of independent variables ADVector A(n); // AD domain space vector ADVector detA(m); // AD range space vector // vectors of reverse mode weights CppAD::vector<double> w(1); w[0] = 1.; // the AD function object CppAD::ADFun<double> f; static bool printed = false; bool print_this_time = (! printed) & (repeat > 1) & (size >= 3); extern bool global_retape; if( global_retape ) while(repeat--) { // choose a matrix CppAD::uniform_01(n, matrix); for( i = 0; i < size * size; i++) A[i] = matrix[i]; // declare independent variables Independent(A); // AD computation of the determinant detA[0] = Det(A); // create function object f : A -> detA f.Dependent(A, detA); extern bool global_optimize; if( global_optimize ) { size_t before, after; before = f.size_var(); f.optimize(); if( print_this_time ) { after = f.size_var(); std::cout << "cppad_det_minor_optimize_size_" << int(size) << " = [ " << int(before) << ", " << int(after) << "]" << std::endl; printed = true; print_this_time = false; } } // get the next matrix CppAD::uniform_01(n, matrix); // evaluate the determinant at the new matrix value f.Forward(0, matrix); // evaluate and return gradient using reverse mode gradient = f.Reverse(1, w); } else { // choose a matrix CppAD::uniform_01(n, matrix); for( i = 0; i < size * size; i++) A[i] = matrix[i]; // declare independent variables Independent(A); // AD computation of the determinant detA[0] = Det(A); // create function object f : A -> detA CppAD::ADFun<double> f; f.Dependent(A, detA); extern bool global_optimize; if( global_optimize ) { size_t before, after; before = f.size_var(); f.optimize(); if( print_this_time ) { after = f.size_var(); std::cout << "optimize: size = " << size << ": size_var() = " << before << "(before) " << after << "(after) " << std::endl; printed = true; print_this_time = false; } } // ------------------------------------------------------ while(repeat--) { // get the next matrix CppAD::uniform_01(n, matrix); // evaluate the determinant at the new matrix value f.Forward(0, matrix); // evaluate and return gradient using reverse mode gradient = f.Reverse(1, w); } } return true; }
/* %$$ $head Use Atomic Function$$ $srccode%cpp% */ bool forward(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; double eps = 10. * CppAD::numeric_limits<double>::epsilon(); // // Create the atomic_forward object corresponding to g(x) atomic_forward afun("atomic_forward"); // // Create the function f(u) = g(u) for this example. // // domain space vector size_t n = 3; double u_0 = 1.00; double u_1 = 2.00; double u_2 = 3.00; vector< AD<double> > au(n); au[0] = u_0; au[1] = u_1; au[2] = u_2; // declare independent variables and start tape recording CppAD::Independent(au); // range space vector size_t m = 2; vector< AD<double> > ay(m); // call atomic function vector< AD<double> > ax = au; afun(ax, ay); // create f: u -> y and stop tape recording CppAD::ADFun<double> f; f.Dependent (au, ay); // y = f(u) // // check function value double check = u_2 * u_2; ok &= NearEqual( Value(ay[0]) , check, eps, eps); check = u_0 * u_1; ok &= NearEqual( Value(ay[1]) , check, eps, eps); // -------------------------------------------------------------------- // zero order forward // vector<double> u0(n), y0(m); u0[0] = u_0; u0[1] = u_1; u0[2] = u_2; y0 = f.Forward(0, u0); check = u_2 * u_2; ok &= NearEqual(y0[0] , check, eps, eps); check = u_0 * u_1; ok &= NearEqual(y0[1] , check, eps, eps); // -------------------------------------------------------------------- // first order forward // // value of Jacobian of f double check_jac[] = { 0.0, 0.0, 2.0 * u_2, u_1, u_0, 0.0 }; vector<double> u1(n), y1(m); // check first order forward mode for(size_t j = 0; j < n; j++) u1[j] = 0.0; for(size_t j = 0; j < n; j++) { // compute partial in j-th component direction u1[j] = 1.0; y1 = f.Forward(1, u1); u1[j] = 0.0; // check this direction for(size_t i = 0; i < m; i++) ok &= NearEqual(y1[i], check_jac[i * n + j], eps, eps); } // -------------------------------------------------------------------- // second order forward // // value of Hessian of g_0 double check_hes_0[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0 }; // // value of Hessian of g_1 double check_hes_1[] = { 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; vector<double> u2(n), y2(m); for(size_t j = 0; j < n; j++) u2[j] = 0.0; // compute diagonal elements of the Hessian for(size_t j = 0; j < n; j++) { // first order forward in j-th direction u1[j] = 1.0; f.Forward(1, u1); y2 = f.Forward(2, u2); // check this element of Hessian diagonal ok &= NearEqual(y2[0], check_hes_0[j * n + j] / 2.0, eps, eps); ok &= NearEqual(y2[1], check_hes_1[j * n + j] / 2.0, eps, eps); // for(size_t k = 0; k < n; k++) if( k != j ) { u1[k] = 1.0; f.Forward(1, u1); y2 = f.Forward(2, u2); // // y2 = (H_jj + H_kk + H_jk + H_kj) / 2.0 // y2 = (H_jj + H_kk) / 2.0 + H_jk // double H_jj = check_hes_0[j * n + j]; double H_kk = check_hes_0[k * n + k]; double H_jk = y2[0] - (H_kk + H_jj) / 2.0; ok &= NearEqual(H_jk, check_hes_0[j * n + k], eps, eps); // H_jj = check_hes_1[j * n + j]; H_kk = check_hes_1[k * n + k]; H_jk = y2[1] - (H_kk + H_jj) / 2.0; ok &= NearEqual(H_jk, check_hes_1[j * n + k], eps, eps); // u1[k] = 0.0; } u1[j] = 0.0; } // -------------------------------------------------------------------- return ok; }
bool base2ad(void) { bool ok = true; using CppAD::NearEqual; double eps = 10. * CppAD::numeric_limits<double>::epsilon(); // // Create the atomic base2ad object atomic_base2ad afun("atomic_base2ad"); // // Create the function f(x) = 1 / g(x) = x // size_t n = 1; double x0 = 0.5; vector< AD<double> > ax(n); ax[0] = x0; // declare independent variables and start tape recording CppAD::Independent(ax); // range space vector size_t m = 1; vector< AD<double> > av(m); // call atomic function and store g(x) in au[0] vector< AD<double> > au(m); afun(ax, au); // u = 1 / x // now use AD division to invert to invert the operation av[0] = 1.0 / au[0]; // v = 1 / u = x // create f: x -> y and stop tape recording CppAD::ADFun<double> f; f.Dependent (ax, av); // g(x) = x // check function value double check = x0; ok &= NearEqual( Value(av[0]) , check, eps, eps); // check zero order forward mode size_t q; vector<double> x_q(n), v_q(m); q = 0; x_q[0] = x0; v_q = f.Forward(q, x_q); ok &= NearEqual(v_q[0] , check, eps, eps); // check first order reverse vector<double> dw(n), w(m); w[0] = 1.0; dw = f.Reverse(q+1, w); check = 1.0; ok &= NearEqual(dw[0] , check, eps, eps); // create ag : x -> y CppAD::ADFun< AD<double> , double > af; af = f.base2ad(); // check zero order forward mode vector< AD<double> > ax_q(n), av_q(m); q = 0; ax_q[0] = x0; av_q = af.Forward(q, ax_q); check = x0; ok &= NearEqual( Value(av_q[0]) , check, eps, eps); // check first order reverse vector< AD<double> > adw(n), aw(m); aw[0] = 1.0; adw = af.Reverse(q+1, aw); check = 1.0; ok &= NearEqual( Value(adw[0]) , check, eps, eps); return ok; }
bool fun_assign(void) { bool ok = true; using CppAD::AD; using CppAD::NearEqual; size_t i, j; // ten times machine percision double eps = 10. * CppAD::numeric_limits<double>::epsilon(); // two ADFun<double> objects CppAD::ADFun<double> g; // domain space vector size_t n = 3; CPPAD_TESTVECTOR(AD<double>) x(n); for(j = 0; j < n; j++) x[j] = AD<double>(j + 2); // declare independent variables and start tape recording CppAD::Independent(x); // range space vector size_t m = 2; CPPAD_TESTVECTOR(AD<double>) y(m); y[0] = x[0] + x[0] * x[1]; y[1] = x[1] * x[2] + x[2]; // Store operation sequence, and order zero forward results, in f. CppAD::ADFun<double> f(x, y); // sparsity pattern for the identity matrix CPPAD_TESTVECTOR(std::set<size_t>) r(n); for(j = 0; j < n; j++) r[j].insert(j); // Store forward mode sparsity pattern in f f.ForSparseJac(n, r); // make a copy in g g = f; // check values that should be equal ok &= ( g.size_order() == f.size_order() ); ok &= ( g.size_forward_bool() == f.size_forward_bool() ); ok &= ( g.size_forward_set() == f.size_forward_set() ); // Use zero order Taylor coefficient from f for first order // calculation using g. CPPAD_TESTVECTOR(double) dx(n), dy(m); for(i = 0; i < n; i++) dx[i] = 0.; dx[1] = 1; dy = g.Forward(1, dx); ok &= NearEqual(dy[0], x[0], eps, eps); // partial y[0] w.r.t x[1] ok &= NearEqual(dy[1], x[2], eps, eps); // partial y[1] w.r.t x[1] // Use forward Jacobian sparsity pattern from f to calculate // Hessian sparsity pattern using g. CPPAD_TESTVECTOR(std::set<size_t>) s(1), h(n); s[0].insert(0); // Compute sparsity pattern for Hessian of y[0] h = f.RevSparseHes(n, s); // check sparsity pattern for Hessian of y[0] = x[0] + x[0] * x[1] ok &= ( h[0].find(0) == h[0].end() ); // zero w.r.t x[0], x[0] ok &= ( h[0].find(1) != h[0].end() ); // non-zero w.r.t x[0], x[1] ok &= ( h[0].find(2) == h[0].end() ); // zero w.r.t x[0], x[2] ok &= ( h[1].find(0) != h[1].end() ); // non-zero w.r.t x[1], x[0] ok &= ( h[1].find(1) == h[1].end() ); // zero w.r.t x[1], x[1] ok &= ( h[1].find(2) == h[1].end() ); // zero w.r.t x[1], x[2] ok &= ( h[2].find(0) == h[2].end() ); // zero w.r.t x[2], x[0] ok &= ( h[2].find(1) == h[2].end() ); // zero w.r.t x[2], x[1] ok &= ( h[2].find(2) == h[2].end() ); // zero w.r.t x[2], x[2] return ok; }
bool link_det_minor( size_t size , size_t repeat , CppAD::vector<double> &matrix , CppAD::vector<double> &gradient ) { // speed test global option values if( global_option["atomic"] ) return false; // ----------------------------------------------------- // setup // object for computing determinant typedef CppAD::AD<double> ADScalar; typedef CppAD::vector<ADScalar> ADVector; CppAD::det_by_minor<ADScalar> Det(size); size_t i; // temporary index size_t m = 1; // number of dependent variables size_t n = size * size; // number of independent variables ADVector A(n); // AD domain space vector ADVector detA(m); // AD range space vector // vectors of reverse mode weights CppAD::vector<double> w(1); w[0] = 1.; // the AD function object CppAD::ADFun<double> f; // --------------------------------------------------------------------- if( ! global_option["onetape"] ) while(repeat--) { // choose a matrix CppAD::uniform_01(n, matrix); for( i = 0; i < size * size; i++) A[i] = matrix[i]; // declare independent variables Independent(A); // AD computation of the determinant detA[0] = Det(A); // create function object f : A -> detA f.Dependent(A, detA); if( global_option["optimize"] ) f.optimize(); // skip comparison operators f.compare_change_count(0); // evaluate the determinant at the new matrix value f.Forward(0, matrix); // evaluate and return gradient using reverse mode gradient = f.Reverse(1, w); } else { // choose a matrix CppAD::uniform_01(n, matrix); for( i = 0; i < size * size; i++) A[i] = matrix[i]; // declare independent variables Independent(A); // AD computation of the determinant detA[0] = Det(A); // create function object f : A -> detA f.Dependent(A, detA); if( global_option["optimize"] ) f.optimize(); // skip comparison operators f.compare_change_count(0); // ------------------------------------------------------ while(repeat--) { // get the next matrix CppAD::uniform_01(n, matrix); // evaluate the determinant at the new matrix value f.Forward(0, matrix); // evaluate and return gradient using reverse mode gradient = f.Reverse(1, w); } } return true; }